我怎样才能维持语言提升?

时间:2017-10-29 14:44:48

标签: compiler-construction bootstrapping

我正在开发一个将被引导的编译器,即编译器将从源代码编译自己。我正在实现一个简化的C ++版本的编译器作为垫脚石。我担心的是,及时,真正的编译器将支持C ++实现没有的功能,编译器源代码将利用这些功能。一旦发生这种情况,C ++实现将无法使用,并且从零开始的能力将丢失。

可以重用git历史记录从先前的状态开始并朝着最终结果工作。另一个选择是确保基于C ++的编译器始终能够编译“真实”编译器,或者通过根据需要扩展C ++版本,或者永远不允许在真实编译器的源代码中使用不受支持的功能。这两者都有其自身的缺点。我想知道是否还有其他技术适用于其他语言。

维护编程语言的引导功能有什么好方法?

对于好奇的结帐http://plange.tech

1 个答案:

答案 0 :(得分:2)

这取决于编译器的目标语言。

一般建议是保留编译器的一些翻译变体。阅读Tombstone diagramspartial evaluation(特别是Futamura预测)。

Ocaml包含一个字节码变体(在一个非常稳定的字节码虚拟机上运行),并将ocamlc编译器的(可移植)字节码保存在其gitsvn存储库中(参见来自官方存储库的boot/ocamlc

在我的GCC MELT(这是一种类似Lisp的语言,翻译成适合作为GCC插件的C ++,遗憾的是我没有时间维护它),我将翻译和生成的C ++代码保存在{ {1}}存储库中的{1}}子目录。

许多生成C代码的编译器(例如bigloochicken,...)都保留了生成的C代码(即使在版本控制存储库中)。 C是如此通用(并且可以被视为几乎可移植的汇编程序),它经常被用作许多实验语言实现的目标语言。 A lot of experimental compilers are targetting C。你可能会保留几个目标(其中一个是C)。或者你也可以有一个天真的解释器(能够运行你的bootstrapping编译器)。

显然(根据您的评论),您选择LLVM作为目标语言。然后,您依赖于LLVM语言(规范)的稳定性。您最好将翻译后的表单保留为LLVM assembly language(以文本形式),例如:在您的版本控制存储库中(因为该翻译后的表单与您的源代码一样珍贵)。

如果LLVM汇编语言演变为不兼容,那么您将遇到麻烦。当发生这种情况时,您可以转换文本形式(这就是为什么文本形式更可取,因为它更好转换)到更新的LLVM语法(假设它没有经常改变),或者像某些类似的语言低级C或Gimple,或使用以前的LLVM代码生成器一段时间。 BTW,C作为目标语言是成功的,原因类似:它主要是兼容的,并且被广泛使用。

Go,D和Rust保留了常用系统和体系结构的二进制ELF可执行文件(Linux / x86-64)。 IIRC中的一些人在安装过程中(从稳定的URL)下载了编译器的前一个二进制文件。

Bones Scheme编译器直接生成x86-64汇编程序,因此它使用源代码分发汇编代码。

一些编译实现某些标准语言(例如SBCL的(超集),对于Common Lisp而言,需要注意在几个平台上进行编译(因此SBCL可以在CLisp上进行自举)。所以核心SBCL编译器是用严格的便携式Common Lisp编写的。

您的增量引导思想是一种众所周知的方法。 J.Pitrat的博客包含了几个关于这个想法的entries

实际上,你应该"冷启动"您的实施经常(例如从版本控制存储库中的已翻译变体开始),至少每周一次。 Bootstrap失败是一个痛苦的错误。有时(当然在每个版本中,可能更频繁地),您将新翻译的表单复制到版本控制存储库。之后一定要进行大量的测试。

可能是"冷启动"进程将使用几个小时的CPU,但您需要经常合理地运行它(至少每月一次,可能更频繁地运行),以确保您的实现处于理智状态。您甚至可以测试生成的已翻译变体是否能够在几个阶段中重新编译。 BTW,GCC至少有3个阶段(需要几个小时的计算机),这是有充分理由的。