C语言 如何用 C 编写 C 编译器?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18247888/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can a C compiler be written in C?
提问by jub0bs
This question may stem from a misunderstanding of compilers on my part, but here goes...
这个问题可能源于我对编译器的误解,但这里是......
One can find the following statement in the preface to the first edition of K&R (page xi):
可以在 K&R 第一版(第 xi 页)的序言中找到以下声明:
The operating system, the C compiler, and essentially all UNIX applications programs (including all of the software used to prepare this book) are written in C.
操作系统、C 编译器以及基本上所有 UNIX 应用程序(包括用于编写本书的所有软件)都是用 C 编写的。
(my emphasis)
(我的重点)
Here's what I don't understand: doesn't that C compiler have to be compiled itself before it can compile any C code? And if that C compiler is written in C, wouldn't compiling it require an already existing C compiler?!
这是我不明白的:在编译任何 C 代码之前,C 编译器不是必须自己编译吗?如果那个 C 编译器是用 C 编写的,那么编译它是否需要一个已经存在的 C 编译器?!
The only way out of this infinite-regression conundrum (or chicken-and-egg problem) is that the C compiler written in C that K&R are referring to was actually compiled with an already existing C compiler that was written in a language other than C. The C compiler written in C then superseded the latter.
解决这个无限回归难题(或先有鸡还是先有蛋的问题)的唯一方法是,K&R 所指的用 C 语言编写的 C 编译器实际上是用现有的 C 编译器编译的,而该编译器是用 C 以外的语言编写的. 用C 编写的C 编译器随后取代了后者。
Or am I completely off?
还是我完全没了?
采纳答案by Yu Hao
It's called Bootstrapping, quoting from Wikipedia:
它被称为Bootstrapping,引用自维基百科:
If one needs a compiler for language X to obtain a compiler for language X (which is written in language X), how did the first compiler get written? Possible methods to solving this chicken or the egg problem include:
如果需要语言 X 的编译器来获得语言 X 的编译器(用语言 X 编写),那么第一个编译器是如何编写的?解决这个鸡或蛋问题的可能方法包括:
- Implementing an interpreter or compiler for language X in language Y. Niklaus Wirth reported that he wrote the first Pascal compiler in Fortran.
- Another interpreter or compiler for X has already been written in another language Y; this is how Scheme is often bootstrapped.
- Earlier versions of the compiler were written in a subset of X for which there existed some other compiler; this is how some supersets of Java, Haskell, and the initial Free Pascal compiler are bootstrapped.
- The compiler for X is cross compiled from another architecture where there exists a compiler for X; this is how compilers for C are usually ported to other platforms. Also this is the method used for Free Pascal after the initial bootstrap.
- Writing the compiler in X; then hand-compiling it from source (most likely in a non-optimized way) and running that on the code to get an optimized compiler. Donald Knuth used this for his WEB literate programming system.
- 用 Y 语言实现 X 语言的解释器或编译器。 Niklaus Wirth 报告说他用 Fortran 编写了第一个 Pascal 编译器。
- X 的另一个解释器或编译器已经用另一种语言 Y 编写;这就是 Scheme 经常被引导的方式。
- 早期版本的编译器是用 X 的一个子集编写的,其中存在一些其他编译器;这就是 Java、Haskell 和最初的 Free Pascal 编译器的一些超集是如何引导的。
- X 的编译器是从另一个存在 X 编译器的体系结构交叉编译的;这就是 C 编译器通常被移植到其他平台的方式。这也是在初始引导后用于 Free Pascal 的方法。
- 用 X 编写编译器;然后从源代码手动编译它(很可能以非优化的方式)并在代码上运行它以获得优化的编译器。Donald Knuth 将其用于他的 WEB 文学编程系统。
And if you are interested, hereis Dennis Richie's first C compiler source.
如果您有兴趣,这里是 Dennis Richie 的第一个 C 编译器源代码。
回答by Pascal Cuoq
See the Chicken and Egg section of the Wikipedia page:
请参阅维基百科页面的鸡肉和鸡蛋部分:
If one needs a compiler for language X to obtain a compiler for language X (which is written in language X), how did the first compiler get written? Possible methods to solving this chicken or the egg problem include:
如果需要语言 X 的编译器来获得语言 X 的编译器(用语言 X 编写),那么第一个编译器是如何编写的?解决这个鸡或蛋问题的可能方法包括:
- Implementing an interpreter or compiler for language X in language Y. Niklaus Wirth reported that he wrote the first Pascal compiler in Fortran.
- Another interpreter or compiler for X has already been written in another language Y; this is how Scheme is often bootstrapped.
- Earlier versions of the compiler were written in a subset of X for which there existed some other compiler; this is how some supersets of Java, Haskell, and the initial Free Pascal compiler are bootstrapped.
- The compiler for X is cross compiled from another architecture where there exists a compiler for X; this is how compilers for C are usually ported to other platforms. Also this is the method used for Free Pascal after the initial bootstrap.
- Writing the compiler in X; then hand-compiling it from source (most likely in a non-optimized way) and running that on the code to get an optimized compiler. Donald Knuth used this for his WEB literate programming system.
- 用 Y 语言实现 X 语言的解释器或编译器。 Niklaus Wirth 报告说他用 Fortran 编写了第一个 Pascal 编译器。
- X 的另一个解释器或编译器已经用另一种语言 Y 编写;这就是 Scheme 经常被引导的方式。
- 早期版本的编译器是用 X 的一个子集编写的,其中存在一些其他编译器;这就是 Java、Haskell 和最初的 Free Pascal 编译器的一些超集是如何引导的。
- X 的编译器是从另一个存在 X 编译器的体系结构交叉编译的;这就是 C 编译器通常被移植到其他平台的方式。这也是在初始引导后用于 Free Pascal 的方法。
- 用 X 编写编译器;然后从源代码手动编译它(很可能以非优化的方式)并在代码上运行它以获得优化的编译器。Donald Knuth 将其用于他的 WEB 文学编程系统。
回答by perror
Usually, a first compiler is written in another language (directly in PDP11 assembler in this case, or in C for most of the "modern" languages). Then, this first compiler is used to program a compiler written in the language itself.
通常,第一个编译器是用另一种语言编写的(在这种情况下直接用 PDP11 汇编程序编写,或者对于大多数“现代”语言用 C 编写)。然后,第一个编译器用于编写用语言本身编写的编译器。
You can read this pageabout the history of the C language. You will see that it is also strongly linked to the UNIX system.
您可以阅读有关 C 语言历史的页面。您将看到它也与 UNIX 系统紧密相连。
回答by Jon Kiparsky
It's perfectly ordinary for a compiler to be written in the language it compiles. One way to achieve this would be to write a complete compiler for language L in some other language, and then to write a new compiler for L in L. A more interesting approach would be to write a minimal compiler for a subset of L in some other language, and then use this minimal subset to improve the compiler, making it less minimal increasing the available subset of L. In this way, a complete compiler can be built.
用它编译的语言编写编译器是很正常的。实现这一点的一种方法是用其他语言为语言 L 编写一个完整的编译器,然后在 L 中为 L 编写一个新的编译器。 一个更有趣的方法是为某些语言中的 L 的子集编写一个最小编译器其他语言,然后使用这个最小子集来改进编译器,使其最小化增加 L 的可用子集。这样,就可以构建一个完整的编译器。

