前 言
Crafting a Compiler
自1988年费希尔和勒布朗合著的Crafting a Compiler出版以来,情况已经发生了很大变化。虽然教师可能还记得那本书保存在5.25英寸软盘上的附带软件,但现在的大多数学生既未曾拥有过也没有见过这样的软盘。学生在课堂上和课外所体验的编程语言发生了许多变化。1991年,这本书以两种形式出现,其中的算法用C语言或Ada语言呈现。虽然现在C语言仍然是一种流行的语言,但Ada语言已经变得鲜为人知,没有达到预期的流行程度。C 语言从C语言发展而来,加入了面向对象的特性。Java是作为一种更简单的面向对象语言开发的,因其安全性和能在Web浏览器中运行而受到欢迎。美国大学理事会指定的大学先修课程已从Pascal改为C ,而后又改为Java。
虽然发生了很多变化,但学生还在继续学习、教师也还在继续教授编译器构造这一课程。编译器和编程语言翻译领域的研究继续快步前进,这是因为编译器以适应日益多样化的体系结构和编程语言为己任。软件开发环境也依赖于编译器与各种软件工具链组件(如语法感知编辑器、性能剖析工具和调试器)的成功互动。所有的现代软件都依赖于编译器来严格检查错误并忠实地翻译程序。
随着时间的推移,一些教科书经历了相对较小的变化,可能增加了一些新的习题或示例。而本书则反映了1988年到1991年期间素材的大量实质性的修订。虽然本书的重点仍然是讲授编译器结构的基本原理,但算法和方法层面已融入最新实践:
● 已经从实际应用中消失的主题(例如,属性文法)的相关内容已被尽量压缩或完全删除。
● 算法以伪代码(pseudocode)的形式呈现,这对于学习过本学科基本算法的学生来说应该很熟悉。伪代码使对算法的简明表述及对算法的目的和构造的合理讨论成为可能。
用特定语言实现这些算法的细节已归入Crafting a Compiler Supplement,该补充材料可在线获取,网址为http://www.pearsonhighered.com/fischer/。
● 调整了语法分析理论和实践的组织方式,以适用于各种教学方法。
有些学生可能会在较高层次上学习这部分内容,以获得自顶向下和自底向上语法分析的宽广视野。其他学生可以更详细地研究特定的方法。
● 编译器的前端和后端由抽象语法树(Abstract Syntax Tree,AST)衔接,AST是作为语法分析的主要产出而创建的。大多数编译器都会构建AST,但是鲜有教科书阐明AST的构造和用法。
引入了访问者模式(visitor pattern),以便在语义分析和代码生成期间遍历AST。
● 提供了实验室练习供教师使用。
教师可以将其中的一部分作为学生的练习,而其他部分则可从我们的课程支持网站
获得。
有些教科书经过修订,增加了更多的研究生水平的素材。虽然这些内容在高级课程中可能有用,但本书的主要读者仍然是学习编译器构造的本科生。研究生课程可以使用第13章和第14章的内容,并将前面的部分作为参考材料。
伪代码和缩写
本书的一个重要变化是,算法不再以任何特定的编程语言(如C或Ada)呈现,而是以伪代码的形式呈现,所使用的风格对于那些研究过最基本算法的人来说应该是熟悉的[CLRS01]。伪代码通过省略不必要的细节来简化算法的描述。然而,伪代码暗示了实际编程语言中使用的结构,因此实现应该是直接的。本书广泛使用缩写(包括首字母缩写)来简化描述,并帮助读者掌握编译器构造中使用的术语。例如,在前言中已经使用了AST作为抽象语法树的缩写。
本书的使用方法
关于编译器构造的入门课程可以从第1~3章开始。关于语法分析技术,可以选择自顶向下语法分析(第5章)或自底向上语法分析(第6章),但有些教师会选择同时介绍这两种方法。可以根据需要讲授第4章的内容,以支持将要学习的语法分析技术。第7章阐述了AST并给出了遍历AST的访问者模式。第8章和第9章介绍语义分析的各个方面,教师可自行决定讲授哪些内容。如果是一学期的课程,则可就此结束。如果是一学年的课时,则可继续学习代码生成,如下所述。
第10章介绍Java虚拟机(Java Virtual Machine,JVM),如果学生要在他们的项目中生成JVM代码,就应讲授这些内容。第11章介绍虚拟机代码生成。希望学生生成机器代码的教师可以跳过第10章和第11章,而只讲第12章和第13章。入门课程可以包括第14章开始部分有关自动程序优化的内容。
第4~6章中涉及语法分析技术的更多细节。第8章和第9章对类型检查和语义分析进行了广泛和深入的研究。第10章和第14章介绍高级概念,如静态单赋值(Static Single Assignment,SSA)形式等。第14章涉及程序分析和转换的高级主题,包括数据流框架。第13章和第14章可以作为研究生编译器课程的基础,辅以前面的章节作为参考材料。
各章概述
第1章 引言
该章首先概述了编译过程。强调从一组组件来构造编译器的概念。概述了编译器的历史,并介绍了生成编译器组件的工具的使用方法。
第2章 一个简单的编译器
该章介绍了简单语言ac,并讨论了将ac转换为另一种语言dc的编译器的每个组件。这些组件以伪代码的形式呈现,完整的代码可以在Crafting a Compiler Supplement中找到。
第3章 词法分析理论与实践
该章介绍了构建编译器词法分析组件的基本概念和技术。具体内容包括如何手工编写词法分析器以及使用词法分析器生成器来实现表驱动的词法分析器。
第4章 文法和语法分析
该章涵盖了形式语言的基本概念,包括上下文无关文法、文法表示、推导以及语法分析树,还介绍了第5章和第6章中将使用的文法分析算法。
第5章 自顶向下语法分析
自顶向下语法分析是构造相对简单的语法分析器的一种流行技术。该章展示了如何使用显式代码或通过构造供通用自顶向下语法分析引擎使用的分析表来编写这样的语法分析器。该章还讨论了语法错误的诊断、恢复和修复。
第6章 自底向上语法分析
大多数现代编程语言编译器使用该章介绍的某种自底向上语法分析技术。从上下文无关文法自动生成这种语法分析器的工具广泛可用。该章描述了构建这些工具的理论,包括一系列日益复杂的方法,这些方法用来解决阻碍从某些文法构建语法分析器的冲突(conflict)。该章还深入讨论了文法和语言的二义性(ambiguity),并提出了理解和解决二义性文法的启发式方法。
第7章 语法制导翻译
从编译器构成组件的角度,该章标志着本书的中点。前面的章节已经介绍了程序的词法分析和语法分析。这些章节的目标是构造AST。该章介绍AST并阐述用于构造、管理和遍历AST的接口。该章是非常关键的,因为后续章节既依赖于理解AST,也依赖于理解促进AST的遍历和处理的访问者模式。Crafting a Compiler Supplement包含了一个关于访问者模式的教程,包括从常见实践经验中提取的示例。
第8章 符号表和声明处理
该章强调使用符号表作为一个抽象组件,可在整个编译过程中使用。为符号表定义了一个精确的接口,并提出了各种实现问题和解决思路,其中包括对嵌套作用域实现的讨论。
该章还介绍了处理符号声明所需的语义分析,包括类型、变量、数组、结构和枚举,同时介绍了类型检查,包括面向对象类、子类和超类。
第9章 语义分析
对于在语法分析时不容易检查的语言规范,需要进行额外的语义分析,包括检查各种控制结构,如条件分支和循环。该章还讨论了异常及其在编译时所需的语义分析。
第10章 中间表示
该章介绍了编译器广泛使用的两种中间表示。第一种是JVM指令集和字节码格式,它已经成为表示Java程序编译结果的标准格式。对于有兴趣在编译器项目中使用JVM的读者,第10章和第11章提供了必要的背景知识和技术。另一种表示是SSA形式,它被许多优化编译器使用。该章定义了SSA形式,但要等到第14章才会介绍它的构造,并给出一些必要的定义和算法。
第11章 虚拟机代码生成
该章讨论针对虚拟机(Virtual Machine,VM)的代码生成。这种目标平台的优点是,运行时支持的许多细节都包含在VM中。例如,大多数VM提供无限数目的寄存器,因此尽管寄存器分配(register allocation)问题很有趣,但可以推迟到掌握了代码生成的基本知识之后再讨论。而且,虚拟机的指令集通常处于比机器码更高的级别。例如,一个方法调用通常由单个VM指令支持,而相同的调用用机器代码实现可能需要更多指令。
虽然对生成机器码感兴趣的读者可能会跳过第11章,但我们建议先学习这一章,然后再尝试生成机器码级别的代码。第11章的思想很容易应用于第12章和第13章,但从VM的角度来看,它们更容易理解。
第12章 运行时支持
在VM中嵌入的许多功能都是对运行时的支持(例如,对管理存储的支持)。该章讨论为现代编程语言提供所需的运行时支持的各种概念和实现策略。研究这些内容有助于理解虚拟机的构造。对于那些为目标体系结构编写代码生成器的人,必须提供运行时支持,因此学习第12章的内容对于创建一个可工作的编译器来说是必不可少的。
该章讨论了静态分配存储、栈分配存储和堆分配存储,还讨论了对非局部存储(nonlocal storage)的引用,以及支持此类引用的帧和显示表等实现结构。
第13章 目标代码生成
该章与第11章相似,区别是代码生成的目标与VM相比是相对低级的指令集。这一章全面讨论了代码生成中产生的主题,包括寄存器分配、临时变量管理、代码调度、指令选择和一些基本的窥孔优化。
第14章 程序优化
大多数编译器都包含一些改进它们生成的代码的功能。该章介绍编译器在程序优化中常用的一些实用技术,还介绍了进阶的控制流分析结构和算法。通过一些相对容易实现的基本优化,介绍了数据流分析(data flow analysis)。研究了此类优化的理论基础,并讨论了SSA形式的构造和使用。
查尔斯·N.费希尔 (Charles N.Fischer) 美国威斯康星大学计算机科学系教授,长期为本科生和研究生讲授编译原理相关课程。研究兴趣为编译器设计与实现。
罗恩·K.塞隆 (Ron K.Cytron) 美国圣路易斯华盛顿大学计算机科学与工程系教授,研究兴趣为实时系统与程序设计语言。
理查德·J.勒布朗 (Richard J.LeBlanc,Jr.) 美国佐治亚理工学院计算机系教授,主讲编译器与解释器方面的课程。曾任ACM教育委员会委员,是SE2004教育规范委员会副主席。
王刚,南开大学计算机学院教授、博士生导师。主要讲授程序设计、算法、编译、并行计算方面的课程。研究兴趣包括计算机理论、海量信息存储、并行与分布式计算、搜索引擎等,特别是在分布式存储系统可靠性技术、云存储用户数据隐私保护、搜索引擎性能优化等方向取得了一系列重要成果。近年来在计算机领域的国际顶尖学术期刊及国际顶级学术会议发表学术论文。主持国家863项目、国家自然科学基金项目、天津市自然科学基金项目等,主持与百度公司、奇虎360公司、华为公司等合作项目。现为IEEE/ACM/中国计算机学会会员、中国计算机学会信息存储专委会委员、中国计算机学会理论计算机专委会委员。