Packrat パーサを手書き by Ruby
とりあえずこんなのでいいのかな
パーサコンビネータは(作って/使って)ない
(あとで気づいたけど、ダメだこれ。tailのメモ化ができていない。というか、いちいちクロージャにしなくてもよかった)
#!/usr/local/bin/ruby19 -w # coding:utf-8 # vi:set ts=3 sw=3: # vim:set sts=0 noet: require 'pp' class Derivs def initialize str @memo = Hash.new do|hash, key| case key when :additive pAdditive hash when :multitive pMultitive hash when :primary pPrimary hash when :decimal pDecimal hash when :char if str.empty? then nil else [str[0, 1], proc{Derivs.new str[1..-1]}] end else raise end end end def [] term @memo[term] end end def pAdditive d if r1 = d[:multitive] then vleft, d1_ = r1 if r2 = d1_.call[:char] then c, d2_ = r2 if c == '+' then if r3 = d2_.call[:additive] then vright, d3_ = r3 return [vleft + vright, d3_] end end end end if r = d[:multitive] then r else nil end end def pMultitive d if r1 = d[:primary] then vleft, d1_ = r1 if r2 = d1_.call[:char] then c, d2_ = r2 if c == '*' then if r3 = d2_.call[:multitive] then vright, d3_ = r3 return [vleft * vright, d3_] end end end end if r = d[:primary] then r else nil end end def pPrimary d if r1 = d[:char] then c, d1_ = r1 if c == '(' then if r2 = d1_.call[:additive] then v, d2_ = r2 if r3 = d2_.call[:char] then c, d3_ = r3 if c == ')' then return [v, d3_] end end end end end if r = d[:decimal] then r else nil end end def pDecimal d if r = d[:char] then c, d1_ = r case c when '0' then [0, d1_] when '1' then [1, d1_] when '2' then [2, d1_] when '3' then [3, d1_] when '4' then [4, d1_] when '5' then [5, d1_] when '6' then [6, d1_] when '7' then [7, d1_] when '8' then [8, d1_] when '9' then [9, d1_] else nil end else nil end end d = Derivs.new '(2+3)*(4+5)' pp d[:additive]