编译器,近在咫尺却又远在天边。当咱们写下任何非机器语言代码后,咱们都须要借助编译器将这些代码变为经过计算机可运行的状态。可是,就是这样一个使用率极高的程序,咱们对其却知之甚少。什么是编译器?编译器对咱们的代码作了什么?又是怎么作的呢?若是你也怀有这些疑问,想要深刻编译器内部一探究竟的话,那就随我一块儿踏上这趟编译器实现的旅程吧。前端
广义上,编译器是这样一个程序:其读入A语言代码,并输出B语言代码。以下图所示:后端
+-------+ A语言代码 -> | 编译器 | -> B语言代码 +-------+
仅从定义上看,A、B能够是同一种语言。也就是说,若是咱们写了一个只是具备“复制粘贴”功能的程序,其也能够被称为是一个编译器。但显然,这样的编译器是无心义的。在实际中,编译器的输入通常是高级语言代码,如C语言、Python语言等,而编译器的输出通常是低级语言代码,如汇编语言、各类字节码等。汇编语言代码经由汇编语言编译器继续编译,最终产生机器语言,以供计算机执行;而字节码可由可以执行此字节码的虚拟机执行。这样,就完成了一个程序从编写到执行的过程。数组
编译器的内部并非一个总体,而是由多个组件分工合做,共同完成编译功能。这些组件整体上可被分为两个部分:编译器前端和编译器后端。以下图所示:函数
+----------+ +----------+ A语言代码 -> | 编译器前端 | -> 中间代码 -> | 编译器后端 | -> B语言代码 +----------+ +----------+
因为咱们写下的高级语言代码并非编译器比较喜欢的形式,故编译器经过编译器前端读取、检查并从新组织源代码,使之等价变换为编译器喜欢的形式,即中间代码;通常来讲,语法错误也由编译器前端负责检查。接下来,编译器后端就拿着中间代码进行进一步的检查、优化,最终生成目标代码。优化
事实上,编译器先后端又分别能够进一步细分为多个组件,这些组件将在咱们接下来的旅程中逐一讲述。设计
在此次旅程的终点,咱们将实现一个名为CMM(即C Minus Minus)语言的编译器,这个编译器的输出将是由咱们本身设计的一套指令集中的指令所构成的指令文件。因此,咱们还将实现一套虚拟机程序,以运行编译器输出的指令文件。code
CMM语言是一门将C语言的语法进行缩减后获得的语言。其主要特色以下:作用域
接下来,就让咱们深刻编译器前端一探究竟吧。请看下一章:《编译器前端概观》。编译器