3.5.包含抽象的语言的解释器
包含抽象的语言的解释器( )
先前Calcualtor
的实现并未给出定义新操作、给变量命名、表达计算的一般方法等的实现。下面给出描述性的实现方法:
1.结构
一个
- 分析器通过计算器解释(
)来产生一个表达式。 - 计算函数侦测表达式的形式;对于调用表达式,它会调用一个函数用于处理某些参数。
两者的计算器(
解析( )
1 | >>> read_line("(car '(1 . 2))") |
计算( )
scheme_read
返回的表达式都传递给scheme_eval
函数,它会在当前环境env
中计算表达式expr
。
scheme_eval
函数会计算
1 | def scheme_eval(expr, env): |
过程调用( )
过程调用通过scheme_apply
实现。它比起先前的calc_apply
更具普遍性。它接受两类参数:PrimitiveProcedure
或LambdaProcedure
。
PrimitiveProcedure
是在fn
的实例属性(
LambdaProcedure
是在body
属性,这是一个body
表达式会在一个新环境里被调用。为了搭建环境,一个新的框架被加入进环境中,在这个框架中,过程的形式参数(body
通过scheme_eval
计算。
递归调用与计算( )
实现计算过程的scheme_eval
和scheme_apply
是相互递归的(
递归的循环以语言原语(
这种处理表达式形式(
2.环境
基本结构
我们希望实现一个Frame
类来构建环境。每个Frame
的实例都代表一个环境,在这个实例中,标记(
Frame
实例由一个binding
字典和parant
框架构成。对于parent=None
。
binding
和define
binding
并不是直接访问的,它通过两个Frame
方法访问:lookup
和define
。lookup
过程会在我们的环境模型中执行frame
的binding
相匹配。如果它找到了,它相关联的值就被返回;否则,lookup
过程会在parent frame
继续该过程。而define
方法在当前frame
中将标记与值相绑定。
考虑下面的程序:
1 | (define (factorial n) |
1 | (factorial 5) |
定义这样一个函数有以下步骤:
- 检查表达式的格式(
),确保它是一个完备的 列表,至少有两个元素与关键字 。 - 分析第一个元素。在本例中,寻找函数名称
和形式参数 。 - 用提供的形式参数创造一个
LambdaProcedure
,body
和parent
环境。 - 在当前环境的第一个
frame
中,将 标志与这个函数绑定。
第二个输入是一个调用表达式。传给scheme_apply
的过程是与LambdaProcedure
。为了应用这一过程,一个新的框架创建了,扩展了原来的父框架。在这个框架中,标志body
部分在这个环境中被计算,它的值也被返回。
3.作为程序的数据
我们可以从模拟(
1 | (define (factorial n) |
我们可以将这个程序看作对一个机器的描述,这个机器包括减法、乘法、相等性测试、双向开关和另一个
相似地,我们可以将
从这个角度,我们的
计算作为执行过程一部分的表达式是一个有活力的编程语言所具的特点。在程序的执行过程中创建并计算表达式的能力是一个有力的工具。
Related Issues not found
Please contact @fyerfyer to initialize the comment