三地址码
复习
- 从抽象语法树降低表示:把高级结构拆简单
- 表达式:由运算组合而成
- 指令:由操作码和操作数组成
TL;DR
- 三地址码把复杂表达式拆成“最多一个运算”的简单指令
- 每条指令形如
x = y op z - 它接近机器指令,又保持独立于具体机器
- 它是一种常见的中间表示形式
正文
降低之后,程序需要一种具体的“样子”来承载。三地址码(three-address code)就是最常用来做 IR 的一种形式。
每条指令只做一件事
三地址码最鲜明的特点,是每条指令最多只包含一个运算,形式通常长这样:
x = y op z (x 等于 y 和 z 运算的结果)
x = y (直接赋值)
goto L (无条件跳转)
if x < y goto L (条件跳转)
所谓“三地址”,指的是这种指令里通常涉及三个位置:一个结果、两个操作数(比如 x = y + z 里的 x、y、z)。当然,像 x = y 这样只有两个的也有,“三地址”只是一个概括的说法。
复杂表达式被拆开
看一个例子。表达式 a + b * c,在三地址码里会被拆成:
t1 = b * c
t2 = a + t1
乘法先算,结果放进临时变量 t1,再用它和 a 相加,结果放进 t2。原本一个复合表达式,变成了两条“一步运算”。优先级、结合性,在这里直接体现成了指令的先后顺序。
它好在哪里
三地址码之所以受欢迎,是因为它站在一个很舒服的位置:
- 足够简单:每条指令只做一步,便于分析和加工
- 足够接近机器:容易进一步翻译成汇编
- 又与机器无关:不像汇编那样绑定某个具体 CPU
于是,它既方便中端做优化,又方便后端生成代码。一层的输出,正好是上一层需要的形状——这正是分层设计追求的效果。
不过,一长串三地址码还是一条“流水账”。要分析程序的控制流,得先把它切成一块块“顺序执行”的段落。下一章就来做这件事。
思考题 1
三地址码为什么叫“三地址”?一条指令最多包含哪些成分?
思考题 2
把
a + b * c拆成三地址码,大概是什么样子?
小结
知识点
- 三地址码每条指令最多一个运算
- 常见形式:赋值、二元运算、跳转
- 复杂表达式被拆成多步并引入临时变量
- 它接近机器又独立于机器,便于优化与代码生成
参考资料
- Wikipedia(zh):三地址码:一种常见的中间表示形式
- Wikipedia(zh):中间表示:编译器内部的程序表示
思考题答案(仅供参考)
思考题 1
“三地址”通常指指令涉及结果与两个操作数这三个位置,例如 x = y + z。它概括了这类“最多一个运算”的指令形式,实际中也有只含两个位置的简单赋值。
思考题 2
大致拆成:t1 = b * c,再 t2 = a + t1。先算乘法、把结果存入临时变量,再与 a 相加得到最终结果。
协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
封面图
设计师 | 南国微雪