文章摘要
作者在20年前初次接触Forth语言,但未深入。2025年,在探索LLM和数学算法后,他决定编写代码,偶然发现Forth相关资源,决定实现一个Forth解释器,并计划用Go和C语言完成。
文章总结
在Go和C中实现Forth语言
我第一次接触Forth语言大约是在20年前,当时在读一本关于嵌入式硬件设计的书。虽然当时我主要是为了学习硬件知识,但快速浏览了Forth章节后,我留下了“这很有趣”的印象,随后便没有再深入。在过去的二十年里,我偶尔会听到关于Forth的讨论,比如大约10到12年前,Factor语言曾短暂引起过关注。
Forth一直被我归类为“奇怪的语言”,直到今年六月,几个因素促使我决定深入研究并实现它:
- 在2025年初,我花了很多时间探索大型语言模型(LLM)的内部机制和数学算法,之后我有了写代码的冲动。
- 我偶然发现了Dave Gauer关于Forth的页面,以及如何实现Forth的指南。
于是,我决定实现一个Forth解释器,原因很简单:为什么不呢?
Forth的两个层次
Forth(至少是标准Forth,而非像Factor这样的衍生版本)可以看作有两个不同的层次:
- 用户层次:你只想使用Forth来编写程序。比如你可能在启动新硬件时,发现Forth是一个有用的计算器、REPL和脚本语言。你并不关心Forth的实现细节,只想完成任务。
- 黑客层次:你对Forth的深层机制感兴趣。比如,Forth的控制流结构(如IF...THEN或BEGIN...UNTIL)本身就是Forth的“词”(words),你可以实现自己的控制流结构,并让它们像标准结构一样无缝且高效。
goforth和ctil的实现
Forth的实现通常采用一种经典的方式,即使用链表字典,其中每个词被表示为一个“线程化”列表,用户代码可以扩展和修改这个字典。因此,Forth的大部分实现可以用Forth本身来编写。
我的第一个实现goforth尝试了一种不同的方法:纯解释器。它支持许多内置词,足以编写有用的程序,但这种方法在用户层次上是可用的,但在黑客层次上则不够,因为宿主语言(Go)的解释器控制了所有流程,无法在Forth中实现IF...THEN等结构。
为了探索Forth的深层机制,我实现了第二个版本ctil,它基于jonesforth的汇编实现,但用C语言编写。ctil允许我们用Forth本身实现大部分功能,比如变量和条件语句。
对Forth的思考
Forth在20世纪70年代的历史背景下非常有意义。它易于在汇编语言中实现,并提供了一个更高层次的语言,可以用作计算器、REPL和领域特定语言(DSL)。Forth是一种连接语言,因此本质上是无点的,这使得它在REPL风格的编程中非常有用。
然而,Forth的堆栈编程模型虽然简洁,但可读性较差,尤其是在没有详细注释的情况下。例如,Forth中的+!操作符的实现虽然功能强大,但堆栈操作非常复杂,难以理解。
总结
我的goforth项目代码已发布在GitHub上,包含两个实现和一个全面的测试框架。实现Forth是一个非常有价值的自我提升项目,它让我深入理解了堆栈机器、解释与编译的混合抽象层次。此外,从头实现编程语言本身就是一件非常有趣的事情!
评论总结
评论内容总结:
关于Forth在Go中的实现:
- s-macke指出,虽然作者的实现适用于其用例,但与原始Forth有较大差异,使用了独立的Go结构,且缺乏引导机制。他提到自己通过
heap []any数据结构成功实现了IF...THEN。- 引用:“His implementation, while working for his use cases, is actually quite far from the originals.”
- 引用:“Well, I did it with a ... heap []any ... data structure. Works well enough.”
- s-macke指出,虽然作者的实现适用于其用例,但与原始Forth有较大差异,使用了独立的Go结构,且缺乏引导机制。他提到自己通过
关于Forth在C++中的实现:
- bertili提到,Forth可以通过C++的
musttail属性以延续传递风格高效实现,并推荐了相关项目。- 引用:“Forth can be beautifully and efficiently implemented in portable c++ using the using continuation passing style via the clang musttail attribute.”
- bertili提到,Forth可以通过C++的
关于代码可读性和Forth的设计哲学:
- astrobe_认为Forth的可读性争议主要源于主观性,强调Forth程序员注重简化和分解,并指出堆栈注释的重要性。他还提到Forth的命名习惯有助于理解函数参数。
- 引用:“This a readability argument, and we know it is 90% subjective.”
- 引用:“Compare with the '+!' proposed by the author himself - any Forth programmer instantly knows it most likely takes 2 arguments and returns nothing.”
- astrobe_认为Forth的可读性争议主要源于主观性,强调Forth程序员注重简化和分解,并指出堆栈注释的重要性。他还提到Forth的命名习惯有助于理解函数参数。
关于文章完整性和函数参数问题:
- johnisgood认为文章似乎未完成,并提到在大型代码库中理解函数参数的困难。
- 引用:“I feel like as if the article itself is not finished at the end.”
- 引用:“How can you know the arity of the functions without adding explicit comments?”
- johnisgood认为文章似乎未完成,并提到在大型代码库中理解函数参数的困难。
总结:评论主要围绕Forth在不同语言中的实现、代码可读性、设计哲学以及函数参数理解等问题展开,观点多样且各有侧重。