The Decaf Book
  • Introduction
  • 语言规范
  • Java 框架分阶段指导
    • 本章导引
    • PA1-A:语法分析器的自动构造
      • 阶段任务
      • 词法分析
      • 抽象语法树
      • 文法分析
    • PA1-B:基于 LL(1) 的语法分析器半自动构造
      • 阶段任务
      • LL(1) 文法分析
      • 错误恢复
    • PA2:语义分析
      • 阶段任务
      • 类型、符号和作用域
      • 访问者模式
      • 符号表构建
      • 类型检查
    • PA3:中间代码生成
      • 阶段任务
      • TAC 程序
      • 面向对象机制
      • 控制流的翻译
    • PA4:中间代码优化
      • 实验内容
      • 基本块
      • 数据流分析概述
      • 数据流优化概述
      • 公共表达式提取
      • 复写传播
      • 常量传播
      • 死代码消除
  • Scala 框架分阶段指导
    • 本章导引
    • PA1:语法分析器的自动构造
      • 阶段任务
      • 词法分析
      • 抽象语法树
      • 文法分析
      • 访问者模式
    • PA2:语义分析
      • 阶段任务
      • 类型、符号和作用域
      • 符号表构建
      • 类型检查
    • PA3:中间代码生成
      • 阶段任务
      • TAC 程序
      • 面向对象机制
      • 控制流的翻译
    • PA3-JVM:JVM 字节码生成
      • 阶段任务
      • JVM 字节码简介
      • 翻译过程
    • PA4:中间代码优化
      • 实验内容
      • 基本块
      • 数据流分析概述
      • 数据流优化概述
      • 公共表达式提取
      • 复写传播
      • 常量传播
      • 死代码消除
  • Rust 框架分阶段指导
    • 本章导引
    • PA1-A:语法分析器的自动构造
      • 实验内容
      • lalr1使用指导
        • 编写lexer
        • impl块的可选属性
        • 产生式和语法动作
        • 解决冲突
        • 一个完整的例子
      • 抽象语法树
      • 框架中部分实现的解释
      • 文件结构
    • PA1-B:基于 LL(1) 的语法分析器半自动构造
      • 实验内容
      • lalr1使用指导
      • 错误恢复
      • 文件结构
    • PA2:语义分析
      • 实验内容
      • 语义分析
      • 符号表
      • visitor模式
    • PA3:中间代码生成
      • 实验内容
      • 中间代码
      • 中间代码中的类型信息
      • 运行时存储布局
      • 面向对象机制
      • tacvm简述
    • PA4:中间代码优化
      • 基本块
      • 数据流分析概述
      • 数据流优化概述
      • 公共表达式提取
      • 复写传播
      • 常量传播
      • 死代码消除
    • PA5:寄存器分配
      • 实验内容
      • 图着色基本原理
      • 着色算法
      • 预着色节点
      • 干涉图节点合并
      • 调用约定
Powered by GitBook
On this page

Was this helpful?

  1. Java 框架分阶段指导
  2. PA3:中间代码生成

阶段任务

在上一阶段中,我们已经完成了对 Decaf 程序的语义分析工作。 针对语义检查通过的程序,我们将在这一阶段把带有类型标注的 AST 进行翻译成适合后端处理的一种中间表示 (Intermediated Representation, IR)。 事实上,框架中已经实现了解释执行该 IR 的模拟器程序,因此你即使不进行后端的工作,在这一阶段结束时也可以在该模拟器上完整地运行 Decaf 程序。 这是一个很大的里程碑,它标志着我们已经完整实现了 Decaf 编译器的前端。

一般来说,把程序翻译为 IR 是各种编译器前端的最后一步工作,这步工作以后编译过程便进入了中端处理或者直接进入后端处理部分。 为了便于翻译工作的进行,在实际的编译过程中往往需要反复地从一种 IR 变为另一种 IR,直到变换成最终的汇编代码或者二进制目标代码为止,其中后面的 IR 总是更加适合“更后端”部分所需的分析和处理。 例如 gcc 的编译过程除 AST 以外还有 GENERIC, GIMPLE, RTL 几种 IR。

在 Decaf 编译器中,为简单起见,我们只涉及一种 IR——三地址码 (Three Address Code, TAC)。 它看起来很像汇编,但是和汇编最大的差异在于——汇编里面使用的是目标平台(如 x86, mips)规定的物理寄存器,其数目有限; 而 TAC 使用的是“伪寄存器”,我们称临时变量,理论上其数目可以无限,实际中我们想要多少就有多少(只要模拟器在运行时操作系统允许占用那么大的内存)。

这一阶段的核心任务是:把带有类型标注的 AST 翻译成语义上等价的 TAC,并在合适的地方加入检查如数组访问越界、数组大小非法等运行时错误的 TAC 指令。 输出的 TAC 通过模拟器运行,得到预期的运行结果(控制台输出)。 在本阶段,你将会体验到“元编程”——编写用来生成代码(TAC)的代码。 通过这个阶段,希望大家能掌握一般的 IR 翻译方法,并且对于过程调用约定、面向对象机制的实现方法、存储布局等内容有所了解。

相关文件

与本阶段相关的文件有:

src
└── main
    └── java
        └── decaf
            └── frontend
            │   └── tacgen
            │       ├── TacGen.java       TAC 生成入口
            │       └── TacEmitter.java   语句和表达式的 TAC 生成、辅助函数
            └── lowlevel
                ├── instr   指令、临时变量
                ├── label   标签
                ├── tac     TAC 程序的生成与模拟运行
                └── log     调试日志相关

其中 decaf.lowlevel 包作为一个库使用,在进行实验时无需阅读其实现代码,只需要了解所提供函数的使用方法。

PreviousPA3:中间代码生成NextTAC 程序

Last updated 5 years ago

Was this helpful?