How To Build a Yacc?(10)

    技术2022-05-11  122

    将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两个属性就好。。

    最新回复(0)