http://d.hatena.ne.jp/torazuka/20120829/stackmachine
を読んで、ruby で逆ポを書いてみた。
最初は普通にやろうと思っていたんだが、書き始めてから正規表現で解決するという作戦に変更。
perl6 なら正規表現による置換一発でかけるのかもしれないなんて思いつつ、perl6 のことは全く知らないのでわからない。
rpn.rb
#!ruby
def rpn( s )
return s if /\A[\d\.]+\Z/=~s
raise "FAIL : #{s}" unless /([\d\.]+)\s+([\d\.]+)\s+([^\d\.\s]+)/=~s
a, b=[$1,$2].map( &:to_f )
r=case $3
when '+'
a+b
when '-'
a-b
when '*'
a*b
when '/'
a/b
end
rpn( s.gsub( $&, r.to_s ) )
end
DATA.each{ |a|
i, x = a.split( "->" ).map( &:strip )
ac = rpn(i)
raise [i,x,ac].inspect unless ac.to_f==x.to_f
puts "ok : %s -> %s"%[i,ac]
}
__END__
1 -> 1
1 2 + -> 3
3 1 - -> 2
10 2 / -> 5
2 5 8 + + -> 15
2 5 8 + * -> 26
2 5 8 * + -> 42
1 2 + 3 4 + * -> 21
2 3 * 4 5 * + -> 26
正規表現なんか使わなくてももっとすっと書けるような気がしてならないが、まあこんなところで。
なんとなく、eval は禁止の方向で。
二項じゃない演算子に対応するためには一手間必要か。
あと、再帰で書いているのでスタックがあふれる危険あり。
末尾再帰になっていると思うので、ループにするのは簡単だと思う。