How To Build a Yacc?(10)

将Vocab和Rule功能组合起来作为一个RuleParser类来提供分析rule_file的功能是个不错的主意,因为对这两个类而言并没有太大的重用的意义,只不过是为了将错误的出现尽可能的控制在局部。

class TestCompiler < Test::Unit::TestCase 
  def test_rule_parser
    create_rule_file
    p = RuleParser.new("rulefile")
    assert(p.rules[0].lt == "nil")
    assert(p.rules[0].rt == ["function_decl"])
    assert(p.vocabs.identify("function") == Vocab::TERMINAL)
  end
end


有了Vocab和Rule,实现RuleParser只是举手之劳。

class RuleParser
  def initialize(file_name)
    @vocabs = Vocab.new
    @rules = Array.new
    compile(file_name)
  end
 
  @@directive = 0
  DIRECTIVE = "%%"
 
  ####################################################
  # 对于 yacc的输入规则文件进行解析
  # 将文件中定义的token和rule分别存入@vocabs, @rules
  # 定义文件分两段:
  # %%
  #  {第一段:token definition}
  # %%
  #  {第二段:rule definition}
  # %%
  ####################################################
  def compile(file_name)
    file = File.open(file_name, "r")
    no = 0
    begin
    file.each do |line|
      no = no+1
      if line.strip().chomp() == DIRECTIVE
         @@directive = @@directive + 1
         next
      end
     
      # @@directive == 0 not started, continue
      # @@directive == 1 start parse terminals
      # @@directive == 2 start parse rules
      # @@directive == 3 end parse     
      case @@directive
        when 0
          next
        when 1
          if !add_terminal(line)
            error(no, line, "parse terminal error")
          end
        when 2
          rule = parse_rule(line)         
          if !rule
            error(no, line, "parse nonterminal error")
          end
          add_nonterminal(rule)
        when 3
         break
      end # end when
    end # end for each
   
    rescue
      raise
    ensure
      file.close()
    end # end begin...
   
  end
 
  def add_terminal(line)
    @vocabs.add_terminal(line)   
  end
 
  def add_nonterminal(rule)
    @vocabs.add_nonterminals(rule.vocabs())
  end
 
  def parse_rule(line)
    rule = Rule.parse(line)
    @rules.push(rule)
    return rule
  end 
   
  def error(no, line, msg)
    raise "Error #{msg} in Line #{no}, #{line}."
  end
 
  private :error
  attr_reader :rules, :vocabs
end



实际上,对RuleParser的test case的设计,无意中凸显了一个事实,那就是应该将RuleParser设计为一个interface, 对外提供至少两个方法:get_rules(分析rule_file得到的rule集合);get_vocabs(分析rule_file得到的vocab集合)。这样,Yacc类就不必依赖于RuleParser的实现,意味着Yacc不必知晓rule_file的特定格式,这些细节只应该由RuleParser的实现类来关心。


在ruby这种动态语言里。。只要你设计出一个类提供rules,vocabs两个属性就好。。
阅读更多
个人分类: 瞎编
上一篇 How To Build a Yacc?(9)
下一篇 How To Build a Yacc?(11)
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭