How To Build a Yacc?(8)

    技术2022-05-11  123

    搞定lex后,很显然,我们要将它加入到Compiler中。 class Compiler   def initialize(rule_file, src_file)     @lex = ExtendLex.new(src_file)   end    def run        return true    end end 要想在run里面真正的干点事,就需要一个shift-reduction算法来识别src_file中的符号流是否能符合rule_file 中所定义的规则。 我们目前只有@lex, 从它那儿我们只能得到符号流,要进行shift-reduction分析,我们需要从rule_file生成DFA,这一点才是关键。为了达到这个目的,得重新写一个类来完成这个功能。 根据这个类的功能,一个紧迫的工作是定义规则文件的格式,以function_decl文法为例: ##### File: ican.y  ############### %% %token function id %token ; , = ( ) %% nil := function_decl : function_decl := function function_name ( argument_list ) ; : function_name := id : p @lex.get_token_string(-1) argument_list := argument_list , id : p @lex.get_token_string(-1) argument_list := id :    p @lex.get_token_string(-1) 以'%%'为分割符,第1个'%%'后面是terminal定义,第2个‘%%’后面定义的是rule, rule的写法就是普通的BNF表达式,后面跟着一个:引出的action表达式,目前我们只执行ruby表达式。这里有几个特定约束:每个NONTERMINAL最终总能推出TERMINAL序列。开始符号由nil := Start_Symbol来定义。 好了,假设我们已经有了一个Yacc类,它所完成的工作就是读入rule_file生成DFA,我们该如何使用(测试)它? #### test.rb require 'rubyunit' class TestCompiler < Test::Unit::TestCase      def create_rule_file         File.open("rulefile","w") do |file|       file.puts "%%/n%token function id/n%token ; , = ( )/n"       file.puts "%%/nnil := function_decl : /n"       file.puts "function_decl := function function_name ( argument_list ) ; : /n"       file.puts "function_name := id : /n"       file.puts "argument_list := argument_list , id : /n"       file.puts "argument_list := id :"     end      end     def test_yacc         create_rule_file         yacc = Yacc.new("rulefile")         yacc.generate        assert(yacc.state[0].size == 2)     end end 在我们上面所定义的rulefile中,DFA的state[0](开始状态)应该是2个item: item1:[nil = # function_decl] item2:[function_decl = # function function_name ( argument_list ) ;] 当然我们可以编写更多的assert, 不过对于一个想象中的类,还是不要对它要求过多。

    最新回复(0)