本节书摘来自华章出版社《编译与反编译技术实战 》一书中的第2章,第2.3节,庞建民 主编 ,刘晓楠 陶红伟 岳 峰 戴超 编著,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
根据不同的用途和侧重点,编译程序可以进一步分类,换句话说,有许多不同种类的编译器变体。譬如:用于帮助程序开发和调试的编译程序称为诊断编译程序,这类编译器可对程序进行详细检查并报告错误;另一类侧重于提高目标代码效率的编译程序称为优化编译程序,这类编译器通常使用多种混合的“变换”来改善程序的性能,但这往往是以编译器的复杂性和编译时间的增加为代价的。通常,将运行编译程序的机器成为宿主机,将运行编译程序所产生的目标代码的机器称为目标机。如果一个编译程序产生不同于其宿主机指令集的机器代码,则称它为交叉编译程序(cross compiler)。还有一类编译器,其目标机器可以改变,而不需要重写它的与机器无关的组件,这类编译器称为可再目标编译器(retargetable compiler),通常,这类编译器难以生成高效的代码,因为其难以利用特殊情况和目标机器特性。目前,很多编译程序同时提供了调试、优化、交叉编译等多种功能,用户可以通过“编译选项”进行选择。
编译器本身也是一个程序,这个程序是怎么编写的呢?早期人们使用汇编语言编写编译器。虽然用汇编语言编写的编译器代码效率很高,但由于汇编语言编程与高级语言编程相比难度较大,对编译器这种复杂的系统编写起来效率不高,因此,后来人们改用高级语言来编写编译器。随着编译技术的逐步成熟,一些专门的编译器编写工具相继涌现,比较成熟和通用的工具有词法分析器生成器(如lex)和语法分析器生成器(如yacc)等。还有一些工具,如用于语义分析的语法制导翻译工具、用于目标代码生成的自动的代码生成器、用于优化的数据流工具等。下面简单介绍利用一些工具实现一个新的语言编译器的基本流程。
在unix环境中编写程序,你往往会邂逅神秘的lex和yacc,而gnu/linux用户则会邂逅flex和bison。
flex是一个与lex兼容的词法分析器生成器,可以用它来生成一个新的语言的词法分析器,flex就是由vern paxon实现的一个lex,使用它既可以节省时间,也可以提高正确性。
bison是一个与yacc兼容的语法分析器生成器,可以用它来生成一个新的语言的语法分析器,使用它也可以提高正确性并节省开发时间,实际上,bison是一个可以把符合 lalr(1)文法规范的上下文无关文法转换成 c语言程序的语法分析器生成器,是一个gnu版本的yacc。
实现一种新语言,需要做的工作主要包括设计文法、进行语法制导的翻译、优化和代码生成,而后续的工作还可以由llvm的相关工具提供支持。
llvm是一个包含一系列模块化可重用编译器和工具链技术的项目。llvm主要的子项目有llvm core libraries、clang、dragonegg、lldb等。其中llvm core libraries
(llvm核心库)提供了一个不依赖于目标平台的优化器,同时还为许多典型架构的cpu提供了代码生成的支持。这些库是围绕着一个有详细说明的中间代码表示形式(llvm ir)建立起来的。也就是说,只要能够把待设计的语言翻译成llvm ir这种中间语言,就可以利用llvm完成代码优化和代码生成的工作。当然,这要求目标cpu架构必须是llvm已经支持的,否则就得自己完成代码生成的工作。clang是一个llvm自身的c/c++/objective-c编译器,目标是提供快速的编译。
dragonegg的功能是把llvm的优化器、代码生成器和gcc 4.5的分析器结合在一起,这样就使得llvm能够编译像ada、fortran等其他gcc编译器前端支持的语言,且能够拥有一些clang不支持的c特性(如openmp等)。lldb则是建立在llvm库和clang之上的一个非常好的本地调试器。