【问题标题】:How can I maintain a language boostrap?如何维护语言引导程序?
【发布时间】:2017-10-29 14:44:48
【问题描述】:

我正在开发一个将被引导的编译器,即编译器将从源代码编译自己。我正在实现一个精简的 C++ 版本的编译器作为垫脚石。我担心的是,随着时间的推移,真正的编译器将支持 C++ 实现不支持的特性,而编译器源代码将利用这些特性。一旦发生这种情况,C++ 实现将无法使用,并且失去了从无到有的能力。

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

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

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

【问题讨论】:

  • 你在试验哪种语言?
  • 您的语言是否公开记录,您的实施是否为免费软件?如果是这样,请提供一些链接。
  • 顺便说一句,您的问题在 SO 上有点偏离主题,但在 softwareengineering.stackexchange.com 上却是强烈的主题;也许应该迁移到那里...
  • 网站是plange.tech。它仍然是 pre-alpha,所以还没有好东西可以玩。至于移民,我不会反对。版主会这样做吗?
  • 在这个阶段,最直接的做法是保留 git 的演变历史。当您甚至还没有开始运行时,为什么还要用这种想法来混乱自己并取得进展?

标签: compiler-construction bootstrapping


【解决方案1】:

这取决于你的编译器的目标语言是什么。

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

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

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

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

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

如果 LLVM 汇编语言发展不兼容,你就会遇到麻烦。当这种情况发生时,您可以将文本形式(这就是为什么文本形式更可取,因为它更容易转换)转换为更新的 LLVM 语法(假设它没有发生太大变化),或类似的语言低级 C 或 Gimple,或者暂时使用以前的 LLVM 代码生成器。顺便说一句,C 作为目标语言之所以成功,也是出于类似的原因:它的发展主要是兼容的,并且被广泛使用。

Go、D 和 Rust 为常见系统和架构 (Linux/x86-64) 保留二进制 ELF 可执行文件。 IIRC 其中一些正在安装期间(从稳定的 URL)下载编译器的先前二进制文件。

Bones Scheme 编译器直接生成 x86-64 汇编器,因此它将汇编器代码与其源代码一起分发。

实现某些标准语言(例如 SBCL,用于 Common Lisp)的某些编译需要注意可在多个平台上编译(因此 SBCL 可以在 CLisp 上引导)。所以核心 SBCL 编译器是用严格和可移植的 Common Lisp 编码的。

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

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

“冷启动”过程可能会使用几个小时的 CPU,但您需要合理频繁地运行它(至少每月一次,并且可能更频繁),以确保您的实现处于正常状态。您甚至可以测试生成的翻译变体是否能够分几个阶段重新编译自身。顺便说一句,GCC 引导至少 3 个阶段(需要几个小时的计算机),这是有充分理由的。

【讨论】:

  • 这是一个有趣的想法。我使用 LLVM 作为后端,因此维护位码表示应该相当简单。
猜你喜欢
  • 2010-09-16
  • 1970-01-01
  • 2011-03-14
  • 2015-03-22
  • 2015-12-08
  • 2016-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多