Status = Struct.new(:text, :pos, :matched, :named, :group_stack, :data)
def deepcopy(a)
Marshal.load Marshal.dump a
end
class Object
unless method_defined?(:tap)
def tap
yield self
self
end
end
end
def match_string(str)
len = str.size
lambda{|nextpart|
lambda{|status|
if status.text[status.pos, len] == str
nextpart.call(deepcopy(status).tap{|s|
s.pos += len
s.matched << str
})
end
}
}
end
def match_eos
lambda{|nextpart|
lambda{|status|
if status.pos == status.text.size
nextpart.call(status)
end
}
}
end
def match_charset(str)
lambda{|nextpart|
lambda{|status|
next if status.pos == status.text.size
if str[status.text[status.pos, 1]]
nextpart.call(deepcopy(status).tap{|s|
s.matched << s.text[s.pos, 1]
s.pos += 1
})
end
}
}
end
def match_ok()
lambda{|nextpart|
lambda{|status|
p status
}
}
end
class Proc
def >>(rhs)
lambda{|nextpart|
self.call(rhs.call(nextpart))
}
end
alias & >>
def |(rhs)
lambda{|np|
lambda{|status|
self.call(np).call(deepcopy(status))
rhs.call(np).call(deepcopy(status))
}
}
end
def *(rep = nil)
f = lambda{|np|
lambda{|s|
(self >> f).call(np).call(deepcopy(s))
np.call(deepcopy(s))
}
}
end
def nocapture
self >> lambda{|np| lambda{|s| s.matched.pop; np.call(s)}}
end
end
def match_any
lambda{|np| lambda{|s| yield(np, s) } }
end
def match_nil
lambda{|np| lambda{|s| np.call(s)}}
end
def group_begin(name)
lambda{|np| lambda{|s|
s.group_stack.push([name, s.matched.length]);
np.call(s)}
}
end
def group_end
lambda{|np| lambda{|s|
name, start = s.group_stack.pop
s.named[name] = s.matched[start..-1].join
np.call(s)
} }
end
def eval_expr(str)
st = Status.new
st.pos = 0
st.matched = []
st.named = {}
st.group_stack = []
st.text = str
st.data = []
expr, additive, multitive, num,expr_bracket, single, calc = 'decl'
expr = match_any{|np, st| additive.call(np).call(st) }
expr_bracket = match_string("(") & expr & match_string(")") & match_any{|np, st|
a,b,c=st.matched.slice!(-3..-1);
st.matched.push calc[b]
np.call(st)
}
calc = lambda{|b|
next b unless Array === b
ret = b[1]
i = 2
while i < b.size
ret = ret.send(b[i], b[i+1]) rescue p(b)
i += 2
end
ret
}
additive = match_any{|np, st|
(
multitive |
multitive & match_charset("+-") & additive & match_any{|np, st|
a,b,c = st.matched.slice!(-3..-1);
a = calc[a] if Array === a && a[0] == :mul
c = calc[c] if Array === c && c[0] == :mul
arr = [:add, a, b, c]
arr = [:add, a, b, *c[1..-1]] if Array === c && c[0] == :add
st.matched.push arr
np.call(st)
}
).call(np).call(st)
}
multitive = match_any{|np, st|
(
single |
single & match_charset("*/") & multitive & match_any{|np, st|
a,b,c = st.matched.slice!(-3..-1)
arr = [:mul, a, b, c]
arr = [:mul, a, b, *c[1..-1]] if Array === c && c[0] == :mul
st.matched.push arr
np.call(st)
}
).call(np).call(st)
}
num = match_any{|np, st|
if a = st.text[st.pos..-1][/^(\d+)/, 1]
s = deepcopy(st)
s.matched << a.to_i
s.pos += a.length
np.call(s)
end
}
single = expr_bracket | num
ret = nil
(expr >> match_eos).call(lambda{|st|ret = st.matched[-1]}).call(st)
calc[ret]
end
p eval_expr("222*67+192*(37-48)")
U3RhdHVzID0gU3RydWN0Lm5ldyg6dGV4dCwgOnBvcywgOm1hdGNoZWQsIDpuYW1lZCwgOmdyb3VwX3N0YWNrLCA6ZGF0YSkKCmRlZiBkZWVwY29weShhKQogIE1hcnNoYWwubG9hZCBNYXJzaGFsLmR1bXAgYQplbmQKY2xhc3MgT2JqZWN0CiAgdW5sZXNzIG1ldGhvZF9kZWZpbmVkPyg6dGFwKQogICAgZGVmIHRhcAogICAgICB5aWVsZCBzZWxmCiAgICAgIHNlbGYKICAgIGVuZAogIGVuZAplbmQKCmRlZiBtYXRjaF9zdHJpbmcoc3RyKQogIGxlbiA9IHN0ci5zaXplCiAgbGFtYmRhe3xuZXh0cGFydHwKICAgIGxhbWJkYXt8c3RhdHVzfAogICAgICAgaWYgc3RhdHVzLnRleHRbc3RhdHVzLnBvcywgbGVuXSA9PSBzdHIKICAgICAgICAgIG5leHRwYXJ0LmNhbGwoZGVlcGNvcHkoc3RhdHVzKS50YXB7fHN8IAogICAgICAgICAgICAgcy5wb3MgICAgICs9IGxlbiAKICAgICAgICAgICAgIHMubWF0Y2hlZCA8PCBzdHIKICAgICAgICAgIH0pCiAgICAgICBlbmQKICAgIH0KICB9CmVuZAoKZGVmIG1hdGNoX2VvcwogIGxhbWJkYXt8bmV4dHBhcnR8CiAgICBsYW1iZGF7fHN0YXR1c3wKICAgICAgIGlmIHN0YXR1cy5wb3MgPT0gc3RhdHVzLnRleHQuc2l6ZQogICAgICAgICAgbmV4dHBhcnQuY2FsbChzdGF0dXMpCiAgICAgICBlbmQKICAgIH0KICB9CmVuZAoKZGVmIG1hdGNoX2NoYXJzZXQoc3RyKQogIGxhbWJkYXt8bmV4dHBhcnR8CiAgICBsYW1iZGF7fHN0YXR1c3wKICAgICAgIG5leHQgaWYgc3RhdHVzLnBvcyA9PSBzdGF0dXMudGV4dC5zaXplCiAgICAgICBpZiBzdHJbc3RhdHVzLnRleHRbc3RhdHVzLnBvcywgMV1dCiAgICAgICAgICBuZXh0cGFydC5jYWxsKGRlZXBjb3B5KHN0YXR1cykudGFwe3xzfCAKICAgCSAgICAgcy5tYXRjaGVkIDw8IHMudGV4dFtzLnBvcywgMV0KICAgICAgICAgICAgIHMucG9zICAgICArPSAxCiAgICAgICAgICB9KQogICAgICAgZW5kCiAgICB9CiAgfQplbmQKCmRlZiBtYXRjaF9vaygpCiBsYW1iZGF7fG5leHRwYXJ0fAogIGxhbWJkYXt8c3RhdHVzfAogICAgIHAgc3RhdHVzCiAgfQogfQplbmQKCmNsYXNzIFByb2MKICBkZWYgPj4ocmhzKQogICAgbGFtYmRhe3xuZXh0cGFydHwKICAgICAgc2VsZi5jYWxsKHJocy5jYWxsKG5leHRwYXJ0KSkKICAgIH0gICAgIAogIGVuZAogIGFsaWFzICYgPj4gCgogIGRlZiB8KHJocykKICAgIGxhbWJkYXt8bnB8CiAgICAgICBsYW1iZGF7fHN0YXR1c3wKICAgICAgICAgc2VsZi5jYWxsKG5wKS5jYWxsKGRlZXBjb3B5KHN0YXR1cykpCiAgICAgICAgIHJocy5jYWxsKG5wKS5jYWxsKGRlZXBjb3B5KHN0YXR1cykpCiAgICAgICB9CiAgICB9CiAgZW5kCgogIGRlZiAqKHJlcCA9IG5pbCkKICAgIGYgPSBsYW1iZGF7fG5wfAogICAgICBsYW1iZGF7fHN8CiAgICAgICAgKHNlbGYgPj4gZikuY2FsbChucCkuY2FsbChkZWVwY29weShzKSkKICAgICAgICBucC5jYWxsKGRlZXBjb3B5KHMpKQogICAgICB9CiAgICB9CiAgZW5kCgogIGRlZiBub2NhcHR1cmUKICAgIHNlbGYgPj4gbGFtYmRhe3xucHwgbGFtYmRhe3xzfCBzLm1hdGNoZWQucG9wOyBucC5jYWxsKHMpfX0gCiAgZW5kCgogIAplbmQKCmRlZiBtYXRjaF9hbnkKICBsYW1iZGF7fG5wfCBsYW1iZGF7fHN8IHlpZWxkKG5wLCBzKSB9IH0KZW5kCgpkZWYgbWF0Y2hfbmlsCiAgbGFtYmRhe3xucHwgbGFtYmRhe3xzfCBucC5jYWxsKHMpfX0KZW5kCgpkZWYgZ3JvdXBfYmVnaW4obmFtZSkKICBsYW1iZGF7fG5wfCBsYW1iZGF7fHN8ICAKCXMuZ3JvdXBfc3RhY2sucHVzaChbbmFtZSwgcy5tYXRjaGVkLmxlbmd0aF0pOyAKCW5wLmNhbGwocyl9IAogIH0KZW5kCgpkZWYgZ3JvdXBfZW5kCiAgbGFtYmRhe3xucHwgbGFtYmRhe3xzfCAgCiAgICAgbmFtZSwgc3RhcnQgPSBzLmdyb3VwX3N0YWNrLnBvcAogICAgIHMubmFtZWRbbmFtZV0gPSBzLm1hdGNoZWRbc3RhcnQuLi0xXS5qb2luCiAgICAgbnAuY2FsbChzKQogIH0gfSAgICAKZW5kCgpkZWYgZXZhbF9leHByKHN0cikKICBzdCA9IFN0YXR1cy5uZXcgCiAgc3QucG9zID0gMAogIHN0Lm1hdGNoZWQgPSBbXQogIHN0Lm5hbWVkID0ge30KICBzdC5ncm91cF9zdGFjayA9IFtdCiAgc3QudGV4dCA9IHN0cgogIHN0LmRhdGEgPSBbXQogIGV4cHIsIGFkZGl0aXZlLCBtdWx0aXRpdmUsIG51bSxleHByX2JyYWNrZXQsIHNpbmdsZSwgY2FsYyA9ICdkZWNsJwogIAogIGV4cHIgPSBtYXRjaF9hbnl7fG5wLCBzdHwgYWRkaXRpdmUuY2FsbChucCkuY2FsbChzdCkgfQogIGV4cHJfYnJhY2tldCA9IG1hdGNoX3N0cmluZygiKCIpICYgZXhwciAmIG1hdGNoX3N0cmluZygiKSIpICYgbWF0Y2hfYW55e3xucCwgc3R8ICAKICAgICAgYSxiLGM9c3QubWF0Y2hlZC5zbGljZSEoLTMuLi0xKTsKICAgICAgc3QubWF0Y2hlZC5wdXNoIGNhbGNbYl0JCiAgICAgIG5wLmNhbGwoc3QpCiAgfQoKICBjYWxjID0gbGFtYmRhe3xifAogICAgIG5leHQgYiB1bmxlc3MgQXJyYXkgPT09IGIKICAgICByZXQgPSBiWzFdCiAgICAgaSA9IDIKICAgICB3aGlsZSBpIDwgYi5zaXplCgkgICAgIHJldCA9IHJldC5zZW5kKGJbaV0sIGJbaSsxXSkgcmVzY3VlIHAoYikKCWkgKz0gMgogICAgIGVuZAogICAgIHJldAogIH0KCiAgYWRkaXRpdmUgPSBtYXRjaF9hbnl7fG5wLCBzdHwKICAgICgKICAgICBtdWx0aXRpdmUgfCAKICAgICBtdWx0aXRpdmUgJiBtYXRjaF9jaGFyc2V0KCIrLSIpICYgYWRkaXRpdmUgJiBtYXRjaF9hbnl7fG5wLCBzdHwgCiAgIAkgICAgIGEsYixjID0gc3QubWF0Y2hlZC5zbGljZSEoLTMuLi0xKTsgCgkgICAgIGEgPSBjYWxjW2FdIGlmIEFycmF5ID09PSBhICYmIGFbMF0gPT0gOm11bAoJICAgICBjID0gY2FsY1tjXSBpZiBBcnJheSA9PT0gYyAmJiBjWzBdID09IDptdWwKCSAgICAgYXJyID0gWzphZGQsIGEsIGIsIGNdIAoJICAgICBhcnIgPSBbOmFkZCwgYSwgYiwgKmNbMS4uLTFdXSAgICAgIGlmIEFycmF5ID09PSBjICYmIGNbMF0gPT0gOmFkZAogICAgICAgICAgICAgc3QubWF0Y2hlZC5wdXNoIGFycgoJICAgICBucC5jYWxsKHN0KQogICAgIH0KICAgKS5jYWxsKG5wKS5jYWxsKHN0KQogIH0KCgogIG11bHRpdGl2ZSA9IG1hdGNoX2FueXt8bnAsIHN0fAogICAoCiAgICAgc2luZ2xlIHwgCiAgICAgc2luZ2xlICYgbWF0Y2hfY2hhcnNldCgiKi8iKSAmIG11bHRpdGl2ZSAmIG1hdGNoX2FueXt8bnAsIHN0fCAKCSAgICAgYSxiLGMgPSBzdC5tYXRjaGVkLnNsaWNlISgtMy4uLTEpCgkgICAgIGFyciA9IFs6bXVsLCBhLCBiLCBjXSAKCSAgICAgYXJyID0gWzptdWwsIGEsIGIsICpjWzEuLi0xXV0gaWYgQXJyYXkgPT09IGMgJiYgY1swXSA9PSA6bXVsCiAgICAgICAgICAgICBzdC5tYXRjaGVkLnB1c2ggYXJyCgkgICAgIG5wLmNhbGwoc3QpCiAgICAgfSAgIAogICApLmNhbGwobnApLmNhbGwoc3QpCiAgfQogICAKICBudW0gPSBtYXRjaF9hbnl7fG5wLCBzdHwKICAgIGlmIGEgPSBzdC50ZXh0W3N0LnBvcy4uLTFdWy9eKFxkKykvLCAxXQogICAgICBzID0gZGVlcGNvcHkoc3QpCiAgICAgIHMubWF0Y2hlZCA8PCBhLnRvX2kKICAgICAgcy5wb3MgKz0gYS5sZW5ndGgKICAgICAgbnAuY2FsbChzKQogICAgZW5kCiAgfQogIHNpbmdsZSA9IGV4cHJfYnJhY2tldCB8IG51bQogIHJldCA9IG5pbAogIChleHByID4+IG1hdGNoX2VvcykuY2FsbChsYW1iZGF7fHN0fHJldCA9IHN0Lm1hdGNoZWRbLTFdfSkuY2FsbChzdCkKICBjYWxjW3JldF0KZW5kCgpwIGV2YWxfZXhwcigiMjIyKjY3KzE5MiooMzctNDgpIikK