S式計算式

mzp2007-06-21

30分プログラム、その62。S式計算機

ちょっとさきの勉強会のネタ。本番は、OCamlで作ったのを持っていくつもりだけれども、とりあえずRubyでも作ってみる。

> 1
1
> (+ 1 2)
3
> (* (+ 2 3) 1 3)
15
require 'strscan'
require 'readline'

def call(name)
  lambda{|x,*args| x.send name,*args }
end

module SExpression
  class Call
    def initialize(op,*args)
      @op = op
      @args = args
    end

    def eval
      @args.map(&call(:eval)).inject(&call(@op))
    end
  end

  class Number
    attr_reader :num
    alias_method :eval,:num

    def initialize(num)
      @num = num
    end
  end

  def self.parse(str)
    str = StringScanner.new(str) if str.class == String
    str.skip /\s+/
    
    if str.skip /\(/ then
      op = str.scan %r![-+*/]!
      
      args = []
      args << parse(str) until str.skip /\)/
      
      Call.new op.to_sym,*args
    elsif str.scan /\d+/ then
      Number.new str.matched.to_i
    else
      raise 'error'
    end
  end
end

while buf = Readline.readline('> ',true)
   puts SExpression.parse(buf).eval
end
  • callは、ちょっと自慢
  • ちゃんとASTも作ってみた
  • 3秒あまった。あまったとは言わんけど