Created
November 13, 2017 20:41
-
-
Save FRex/65506c5dd14d36fa9555437e0053f73c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local io = require'io' | |
local math = require'math' | |
local function push(s, v) s[#s + 1] = v; return v end | |
local function top(s) return s[#s] end | |
local function pop(s) local r = top(s); s[#s] = nil; return r end | |
local function empty(s) return #s == 0 end | |
local function fixtoplist(stack) | |
local oldtop = top(stack) | |
if oldtop and #oldtop == 1 then | |
newtop = push(stack, {}) | |
oldtop[2] = newtop | |
oldtop = newtop | |
end | |
return oldtop | |
end | |
local function parse(code) | |
local stack = {} | |
for token in code:gmatch('%S+') do | |
if tonumber(token) ~= nil then token = tonumber(token) end | |
if token == '(' then | |
local oldtop = fixtoplist(stack) | |
local newtop = push(stack, {opening = true}) | |
if oldtop then oldtop[1] = newtop end | |
elseif token == ')' then | |
while not empty(stack) and not top(stack).opening do | |
pop(stack) | |
end | |
local r = pop(stack) | |
if empty(stack) then return r end | |
else | |
fixtoplist(stack)[1] = token | |
end | |
end --for token | |
end --function parse | |
local function progtostr(x, types) | |
if x == nil then return '@NIL' end | |
if type(x) ~= 'table' then | |
if types then | |
return ('%s[%s]'):format(type(x), tostring(x)) | |
else | |
return tostring(x) | |
end | |
end | |
return ('(%s %s)'):format(progtostr(x[1], types), progtostr(x[2], types)) | |
end | |
local function listhead(t) | |
return t[1], t[2] | |
end | |
local function listend(t) | |
return #t ~= 2 | |
end | |
local funcs = {} | |
funcs['+'] = function(t) return 'PLUS' end | |
local function printf(fmt, ...) io.stdout:write(fmt:format(...)) end | |
local eval | |
local function iterlist(l) | |
local f = function(s) | |
ll = s[1] | |
if ll == nil then return nil end | |
s[1] = ll[2] | |
return ll[1] | |
end | |
return f, {l} | |
end | |
local funcs = {} | |
funcs['+'] = function(l) | |
local sum = 0 | |
for x in iterlist(l) do sum = sum + eval(x) end | |
return sum | |
end | |
funcs['*'] = function(l) | |
local prod = 1 | |
for x in iterlist(l) do prod = prod * eval(x) end | |
return prod | |
end | |
local function openlist(l) return l[1], l[2] end | |
funcs['/'] = function(l) | |
local a, l = openlist(l) | |
local b = openlist(l) | |
return eval(a) / eval(b) | |
end | |
funcs['//'] = function(l) | |
local a, l = openlist(l) | |
local b = openlist(l) | |
return math.floor(eval(a) / eval(b)) | |
end | |
funcs['..'] = function(l) | |
local parts = {} | |
for x in iterlist(l) do table.insert(parts, eval(x)) end | |
return table.concat(parts) | |
end | |
funcs['sin'] = function(l) return math.sin(eval(l[1])) end | |
funcs['cos'] = function(l) return math.sin(eval(l[1])) end | |
funcs['pi'] = math.pi | |
eval = function(l) | |
--print('aa', l, l[1], l[2]) | |
if type(l) == 'number' then return l end | |
if type(l) == 'string' then | |
local q = string.byte"'" | |
if l:byte(1) == q and l:byte(-1) == q then return l:sub(2, -2) end | |
return funcs[l] or l | |
end | |
local first = eval(l[1]) | |
first = funcs[first] or first | |
if type(first) == 'function' then return first(l[2]) end | |
return first | |
end | |
local function interpret(code) | |
code = code:gsub('%(', ' ( '):gsub('%)', ' ) ') | |
program = parse(code) | |
return eval(program) | |
end | |
if arg then | |
for i=1,#arg do | |
result = interpret(arg[i]) | |
printf('Result: %s\n', tostring(result)) | |
end | |
end | |
local function simplify(code, types) | |
code = code:gsub('%(', ' ( '):gsub('%)', ' ) ') | |
program = parse(code) | |
return progtostr(program, types) | |
end | |
return {interpret = interpret, simplify = simplify} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment