如何用C编写C编译器?

jub*_*0bs 57 c compiler-construction kernighan-and-ritchie

这个问题可能源于我对编译器的误解,但是这里......

人们可以在第一版K&R(第xi页)的序言中找到以下陈述:

操作系统,C编译器和基本上所有UNIX应用程序(包括用于编写本书的所有软件)都是用C语言编写的.

(我的重点)

这是我不明白的事情:C编译器在编译任何C代码之前是否必须自行编译?如果那个C编译器是用C编写的,那么编译它是否需要一个已经存在的C编译器?!

摆脱这种无限回归难题(或鸡与鸡蛋问题)的唯一方法是用K和R编写的用C编写的C编译器实际上是用已经存在的用C语言编写的C编译器编译的.用C编写的C编译器取代了后者.

还是我完全脱了?

Yu *_*Hao 41

它被称为Bootstrapping,引自维基百科:

如果需要语言X的编译器来获取语言X的编译器(用X语言编写),第一个编译器是如何编写的?解决这个鸡肉或鸡蛋问题的可能方法包括:

  1. 在语言Y中为语言X实现解释器或编译器.Niklaus Wirth报告说他在Fortran中编写了第一个Pascal编译器.
  2. X的另一个解释器或编译器已经用另一种语言Y编写; 这就是Scheme经常被引导的方式.
  3. 早期版本的编译器是在X的子集中编写的,其中存在一些其他编译器; 这就是Java,Haskell和初始Free Pascal编译器的一些超集如何被引导.
  4. X的编译器是从另一个架构交叉编译的,其中存在一个X的编译器; 这就是C的编译器通常如何移植到其他平台.这也是初始引导后用于Free Pascal的方法.
  5. 在X中编写编译器; 然后从源代码手工编译它(很可能是以非优化的方式)并在代码上运行它以获得优化的编译器.Donald Knuth将此用于他的WEB文字编程系统.

如果您有兴趣,这里是Dennis Richie的第一个C编译器源代码.


Pas*_*uoq 9

请参阅维基百科页面的鸡肉和鸡蛋部分:

如果需要语言X的编译器来获取语言X的编译器(用X语言编写),第一个编译器是如何编写的?解决这个鸡肉或鸡蛋问题的可能方法包括:

  • 在语言Y中为语言X实现解释器或编译器.Niklaus Wirth报告说他在Fortran中编写了第一个Pascal编译器.
  • X的另一个解释器或编译器已经用另一种语言Y编写; 这就是Scheme经常被引导的方式.
  • 早期版本的编译器是在X的子集中编写的,其中存在一些其他编译器; 这就是Java,Haskell和初始Free Pascal编译器的一些超集如何被引导.
  • X的编译器是从另一个架构交叉编译的,其中存在一个X的编译器; 这就是C的编译器通常如何移植到其他平台.这也是初始引导后用于Free Pascal的方法.
  • 在X中编写编译器; 然后从源代码手工编译它(很可能是以非优化的方式)并在代码上运行它以获得优化的编译器.Donald Knuth将此用于他的WEB文字编程系统.


per*_*ror 8

通常,第一个编译器是用另一种语言编写的(在这种情况下直接在PDP11汇编器中,或者在大多数"现代"语言中用C编写).然后,第一个编译器用于编写用语言本身编写的编译器.

您可以阅读此页面有关C语言的历史记录.您将看到它也与UNIX系统紧密相关.

  • 小心地将1970年的事实传到今天。GCC切换到C ++ :-) (2认同)
  • 嗯,C++ 中的 GCC ......我对此有点怀疑(也很害怕!:-))。 (2认同)
  • http://gcc.gnu.org/gcc-4.8/changes.html第一行。 (2认同)

Jon*_*sky 6

编译器用它编译的语言编写是完全普通的.实现这一目标的一种方法是用其他语言编写一个完整的语言L编译器,然后在L中为L编写一个新的编译器.一个更有趣的方法是为一些L的子集编写一个最小的编译器其他语言,然后使用这个最小子集来改进编译器,使其增加L的可用子集的最小化.这样,可以构建完整的编译器.