编译原理(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