如何用C编写C编译器?

时间:2013-08-15 07:11:40

标签: c compiler-construction kernighan-and-ritchie

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

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

  

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

(我的重点)

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

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

还是我完全离开了?

4 个答案:

答案 0 :(得分:35)

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

  

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

  1. 在语言中为语言X实现解释器或编译器 Y. Niklaus Wirth报道他写了第一个Pascal编译器 的Fortran。
  2. X的另一个解释器或编译器已经写入 另一种语言Y;这就是Scheme经常被引导的方式。
  3. 早期版本的编译器是用X的子集编写的 其中存在一些其他编译器;这是一些超集的方式 Java,Haskell和最初的Free Pascal编译器都是 自举。
  4. X的编译器是从另一个架构交叉编译的 有一个X的编译器;这就是C的编译器 通常移植到其他平台。这也是用于的方法 初始引导后自由Pascal。
  5. 在X中编写编译器;然后从源头手工编译它(大多数 可能以非优化的方式)并在代码上运行该代码 优化的编译器。唐纳德·克努特(Donald Knuth)将此用于他的WEB文化 编程系统。
  6. 如果您有兴趣,here是Dennis Richie的第一个C编译器源代码。

答案 1 :(得分:9)

请参阅Wikipedia page的鸡肉和鸡蛋部分:

如果需要语言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文字编程系统。

答案 2 :(得分:6)

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

您可以阅读此page有关C语言历史的信息。您将看到它也与UNIX系统紧密相关。

答案 3 :(得分:5)

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