Skip to content

Instantly share code, notes, and snippets.

@randrews
Created June 3, 2015 04:45
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save randrews/5eab368f35ab8e774433 to your computer and use it in GitHub Desktop.
Save randrews/5eab368f35ab8e774433 to your computer and use it in GitHub Desktop.
Toy calculator in Lua, version 2
setmetatable(_ENV, { __index=lpeg })
VARS = {}
function eval(...)
local args = {...}
local accum = args[1]
for i = 2, #args, 2 do
local operator = args[i]
local num2 = args[i+1]
if operator == '+' then
accum = accum + num2
elseif operator == '-' then
accum = accum - num2
elseif operator == '*' then
accum = accum * num2
elseif operator == '/' then
accum = accum / num2
end
end
return accum
end
function assign(ref, value)
ref.scope[ref.index] = value
return value
end
function lookup(ref)
return ref.scope[ref.index]
end
function makeref(...)
local indices = {...}
local tbl = VARS
for i = 1, #indices-1 do
tbl = tbl[indices[i]]
end
return {scope=tbl, index=indices[#indices]}
end
spc = S(" \t\n")^0
digit = R('09')
number = C( (P("-") + digit) *
digit^0 *
( P('.') * digit^0 )^-1 ) / tonumber * spc
lparen = "(" * spc
rparen = ")" * spc
lbrack = "[" * spc
rbrack = "]" * spc
comma = "," * spc
expr_op = C( S('+-') ) * spc
term_op = C( S('*/') ) * spc
letter = R('AZ','az')
name = C( letter * (digit+letter+"_")^0 ) * spc
stmt = spc * P{
"STMT";
STMT =
V("REF") * "=" * spc * V("VAL") / assign +
V("EXPR"),
EXPR = V("TERM") * ( expr_op * V("TERM") )^0 / eval,
TERM = V("FACT") * ( term_op * V("FACT") )^0 / eval,
REF = name * (lbrack * V("EXPR") * rbrack)^0 / makeref,
FACT =
number / eval +
lparen * V("EXPR") * rparen / eval +
V("REF") / lookup,
ARRAY = lbrack * Ct( V("VAL_LIST")^-1 ) * rbrack,
VAL_LIST = V("VAL") * (comma * V("VAL"))^0,
VAL = V("EXPR") + V("ARRAY")
}
function test(expr)
assert(expr:match(" 1 + 2 ") == 3)
assert(expr:match("1+2+3+4+5") == 15)
assert(expr:match("2*3*4 + 5*6*7") == 234)
assert(expr:match(" 1 * 2 + 3") == 5)
assert(expr:match("( 2 +2) *6") == 24)
stmt:match("a=3"); assert(VARS.a == 3)
assert(stmt:match("a") == 3)
assert(stmt:match("a * 5") == 15); VARS.a=nil
stmt:match("a = [ 4, 5, 6 ]");
assert(VARS.a[1] == 4)
assert(VARS.a[2] == 5)
assert(VARS.a[3] == 6)
VARS.a=nil
stmt:match("b = [ ]");
assert(VARS.b[1] == nil)
VARS.b=nil
stmt:match("c = [[1,2], [3,4]]")
assert(VARS.c[1][1] == 1)
assert(VARS.c[1][2] == 2)
assert(VARS.c[2][1] == 3)
assert(VARS.c[2][2] == 4)
assert(stmt:match("c[4/2][1]") == 3)
stmt:match("c[3] = 5")
assert(VARS.c[3] == 5)
VARS.c=nil
end
function repl(file)
file = file or io.input()
parser = stmt
for line in file:lines() do
print(parser:match(line))
end
end
@randrews
Copy link
Author

Yeah, exactly, what eric-2 said. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment