1 Star 0 Fork 0

jiazhenhua / yet-another-lisp-interpreter

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
lisp_interpreter.py 6.37 KB
一键复制 编辑 原始数据 按行查看 历史
jiazh 提交于 2023-05-07 17:13 . 命令行增加参数:
import re, signal, sys
# 解析字符串(源代码), 生成树法树(AST) 例如:'(+ 2 (+ 3 4))' => [['+', '2', ['+', '3', '4']]]
def parse(expt):
expt = re.sub("\(", " ( ", expt)
expt = re.sub("\)", " ) ", expt)
expt = re.sub("\[", " ( ", expt)
expt = re.sub("\]", " ) ", expt)
expt = re.sub("'\\s+", "'", expt)
res = []
for i in expt.strip().split(): # split后,代码解开成好多单词的list
if i != ')':
if re.match("^[0-9]+$", i): i=int(i)
elif re.match("^[0-9][0-9.]*$", i): i=float(i)
elif re.match("'[^(]", i): i=['quote', i[1:]]
res.append(i)
if i == ')': # 碰到), 回找(, 把之间的内容做成下一级list
tmp = []
while res and res[-1] not in ["(","'("]:
tmp.insert(0, res.pop())
if res and res[-1] == "(" : res[-1] = tmp
if res and res[-1] == "'(": res[-1] = ['quote', tmp]
return res # 返回是list嵌套list的树形结构
# 求值函数eval(): 解析出基本元素, 然后调用apply()执行
global_env={}
def eval(expt, env):
# 处理 符号:
if type(expt) is not list:
if expt in ['+','-','*','/','=','<','>',
'eq?','and','or','not','zero?','null?','atom?','pair?','number?','quit']:
return [expt] # 基本运算符返回自身
elif expt in ['#t', '#f']: # 布尔值
return True if expt == '#t' else False
elif type(expt) in [int, float]:
return expt
elif expt in env:
return env[expt] # 先搜索: 局部变量/符号
elif expt in global_env:
return global_env[expt] # 后搜索: 全局变量/符号, 所以局部变量覆盖全局变量
elif expt == 'env':
for k in global_env.keys(): # 调试用, 方便看当前env内容
print(41*'-','\n'+k+':', global_env[k])
else:
print('symbol not defined: %s'%expt)
raise NameError
# 处理 表达式:
if type(expt) is list:
if expt[0] == 'define': # 添加一个全局条目
if type(expt[1]) is list:
k,v = expt[1][0],['lambda',expt[1][1:],expt[2]]
else:
k,v = expt[1],expt[2]
global_env[k] = eval(v, env)
print('new symbol defined: %s'% k)
elif expt[0] == 'let':
for k,v in expt[1]:
env[k] = eval(v, env)
return eval(expt[2], env)
elif expt[0] == 'quote': # 引用
return expt[1]
elif expt[0] == 'car': # (car '(a b c)) => a
return eval(expt[1], env)[0]
elif expt[0] == 'cdr': # (cdr '(a b c)) => (b c)
return eval(expt[1], env)[1:]
elif expt[0] == 'cons': # (cons 'a '(b c)) => (a b c)
p1 = eval(expt[1], env)
p2 = list(eval(expt[2], env)).copy()
p2.insert(0, p1)
return p2
elif expt[0] == 'cond': # 分支结构,相当于switch...case
for p,t in expt[1:]: # 遍历所有条件,找到第一个True,或else
if p=='else' or eval(p, env)==True:
return eval(t, env)
elif expt[0] == 'lambda': # lambda和当时的环境形成一个闭包!
saved_env = env.copy()
return [expt[0], expt[1], expt[2:], saved_env]
else: # 递归解析所有符号, 然后apply执行
expt = [eval(i, env) for i in expt]
return apply(expt[0], expt[1:])
def apply(expr, args):
if expr[0] == '+': return args[0] + args[1]
elif expr[0] == '-': return args[0] - args[1]
elif expr[0] == '*': return args[0] * args[1]
elif expr[0] == '/': return args[0] / args[1]
elif expr[0] == '=': return args[0] == args[1]
elif expr[0] == '<': return args[0] < args[1]
elif expr[0] == '>': return args[0] > args[1]
elif expr[0] == 'eq?': return args[0] == args[1]
elif expr[0] == 'and': return args[0] and args[1]
elif expr[0] == 'or' : return args[0] or args[1]
elif expr[0] == 'not': return not args[0]
elif expr[0] == 'zero?': return 0 == args[0]
elif expr[0] == 'null?': return 0 == len(args[0])
elif expr[0] == 'atom?': return type(args[0]) not in [list,tuple]
elif expr[0] == 'pair?': return type(args[0]) in [list]
elif expr[0] == 'number?': return type(args[0]) in [int, float]
elif expr[0] == 'quit': exit(0)
elif expr[0] == 'lambda':
pars, body, env = expr[1:]
env = env.copy()
for k,v in zip(pars, args): env[k] = v # 形参/实参->env表
for i in body: ret = eval(i, env) # 求值
return ret # 返回
def run(code):
try:
ast = parse(code) # 解析语法树
for i in ast: # 爬树求值
v = eval(i, {})
if v is not None: print(v)
except Exception as e:
print('find error(s):', e)
if __name__ == '__main__':
signal.signal(signal.SIGINT, lambda a,b:())
print ('-'*60)
print ('welcome to yet another lisp interpreter by jia.')
print ('version 0.03')
print ('have fun!')
print ('-' * 60)
if len(sys.argv) > 2:
for f in sys.argv[2:]:
lines = open(f, encoding='utf-8').readlines()
code = ''.join([i.split(';')[0] for i in lines]) # 遍历每一行, 去掉分号后面的内容(注释)
run(code)
if sys.argv[1] == '-load': pass #-load用于加载一些预置库,然后进入命令行
if sys.argv[1] == '-run': exit(0) #-run 执行完所有文件后退出
while True:
try:
code = input("jia-λ > ") #提示符:输入代码
while True:
ast = parse(code) #预解析
unfold = (ast.count('(')) #未配对的'('表示未完待续
indent = (9+3*unfold)*' ' #按未配对的'('的个数缩进
if unfold == 0:
break
code += ' ' + input(indent) #下一行继续输入,自动缩进
run(code)
except EOFError:
print('\n ^C')
continue
Scheme
1
https://gitee.com/jiazhenhua/yet-another-lisp-interpreter.git
git@gitee.com:jiazhenhua/yet-another-lisp-interpreter.git
jiazhenhua
yet-another-lisp-interpreter
yet-another-lisp-interpreter
master

搜索帮助