-
Notifications
You must be signed in to change notification settings - Fork 161
/
Copy pathlisp.py
104 lines (93 loc) · 2.68 KB
/
lisp.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# This is a LISP parser implemented in python,
# written after reading Peter Novig's lis.py essay http://www.norvig.com/lispy.html
def tokenize(program):
return program.replace('(', '( ').replace(')', ' )').split()
def parse(program):
tokens = tokenize(program)
return get_next(tokens)
Symbol = str
def atom(token):
try:
return int(token)
except:
try:
return float(token)
except:
return Symbol(token)
def get_next(tokens):
token = tokens.pop(0)
if token =='(':
parsed = []
while True:
token = tokens[0]
if token==')':
tokens.pop(0)
break
else:
parsed.append(get_next(tokens))
return parsed
elif token==")":
raise Exception("Syntax Error")
else:
return atom(token)
class Env(dict):
def __init__(self, parent={}):
dict.__init__(self)
self.parent = parent
def __getitem__(self, name):
if name in self:
return dict.__getitem__(self, name)
if name in self.parent:
return self.parent[name]
raise KeyError
global_env = Env()
import operator as op
global_env.update({
'+':op.add, '-':op.sub, '*':op.mul, '/':op.div,
'>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq,
'abs': abs,
})
class Proc(object):
def __init__(self, args, exp, env):
self.args = args
self.exp = exp
self.env = Env(env)
def __call__(self, *arguments):
for n, v in zip(self.args, arguments):
self.env[n] = v
return eval(self.exp, self.env)
def eval(exp, env = global_env):
if isinstance(exp, basestring):
return env[exp]
elif isinstance(exp, (int, float)):
return exp
elif isinstance(exp, list):
head = exp[0]
if head=="define":
_, name, val = exp
env[name] = eval(val, env)
elif head=="set!":
_, name, val = exp
if name not in env:
raise Exception("Undefined")
env[name] = eval(val, env)
elif head=="quote":
return exp[1]
elif head=="if":
test = eval(exp[1], env)
if test:
return eval(exp[2], env)
else:
return eval(exp[3], env)
elif head=="lambda":
return Proc(exp[1], exp[2], env)
else:
proc = env[head]
return proc(*[eval(arg, env) for arg in exp[1:]])
def repl():
while True:
program = raw_input("LISP > ")
val = eval(parse(program))
if val:
print val
repl()