step3 实验指导
词法语法分析
如果你使用工具完成词法语法分析,修改你的语法规范以满足要求,自行修改词法规范,剩下的交给工具即可。
语义检查无需修改。
如果你是手写分析,TODO
IR 生成
我们同样引入一类 IR 表示二元操作。 执行二元操作的 IR 时,两个操作数需要位于栈顶,然后它们被弹出、进行相应操作,再把结果压入栈顶。
不妨规定二元操作的右操作数在栈顶,左操作数在右操作数下面,那么有如下例子:
3-10
翻译成push 3 ; push 10 ; sub
三条指令。+------------+ 栈顶 | 10 | +------------+ ----------> +------------+ 栈顶 | 3 | 执行 sub | -7 | +------------+ +------------+ | ...... | | ...... |
指令 | 参数 | 含义 | IR 栈大小变化 |
---|---|---|---|
add |
无参数 | 弹出栈顶两个元素,压入它们的和 | 减少 1 |
sub |
无参数 | 弹出栈顶两个元素,压入它们的差,顺序如上 | 减少 1 |
mul 、div 、rem |
无参数 | ……乘除模 | 减少 1 |
类比 step2,生成 IR 时 Visitor 遍历 AST 遇到二元操作,需要(注意 1. 和 2. 的顺序)
- 首先生成左操作数的 IR(左操作数入栈,栈顶是左操作数)
- 然后生成右操作数的 IR(右操作数入栈,栈顶是右操作数)
- 根据操作不同生成对应的二元 IR
上面的 3 步执行完后,栈大小比执行第 1. 步以前增加 1,栈顶就是二元操作的结果。 这符合我们在 step1 中的假设:
考虑源代码中某个表达式被翻译成了一系列 IR 指令,那么从任何初始状态出发执行这些 IR 指令, 完成后 IR 栈大小增加 1,栈顶就是表达式的值。
汇编生成
仿照 step2 所说,用 gcc 自己确定 sub
/mul
/div
/rem
的汇编。
IR | 汇编 |
---|---|
add |
lw t1, 4(sp) ; lw t2, 0(sp) ; add t1, t1, t2 ; addi sp, sp, 4 ; sw t1, 0(sp) |
sub ,mul ,div ,rem |
…… |
任务
- 改进你的编译器,支持本节引入的新特性,通过相关测试。
- 实验报告中回答思考题。
总结
本节重点是执行过程中栈的变化,以及上面提到的 step1 的假设,参见上面 IR 生成一节。