step3 实验指导

本实验指导使用的例子为:

1+3

词法语法分析

在 step3 中,我们引入了算术运算,因此需要引入新的抽象语法树节点:

Python 框架

节点 成员 含义
Binary 左操作数 lhs,右操作数 rhs,运算类型 op 二元运算

对有兴趣的同学:虽然 -22-3 里面的 - 意义不同,但 lexer 不知道这点(parser 才知道),所以它们都会用同样的 token kind - 表示。 但有时,可能需要后续阶段告诉 lexer(或 parser)一些信息,最经典的例子是 “typedef-name identifier problem”

C++ 框架

类似step2,对每种二元运算实现了不同的语法树节点

节点 成员 含义
AddExpr 左操作数 e1,右操作数 e2 加法运算
SubExpr 左操作数 e1,右操作数 e2 减法运算
MulExpr 左操作数 e1,右操作数 e2 乘法运算
DivExpr 左操作数 e1,右操作数 e2 除法运算
ModExpr 左操作数 e1,右操作数 e2 取模运算

语义分析

同 Step2。

中间代码生成

与一元操作类似,针对加法,我们需要设计一条中间代码指令来表示它,给出的参考定义如下:

请注意,TAC 指令的名称只要在你的实现中是一致的即可,并不一定要和文档一致。

指令 参数 作用
ADD T0,T1 将两个参数相加

因此,测例可以翻译成如下的中间代码:

_T0 = 1
_T1 = 3
_T2 = ADD _T0, _T1

目标代码生成

step3 目标代码生成步骤的关键点与 step2 相同,针对中间代码指令,选择合适的 RISC-V 指令来完成翻译工作。

li t0, 1
li t1, 3
add t2, t0, t1

思考题

  1. 我们知道“除数为零的除法是未定义行为”,但是即使除法的右操作数不是 0,仍然可能存在未定义行为。请问这时除法的左操作数和右操作数分别是什么?请将这时除法的左操作数和右操作数填入下面的代码中,分别在你的电脑(请标明你的电脑的架构,比如 x86-64 或 ARM)中和 RISCV-32 的 qemu 模拟器中编译运行下面的代码,并给出运行结果。(编译时请不要开启任何编译优化)
#include <stdio.h>

int main() {
  int a = 左操作数;
  int b = 右操作数;
  printf("%d\n", a / b);
  return 0;
}

总结

本步骤中其他运算符的实现逻辑和方法与加法类似,可以参考二元加法的实现方法设计实现其他二元运算符。

results matching ""

    No results matching ""

    results matching ""

      No results matching ""