前言A Retargetable C Compiler: Design and Implementation编译器是程序员使用的关键工具,程序员每天都在使用编译器,并且非常依赖于其正确性和可靠性。编译器必须接受程序语言的所有标准定义,以便源代码可以实现跨平台的可移植性。编译器必须生成高效的目标代码,但更重要的是,编译器必须生成正确的目标代码,只有可靠的编译器才能生成可靠的应用程序。编译器本身是一个大而复杂的应用程序,值得我们深入分析研究。本书介绍了ANSI C语言编译器lcc的大部分实现,对编译器的介绍方式与B. W. Kernighan和P. J. Plauger合著的《Software Tools》(Addison-Wesley,1976)一书对文本处理(例如文本编辑和宏处理)的介绍类似。研究实用的工具软件,是学习软件设计和实现技术的最好方法。本书在代码级详细介绍了一个实用的编译器,该编译器的完整源代码可在ftp.cs.princeton.edu(128.112.152.13)服务器的publcc目录下,通过匿名ftp服务得到。lcc不是一个研究系统,而是一个实用的编译器产品。从1988年开始,lcc就用于编译实际程序,现在每天都有数百名C程序员在使用它。由于本书详细分析了lcc编译器的设计与实现,因此用于介绍相关支撑材料的篇幅较少,仅展示了涉及的理论知识,而更为系统的编译技术的介绍可以参见其他教材。本书有意省略一些涉及琐碎和重复实现的语言特征,而将这部分内容作为练习。显然,本书将使读者对编译器的构造有更多的了解。然而只有少数程序员需要了解编译器的设计与实现,大多数程序员从事的是应用程序或其他系统程序的开发。但是,基于以下4个原因,大多数C程序员都可以从本书中受益。第一,一般来说,如果程序员能够理解C编译器的工作原理,通常可以成为较好的程序员,特别是较好的C程序员。编译器设计者必须全面准确地理解C语言的每一个特性,程序员通过学习这些特性的实现,能够更好地掌握语言本身及其在现代计算机上的高效实现。第二,大多数程序设计教材都是通过一些精简的示例来说明编程技巧的,但大多数程序员都是在从事大型程序的开发,在开发过程中需要不断修改程序,很少有带详细说明的示例可以作为大型程序设计的参考。lcc不是完美的,但是本书详细说明了该程序的优缺点,可以作为大型程序开发的参考。第三,编译器是计算机科学中理论与实践相结合的最好典范。lcc展示了理论与实践的相互作用及其精美的结果,展示了实践需求牵引理论的发展,这些都可以清楚地从代码中找到。通过一个真实的程序来研究这些相互作用,可以帮助程序员理解何时、何地以及如何运用不同的技术。此外,lcc也阐明了众多的C编程技术。第四,这本书本身是一个文本程序(literate program),如同D. E. Knuth所著的《TeX: The Program》(Addison-Wesley,1986)一样,本书包括lcc的源代码及说明。为了方便读者理解,本书并未按源程序的顺序对程序代码进行讲解,而是有意进行了调整。无论是对于在校学生还是专业技术人员,本书都非常适合自学使用。本书为lcc提供了说明完整的源代码,希望进行编译技术实践的人员,以及在需要使用或实现基于语言的工具和技术的应用领域(如用户接口)中工作的专业人员,将会对本书感兴趣。lcc的相关信息可通过以下地址获得:www.cs.princeton.edusoftwarelcc。本书全面而真实地展示了一个大型软件系统,可作为软件工程课程的分析实例。对于编译课程来说,本书弥补了传统编译教材的不足。本书介绍了C编译器的一种实现方法,而传统教材主要介绍编译过程中遇到的各种问题的解决算法,因此传统教材受篇幅限制只能介绍一些实验性的编译器,代码生成也通常面向较高的级别,以避免与具体的机器相关。因此,许多教师要求学生完成接近实际的编译器项目,使学生获得实践经验。通常,教师必须从头开始编写编译程序,而学生复制其中的大部分,修改后利用其余的部分。然而,由于编译器只是实验性的,文档往往显得不够充分,这种情形使教学双方都不满意。本书通过对一个实际编译器的大部分程序进行文档说明,并提供源代码,为教师提供了一种新的选择。本书介绍了完整的代码生成器,代码生成面向MIPS R3000、SPARC和Intel 386及其后续体系结构等不同的平台。本书利用了最新的研究成果,根据目标机器的紧缩规范(compact specification)生成代码生成器。这些方法使得我们能够针对多种机器展示完整的代码生成器,这是其他书籍无法做到的。通过介绍多个代码生成器,既避免了本书依赖于单一的机器,又有助于学生了解如何设计可变目标的软件。教师布置的作业可以是增加编译器接受的语言特征、优化、改变目标机器等。本书如果与传统教材配合使用,也可以要求学生使用不同的算法代替现有的模块作为实践作业。如果以实现一个实验编译器作为实践作业,则可能在低级基础结构和重复的语言特征上花费大量的时间。采取上述方法,就能够更接近实际的编译器工程实践。本书的许多练习都涉及编译器工程问题。除传统的编译目的外,lcc也有其他用途。例如,它可以用于构建一个C程序浏览器,或者根据