Ken 说,C 编译器是用 C 语言编的。
以下有一些是我自己的猜想: 这并不是说第一个 【C 编译器二进制文件】 就能编译完整的 C 程序。 C 编译器一开始处于创世纪的时代,非常简单, 我猜想肯定是机器语言写的,但是不用很复杂, 只需要最最基本的一点点就够了。 之后 C 编译器开始用 C 语言写了,写完后用 最初的编译器编译,这样新版本的 C 编译器诞生了。 然后再重新添加新的功能,修改编译器源程序, 再用上一个版本的编译器编译最新版本的编译器源程序, 编译后的二进制文件替换上一个版本的编译器二进制文件。 就这样,C 编译器不断得训练自己,使自己的 C 语言 知识越来越丰富,到最后,它完全实现了 C 语言规范, 可以正式发布给大家使用了。 跟人不一样,人学了一点新的语言知识后,很可能 会忘掉,然后再学,反复几下,可能就记得久一点, C 编译器不同,只要告诉它一次,它就永远记住了。 下面举个例子来说明一下 Ritchie, Ken 他们是如何 训练编译器的。 C 语言中的字符常量及字符串中可以用反斜杠 \ 字符 来转义,比如 \\ 表示 \,\n 表示一个换行符, \t 表示 按一个Tab键产生的制表符。 在引入这个转义机制以前,C 编译器认为 char *a="\\"; 这个写法表示由2个反斜杠组成的字符串。 现在改写编译器的源代码为: ... c = next(); if(c != '\') return c; c = next(); if(c == '\') return '\'; ... 用老的编译器重新编译修改后的源代码,生成后的编译器 现在就有能力识别 \ 是转义符了。然后用新编译器编译时, char *a="\\"; 就是表示由1个反斜杠组成的字符串了。 这个时候,新的编译器反倒不能正确编译它自身的源码了, 因为 '\' 不再表示单个 \ 字符了,c = '\' 就非法了。 所以这时候就要写成 ... c = next(); if(c != '\\') return c; c = next(); if(c == '\') return '\\'; ... 然后再重新编译一遍,虽然没有增加新的能力,但是源代码 的表现方式已经彻底改变了。 之后,要增加新的转义项目,比如把 \n 转义为一个换行符。 不是简单地添加一句 if(c == 'n') return '\n'; 就可以的,因为编译器现在还不知道 \n 的意思,所以你 写成 '\n' 并不能转义为换行符。 所以现在只能写成 if(c == 'n') return 10; 因为换行符的 ASCII 码是10。这样编译器能够接收了。编译完 生成新的编译器后,再修改原来的编译器代码为: if(c == 'n') return '\n'; 现在编译器就懂了,然后重新编译它自身的源程序。 类似地,要增加别的转义项目,也要如此这般地训练编译器。 |
|