逆ポーランド記法的配列を出力する計算機

class Calcp
  prechigh
    nonassoc UMINUS
    left '*' '/'
    left '+' '-'
  preclow
  options no_result_var
rule
  target: exp
        | { result = [] }

  exp: exp '+' exp { val[0] + val[2] + ['+'] }
     | exp '-' exp { val[0] + val[2] + ['-'] }
     | exp '*' exp { val[0] + val[2] + ['*'] }
     | exp '/' exp { val[0] + val[2] + ['/'] }
     | '(' exp ')' { val[1] }
     | '-' NUMBER  =UMINUS { [val[1], :UM] }
     | NUMBER { [val[0]] }
end

---- header

require 'strscan'
require 'readline'

---- inner

class Scanner
  def initialize(src)
    @ss = StringScanner.new(src)
  end

  def scan
    until @ss.eos?
      if tok = @ss.scan(/\A\s+/)
      elsif tok = @ss.scan(/\A\d+/)
        yield :NUMBER, tok.to_i
      elsif tok = @ss.scan(/\A.|\n/o)
        yield tok, tok
      end
    end

    yield false, '$'
  end
end # Scanner

def parse(str)
  scanner = Scanner.new(str)
  yyparse scanner, :scan
end

---- footer

parser = Calcp.new

while buf = Readline.readline('> ', true)
  print('=> ', parser.parse(buf).inspect, "\n")
end


~/work$ racc calc.y
~/work$ ruby calc.tab.rb
> 1 + 2 * 3 / 4 - 5 + ( -7 * 8 )
=> [1, 2, 3, "*", 4, "/", "+", 5, "-", 7, :UM, 8, "*", "+"]