自制脚本语言[5.1] if-else分支语句
目录
注意
本文最后更新于 2023-07-30,文中内容可能已过时。
本篇来尝试描述下if-else
语句如何进行实现。
基本内容
语法树部分
先掏出之前给读者看过的这张图, 然后笔者来解释一下其中的内容。
显而易见, 左侧部分是源代码, 右侧部分是一个大致的AST图示。
前两个部分就是一个赋值语句, 一个声明语句。 没什么好描述的。
由图示可知下面的内容。
- 把
if-else
语句 拆分成了一个单独的if
语句和一个单独的else
语句 - 把
if
语句继续拆分成一个condition
部分,一个执行代码块部分。 - 所以我们现在就有了三个小部分。
if.condition
if的 条件部分if.block
if的代码块部分else
else 语句的代码块部分
- 这三个小块的逻辑也比较简单。
if.condition == true
的时候执行if.block
否则执行else
直接在AST上进行运算
如果像现在的langX一样直接在语法树上进行运算的话, 按照下面的方式处理应该就可以了。
笔者现在不建议这样做,因为字节码在进行跳转的时候应该比这种方式简单太多了。
- 先运算
if.condition
部分的代码, 然后把结果保存 - 在
if
块的地方判断结果, 并把if.condition
的结果设置成自己的结果- 如果
if.condition
部分是true
则执行if.block
。 否则什么都不做
- 如果
- 在
if_else
部分 判断if
节点的值, 如果为false
,则执行else
部分
使用字节码进行运算
使用字节码尝试实现的话,核心部分应该在于跳转,所以加上适当的跳转字节码即可。
就像我们前面说过的, 字节码是一条一条指令进行执行的, 所以我们再适当的地方插入适当的跳转指令即可。
我们先来看几个自定义指令。 基于栈的指令。
cjmp
有条件的跳转指令 全写应该是:condition jump
- 此指令存在一个参数, 表示要跳到的指令序号。
- 由于序号在本文中难以确定, 且可能会变化, 所以使用标签来代指。
- 这个指令首先获取栈顶元素, 并将该元素出栈
- 之后判断栈顶元素的值, 如果值是
false
的话, 就跳转, 否则此指令无任何效果
jmp
无条件的跳转指令- 此指令存在一个参数, 表示要跳到的指令序号。
- 由于序号在本文中难以确定, 且可能会变化, 所以使用标签来代指。
- 直接跳转到指定的行数
seti
设置一个变量的值为一个整形数字seti [varName] [intValue]
dec
声明一个变量abci
i 结尾的表示有一个参数是直接的int值。 很可能是第二个参数。label:
使用冒号结尾的当做一个标签, 去掉冒号的部分即为标签的名字。- 在真正的字节码里面应该是不直接使用变量名的, 而是会把变量名转换成数组的索引。 笔者目前只用于示意说明,所以这样写了。
- 附加阅读 字节码列表
字节码列表
里面的字节码进行了适当的优化, 所以和本篇内容略微有些出入。
下面看一段模拟指令。 (伪代码)
|
|
这部分的逻辑其实并不算特别复杂。只不过在字节码层面可能没有那么明确的区分 分支。
并且在这个示例中使用了一个反转的做法,当条件值为false
的时候才进行跳转, 否则什么都不做。
笔者直接把if.block
的语句放在了if.condition
下面, 是接着给的,当条件满足的时候,直接挨个执行指令, 然后在if.block
结尾的地方加上一个无条件跳转语句, 跳出当前的if-else
部分。
字节码部分可能不是那么好懂, 不过没关系, 后面会有更多类似的内容, 看懂了就会懂了。