Skip to content

Instantly share code, notes, and snippets.

@jklmnn
Created October 18, 2018 10:45
Show Gist options
  • Save jklmnn/9c415b95f920dc79ebcd53b7bc26b1ab to your computer and use it in GitHub Desktop.
Save jklmnn/9c415b95f920dc79ebcd53b7bc26b1ab to your computer and use it in GitHub Desktop.
Python Lisp S-Expression interpreter
#!/usr/bin/env python3
# Python Lisp S-Expression interpreter
#
# Example:
# ./pylisp.py "(+ (* 2 3) 1)" executes (2 * 3) + 1 and yields 7
#
# currently only + - / + and = are supported operations
import sys
class Lisp:
def __init__(self):
setattr(self, "+", lambda args: sum([int(a) for a in args]))
setattr(self, "-", self.sub)
setattr(self, "*", self.mul)
setattr(self, "/", self.div)
setattr(self, "=", lambda args: "nil" if False in [str(args[0]) == str(i) for i in args] else "T")
def sub(self, args):
if len(args) > 1:
return int(args[0]) - self.add(args[1:])
elif len(args) == 1:
return -int(args[0])
else:
return 0
def mul(self, args):
x = int(bool(len(args)))
for a in args:
x *= int(a)
return x
def div(self, args):
if len(args) == 1:
return 1 / int(args[0])
elif len(args) > 1:
return int(args[0]) / self.mul(args[1:])
else:
raise RuntimeError("div requires at least one argument")
def eval(self, expr):
l = [self.eval(l) if isinstance(l, list) else l for l in expr]
return getattr(self, l[0])(l[1:])
def parse(self, expr):
return self.__parse(expr[1:-1])
def __parse(self, expr):
e = expr.strip(" ")
if len(e) < 1:
return "nil"
t = []
if e[0] == "(":
d = 0
r = ""
for c in e:
if c == "(":
d += 1
elif c == ")":
d -= 1
r += c
if d == 0:
t.append(self.__parse(r[1:-1]))
if len(e[len(r):]):
t.extend(self.__parse(e[len(r):]))
break
else:
if " " in e:
t.append(e[:e.index(" ")])
t.extend(self.__parse(e[e.index(" ") + 1:]))
else:
return [e]
if t:
return t
else:
return "nil"
if __name__ == "__main__":
l = Lisp()
for arg in sys.argv[1:]:
print(l.eval(l.parse(arg)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment