Compiler construction 自行编译的编译器(引导)
我读过有关自举的书,但还没有完全理解。 我想解释一下我是如何看待它的,如果它不是真的,请你指出。 要创建自行编译的编译器,应遵循以下步骤: 假设有X和Y编程语言Compiler construction 自行编译的编译器(引导),compiler-construction,bootstrapping,Compiler Construction,Bootstrapping,我读过有关自举的书,但还没有完全理解。 我想解释一下我是如何看待它的,如果它不是真的,请你指出。 要创建自行编译的编译器,应遵循以下步骤: 假设有X和Y编程语言 编写一个从X语言到Y语言的编译器f。对于Y中的每一个代码a,编译器给出f(a) 从Y到Y编写编译器g。因为编译器g是用Y语言编写的,所以编译器f可以编译它。因此,我们可以理解f(c)=g是从Y到Y的编译器 您可以再次使用g编译C,然后g(C)=g-编译器编译自己 我觉得我的解释缺少重要细节。 如果有人能像我一样用数学符号来解释,我会很高
如果有人能像我一样用数学符号来解释,我会很高兴的。在大多数情况下,你的步骤似乎是正确的,只是你似乎一直在混淆源语言和目标语言。我不确定这些只是打字错误还是你真的感到困惑。下面是我对引导的正式描述,与您的描述很接近,但在源代码、目标语言和实现语言之间有一个更清晰的区别,还有一点更详细: 设X为源语言(即您新发明的语言),Y为目标语言(如汇编语言或机器语言),Z为另一种语言,至少已有一种实现。设
T:X->Y
为翻译方案,将用语言X编写的有效程序翻译成用语言Y编写的等效程序。换句话说,对于用X编写的任何有效程序X,T(X)
应生成一个用Y编写的程序Y,该程序Y的行为等同于X
的定义行为
现在我们要做的第一件事是在编程语言Z中实现这个函数T。我们把这个实现称为C_0
。由于Z的实现已经存在,我们现在可以开始编译X程序了。这是你的第一步,除非你在第二句话中似乎已经改变了X和Y
在我们这样做之后,我们现在可以再次实现T,但这次是用语言X。因此我们编写了一个程序C_1
,它相当于C_0
,但是是用X而不是Z编写的。我们仍然在从X编译到Y,但是我们在X中进行编译。我们现在可以使用C_0
来应用T(C_1)
,我们得到一个(另一个)正在使用X编译器。这与您的步骤类似,只是我们仍然将X
转换为Y
。将X翻译成它自己是没有意义的,因为那只是无所作为。而将Y翻译成它自己就更没有意义了,因为Y甚至不是我们的源语言
我们现在也可以通过使用
C_1
而不是C_0
来应用T(C_1)
,但在这一点上,这仅对测试目的有用(确保编译器工作)。理想情况下,C_1(C_1)
的结果应该与C_0(C_1)
的Y代码完全相同。一旦我们开始向X添加功能,我们可能只在C_1
中实现它们,因此在这一点上我们希望停止使用C_0
,这样我们就可以利用新的功能了。想象一下,您想要创建一种新的语言,称为XYZPDQ。你知道C,所以你用C为XYZPDQ编写了编译器。它可以工作,所以现在你可以用语言XYZPDQ编写代码并编译它——使用你用C编写的编译器,也许叫做XYZPDQc
事实上,您非常喜欢它,以至于第二次编写编译器——但这次是用XYZPDQ语言编写的。使用用C编写的编译器(XYQPDQc程序)编译XYZPDQ编译器代码(用XYZPDQ本身编写)。其结果是您可以运行一个新程序,可能称为XYZPDQc2
现在,您可以使用XYZPDQc2程序编译在XYZPDQ中编写的XYZPDQ编译器,因此编译器(实际上)正在编译自己
此时:您已经启动了一种编译语言。我对您使用的“from”和“to”感到困惑。我觉得其中一个介词应该是in。从Y到Y的编译器实际上没有意义(除非Y是JavaScript,我想)-那只是标识函数。Y中从Y到Z的编译器(例如汇编)会更有意义。此链接将提供关于构建自编译编译器的完整描述和个人经验(您的!)。没有什么比做一次更能真正理解它了。