# 中间代码生成

## 简单语句的翻译

1. 表达式
   - 从符号表获取地址
   - 产生临时变量
   - 输出翻译后的三地址指令

2. switch 语句
   - 计算表达式的值，每个 case 语句里的代码，匹配到哪个 case 就执行哪个 case 语句里的代码
   - 分支数较少时，分别判断跳转
   - 分支数较多时，将分支测试代码集中在一起，便于更好生成
   - 也可以中间代码增加 case 语句，便于代码生成器特别处理

3. 过程和函数的翻译，综合属性 paramlist，记录所有参数

## 控制流与布尔表达式翻译

1. 控制流语句的文法

$$S\to{\rm if}\ B\ {\rm then}\ S_1|{\rm if}\ B\ {\rm then}\ S_1\ {\rm else}\ S_2|{\rm while}\ B\ {\rm do}\ S_1|S_1;S_2$$

2. 要知道 $B$ 的为真或假时跳转到的目标，$B,S_1$分别输出多少指令是不确定的，引入标号，用于跳转
   - 指向 $S$ 内部的标号，使用 newLabel
   - 指向 $S$ 外部的标号，从 $S$ 继承

## 标号回填与布尔表达式

1. 布尔表达式短路计算翻译中，产生了转移目标不明确的条件或无条件代码
   - 解决方案：生成跳转指令时不指定目标地址，在确定之后再回填到翻译代码中
   - 具体实现：将有相同转移目标的转移代码的**编号串起来形成链**，可以方便回填目标地址，链表为综合属性，可以和 LR 结合
   - 一个布尔表达式，有两个综合属性：truelist 和 falselist，分别为转向真出口和转向假出口的代码指令链

2. 基于标号回填的布尔表达式翻译

## 标号回填与控制流语句

## 类型表达式及自动构造

1. 类型可以是语法的一部分，因此也是结构的，包括基本类型与复杂类型

2. 类型表达式
   - 基本类型是类型表达式
   - 可为类型表达式命名，**类名** 也是类型表达式
   - 类型构造算子作用于类型表达式可以构成新的类型表达式

3. 类型表达式的 SDD
   - 每个文法符号要有综合属性 (为对应的类型表达式)和继承属性 (将类型信息从左到右传递)

4. 类型表达式的 SDT
   - 引入记号，使符合 LR 分析

## 符号表与声明语句翻译

1. 符号表
   - 符号表的使用和修改伴随编译的全过程
   - 存储实体的各种信息，如变量名、函数名、对象、类、接口等，包括类型信息、所占用内存空间、作用域
   - 用于编译过程中的分析与合成
     - 语义分析：如使用前声明检查、类型检查、确定作用域等
     - 合成：如类型表达式构造、内存空间分配等
   - 符号表与作用域有关

2. 声明语句翻译
   - 分配存储单元：名字、类型、字宽、偏移
   - 作用域的管理：过程调用
     - 过程嵌套声明：每个过程内声明的符号要置于该过程的符号表中，方便地找到子过程和父过程对应地符号
   - 记录类型的管理：单独建符号表，域的相对地址从0开始
   - **不产生中间代码指令但要更新符号表**

3. 符号表的组织与管理
   - 各过程有各自的符号表：**哈希表**
   - 符号表间有双向链
     - 父->子：过程中有哪些子过程定义
     - 子->父：分析完子过程继续分析父过程
   - 维护符号表栈和地址偏移量栈：保存尚未完成的过程的符号表指针和相对地址

## 数组寻址的翻译

1. 数组元素地址计算，考虑基地址，数组下标的下界，数组元素宽度以及数组元素下标，其中基地址、下标下界、宽度均为常数，在编译时计算，减少运行时计算
   - 数组下标对应的地址对多维考虑递推

2. 数组元素地址计算翻译方案
   - 下标翻译时需要数组信息，这些都要通过继承属性传递
   - 不过继承属性计算不适合移进归约分析，需要考虑修改文法
   - 简单添加助记符也是可以的，不过会使文法变得复杂
   - 也可以考虑修改文法，使得数组名成为后续下标的子结点，避免继承属性的出现