返回
日拱一卒,用Python写一个Lisp解释器(三)
闲谈
2024-02-03 07:35:56
大家好,日拱一卒,我是梁唐。本文始发于公众号Coder梁。
我们继续来肝伯克利CS61A的scheme project,这是这个project的第三篇,如果漏掉了之前的建议先去补一下。
课程链接:https://www.youtube.com/watch?v=PngQkdxD2xc&list=PL-XXv-cvO-8kT69O7lfcH7G_Scy-qVDL1
项目原文链接:https://inst.eecs.berkeley.edu/~cs61a/fa19/projects/scheme/scheme.html
项目仓库:https://github.com/josephzeng/scheme
前两节的解析:
Lisp解释器 一: 基础类型和变量绑定
Lisp解释器 二: 宏定义
这节我们来实现几个函数的解释,因为大部分列表相关的函数都靠对 cons cell 的操作实现,而 cons cell 也是 scheme 内置的数据结构,所以这一节有几个函数实现起来和 C 语言写 Scheme 解释器基本一样。
cons
对应的python代码
def cons(env, a, b):
pair = memory.make_object('pair', env)
memory.set(pair, a)
memory.set(pair + 1, b)
return pair
car
对应的python代码
def car(env, a):
if not isinstance(a, int) or a < memory.min_addr or a >= memory.max_addr or a % 2 != 0:
raise SchemeError("Car requires a pair")
return memory.get(a)
cdr
对应的python代码
def cdr(env, a):
if not isinstance(a, int) or a < memory.min_addr or a >= memory.max_addr or a % 2 != 0:
raise SchemeError("Car requires a pair")
return memory.get(a + 1)
display
对应的python代码
def display(env, a):
print(a)
eval_string
对应的python代码
def eval_string(env, s):
s = s.strip()
if len(s) == 0:
raise SchemeError("Eval_string requires an input string")
a = tokenize_string(env, s)
b = eval_list(env, a)
if b != None:
display(env, b)
begin
对应的python代码
def begin(env, *args):
ret = None
for arg in args:
ret = eval_sexpr(env, arg)
return ret
lambda
对应的python代码
def lambda(env, *args):
params = args[0]
body = list(args[1:])
exp = memory.make_object('lambda', env)
memory.set(exp, params)
memory.set(exp + 1, body)
memory.set(exp + 2, env)
return exp
if
对应的python代码
def if_stmt(env, *args):
cond = args[0]
true_clause = args[1]
false_clause = None
if len(args) > 2:
false_clause = args[2]
if eval_sexpr(env, cond) == TRUE:
return eval_sexpr(env, true_clause)
else:
return eval_sexpr(env, false_clause)
define
对应的python代码
def define(env, *args):
if len(args) < 2:
raise SchemeError("Define requires at least 2 arguments")
var = args[0]
exp = eval_sexpr(env, args[1])
if not isinstance(var, str):
raise SchemeError("Define requires a variable name")
env.define(var, exp)
quote
对应的python代码
def quote(env, *args):
return args[0]
set!
对应的python代码
def set(env, *args):
if len(args) != 2:
raise SchemeError("Set! requires 2 arguments")
var = args[0]
exp = eval_sexpr(env, args[1])
if not isinstance(var, str):
raise SchemeError("Set! requires a variable name")
env.set(var, exp)
or
对应的python代码
def or_expr(env, *args):
ret = FALSE
for arg in args:
ret = eval_sexpr(env, arg)
if ret == TRUE:
return ret
return ret
and
对应的python代码
def and_expr(env, *args):
ret = TRUE
for arg in args:
ret = eval_sexpr(env, arg)
if ret == FALSE:
return ret
return ret
这节的大部分代码和 C 语言写的 Scheme 解释器是一致的,只是在 Python 中,内建函数的定义风格不太一样。