parser generator書いてみた(3)
度重なる仕様変更でこんな感じに書くようになった.
Lexer = ParserGenerator::Lexer.new(/[ \t\n\r\v]+/) { token(:operator, /[+-]/) {|ma| ma[0].to_sym } token(:operator2, /[*\/]/) {|ma| ma[0].to_sym } token(:integer, /[0-9]+/) {|ma| ma[0].to_i } token(:identifier, /[a-z]+/) {|ma| ma[0].to_sym } } Parser = ParserGenerator::Parser.new(Lexer) { rule(:expr, seq(:term, repeat(:operator, :term))) {|term, ary| ary.inject(term) {|r, (op, x)| r.__send__(op.content, x) } } rule(:term, seq(:factor, repeat(:operator2, :factor))) {|factor, ary| ary.inject(factor) {|r, (op, x)| r.__send__(op.content, x) } } rule(:factor, seq(opt(:operator), select(:integer, :identifier))) {|sign, token| case token.type when :integer token.content when :identifier 10 end * if sign && sign.content == :- -1 else 1 end } } parser = Parser.new p parser.parse("x / 2 + -4 * 5", :expr) # => -15
いきなりparserオブジェクトを生成するのではなく,parserクラスを生成するようにした.lexerも同じく.parserにlexerクラスを渡すのはどちらのタイミングでもいい.parserクラス生成時に渡したlexerクラスは,そのparserクラスのデフォルトのlexerになる.