pymatlab_interp 解释器开发教程第五部分: 语句与控制流扩展。
pymatlab_interp 解释器开发教程 (5) 语句与控制流扩展
引言
之前已经完成了表达式求值的整个流程,并且实现了自动代码生成。
这一节就扩展一下语句和控制流。
语句
先说明一下表达式,语句和控制流的关系与区别。
-
表达式是编程语言中用于计算值的代码片段。 例如,在数学运算
2 + 3
中,2 + 3
就是一个表达式,其结果是一个数值5
。表达式可以包含变量、函数调用、操作符等元素。 -
语句则是执行某些操作或指令的代码块。语句不会返回一个值,它们的目的在于改变程序的状态。 例如,赋值语句
x = 5
将数字5
赋值给变量x
;打印语句print("Hello, world!")
则会输出一段文本到屏幕上。 -
控制流指的是程序中指令的执行顺序。在大多数情况下,程序会从上到下依次执行每一行代码,但通过使用控制流结构,如条件语句和循环,可以改变这一顺序。
可以发现,表达式可以是一个语句,控制流也可以是语句。
控制流有两种典型的语句:
- 条件语句:(如
if
,else if
,else
)允许程序基于特定条件选择性地执行代码块。 - 循环语句:(如
for
,while
)使代码块能够重复执行,直到满足某个条件为止。
为了实现控制流,需要对代码分块(划分作用域)。分块的过程也可以看作语句。
甚至内置的函数操作,比如我们可以让 DISP 打印直接作为一种语句执行。
接下来就扩展 parser 和 interpreter 实现这些。
Stmt 实现
为了表示源代码的结构,需要定义表示语句的节点。
下面是对Stmt
类及其派生类的说明,它们代表了源代码中不同的语句类型:
-
Stmt
基类:这是所有语句节点的基类,它包含了基本的初始化方法和一个accept
方法,后者用于实现访问者模式。 -
Expression
类:表示表达式语句,即一个单独的表达式作为语句执行, 例如一个赋值或计算表达式。这个类包含一个expression
属性,该属性是一个Expr
类型的实例,表示具体的表达式。 -
Block
类:表示代码块语句,即一系列语句的集合,通常在控制流结构如if
或while
中使用。Block
类包含一个statements
属性,这是一个Stmt
类型的列表,表示代码块中的所有语句。 -
Disp
类:表示输出语句,如打印语句,它包含一个expression
属性,表示要输出的表达式。 -
If
类:表示条件语句,具有condition
、then_branch
和else_branch
属性,分别表示条件表达式、真分支和假分支的语句。 -
While
类:表示循环语句,包含condition
和body
属性,分别表示循环条件和循环体内的语句。
和之前的 Expr
一样,这些类的accept
方法实现了访问者模式,允许通过传递一个访问者对象给accept
方法,来访问和处理AST中的各个节点,而无需修改这些节点的类定义。
我们可以使用之前提到的自动生成代码的框架,用以下代码创建 Stmt 类:
1 |
|
生成的 Stmt 如下:
1 |
|
parser 扩展
parser 需要做如下扩展:
其中 statement
函数作为主入口点,根据当前解析到的令牌类型决定调用哪个子函数进行更深入的解析。
-
statement
: 根据当前的输入解析不同类型的语句,如if语句、while语句、打印语句或简单的表达式语句。 -
assignment
: 解析赋值语句。它首先尝试解析一个可能带有等号的表达式,如果遇到等号,则解析出赋值操作的右侧表达式,并构建一个Assign
节点,表示赋值操作。 -
expression
: 调用assignment
来解析一个表达式。 -
expressionStatement
: 解析一个表达式语句,以换行符结束,构建一个Expression
节点。 -
block
: 解析一个由多个语句组成的代码块,直到遇到指定的结束标记,返回一个Block
节点,其中包含一系列语句。 -
printStatement
: 解析一个打印语句,以换行符结束,构建一个Disp
节点。 -
ifStatement
: 解析一个if语句,包括条件表达式、then分支和可选的else分支,构建一个If
节点。 -
whileStatement
: 解析一个while循环语句,包括条件表达式和循环体,构建一个While
节点。
代码实现如下:
1 |
|
interpreter 扩展
解释器需要处理不同的语句类型,执行代码块,以及评估表达式的值。
因此 interpreter 需要的扩展如下:
-
interpret
: 解释器的入口点,接收一个语句列表,依次执行每个语句。 -
execute
: 执行单个语句。如果传入的语句不为空,它会调用stmt.accept(self)
方法,利用访问者模式执行相应的语句处理逻辑。 -
executeBlock
: 用于执行一组语句,即代码块。首先保存当前的环境,然后设置一个新的环境,在这个新环境中依次执行代码块中的每个语句,最后恢复原来的环境状态。 -
evaluate
: 评估表达式的值,返回表达式的结果。这里使用expr.accept(self)
调用访问者模式,基于表达式的类型执行相应的评估逻辑。 -
visit_Expression
: 处理表达式语句,通过调用evaluate
方法来评估并忽略其结果。这是因为表达式语句通常是为了其副作用(如赋值),而不是为了返回值。 -
visit_Block
: 处理代码块语句,调用executeBlock
方法执行其中的所有语句。 -
visit_Disp
: 处理输出语句,先评估表达式的值,然后将其打印到标准输出。 -
visit_If
: 处理条件语句,先评估条件表达式的值,如果条件为真,则执行then_branch
;如果提供了else_branch
且条件为假,则执行else_branch
。 -
visit_While
: 处理循环语句,评估条件表达式的值,只要条件为真,就持续执行循环体内的语句。
代码实现如下:
1 |
|
interpreter测试
简单起见,直接在 __main__
里测试,代码如下:
这里多写了几个测试样例,可以选择执行测试。
1 |
|
这里我们给出 stmt_test_code3 的执行结果,对比源代码可知执行结果是正确的。
1 |
|
附录:parser.py 完整代码
1 |
|
附录:interpreter.py 完整代码
1 |
|