概述
约 1112 字大约 4 分钟
2025-01-14
编译器中的核心数据结构是其所编译程序的表示形式。编译器中的大多数遍历过程读取并操作这种中间表示(IR)。因此,关于表示什么以及如何表示这些内容的决策在编译成本及其效果方面起着关键作用。本章将对编译器使用的IR进行综述,包括图形IR、线性IR及这两种形式的混合体,同时还会介绍编译器维护的辅助数据结构,如符号表。
编译器通常被组织为一系列的遍历过程。随着编译器对其翻译的代码获取更多的知识,它必须记录这些知识并将它们传递给后续的遍历过程。因此,编译器需要一种表示所有关于程序的事实的方法。我们将这种数据结构的集合称为中间表示(IR)。一个编译器可能只有一种IR,也可能有一系列在将源代码翻译成目标语言的过程中使用的IR。编译器依赖IR来表示程序;它不会回溯参考源文本。IR的特性对编译器能对代码做什么和不能做什么有直接影响。
使用IR使得编译器可以对代码进行多次遍历。如果编译器能够在一次遍历中收集信息并在另一次遍历中使用这些信息,它可以为输入的程序生成更高效的代码。然而,这种能力也施加了一个要求:IR必须能够表示所推导出的信息。因此,编译器还会构建各种辅助的数据结构来表示推导出的信息,并提供对该信息的有效访问。这些结构也是IR的一部分。
概念性路线图
本章关注于编译中IR设计和使用相关的问题。一些编译器使用树和图来表示被编译的程序。例如,解析树可以轻松捕捉由解析器构建的推导,而Lisp的S表达式本身就是简单的图。由于大多数处理器依赖于线性的汇编语言,编译器经常使用类似于汇编代码的线性IR。这样的线性IR可以揭示目标机器本地代码的特性,为编译器提供优化的机会。
随着编译器构建程序的IR形式,它会发现并衍生出可能不适合简单地放入树、图或线性IR中的信息。编译器必须理解程序的名字空间,并建立辅助结构来记录这些派生的知识。它必须创建存储布局计划,以便编译后的代码能够将值存储到内存并在需要时检索它们。最后,它需要通过名称高效访问所有派生的信息。为了满足这些需求,编译器构建了一组与树、图或线性IR共存的辅助结构,形成了编译器关于程序知识库的关键部分。
概述
现代多遍编译器使用某种形式的IR来建模被分析、转换和优化的代码。编译器中的大多数遍都消费IR;由扫描器产生的分类词流可以被视为一种设计用于在扫描器和解析器之间通信的IR。编译器中的大多数遍也产生IR;代码生成器中的遍可能是例外。许多现代编译器在单次编译过程中使用多种IR。在基于遍的编译器中,IR作为代码的主要表示形式。
编译器的IR必须具有足够的表达力以记录编译器可能需要在各遍之间传输的所有有用信息。源代码本身对于这个目的来说是不够的;编译器衍生出的很多信息在源代码中没有表示。例如,包括变量的地址或传递给定参数的寄存器编号。为了记录编译器必须编码的所有细节,大多数编译器编写者会增强IR。IR通过表和集等结构来记录附加信息,这些结构构成了IR不可或缺的一部分。
更新日志
c7425
-更新中间代码生成于