正文

Forth 语言概要(3)2005-08-05 14:12:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/forth/3455.html

分享到:

8. 汇编器
大多数 Forth 系统都包含一个宏汇编器,为它们所在的 CPU 进行汇编语言编程。通过使用定义字 CODE ,程序员可以创建由实际的机器代码组成的定义。 CODE 定义可以用来完成 I/O 、算术原语和其它依赖机器(时间紧迫)的处理功能。当程序员使用 CODE 时,他就和使用其它汇编器一样对 CPU 有完全的控制能力, CODE 定义的字以机器速度全速运行。

这是 Forth 的一个重要特点。它允许那些明显地依赖机器的代码通过机器无关接口变换成为可管理的片断。当需要把应用移植到不同的处理器上时,我们仅仅需要重新编写 CODE 字,这些 CODE 字就可以严格地按相同的方法与其它 Forth 字进行交互。

Forth 汇编器本身也是极其紧缩的(典型地为 1K 字节),它们可以和编译器、编辑器以及其它编程工具一起驻留在系统中。这就意味着程序员可以打入很短的 CODE 定义,然后立即执行它们,这个能力在调试客户硬件时特别有用。

9. 虚拟存储
Forth 最后一个独特的组成元素是它按数据和源程序虚拟存储器的方式使用磁盘(或者其它海量存储器)。在地址解释器的情况下,这种方法在历史上是典型的 Forth 方式,但现在并不通用。磁盘被分成 1024 字节大小的块,在内存中则准备两个或者多个缓冲区,数据在引用时被自动读入缓冲区。每个块有固定的块号,直接对应于本地存储系统的物理位置。任何时候程序需要访问时,它都会在内存中找到数据,并不需要显式的读写操作。

这样一个面向块的磁盘管理方法对于 Forth 独立系统的实现是简单和高效的,结果是块为独立和协同驻留 Forth 实现中的源程序和数据处理提供了一个完全透明的机制。

在源程序块中的定义通过 LOAD 命令编译到内存中。许多系统包含一个编辑器,它把每个块组织成 64 字符 16 行的显示模式并提供命令来修改源程序。

源块在历史上曾经是 Forth 风格的一个重要组成元素。就像 Forth 的定义可以被视为自然语言中的句子,一个块相当于是一个段落,通常包含有与一个主题相关的定义,比如“向量处理”。在块文本的顶行含有这个主题的注释说明,应用程序可以按实际需要来选择装入块。

块也被用于存储数据。小的记录可以组合进一个块,大的记录也可以分布在几个块中。程序员可以根据应用的需要分配块,独立的 Forth 系统还能够按磁头运动最少的原则来组织数据以优化系统,还有几个开发商提供了基于 Forth 块的文件和数据库系统。

在主机操作系统之上运行的 Forth 版本使用文件系统来实现块机制,另外也提供基于操作系统环境的一般文件操作方法。

10. 数据结构
所有的高级字共享相同的数据结构,这种字的首部含有文本解释器识别一个字所需要的数据信息,见图 3 所示。



图 3 定义的首部

“LINK”字段包含字典中前一个命令的首部地址,在搜索字典时需要这个地址。

“名字长度”字段包含名字中全部字符的数量,后随这些字符,在解释过程中进行名字匹配时需要这些数据。许多 Forth 系统仅仅存储名字的前3个字符,这可以在占用空间最小的情况下避免名字冲突,而许多系统的名字长度允许在 3-31 个字符之间选择。

本文解释器从字典的最后一个入口开始处理,并沿着链表向后查找直到匹配名字为止。现在还有许多系统提供散列算法,它们把字典分成几个表,每次只查找其中的一个,这种方式可以大大地节省查找时间。

“代码指针”是这个字将被执行的第一个指令的 CFA ,它形成了定义体的第一个入口。它也是代码的地址,这个地址解释定义的其它部分,对于不同的数据结构将指向不同的代码。



图 4 不同的数据类型所指向的行为也不同

字的其它部分也就是定义体,它依不同的数据类型而不同,如图 4 所示:

•  在汇编 (CODE) 定义中,体中含有定义命令行为的机器操作码列表,因此 CFA 含有这个体的地址;

•  在诸如 VARIBLE 和 CONSTANT 这样的数据结构命令中,字义的体中含有实际的数据。 CFA 含有处理这些数据所需要的子程序的入口地址,用户定义数据结构的例子如图 5 所示。

•  在高级 : (冒号)定义中,字的体中含有构成这个定义的所有以前定义字的地址列表。 CFA 是地址解释器 (:) 的地址。

11. 程序举例
下面是一个典型的 Forth 源程序块。这个应用程序用来控制 8 个 LED 提示灯,它也说明了 Forth 定义是如何组合以形成应用环境的。



图 5 一个源程序块

注意第一行 (LINE 0) 的注释说明了这个块中所列出的其它字的属性,这一行通常被称为索引行。多数 Forth 系统都有一个命令字来查找块的第一行以发现哪个块是应用程序所需要的。

所有的 LED 通过一个位于地址 40H 的 8 位口来访问。这个位置通过第一行的常数定义给出,于是这个口可以通过名字来引用,而如果以后硬件地址改变了,我们也仅仅需要调整这个常数。字 LIGHTS 在堆栈上返回这个地址,定义 LIGHT 得到栈顶值并把它发送到设备上。这个值的属性是位掩码,每一位对应一个 LED 。于是命令:

255 LIGHTS

将点亮所有的灯,而命令

0 LIGHTS

将关闭所有的灯。如果硬件变化了,我们也只需要改写字 LIGHTS 以适应新的硬件,而应用程序的其它部分则不需要做任何改变。

行 4-6 含有对我们终端输入进行的处理,终端输入是为了能够进行简单的诊断以确认各个方面都能够工作正常。这里 DELAY 含有以微秒为单位的延时时间,执行字 DELAY 返回这个变量的地址。 DELAY 的两个值是由 FAST 和 SLOW 定义的,使用 Forth 的操作!(读作 STORE )从栈顶得到地址和值,并把值存储到相应的地址中。

定义 COUNT 运行一个从 0-255 的循环(在字 DO 和 LOOP 之间)。字 I 把循环的当前值放到栈顶,然后发送给 LIGHTS 。接着系统等待由 DELAY 指定的时间。

字 @ (读作 FETCH )从 DELAY 提供的地址读取一个值,并把这个值交给 MS 等待指定的毫秒。执行 COUNT 的结果就是以指定的速率从 0 到 255 之间计数。可以这样调用:

SLOW COUNTS 或者

FAST COUNTS

8-10 行提供单独命名灯的能力。在这个应用中,它们用作灯的指示器。字 LAMP 是一个使用位掩码作为参数的定义字。字 CREATE 把一个首部编译进字典,同时字,(逗号)把掩码放到定义体中。字 DOES> 把代码地址放到新字的 CFA 中。于是当新字执行时,它的动作就是获得所定义的新字体中的第一个项目的内容。

行9和10使用 LAMP来命名特别的指示灯。当其中的一个字比如 POWER 执行时,掩码就返回到栈顶。实际上,这种行为与 Forth 字 COSNTANT 一样。但是 LAMP 是一个例子,像这样使用 CREATE …… DOES> 定义字的能力是 Forth 语言最强大的功能之一,它允许我们定义基于数据结构的“智能应用”。

最后,行 13-15 ,我们有了控制灯面板的字。 LAMPS 是一个变量,它包含有灯的当前状态。字 LAMP-ON 得到一个掩码(由其中一个 LAMP 字提供),然后点亮灯。 LAMP-OFF 将指定的灯关闭,同时改变 LAMPS 的状态。

在应用程序的其它地方,灯的名字和 LAMP-ON 、 LAMP-OFF 可能才是需要直接执行的字。用法是:

POWER LAMP-ON 或

SAMPLING LAMP-OFF

在系统上编译这个代码块的时间大约是半秒,包括从磁盘上读入的时间。这样程序员就有可能简单地打入一个定义然后立即执行它。另外我们总是具有与外部设备直接通信的能力。我们可以首先打入:

HEX FF 40 OUTPUT

来看看是不是所有的灯都亮。如果不是,可以假定有些地址不对,因为上面的句子是把全 1 直接发送给设备。这种类型的交互在与硬件打交道的时候特别有用,它们能够缩短硬件的开发时间。

12. 扩展
由于 Forth 是可扩展的,大量的开发商为 Forth 语言的应用提供许多扩展产品。这些扩展包括自动化的文档、终端驱动、磁盘文件管理、数据库管理、目标编译器、交叉编译器和 META 编译器。

一个目标编译器允许我们使用一个主机 CPU 比如PC机来编写系统程序。程序可以通过键盘编辑和交互式地测试,之后可以把这些程序编译到目标环境中并产生对应的 ROM 代码。目标编译器的一个功能就是剔除目标系统中不需要的代码,比如编辑器、编译器和汇编器。通过这些工作,运行系统的 ROM 开销可以从开发系统所占用的 8K 字节减少到大约 600 个字节。

交叉编译器与目标编译器类似,它允许用户在主机上开发和测试代码,然后交叉编译器将像目标编译器一样编译 Forth 系统,只是交叉编译器是使用不同的机器语言、为不同的目标 CPU 产生代码。这个特点允许快速地为新的 CPU 开发新的 Forth 系统,由于 Forth 系统主要是用 Forth 语言编写的,所以我们只需要为新的处理器编写一个汇编器,然后为新的处理器进行 Forth 系统的交叉编译就可以了。大多数的 Forth 系统就是用这种方式开发的,结果, Forth 通常成为一个新处理器上的首选语言之一。

写一个 Forth 编译器的过程也被称为 META 编译。 

阅读(2719) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册