关于编译原理 - (绪)

开坑编译原理系列,其实我也不懂怎么能不能讲清楚,以及能不能写完整,就权且先开着。

编译器的自举原理

刚接触编译原理的时候,我的脑子里都是一些乱七八糟的东西:比如,一种语言是怎么诞生的?为什么用同一语言写的编译器能编译它自己?那么编译器本身的代码又是怎么被编译的?既然系统已经可以完成对编译器代码的编译了,为什么还需要编译器 233333…

现在问出来感觉挺逗的,原谅以前的我并不知道编译器的自举原理。如同鸡生蛋的问题,如果你想创造一门语言并且用这个语言来写编译器的话,拿 C 语言来说,这个过程是这样的:

用汇编语言(或其他语言)写一个编译器 a,用 C 语言也写一个编译器 b,用编译器 a 编译 b,得到了一个可执行的编译器 b。接着就可以用 C 语言编译器编译 C 语言本身。或许你想更新编译器 b 的版本,那么用编译器 a 再次编译即可。

编译器与解释器

编译:指的是用高级语言编写的源程序翻译成目标程序。

编译器也是一个程序,它把源程序翻译成目标语言编写的中间代码 (机器码),而后对其加以解释执行。

与之相提的是解释器,解释器可以边读语句边执行指令。看到轮子哥说解释器就是编译器+虚拟机,我是这样理解的,解释器将源语言翻译成低级语言,随后由虚拟机来运行低级语言。

编译的过程

让我们回想一下我们初学英语的过程:
背单词 -> 学习语法 -> 学习句子

事实上,编译的过程和学语言的过程是相似的:

1.词法分析 (lexical analysis):

扫描语句中的每个(token)。

2.语法分析 (syntax analysis / parsing):

具体的任务是:接受一个(非)终结符号串作为输入,找出从文法的开始符号推导出这个串的方法。

设计算法将词法分析器生成的各个词法单元生成树形(语法树)的中间表示。

考虑优先级以及符号匹配问题。

3.语义分析 (semantic analyzer):

语义分析最主要的一部分是类型检查:

运算分量与运算符是否能匹配;数组的下标是否下溢或类型错误;类型转换是否正确;等等。

4.中间代码生成: 生成近似 “三地址指令” 的中间代码

5.中间代码优化

6.生成目标代码

一趟与多趟

(pass) 指的是对源程序或者中间语言程序从头到尾扫尾并完成一定的任务的过程。

一趟编译器与多趟编译器的代码结构是截然不同的:

一趟编译器中,以上步骤都是在一趟中完成的。整个过程通常以语法分析为核心,也叫做语法制导翻译。

而多趟编译器中,以上步骤分别进行一趟,趟与趟之间存在逻辑上的先后关系,一般采用顺序结构或者并发结构。

关于编译原理系列的内容

我打算开两大部分,一部分是理论,另一部分是 coding 的过程。

内容就围绕以上的编译过程进行详细说明。

写一个完整的 C 语言编译器的困难与挑战:

当然,我是在立 flag,只不过 C 语言本身就相对复杂,要写它的编译器我觉得是存在困难的,对一些问题目前真是一点头绪都没有,我想先写完基本文法再接着考虑实现以下编译:

1.C 语言的参数传递机制:拷贝/引用

2.预编译 (宏)

3.联合编译


最后我想说有些人觉得东西太老就不愿意去学,我觉得是错的。来过 CS,就不要枉费这门学科最初包含的东西。东西是老了点,但也请心存敬畏。

共勉。