编译原理--中间代码生成
基础
DAG
语法树是一种图形化的中间表示。但语法树中,公共子表达式每出现一次,就有一个对应的子树,产生了大量冗余,
因此定义了另一种中间表示:有向无环图(Directed Acyclic Graph, DAG)
有向无环图的构造与抽象语法树类似。
三地址代码
一般包括一个运算符和之多三个运算分量(地址),所以叫做三地址代码。这里的地址包括:变量、常量、临时变量。
- 指令集合
- 运算/赋值指令:x=y op z ,x = op y
- 复制指令:x=y
- 无条件转移指令:goto L
- 条件转移指令:if x goto L ,ifFalse x goto L
- 条件转移指令:if x relop y goto L
- 过程调用/返回 p(x1, x2, …, xn)
• param x1 //设置参数
• param x2
• …
• param xn
• call p, n //调用子过程p,n为参数个数 - 带下标的复制指令:x=y[i] x[i]=y • 注意:i表示离开数组位置第i个字节,而不是数组的第i个元素
- 地址/指针赋值指令: • x=&y x=*y *x=y
-
三地址代码的四元式表示
格式(字段): op arg1 arg2 result
如:+ x y z
对于有些指令,一些参数是空缺的,如param x1 null null
[if goto] x null L
-
三地址代码的三元式表示
op arg1 arg2
使用三元式的位置来引用三元式的运算结果 -
三地址代码的间接三元式表示
包含了一个指向三元式的指针的列表 我们可以对这个列表进行操作,完成优化功能;操作时不 需要修改三元式中的参数 -
静态单赋值SAA
问题
声明语句的翻译
PPT 24-54
表达式和赋值语句的翻译
- 数组引用生成代码的翻译方案
非终结符号L的三个综合属性
- L.addr指示一个临时变量,计算数组引用的偏移量 ij * wj
- L.array是一个指向数组名字对应的符号表条目的指针, L.array.base为该数组的基地址
- L.type是L生成的子数组的类型,对于任何数组类型t,其宽度由 t.width给出,t.elem给出其数组元素的类型
控制流翻译
- 文法:B表示布尔表达式,S代表语句 S → if (B) S1 ; S → if (B) S1 else S2 ;S → while (B) S1 . 代码的布局见下图
- 继承属性
- B.true:B为真的跳转目标
- B.false:B为假的跳转目标
- S.next:S执行完毕时的跳转目标
例:
布尔表达式的翻译
- 当布尔表达式的计算用于跳转分治
布尔表达式翻译的主要语义动作是跳转,而跳转的标签主要根据短路规则来确定。
- 当布尔表达式的计算用于赋值
采用临时变量的方法
switch 语句的翻译
过程调用的翻译
回填
布尔表达式用于语句的控制流时,它总是在取值true时和取值false 时分别跳转到某个位置
-
引入两个综合属性
- truelist: 包含跳转指令(位置)的列表,这些指令在取值true时执行
- falselist:包含跳转指令(位置)的列表,这些指令在取值false时执行
-
辅助函数
- Makelist(i):创建一个只包含i的列表
- Merge(p1,p2):将p1和p2指向的列表合并
- Backpatch(p,i):将i作为目标标号插入到p所指列表中的各指令中
-
控制转移语句的回填
M的作用就是用M.instr记录下一个指令的位置 • N的作用是生成goto指令坯,N.nextlist只包含这个指令 的位置