Forth:黑客的语言(2017)

2021-02-18 00:44:46

让我们从一个有争议的声明开始:Forth是黑客的编程语言。对于不存在的奇怪CPU架构,Forth中的编码有点像交互式编写汇编语言。 Forth是一个虚拟机,一个解释的命令行和一个编译器。所有这些都非常简单,可以轻松地在几千字节的内存中运行。当您的Forth代码正确时,它读起来就像是自然语言的句子,但是到达那里涉及一些难题的解决。

如果Python使用汇编语言睡着了,Forth就是您所能得到的:交互式,富有表现力,没有语法上的负担,但仍然非常接近。是高级语言还是低级语言?是的!或者说,这是一条通往另一条道路的最短路径。您可以而且必须直接在Forth中窥探并戳入内存,但是您也可以足够快地构建一个高级代码主体,以至于不介意。我认为,实时编码和与硬件的接近性的结合使Forth非常适合探索新的微控制器或将其用于您的项目。在其中编写硬件抽象层是一种有趣的语言。

但是,福斯(Forth)也像是高台表演。如果C给您足够的绳索来吊住自己,Forth就是一个带着眼镜蛇爬行的喷火器。没有类型检查,没有范围,也没有数据和代码的分离。您可以做一些可怕的事情,例如将2重新定义为一个函数,该函数将返回7,并且在您的数学无法使用后永远消失。 (但是为什么呢?)您可以轻松跳入内存的不良区域并使系统崩溃。您将在任何给定的时间为堆栈上的哪些数据建立良好的心理模型,否则您将遭受痛苦。如果您希望编译器为您担心代码安全性,请参阅Rust,Ada或Java。您在这里找不到。四是关于简单性和灵活性。

简单灵活也意味着可扩展。默认情况下,大多数Forth系统几乎不包含任何内容。例如,如果您喜欢面向对象的样式编程,那么Gforth会提供不少于三个不同的对象框架,您可以选择最适合您的问题或最适合您的样式的对象。您可以修改Forth编译器或解释器本身,因此,如果要进行类型检查,可以添加它。一些Forth实现只用本机汇编或C语言编写二十或三十个函数,其余的则用Forth引导。 Faster Forths完全以汇编语言实现,并进行了一些编译时优化,即使您键入时进行编译,它也可以在目标微控制器本身上以几乎与其他任何东西一样快的速度运行。

如果要设计企业银行业务后端,Forth可能不是您想要学习的语言。另一方面,运行物理模拟的一串闪烁的LED并不是什么“企业”。无论从美感还是贬义上讲,Forth都是黑客的语言。我不确定这是否会完全帮助您完成“实际工作”,而且您的工程师类型现在可能想离开。但是,如果您想调整语言本身,或者使用它来推动您的硬件,或者只是玩耍,Forth就是很棒的选择。我内的骇客认为这很有趣,非常适合小型的微控制器专案。

Forth是仅次于汇编语言的最简单的语言。 Forth在极端情况下是过程性的-Forth程序实际上只是一系列子例程,在Forth术语中称为“单词”。没有语法,所有单词都用空格隔开,并从左到右进行解析。除了少数编译例外,所有单词都可以立即运行,因此Forth解释器不必再等待下一个单词。运行此代码!如果您已经定义了单词run,this和code,那么Forth是有效的!并按照您期望的顺序调用这三个词。

这种简单设置的必然结果是,Forth使用了所谓的反向波兰表示法(RPN)。如果Forth解释器现在要执行+字,则它必须已经将要添加的两个数字加到堆栈上。否则,它必须等待下一个数字出现才能完成加法。再读一遍,让它沉入其中。它与您习惯的有所不同,并且很重要。

任何其他顺序或语法都不必要地复杂。您认为写数学的“自然”方式很疯狂,因为+运算符的超前性质要求括号或“运算顺序”必须明确。看2 + 3 *4。在这里得到14绝对不是自然的-这是带有隐式规则的复杂语法的结果。您必须先阅读整个“句子”,找到*,记住它的优先级高于+,首先对其进行评估,然后再返回加法来完成,即使+是句子中的第二个单词。一台计算机不想知道“操作顺序”,它只想添加两个数字,最好是已经位于ALU寄存器中的数字。不相信我吗?阅读机器代码。

Forth和RPN,将其写为2 3 4 * +或3 4 * 2 +。无论哪种方式,操作员都会处理可用的任何数字。如果您不认为这是“反向”,“抛光”甚至是“记号”,那么您将走上正确的道路。您只需按照执行顺序将其写下即可。 (那有多疯狂!!!)

我喜欢将RPN视为错位的计算等同物;开始烹饪之前,您需要先准备好所有食材。这是Forth代码的工作方式:get.broccoli chop.broccoli get.beef slice.beef get.oyster-sauce sauce.fry有些元素自然可以互换-您可以在西兰花前获取并切片牛肉-但总体顺序是这对程序很重要,而且您真的不想在牛肉入锅时又回切西兰花。但是,当您坚持写作3 + 4而不是3 4 +时,这正是您要做的事情。

定义并编译新单词::进入编译模式;退出。这样的编译会立即进行。在后台,Forth解释器正在查找定义中使用的每个单词,然后将它们简单地串在一起。如您现在所见,函数名称本身就是该规则的一个例外。

编译您的第四个单词::7 3 4 +;。它不是很有用,但是会创建一个名为7的单词,它将3和4放在堆栈中,然后运行加法单词。 “结果”是,无论您以前在堆栈中拥有多少,现在您都将获得7。一个经过优化的Forth编译器只会将7压入堆栈。

所有编程都是将复杂的任务分解为合理大小的块。构成“合理”的内容在某种程度上取决于语言,某种程度上取决于程序员的风格以及某种文化时代精神。与在C语言中进行函数调用相比,在Forth中执行单词所需的开销要少得多,而且即使对于有经验的Forthers,遵循长代码逻辑也可能会令人费解,因此Forth单词的定义往往非常短,通常包含注释的单行代码。您会经常编译。

Forth的心脏和灵魂是数据堆栈,此后称为“堆栈”。 Forth是一种基于堆栈的语言,在您用Forth进行一段时间编码之前,您无法理解它的真正含义以及对堆栈的看法如何影响您的编码生活。第四句话不带参数或返回值,而是在调用它们时对栈中的任何数据进行操作。

堆栈是Forth最好和最差的部分。当您的堆栈内容与操作它们的单词对齐时,结果便是无与伦比的美观和效率代码。当他们不一致时,您会发现自己想知道面向对象的人是否不合适,并且将数据与方法结合起来毕竟是一个好主意。

Forth编程中的头是用一个单词找出堆栈上需要的内容,并确保事先使用的单词将其保留在堆栈上。从这个意义上讲,Forth程序员定义了单词,但是需要思考一些短语,其中堆栈的内容以空开始,然后以这种方式结束。就像C在函数作用域内使用堆栈的方式一样,只保留局部变量直到函数完成操作,然后再覆盖它们。

作为这种链接的具体示例,想象一下一个gpio-set字,它将GPIO引脚设置为高电平。它可能需要端口和引脚号来完成工作。一种特别的Forthy实现方式是为要使用的零件上的每个引脚定义一个词::PA3 PORTA 3;然后,您可以使用PA3 gpio-set点亮引脚A3上的LED。在C语言中,您首先要定义一个包含端口和引脚号的结构,然后定义gpio-set以采用该类型的结构。在Forth中,这是隐式的:请确保引脚字将端口和引脚号压入堆栈,然后确保引脚处理字期望它们。这不安全,但是很简单。

Forth绝对最糟糕的部分是堆栈操作。人们通常通过学习堆栈操作来开始学习Forth,这确实很重要,但是却很琐碎。诸如swap,drop和dup之类的词使您可以在堆栈上四处移动项目,但是给定单词中太多的“堆栈杂耍”操作可能是Forth代码不良的标志,而不是良好的标志。您肯定会使用这些词,但这不是尸体被埋藏的地方。

相反,堆栈是要在处理步骤之间放置绝对最小量的数据的地方。当然,项目的数量必须足够小,以免耗尽有限的堆栈空间。但是,第二个原因是,要记住太多的堆叠项根本很难。习惯了Forth之后,您可以内部化的堆栈数量可能会从三个增加到五个或七个,但是如果让堆栈长时间不修剪就变得很困惑。

因此,福斯是一场灾难。这是一种您必须自己管理堆栈的语言,而不会陷入无休止的堆栈杂乱网中的唯一希望就是使事情尽可能简单。第四位拥护者声称这也是它的最大优点-总是存在使事情保持简单明了的压力,因为做任何其他事情都会将无法数字化的错误嵌入代码中,从而使您发疯。我不知道这是斯德哥尔摩综合症,还是我的内心是极简主义者,还是喜欢挑战,但这实际上就是Forth如此精巧的原因之一。

其他编程语言允许您处理数十个变量,因为编译器会为您跟踪不同的作用域,并跟踪每个(局部)变量在堆栈中的深度。福斯没有。这意味着您需要考虑事物运行的顺序。 Forth迫使您内部化一些理想的编译器可以为您完成的优化。这可能会导致代码非常紧凑或令人头疼。这取决于程序员和问题。

以我的经验,简单的语法,计算机友好的排序方式以及对透明性和简单性的强调,实际上使在Forth中正确处理事情变得异常容易。

但是关于福思的哲学上的胡言乱语。如果您愿意,可以在其他地方大量阅读。 (请参阅下面的词汇表。)出于以下三个原因,Forth对硬件黑客而言现在比以往任何时候都更加有趣。第一个原因是Forth是为1970年代末和1980年代初的计算机开发的,而这种强大的功能和成熟度恰恰是目前市场上每3美元的微控制器中所能找到的。其他两个原因交织在一起,但围绕一个特定的Forth实现。

有四百万个,每一个都是一片特殊的雪花。我们已经介绍了AVR的Forth,ARM的Forth,以及ESP8266的Forth。开个玩笑说,如果您已经看到一个Forth实施,就已经看到了一个Forth实施。但是我认为这太愤世嫉俗了-Forth是计算机编程问题的一种思考方式,因为它是特定的实现方式。学习一个后,您将有良好的基础学习其他任何一个。

无论如何,几年前,一位物理研究生[Matthias Koch]为MSP430编写了Forth,因为他需要一个微控制器来收集用于实验的模拟数据。那就是“ Mecrisp”。后来,他需要更快的速度并将其重新编写为ARM Cortex M系列芯片,我们得到了“ Mecrisp-Stellaris”。

这就是令人赞叹的地方。 [Jean-Claude Wippler]是JeeLabs中的“ J”,他决定至少在引擎盖下,在Forth实施新的分布式电气和环境传感器系统。为此,他需要一个硬件抽象层。 Mecrisp-Stellaris与JeeLabs库的结合对于整个ARM微控制器来说是一个巨大的Forth生态系统,并且在过去两年中,所有这些都是由一小撮有思想的黑客开发的。两者结合在一起,提供了非常令人愉悦的Forth微控制器黑客体验,就像奇怪的交互式Arduino。

因此,如果您想跟踪一个非常奇怪的兔子洞,或者对真正的黑客编程语言有所了解,或者只是四处闲逛,请继续关注。在几周后,我将发布有关STM32系列ARM芯片上的Mecrisp-Stellaris入门的动手指南。

一个良好的最低Mecrisp-Stellaris开发环境将由一个便宜的STM32F103开发板,一个ST-Link v2(或更高版本)的编程器以及一个USB-TTL串行适配器组成。很有可能您至少已经开始使用后者了。如果是这样,根据您的居住地,您可以将其余的住房设置为10美元,10欧元或10英镑。 “ STM32F103”和“ ST-link”应该可以帮助您在eBay上进行设置。

因此,现在订购一些零件。 在等待交付时,请完成此非常好的在线教程。 执行此操作,下次您将被设置。 如果要进一步操作,可以为台式计算机下载Forth并开始阅读其他一些介绍。 Brodie的“ Starting FORTH”是Forth的典型介绍,但是有些过时了(可以跳过有关磁盘访问的第3章)。 如果您希望简洁而不是幽默,请查阅《 J.V. Noble入门指南》或Gforth教程。 未经FORTH,Inc.许可使用的《 Starting FORTH》中的所有图像。原件自然是黑白的,而不是Hackaday深色木炭和黄色。