Forth Moving Lisp Moving Forth

Forth Moving Lisp Moving Forth

Let Over Lambda — 50 Years of Lisp by Doug Hoyte

Lisp Moving Forth Moving Lisp Weird By Design

This chapter is a culmination of many macro techniques we have looked at so far in this book. Using macro abstractions we have developed, we create an implementation of one of my favourite programming languages: forth. Although this implementation embodies most of the important ideas of forth, it is very different and lispy. Though there are certain interesting uses for the code in this chapter, its primary purpose is to teach the concepts and fundamentals of forth meta-programming to a lisp audience and to be a platform for discussing the central theme of this book—creating and using duality of syntax with macros.

本章是我们在这本书中探讨过的许多宏技术的结晶。利用我们已经开发的宏抽象,我们创建了本人最喜欢的编程语言之一:Forth 的实现。尽管这一实现体现了 Forth 的大部分重要思想,但它与传统的 Forth 非常不同,且带有浓厚的 Lisp 风格。虽然本章中的代码有一些有趣的用途,但其主要目的是向 Lisp 受众传授 Forth 元编程的概念和基础知识,并作为一个平台来讨论本书的核心主题——利用宏创建和使用语法二元性。

Forth, more so than every language except lisp, has a rich, fascinating history and I’m grateful for having discovered it. For that reason, and for everything else, this chapter is dedicated with love to my father Brian Hoyte who introduced me to forth and to computer programming. This chapter was partially inspired by [THREADING-LISP] and by the research of Henry Baker[LINEAR-LISP][LINEAR-LISP-AND-FORTH].

除了 Lisp 之外,Forth 拥有比任何其他语言都更丰富、更迷人的历史,我很庆幸自己发现了它。出于这个原因,以及其他一切,本章谨献给我挚爱的父亲 Brian Hoyte,是他将我引入了 Forth 和计算机编程的世界。本章的部分灵感来源于 [THREADING-LISP] 以及 Henry Baker 的研究 [LINEAR-LISP][LINEAR-LISP-AND-FORTH]。

Forth was the first programming language that was created and developed without strong government, academic, or corporate sponsors—or at least the first such language to succeed. Instead of being motivated by the needs of a large organisation, forth was independently invented by Chuck Moore around 1968 to solve his own computing needs in astronomy, hardware design, and more. Since then, forth has been distributed, implemented, and improved upon by a passionate grass-roots user community[EVOLUTION-FORTH-HOPL2]. Contrast forth with the MIT (and later DARPA) patronage of early lisps and COMMON LISP, IBM’s FORTRAN, and AT&T’s unix language C.

Forth 是第一种在没有强大的政府、学术界或企业赞助的情况下创建和开发的编程语言——或者至少是第一种取得成功的此类语言。Forth 并非出于大型组织的需求,而是由 Chuck Moore 在 1968 年左右独立发明,旨在解决他在天文学、硬件设计等领域的计算需求。从那时起,Forth 一直由一个充满激情的草根用户社区进行分发、实现和改进 [EVOLUTION-FORTH-HOPL2]。对比一下 Forth 与早期 Lisp 和 COMMON LISP 背后麻省理工学院(及后来的 DARPA)的资助,以及 IBM 的 FORTRAN 和 AT&T 的 Unix 语言 C,便可看出其不同。

Because of these roots, and because of a generally different philosophy of the role of computer software and hardware, forth is different. Even more so than lisp, forth looks weird. But like lisp, forth looks weird for a reason: it was designed with more in mind than style. Forth is weird by design, and this design relates to macros.

由于这些根源,以及对计算机软件和硬件角色的普遍不同哲学,Forth 与众不同。甚至比 Lisp 更甚,Forth 看起来很怪异。但像 Lisp 一样,Forth 的怪异是有原因的:它的设计不仅仅考虑了风格。Forth 的怪异是刻意为之的,而这种设计与宏有关。

Today, forth is most commonly seen in so-called embedded platforms—computers that are severely resource constrained. It is a testament to the design of forth that the language can be entirely implemented on almost every programmable computer system ever created. Forth is designed to be as easy as possible to implement and experiment with. In fact, creating a forth clone is so profoundly trivial that inventing a forth-style stack based language or two is almost a rite-of-passage for programmers interested in the design of programming languages. Some stack based languages that can trace roots back to forth and have made interesting contributions are PostScript and Joy.

今天,Forth 最常见于所谓的嵌入式平台——即资源极其受限的计算机。Forth 能够几乎在有史以来创建的每一个可编程计算机系统上完整实现,这证明了其设计的卓越。Forth 的设计初衷是尽可能易于实现和实验。事实上,创建一个 Forth 克隆版是如此简单,以至于发明一两种 Forth 风格的栈式语言几乎成了对编程语言设计感兴趣的程序员的“成人礼”。一些可以追溯到 Forth 并做出过有趣贡献的栈式语言包括 PostScript 和 Joy。

Often important forth implementation decisions are based on the exact resources of the computer that forth is being implemented on. Forth programmers have devised a set of abstract registers that need to be either mapped into real registers, mapped into memory locations, or possibly implemented in a different way altogether. But what do we do if we are implementing a forth on lisp, an environment with unlimited potential and few restrictions? Rather than simply impose an arbitrary mapping of forth abstract registers into lisp code, we try to take a step back. What would forth look like if Chuck had a lisp machine? Rather than fitting forth to the capabilities of an arbitrary machine, real or virtual, we explore a minimal set of forth abstract registers, optimised for simplicity and capability when implemented on lisp.

通常,重要的 Forth 实现决策基于 Forth 所运行计算机的确切资源。Forth 程序员设计了一套抽象寄存器,这些寄存器需要映射到真实寄存器、映射到内存位置,或者以完全不同的方式实现。但是,如果我们是在 Lisp(一个潜力无限且限制极少的环境)上实现 Forth,我们该怎么做呢?我们不应简单地将 Forth 抽象寄存器强行映射到 Lisp 代码中,而是尝试退后一步。如果 Chuck 当年拥有一台 Lisp 机器,Forth 会是什么样子?我们不再让 Forth 去适应任意机器(无论是真实的还是虚拟的)的能力,而是探索一套最小化的 Forth 抽象寄存器,并针对在 Lisp 上实现时的简洁性和能力进行了优化。

But really, searching for an optimal set of abstract concepts is what Chuck did while he created forth, using his experience of dozens of different forth implementations on as many architectures. This is why forth is so great. Like lisp, forth represents a high local maximum in the space of language design, and also like lisp, forth is not so much a programming language or a set of standards, but instead a building material and collection of wisdom regarding what works and what doesn’t.

事实上,寻找一组最优的抽象概念正是 Chuck 在创建 Forth 时所做的事情,他利用了自己在多种架构上实现数十种不同 Forth 的经验。这就是 Forth 如此伟大的原因。像 Lisp 一样,Forth 代表了语言设计空间中的一个高局部极大值;也像 Lisp 一样,Forth 不仅仅是一种编程语言或一套标准,它更像是一种构建材料,以及关于什么可行、什么不可行的智慧结晶。

FORTH-REGISTERS (defvar forth-registers '(pstack rstack pc dict compiling dtable))

The forth-registers variable is a list of symbols that represent abstract registers for our forth machine. Of course lisp doesn’t think in terms of registers and fixnums, but instead variables and symbols. It may seem strange to start our development of a forth environment here, with just a list of variable names, but this is in fact always the first step in implementing a forth system. Creating a forth is an ingenious process of bootstrapping exceeded in beauty and cleverness only by lisp itself. A modest description of this process follows.

forth-registers 变量是一个符号列表,代表了我们 Forth 机器的抽象寄存器。当然,Lisp 并不以寄存器和定点数(fixnums)的思维方式运作,而是使用变量和符号。从这里开始开发 Forth 环境,仅仅列出一堆变量名,看起来可能很奇怪,但这实际上始终是实现 Forth 系统的第一步。创建 Forth 是一个巧妙的自举(bootstrapping)过程,其美妙和精巧程度仅次于 Lisp 本身。下面是对这一过程的简要描述。

One of the characteristic features of forth is its direct access to the stack data structures used by your program both to pass parameters to subroutines and to keep track of your execution path throughout these subroutines. Forth is especially interesting because—unlike most programming languages—it separates these two uses of the stack data structure into two stacks you can fool with. Most languages don’t allow you to directly manipulate the stack at all. In a typical C implementation, the parameters of a function call and its so-called return address are stored in a single, variable-sized stack frame for every function invocation. In forth, they are two different stacks called the parameter stack and the return stack, which are represented as our abstract registers pstack and rstack. We use the COMMON LISP push and pop macros, meaning these stacks are implemented with cons cell linked lists instead of the array data structures used in most forths.

Forth 的一个特征是能够直接访问栈数据结构,该结构既用于向子程序传递参数,也用于跟踪这些子程序中的执行路径。Forth 特别有趣的地方在于——与大多数编程语言不同——它将栈数据结构的这两种用途分成了两个你可以操作的栈。大多数语言根本不允许你直接操作栈。在典型的 C 实现中,函数调用的参数及其所谓的返回地址存储在每次函数调用时生成的单个可变大小的栈帧中。在 Forth 中,它们是两个不同的栈,分别称为参数栈(parameter stack)和返回栈(return stack),它们由我们的抽象寄存器 pstackrstack 表示。我们使用 COMMON LISP 的 pushpop 宏,这意味着这些栈是用 cons 单元链表实现的,而不是大多数 Forth 中使用的数组数据结构。

The abstract register pc is an abbreviation for program counter, a pointer to the code we are currently executing. What forth code is and how we can point to it will be explained shortly, as will our abstract registers compiling and dtable.

抽象寄存器 pc 是程序计数器(program counter)的缩写,指向我们当前正在执行的代码。什么是 Forth 代码以及我们如何指向它,稍后会进行解释,我们的抽象寄存器 compilingdtable 也会一并说明。

FORTH-WORD (defstruct forth-word name prev immediate thread)

Another bu… (Text truncated)

FORTH-WORD (defstruct forth-word name prev immediate thread)

另一个 bu…(文本截断)