mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-03-04 13:15:55 +08:00

The primary purpose of this change is to disambiguate between `else if` and `else \n if`. Even though it's a breaking change, since it's at the very early state we're allowed to make such breaking syntax change. lang.write function moved to io and io.stdin, io.stdout, io.stderr added for future streamed io operations io.File read, write, open, close, getline, seek, tell implemented str * int multiplication implemented
106 lines
2.2 KiB
Plaintext
106 lines
2.2 KiB
Plaintext
|
|
## Evalivate a lisp like expression.
|
|
## - Only single digit numbers are allowed.
|
|
## - No space is allowed.
|
|
##
|
|
## (+(*23)(/9(-85))) is equivalent of
|
|
## (+ (* 2 3) (/ 9 (-8 5))) = 9
|
|
|
|
tests = {
|
|
"(+(*23)(/9(-85)))" : 9,
|
|
"(-(*33)(+5(-43)))" : 3,
|
|
"+(/6(+1(-65)))(-9(*42))" : 4,
|
|
"-(*(+2(*1(-54)))3)(+1(/88))" : 7
|
|
}
|
|
|
|
def main()
|
|
for expr in tests
|
|
r = eval(expr, 0); assert(r[1] != -1)
|
|
val = r[0]
|
|
assert(val == tests[expr])
|
|
end
|
|
print("ALL TESTS PASSED")
|
|
end
|
|
|
|
## -------------------------------------------------
|
|
|
|
## Return [value, index], if error index will be -1.
|
|
def eval(expr, ind)
|
|
c = expr[ind]; ind += 1
|
|
|
|
if c == '('
|
|
r = eval(expr, ind)
|
|
val = r[0]
|
|
ind = r[1]
|
|
if ind == -1 then return [null, -1] end
|
|
if ind == expr.length then
|
|
print("Invalid expression.")
|
|
return [null, -1]
|
|
end
|
|
assert(ind < expr.length)
|
|
c = expr[ind]; ind += 1
|
|
if c != ')'
|
|
print("Expected ')'"); return [null, -1]
|
|
end
|
|
return [val, ind]
|
|
|
|
elif c == '+'
|
|
r = binary_op(expr, ind)
|
|
if not r[0] then return [null, -1] end
|
|
return [r[1] + r[2], r[3]]
|
|
|
|
elif c == '-'
|
|
r = binary_op(expr, ind)
|
|
if not r[0] then return [null, -1] end
|
|
return [r[1] - r[2], r[3]]
|
|
|
|
elif c == '*'
|
|
r = binary_op(expr, ind)
|
|
if not r[0] then return [null, -1] end
|
|
return [r[1] * r[2], r[3]]
|
|
|
|
elif c == '/'
|
|
r = binary_op(expr, ind)
|
|
if not r[0] then return [null, -1] end
|
|
return [r[1] / r[2], r[3]]
|
|
|
|
elif isnum(c)
|
|
val = ord(c) - ord('0')
|
|
assert(0 <= val and val < 10)
|
|
return [val, ind]
|
|
|
|
else
|
|
print("Uexpected token:", c)
|
|
return [null, -1]
|
|
|
|
end ## switch(c)
|
|
|
|
end
|
|
|
|
## return [success, v1, v2, index]
|
|
def binary_op(expr, ind)
|
|
r = eval(expr, ind)
|
|
v1 = r[0]; ind = r[1]
|
|
if ind == -1 then return [false, null, null, -1] end
|
|
|
|
r = eval(expr, ind)
|
|
v2 = r[0]; ind = r[1]
|
|
if ind == -1 then return [false, null, null, -1] end
|
|
|
|
return [true, v1, v2, ind]
|
|
end
|
|
|
|
|
|
## Return true if c in numeric.
|
|
def isnum(c)
|
|
k = ord(c) - ord('0')
|
|
## TODO: k in 0..10
|
|
return (0 <= k and k < 10)
|
|
end
|
|
|
|
## -------------------------------------------------
|
|
|
|
## if __name__ == '__main__' ;)
|
|
main()
|
|
|