41 lines
1.1 KiB
Lua
41 lines
1.1 KiB
Lua
require"lpeg"
|
|
|
|
P, R, C, S, V = lpeg.P, lpeg.R, lpeg.C, lpeg.S, lpeg.V
|
|
|
|
--matches arithmetic expressions and returns a syntax tree
|
|
expression = P{"expr";
|
|
ws = P" "^0,
|
|
number = C(R"09"^1) * V"ws",
|
|
lp = "(" * V"ws",
|
|
rp = ")" * V"ws",
|
|
sym = C(S"+-*/") * V"ws",
|
|
more = (V"sym" * V"expr")^0,
|
|
expr = V"number" * V"more" + V"lp" * lpeg.Ct(V"expr" * V"more") * V"rp" * V"more"}
|
|
|
|
--evaluates a tree
|
|
function eval(expr)
|
|
--empty
|
|
if type(expr) == "string" or type(expr) == "number" then return expr + 0 end
|
|
|
|
--arithmetic functions
|
|
tb = {["+"] = function(a,b) return eval(a) + eval(b) end,
|
|
["-"] = function(a,b) return eval(a) - eval(b) end,
|
|
["*"] = function(a,b) return eval(a) * eval(b) end,
|
|
["/"] = function(a,b) return eval(a) / eval(b) end}
|
|
|
|
--you could add ^ or other operators to this pretty easily
|
|
for i, v in ipairs{"*/", "+-"} do
|
|
for s, u in ipairs(expr) do
|
|
local k = type(u) == "string" and C(S(v)):match(u)
|
|
if k then
|
|
expr[s-1] = tb[k](expr[s-1],expr[s+1])
|
|
table.remove(expr, s)
|
|
table.remove(expr, s)
|
|
end
|
|
end
|
|
end
|
|
return expr[1]
|
|
end
|
|
|
|
print(eval{expression:match(io.read())})
|