87 lines
2.2 KiB
Text
87 lines
2.2 KiB
Text
-- If string is empty, returns zero.
|
|
local function to_double_or_zero(s)
|
|
local n = tonumber(s)
|
|
return n ? n : 0
|
|
end
|
|
|
|
local function multiply(s)
|
|
local b = s:split("*"):map(|c| -> to_double_or_zero(c))
|
|
return tostring(b[1] * b[2])
|
|
end
|
|
|
|
local function divide(s)
|
|
local b = s:split("/"):map(|c| -> to_double_or_zero(c))
|
|
return tostring(b[1] / b[2])
|
|
end
|
|
|
|
local function add(s)
|
|
local t = s:gsub("^%+", ""):gsub("%++", "+")
|
|
local b = t:split("+"):map(|c| -> to_double_or_zero(c))
|
|
return tostring(b[1] + b[2])
|
|
end
|
|
|
|
local function subtract(s)
|
|
local t = s:gsub("(%+%-|%-%+)", "-")
|
|
if "--" in t then return add(t:replace("--", "+")) end
|
|
local b = t:split("-"):map(|c| -> to_double_or_zero(c))
|
|
return tostring(#b == 3 ? -b[2] - b[3] : b[1] - b[2])
|
|
end
|
|
|
|
local function eval_exp(s)
|
|
local t = s:gsub("[()]", "")
|
|
local pmd = "%d+%.?%d*%s*[*/]%s*[+-]?%d+%.?%d*"
|
|
local pm = "%*"
|
|
local pas = "%-?%d+%.?%d*%s*[+-]%s*[+-]?%d+%.?%d*"
|
|
local pa = "%d%+"
|
|
|
|
while true do
|
|
local exp = t:match(pmd)
|
|
if !exp then break end
|
|
local exp2 = exp:match(pm)
|
|
if exp2 then
|
|
t = t:replace(exp, multiply(exp))
|
|
else
|
|
t = t:replace(exp, divide(exp))
|
|
end
|
|
end
|
|
|
|
while true do
|
|
local exp = t:match(pas)
|
|
if !exp then break end
|
|
local exp2 = exp:match(pa)
|
|
if exp2 then
|
|
t = t:replace(exp, add(exp))
|
|
else
|
|
t = t:replace(exp, subtract(exp))
|
|
end
|
|
end
|
|
|
|
return t
|
|
end
|
|
|
|
local function eval_arithmetic_exp(s)
|
|
local t = s:gsub("%s", ""):gsub("^%+", "")
|
|
local ppara = "%([^()]*%)"
|
|
while true do
|
|
local exp = t:match(ppara)
|
|
if !exp then break end
|
|
t = t:replace(exp, eval_exp(exp))
|
|
end
|
|
return to_double_or_zero(eval_exp(t))
|
|
end
|
|
({
|
|
"2+3",
|
|
"2+3/4",
|
|
"2*3-4",
|
|
"2*(3+4)+5/6",
|
|
"2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10",
|
|
"2*-3--4+-0.25",
|
|
"-4 - 3",
|
|
"((((2))))+ 3 * 5",
|
|
"1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10",
|
|
"1 + 2*(3 - 2*(3 - 2)*((2 - 4)*5 - 22/(7 + 2*(3 - 1)) - 1)) + 1"
|
|
}):foreach(|s| -> do
|
|
local r = eval_arithmetic_exp(s)
|
|
if r % 1.0 == 0 then r = math.round(r) end
|
|
print($"{s} = {r}")
|
|
end)
|