Forth 系统实现 |
作者 Brad Rodriguez |
| 编译 赵宇 张文翠 |
第四部分 汇编器还是 META 编译器
撰写本文的过程贯穿着一个指导思想:“保持最短”。本着这个原则,我把源程序列表安排到另外的地方,对此我表示歉意。现在,我们主要试图讨论以下话题:
你如何开始构造一个 Forth 系统?
你现在已经知道了,主要的 Forth 程序代码是高级串线,它们通常被编译成一系列地址。在 FIG-Forth 时代和早期的 Forth 实践中,汇编语言是唯一可用的程序设计语言工具。汇编语言对于编写 Forth 的 CODE 字是非常好的,但是高级串线必须用一系列的 DW 伪指令来编写。例如, Forth 字:
: MAX ( n n - n) OVER OVER < IF SWAP THEN DROP ;
必须写成
DW OVER,OVER,LESS,ZBRAN
DW MAX2-$
DW SWAP
MAX2: DW DROP,SEMIS
后来,由于可以实际工作的 Forth 系统越来越普及, Forth 编写者开始把 Forth 编译器修改成为交叉编译器,通过运行在 CP/M (或者苹果 II ,或者其它任何什么微机系统)的 Forth 系统,你就可以为其它 CPU 编写 Forth 程序、更改 Forth 系统或者为那个 CPU 编写一个全新的 Forth 系统。
由于是从 Forth 内部创建一个全新的 Forth 系统,这种编译器被称为“META 编译器”。计算机科学的学究们反对这样的称谓,所以有些 Forth 编写者仍然使用“交叉编译”和“重新编译”的术语,这两个术语之间的差异是:“重新编译”只能为相同的 CPU 产生新的 Forth 系统。
现在大多数 PC 机上的 Forth 都是通过 META 编译产生的,但是,在嵌入式系统领域却产生了意见分歧。
使用汇编器编写 Forth 系统的观点认为:
META 编译器神秘难懂,你必须完全理解一个 META 编译器然后才能使用它;
一般的程序员都懂得汇编器;
汇编器对于一个新的 CPU 总是可用的;
汇编器处理许多优化(比如长短调用格式);
汇编器处理前向引用和特殊的寻址模式,而许多 META 编译器通常不能做到;
汇编程序员可以使用熟悉的编辑器和调试工具;
代码的产生是完全可见的,没有向程序员“隐藏”任何东西;
改变 Forth 模型非常容易,而许多设计的考虑却影响 META 编译器的内部;
使用 META 编译器的观点认为:
你是在编写“正常”的 Forth 代码,它当然易于阅读和调试;
一但你理解了你的 META 编译器,你就可以很容易地把它移植到新的 CPU 上 ;
你需要的唯一工具就是你的计算机上的 Forth 系统;这一点对于没有 PC 的人特别实用,因为现在的许多交叉汇编器要求 PC 机或者工作站。
我用各种方式编写过几个 Forth 系统,所以要作出选择是很痛苦的。我倾向于使用 META 编译器:我发现 Forth 的 MAX 代码比等效的汇编代码易读、易懂。反对使用 META 编译器的观点许多已经被现代的“专业”编译器所克服,如果你使用 Forth 工作,我强烈建议你考虑一个商业化产品。唉,公共的 META 编译器(包括我自己的)依然落后于时代,笨拙同时神秘。
所以我准备为 Forth 程序员提供基本的材料,告诉你作出自己的选择。我将给出 META 形式的MC6809 代码,为 F83 ( IBM PC CP/M ST )提供 META 编译器。 Z80 代码将使用 CP/M 汇编器写成。 8051 代码使用公共的 PC 交叉汇编器编写。
使用 C 语言编写 Forth 系统?
如果不讨论“用C语言编写 Forth 系统”这个新的方法,本文就将是不完全的。 C 语言比汇编器具有更好的可移植性 -- 理论上,你所要作的全部工作就是为任何 CPU 重新编译相同的代码。
这种方法的缺点是:
在设计决策选择上更缺少灵活性;比如,不可能实现直接串线编码,也不可能优化寄存器的分配;
增加原语之后,你必须重新编译 C 源代码;
某些 C 语言实现的 Forth 使用了效率很低的串线技术,比如多个 CASE 语句;
大多数 C 编译器产生的代码比汇编语言程序员的代码低效;
但是对于那些 UNIX 系统和不支持汇编语言编程的 RISC 工作站来说,这却是 Forth 得以运行的唯一方法。最完全和广泛使用的公共域 C 语言 Forth 系统是 TILE 。如果你没有运行 UNIX 系统,你可以看一下文件 HENCE4TH_1.2.A 。
为了继续以前的比较,还是先来看看 HENCE4TH 的 MAX 定义。为了清楚起见,我略去了字典头:
_max()
{
OVER OVER LESS IF SWAP ENDIF DROP
}
不使用汇编器,用 C 语言编写核心 CODE 定义,比如,这是 HENCE4TH 的 SWAP 定义:
_swap()
{
register cell i = *(dsp);
*(dsp) = *(dsp + 1);
*(dsp + 1) = i;
}
请注意:用 C 编写 Forth 字有非常不同的技术,所以这些字在 CForth 和 TILE 中可能差异非常大。
在 MC68000 或者 SPARC 工作站上,这样的编码可以产生非常好的代码。不过,一但你计划用 C 来实现 Forth ,你也需要理解用汇编语言实现 Forth 是怎样工作的。所以请继续阅读本文。
参考文献
[CAS80] Cassady, John J., METAForth: A Metacompiler for Fig- Forth , Forth Interest Group (1980).
[MIS90] HenceForth in C , Version 1.2, distributed by The Missing Link, 975 East Ave. Suite 112, Chico, CA 95926, USA (1990). This is a shareware product available from the GEnie Forth Roundtable.
[ROD91] Rodriguez, B.J., letter to the editor, Forth Dimensions XIII:3 (Sep/Oct 1991), p.5.
[ROD92] Rodriguez, B.J., "Principles of Metacompilation," Forth Dimensions XIV:3 (Sep/Oct 1992), XIV:4 (Nov/Dec 1992), and XIV:5 (Jan/Feb 1993). Note that the published code is for a fig-Forth variant and not F83. The F83 version is on GEnie as CHROMIUM.ZIP
[SER91] Sergeant, Frank, "Metacompilation Made Easy," Forth Dimensions XII:6 (Mar/Apr 1991).
[TAL80] Talbot, R.J., fig-Forth for 6809 , Forth Interest Group, P.O. Box 2154, Oakland, CA 94621 (1980).
[TIN91] Ting, C.H., "How Metacompilation Stops the Growth Rate of Forth Programmers," Forth Dimensions XIII:1 (May/Jun 1991), p.17.
|