【问题标题】:Symbol Table Design and Implementation in RubyRuby中的符号表设计与实现
【发布时间】:2012-01-26 01:20:36
【问题描述】:

我正在用 Ruby 构建一个词法分析器,并且即将开始在符号表中收集和存储符号。我的主要问题是关于符号的设计,以及它是否应该是静态表(意味着所有数据都将保存在类级别)还是应该基于实例。

选项 1:类级数据结构

require 'SymbolTableEntry.rb'

class SymbolTable
  @sym_table = Array.new(500)
  def initialize()
  end

  def SymbolTable.add(element, index)
    @sym_table[index] = element if element.is_a? SymbolTableEntry
  end

  def SymbolTable.to_s
    pp @sym_table
  end
end

使用这种方案,SymbolTable 类具有某种“静态”功能,这意味着我实际上并没有创建 SymbolTable 的实例,唯一存在的对象是类级别的对象。

(假设SymbolTableEntry 是一个有效的对象,即使我没有在这里定义它)

例如:

irb(main):002:0> require 'SymbolTable.rb'
=> true

irb(main):003:0> ste = SymbolTableEntry.new
=> #<SymbolTableEntry:0x7ef36884>

irb(main):004:0> SymbolTable.add(ste, 10)
=> #<SymbolTableEntry:0x7ef36884>

irb(main):005:0> SymbolTable.to_s
[nil,
 nil,
 nil,
 nil,
 nil,
 nil,
 nil,
 nil,
 nil,
 nil,
 #<SymbolTableEntry:0x7ef36884>]
=> nil

选项 2:实例级数据结构

require 'rubygems'
require 'backports'
require 'SymbolTableEntry.rb'

class SymbolTable
  def initialize()
    @sym_table = Array.new(10)
  end

  def add(element, index)
    @sym_table[index] = element if element.is_a? SymbolTableEntry
  end

  def to_s
    pp @sym_table
  end
end

使用这个方案,我实际上需要实例化 SymbolTable 类的一个实例,以便将值添加到符号表中。

irb(main):001:0> require 'SymbolTable.rb'
=> true

irb(main):002:0> st = SymbolTable.new
=> #<SymbolTable:0x7eeb6c9c @sym_table=[nil, nil, nil, nil, nil, 
                                        nil, nil, nil, nil, nil]>

irb(main):003:0> ste=SymbolTableEntry.new
=> #<SymbolTableEntry:0x7eeb4d5c>

irb(main):004:0> st.add(ste,10)
=> #<SymbolTableEntry:0x7eeb4d5c>

irb(main):007:0> st.to_s
[nil,
 nil,
 nil,
 nil,
 nil,
 nil,
 nil,
 nil,
 nil,
 nil,
 #<SymbolTableEntry:0x7eeb4d5c>]
=> nil

我很想听听关于您将使用或更喜欢使用哪种设计的任何和所有意见,以及关于 ruby​​ 代码的任何 cmets。

谢谢

【问题讨论】:

    标签: ruby symbol-tables symbol-table


    【解决方案1】:

    优先考虑实例变量而不是类变量,如果没有其他原因,使用类变量的类对单元测试有点痛苦。

    您可以使用实例变量,但仍然有一个符号表来统治它们。一种方法是将符号表分配给全局变量:

    $symbol_table = SymbolTable.new
    

    在某些语言中,使用全局变量的类很难测试。在 Ruby 中,它们并没有那么糟糕,因为鸭子类型允许您在执行被测对象之前将模拟对象分配给全局变量。

    或者,您可以使用单例模式。 Ruby 附带了一个库来简化此操作:

    require 'singleton'
    class SymbolTable
      include Singleton
      ...
    end
    

    要检索 SymbolTable 的唯一实例,如果需要,请创建它:

    SymbolTable.instance
    

    【讨论】:

    • 谢谢,这很有帮助。
    • 我认为 Singleton 绝对是要走的路,因为在整个编译过程中我肯定只需要 SymbolTable 的 1 个实例。谢谢
    【解决方案2】:

    使用实例变量。但不是(至少不仅是)出于测试处理的原因。而是因为

    • 每个解析过程都会生成自己的符号表,因此您一次可能有多个符号表
    • 只有在解析过程正在进行时才需要符号表
    • 类变量引入了进行同步以实现线程安全的必要性——即使每个解析进程都可以使用自己的一组符号完美地运行

    干杯

    罗伯特

    【讨论】:

    • 总体目标是构建一个功能正常的编译器,它一次只能编译一个源文件。但这是实例变量的一个很好的论据。谢谢。
    • 即使您一次只需要编译一个文件,这里也不需要全局变量。相反,编译状态很容易在编译过程中幸存下来,并且在内存中毫无用处。另外,如果您决定可以并行进行多个编译,这似乎并不不切实际。
    【解决方案3】:

    快速澄清一下 Robert 和 Wayne 给出的几个答案,他们都提到了类变量

    最初的问题根本不建议使用类变量,但确实询问了使用类实例变量。 Hunter 提出的第一个选择使用类对象本身作为符号表的单个实例(状态存储在类实例变量中),而第二个选项使用更典型的类/实例框架,状态存储在 Symbol 的实例中表。

    Ruby 的类变量与类实例变量不同,一般应避免使用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-31
      • 2013-10-10
      • 1970-01-01
      • 2012-03-31
      • 1970-01-01
      • 1970-01-01
      • 2022-11-24
      • 2014-06-30
      相关资源
      最近更新 更多