1 中间语言
中间表示 IR,Intermediate Representation
LLVM,Low Level Virtual Mechine
后缀表示(逆波兰式)
比如 ( 8 - 5 ) + 2 的后缀表示是 8 5 - 2 +,不需要括号,前提:算符无二义
优点:便于计算机处理表达式,如求值,代码生成等
表达能力:可以拓广到表示赋值语句和控制语句,适合底层实现;但是很难用栈来描述控制语句的计算
前缀表示(波兰式)
一种逻辑、算数和代数的表示方法,如 op (a, b, c),用于简化命题逻辑,适合上层表达
图形表示
- 语法树是一种图形化的中间表示
- 有向无环图 DAG 也是一种中间表示

构造赋值语句语法树的语法制导定义
mkUNode (op, child) 是构造一元运算节点的函数
这里用的是二义文法,比如 + 和 * 没有在文法中规定优先级,但是看成和平凡情况一样
| 产生式 | 语义规则 |
|---|---|
| S → id = E | S.nptr = mkNode ( 'assign', mkLeaf (id, id.entry), E.nptr ) |
| E → E~1~ + E~2~ | E.nptr = mkNode ( '+', E~1~.nptr, E~2~.nptr ) |
| E → E~1~ * E~2~ | E.nptr = mkNode ( '*', E~1~.nptr, E~2~.nptr ) |
| E → -E~1~ | E.nptr = mkUNode ( 'uminus', E~1~.nptr ) |
| E → (E~1~) | E.nptr = E~1~.nptr |
| F → id | E.nptr = mkLeaf (id, id.entry) |
三地址代码
一般形式:x=y\ \textbf{op}\ z,最多 1 个算符,最多 3 个计算分量(均为运算对象的地址)
例如,表达式 x+y*z 翻译成三地址语句序列是
- t_1=y*z
- t_2=x+t_1
三地址代码是语法树或者 DAG 的一种线性表示
- 对语法树进行后序遍历产生后缀式,后缀式可以容易地转化成三地址代码
- 编译器实现中会建立后序线索树,方便代码生成、求值等

常用的三地址语句
- 赋值语句 x=y\textbf{ op }z\quad\quad x=\textbf{op }y
- 复写语句 x=y
- 无条件转移 \textbf{goto}\ L
- 条件转移 \textbf{if }x\textbf{ relop }y\ \textbf{goto}\ L
- 过程调用 \textbf{param}\ x(参数设置)\textbf{call }p,n(调用含 n 个参数的子过程 p)
过程调用的典型使用是
param x1 param x2 ... param xn call p, n这些指令是过程调用 p(x_1,...,x_n) 的中间代码
- 过程返回 \textbf{return }y
- 索引赋值 x=y[i]\quad x[i]=y
- 地址和指针赋值 x=\&y\quad x=*y\quad *x=y
静态单赋值
static single-assignment, SSA
- 一种便于某些代码优化的中间表示
- 和三地址代码有一些区别:所有赋值指令都是对不同名字的变量的赋值

- 新问题:有一些变量可能在不同的控制流路径上都被定值,如:
if (flag) x = -1;
else x = 1;
y = x * a;
改成:(Phi 算子:汇合对多个可能定值的引用)
if (flag) x1 = -1;
else x2 = 1;
x3 = φ(x1, x2); // 由flag的值决定用x1还是x2
y = x3 * a;
例子
prod = 0;
i = 1;
do {
prod = prod + a[i];
i = i + 1;
} while (i <= 20);
三地址码:
1 prod = 0
2 i = 1
3 t1 = 4 * i
4 t2 = a[t1] // 元素地址要转换成按字节寻址
5 t3 = prod + t2
6 prod = t3 // 可以重复定值,上面的Phi只是用于面对在多个控制流中
7 t4 = i + 1
8 i = t7
9 if i <= 20 goto 3.