racc: 電卓

四則演算しかできないschemeみたいなものを作ってみる。

class CalcParser
rule
  expression: '(' OPERATOR operands ')'
                {
                  result = calc(val[1], val[2])
                }

  operands  : operand
                {
                  result = [val[0]]
                }
            | operands operand
                {
                  result.push val[1]
                }

  operand   : NUMBER
            | expression
end

---- inner

def calc(operator, operands)
  i = operands.shift

  operands.each {|operand|
    case operator
    when '+'; i += operand
    when '-'; i -= operand
    when '*'; i *= operand
    when '/'; i /= operand
    end
  }

  return i;
end

def parse(f)
  @q = []

  f.each {|line|
    until !line or line.empty?
      case line
      when /\A\s+/
      when /\A\d+/
        @q.push [:NUMBER, $&.to_i]
      when /\A[+-\\*\/]/
        @q.push [:OPERATOR, $&]
      when /\A./
        c = $&
        @q.push [c, c]
      end
      line = $'
    end
  }

  @q.push [false, '$end']
  do_parse
end

def next_token
  @q.shift
end

---- footer

parser = CalcParser.new

File.open(ARGV[0]) {|f|
  puts parser.parse(f)
}