编译原理(7) 中间代码生成
2023-08-09 14:53:19 # NJU # 编译原理

中间代码生成

一、表达式的翻译与控制流的翻译

1. 核心

1.1 大局观

1.2 分工、合作

image-20221226161923069

分工: $B$, $S_1$ 各自负责自己的中间代码生成

合作: $B$ 为 true 或 false 时, 需要跳转到不同的位置(类似 goto label), 这个位置 $B$ 不知道, 需要父节点(或父父节点..)通过继承属性传递信息

  • 当 $B$ 为 true, $S$ 知道应该跳转到哪
  • 当 $B$ 为 false, $P$ 知道应该跳转到哪

2. 表达式的翻译

2.1 总览

  • 起始符号为第三段的 $P$
image-20221226163911815

2.2 表达式的中间代码翻译

  • 综合属性 $\textcolor{green}{E.code}$: 中间代码
  • 综合属性 $\textcolor{blue}{E.addr}$: 变量名(包括临时变量)、常量
image-20221226170705741
  • LLVM IR
    • 因为没有被使用过, 设置优化后会全部删掉
image-20221226165931772

2.3 数组引用的中间代码翻译

  • 声明: $\text{int } a[2][3]$
  • 数组引用: $x = a[1][2];\ a[1][2] = x$
  • 需要计算 $a[1][2]$ 相对于数组基地址 $a$ 的偏移地址
    • $addr(a[1][2]) = \textcolor{blue}{base} + 1 \times 12 + 2 \times 4$
image-20221226171518951 image-20230104195326682
  • 综合属性 $\textcolor{green}{L.array(.base)}$: 数组基地址(即,数组名)
  • 综合属性 $\textcolor{red}{L.addr}$: 偏移地址
image-20230104195549841
  • eg: $c + a[i][j]$

    image-20230108132058170
  • GEP Instruction

    为什么要多一个 i64 0:

    • %2 指向的是这一整个数组,如果直接对其偏移就会偏移 n 个数组大小的位置
    • 因此需要 i64 0,先对其解一层([0])
    image-20230108132135329

2.4 控制流语句与布尔表达式的中间代码翻译

继承属性 $\textcolor{blue}{B.true, B.f alse, S.next}$ 指明了控制流跳转目标

image-20230108132248288
  • 继承属性 $\textcolor{red}{S.next}$
    • $S.next$ 为语句 $S$ 指明了 “跳出” $S$ 的目标
    • $P$ “知道” $S.next$ 在哪,会在 $S$ 后面添加标签
  • 代表了表达式的翻译, 包括数组引用
image-20230109214843035 image-20230109215321211
if 语句
image-20230109215437475
  • 举例

    image-20230109220923761
if-else 语句
image-20230109221547115
  • 举例

    image-20230109221603920
while 语句
image-20230113173701643
  • 举例
image-20230113173815940
并列语句
image-20230113180355333

2.5 布尔表达式的中间代码翻译

image-20230113180528906
  • image-20230113180725060
  • !

    image-20230113180821400
  • ||

    image-20230113180906940
  • &&

    image-20230113181038343
  • rel

    image-20230113181113631
示例
image-20230113182158071 image-20230113182220865
image-20230113182136913

2.6 布尔表达式的作用

image-20230113210020300 image-20230113210031118