假设我编写了一种编程语言;对于同名,我会称之为 lang .
为了开始写作 lang 的漫长旅程,我决定开始写作lang . 我实际上无法运行它,因为没有什么可以运行自己运行的程序 .
所以我首先在Java中为 lang 编写另一个编译器 . 这一次,当我完成后,我决定将其转换为字节码,然后将其保留 . 我现在有一个工作的编译器,它将我的所有 lang 代码转换为字节码 .
所以我决定将我的自编译器插入到我刚刚用Java编写的编译器中 . 然后我将自编译器转换为Bytecode,并丢弃Java编译器 . 我现在有一个 lang 编译器,纯粹编写,转换成字节码,随时可以使用 .
这创建了一个可靠的程序,我理解所有这些,但我的问题是,相对于JVM的编译器设计, what if I decide to release an update for my language? How do I go about updating the Bytecode? Do I simply re-write the updated version of the language in the older one?
我问这个是因为这就是我想要做的 . 编写一个不存在的语言,然后首先通过Java创建编译器将其引导到JVM .
它与C语言相同 . 写了C with Classes,然后写了C,最后C和Classes被放弃了用于自举C语言 . 但那么他们究竟如何更新语言呢?
4 回答
我将从您开发中的两种可能情况中回答这个问题 . 使用任何字节码语言,您可以随时更新虚拟机或语言 .
假设您首先要更新语言以获得新语法或更改当前语义 . 然后,您将保留当前编译的编译器在 lang (编译器A)中编写并编辑其源代码,以便它可以正确编译您的新功能 . 然后使用旧编译器编译编译器 . 如果需要,您现在可以重写编译器以使用新功能,然后使用编译器B编译它以为您提供编译器C.
如果JVM发生变化怎么办?那么在这种情况下,您将保留旧版本的JVM,调整编译器以应对新的字节码更改,然后使用旧版本进行编译(这类似于之前的编译器B) . 这将为您提供一个编译器,编译为新的字节码,但在旧的VM上运行 . 下一步是让它自己编译,现在你有了一个在新VM上运行的新编译器(类似于编译器C) .
我不认为你的编译器是最好的方法 .
我从语言的语法开始 .
接下来是词法分析器/解析器,用于将我语言中的表达式转换为抽象语法树(AST) . AST是表达式的正确中间表示 .
您可以通过编写遍历AST的代码生成器为您选择的虚拟机或处理器发出字节码或汇编语言指令 .
您的更新在哪里发生?
如果它是语言基础,则必须修改语法和字节码发射 .
如果要优化字节码或移植到新处理器,则必须修改代码生成器 .
第一个 lang 编译器可以写在 lang 的子集中 . 而且你只需要一个子集(bootstrap)编译器(甚至是interoreter) . 这可以用java编写 .
之后,可以在 lang 中编写更广泛的编译器 . 较新的版本也可以 .
您甚至可以编写一个将lang程序转换为java的转换器,并使用它在lang中创建第一个转换器,然后将其转换为字节码编译器 .
新版本的编译器只能由前一个编译 . 例如,要编译G 4.6,您应该使用G 4.5,而不是G 1.0 .
顺便说一句,没有必要为 lang 本身编写编译器 . 它即将证明一种语言是"mature",但有些语言不需要证明这一点 .