如何用C编写C编译器?
这个问题可能源于我对编译器的一个误解,但是这里有…
在第一版K&R(第xi页)的前言中可以find以下的说明:
操作系统, C编译器和基本上所有的UNIX应用程序(包括用来编写本书的所有软件)都是用C语言编写的。
(我的重点)
以下是我不明白的事情:C编译器在编译任何C代码之前是否必须进行编译? 如果这个C编译器是用C语言编写的,不会编译它需要一个已经存在的C编译器?!
这个无限回归难题(或鸡与蛋问题)的唯一出路是用K&R编写的用C编写的C编译器实际上是用一个已经存在的用C以外的C编译器编译的用C编写的C编译器代替后者。
还是我完全脱落?
这就是所谓的引导 ,从维基百科引用:
如果需要用于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识字编程系统。
如果你有兴趣, 这里是Dennis Richie的第一个C编译器源代码。
请参阅维基百科页面的鸡蛋部分:
如果需要用于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识字编程系统。
通常,第一个编译器是用另一种语言编写的(在这种情况下,直接在PDP11汇编程序中,或者在大多数“现代”语言中,在C中编译)。 然后,这个第一个编译器被用来编写用这种语言编写的编译器。
你可以阅读这个关于C语言历史的页面 。 您将会看到它也与UNIX系统有很强的联系。
用编译的语言编写编译器是非常普通的。 实现这一目的的一种方法是用一种其他语言编写一个完整的L语言编译器,然后在L中为L编写一个新的编译器。一个更有趣的方法是在一些L编写一个最小编译器其他语言,然后使用这个最小的子集来改进编译器,使得增加L的可用子集的次数减到最小。这样就可以build立一个完整的编译器。