—、一种有生命力的语言 假设你是一位办公室管理人员并且刚刚雇用了一位热心的新助手。第一天你教给这位助手打印图件的正确格式(假定这位助手已掌握打字技术)。在当天结束时,你只需说"请打印这个"。 第二天你对他讲解档案制度。你花了二上午时间来解释如何归档,下午你就只需说"请把这个归档"。 到了周末你便可以用一种简记的形式同助手交谈了。"请发出这封信",意思包含"打印它,让我签发,照相复制,附本归档,邮寄原件"。这样,你和你的助手就能更愉快更有效地自由执行你的商业事务了。 良好的组织和有效的通讯要求你: ①对有用的任务加以定义并对它们命名; ②把各个相关的任务组合成一些较大的任务,并给它们相应命名等等。 FORTH 正是按上述方法(除了你不必说"请"之外)让你来组织你自己的过程并和计算机建立联系。 作为一个例子,我们设想用 FORTH 编程来控制一台由微机控制的洗衣机。在该例中主要命令被命名为 WASHER。下面是用 FORTH 书写的 WASHER 的定义: : WASHER WASH SPIN RINSE SPIN ; 在 FORTH 中,冒号表示一个新定义的开始。 冒号后的第一个词 WASHER 是新过程的名称。其余的词 WASH、SPIN、RINSE 和 SPIN 组成该新过程的定义。最后的分号表示定义结束。 组成 WASHER 定义的每一个词都必须是在洗衣机控制程序中已被定义过的词。例如,察看定义 RINSE: : RINSE FILL AGITATE DRAIN ; 可以看到它是由词 FILL、AGITATE 和 DRAIN 组成的。而且这些词又应是本例中其它地方已定义过的词。例如可以查到 FILL 的定义: : FILL FAUCETS OPEN TILL-FULL FAUCETS CLOSE ; 在这个定义中,我们既涉及了对象(faucts、水龙头)又涉及了动作(open 和 close、开和关)。而且定义了词 TILL-FULL 去建立一个"延迟循环",它指示当从到达水平面时开关已被启动的时间,没有其它动作。 如果我们顺着这些定义察看下去,最终将会发现它们都是由一组非常有用的、组成全部FORTH系统的基本命令定义的。在 PolyFORTH 中大约包含 300 条基本命令。这些命令中的许多命令本身也是由如同本例中的"冒号定义"所定义的,另一部分由特定机器的机器语言直接定义。在 FORTH 中,一条已定义的命令称为一个"词"。 用其它词定义一个词的能力称为"扩展性"。这种扩展性导致了一种非常简单、结构天然严谨、功能无限扩展的程度设计格式。无论你的程序是流水运行,还是获取科学计算、商业管理或游戏中的数据,你都可以根据特定需要建立你自己的"有生命力的语言"——各种词。 二、人机会话 FORTH 有许多独有的特点,其中之一就是简单地呼叫一个词的名字便可以执行它。若在终端键盘上操作,只要键入词的名字再按 RETURN 键即可。自然也可以在其它的定义中放入该词的名字,再由其它词来使用它。 由于只要键入一命令,机器便可执行该命令,所以 FORTH 被称为"会话式"语言。 首先我们给出一个你能亲自试验的例子,并显示出把一些简单的命令组合成一些功能极强的命令的步骤。在此我们将使用一些控制终端屏幕或打印机的简单 FORTH 词。现在让我们熟悉一下通过终端键盘与 FORTH "交谈"的技巧。 请坐在你实际的或假想的终端前面。我们将假定你已请求别人为你装备了使用 FORTH 的所有软硬件,或者你了解如何装备。 现在请按下键: RETURN 这时计算机将回答: OK RETURN 键是你用来使 FORTH 知道你的请求的信息。OK 是 FORTH 回答它已完成你的请求而且没有出错的信息。在上面的情况下,你要求 FORTH 不进行任何工作,所以它遵从你的请求不做任何事情,只是回答 OK。(OK可能是大写字母,也可能是小写字母,这取决于你的终端)。 现在键入: 15 SPACES 如果你在键入过程中发生错误,可以按"backspace"键进行修改。方法是使光标回到发生错误的位置,重新键入正确的字符,然后继续。在一行键入正确后再按 RETURN 键。(一旦按下 RETURN 键后就无法再对本行进行修改了)。 注:1)有的FORTH书刊称为"字"。为了不与存疑的"字长"相混淆,我们译为"词"(word),而且在本书中我们把内容中的一个字(18bit)称为一个"单元"(cell)。
在本节中,我们利用符号 <CR> 来表明你必须按 RETURN 键的地方。例如: 15 SPACES <CR> OK 当你按下 RETURN 键时,FORTH 随后打印出 15 个空格,再回打 OK,表示已处理了你的要求。 现在键入: 42 EMIT <CR> * OK 短语"42 EMIT"告诉 FORTH 打印一个"*"号,因此 FORTH 打印出一个星号后再回答 OK。 我们可以在同一行中键入多个命令,例如: 15 SPACES 42 EMIT 42 EMIT <CR> * OK 这时,FORTH 打印出 15 个空格和两个星号。请注意:对于键入的词或数,可以用任意多个空格分开。但是要使 FORTH 能把它们当作词或者是数来识别,至少要用一个空格分开。 如果我们要多次使用短语: 42 EMIT 我们可以把它定义为一个词"STAR": : STAR 42 EMIT;<CR> OK 其中"STAR"是名字,"42 EMIT"是定义。请注意,必须把冒号和分号与邻近的词用空格隔开。另外,为了使 FORTH 定义易于为人们阅读,我们习惯于把定义的名字和内容用二个空格分开。 当你已经键入上述定义并按了 RETURN 键后,FORTH 回答 OK,这表明 FORTH 已认可该定义并将记住它。 现在键入: STAR <CR> * OK FORTH 便执行你的定义而打印一个星号。 象 STAR 这样你自己定义的词和象“EMIT”这样系统中已定义的词之间并没有什么区别。 下面介绍另一个系统定义的词“CR”,它在你的终端上执行换行。例如: CR <CR> OK FORTH 则先执行回车换行,再打印OK(在下一行)。 如果你的FORTH系统中没有这个词,你可以自己立即定义它: : CR 13EMIT 10 EMIT ; 现在请试试: CR STAR CR STAR CR STAR<CR> * * * OK 然后请把 CR放在定义中,如:
: MARGIN CR 30 SPACES ; <CR>OK 现在我们就能键入: MARGIN STAR MARGIN STAR MARGIN STAR<CR> 它将在离左边30个空格的竖线上打印3个星号。 为了下面的需要我们把MARGIN STAR组合起来定义成一个词: : BLIP MARGIN STAR ; <CR>OK 我们还需要定义在水平分析打印多个星号的词(我们将在后面解释它是如何工作的): : STARS 0 DO STAR LOOP ; <CR>OK 现在我们可以键入: 5 STARS<CR> ***** OK 或者 15 STARS<CR> ***********************************OK 或者要求打印任意多个星号。 我们还需要定义一个词,它先执行MARGIN,然后再打印5个星号: : BAR MARGIN 5 STARS ; <CR>OK 现在我们可以键入: BAR BLIP BAR BLIP BLIP CR<CR> 并得到一个由星星组成字母“F”(代表Forth),它应该是这样的:: ***** * ***** * * 最后一个步是把这个新的过程定义成词,称此词为“F”。 : F BAR BLIP BAR BLIP BLIP CR ; <CR>OK 通过上面的例子,你已经了解到简单的Forth命令可以成为更复杂的命名基础。 当列表显示一个Forth应用程序时,我们可以看到它是由一系列功能逐步增长的定义组成,而不是由一个个依次执行的指令系列组成。 作为一个Forth应用的实际程序,我们把前面的实验应用程序列表如下(开头的数字是行号,第0行是注释行,FORTH用括号括起要注释的内容): 0 ( LARGE LETTER F ) 1 :STAR 42 EMIT ; 2 :STARS 0 DO STAR LOOP ; 3 :MARGIN CR 30 SPACES ; 4 :BLIP MARGIN STAR ; 5 :BAR MARGIN 5 STAR ; 6 :F BAR BLIP BAR BLIP BLIP CR ; 三、词 典 FORTH 的每个词和它的定义都被登记在 FORTH 词典中。机器启动时,词典中已包含了许多词,这时,你自己定义的词也可以登记进词典。 当你定义一个新词时,FORTH 便把你的定义翻译成词典形式写入词典条目。这个过程称为"编译"。例如,当你键入一行: : STAR 42 EMIT;<CR> 编译程序便把该新定义编译进词典。但编译程序不直接打印出星号。 一旦词被登记进词典,它是如何被执行的呢?让我们在终端直接键入下述行(不在定义内部): STAR 30 SPACES <CR> 这时将启动称为“INTERPRET”的词,也称为"文本解释程序"。该词进行如下操作: ①文本解释程序首先扫描输入流,寻找以空格分隔的字符串; ②当发现这样的字符串时,它便到词典中去查对该字符串; ③若在词典中找到这样一个词,它便把该词的定义指给一个称为“EXECUTE”的词,“EXECUTE”便执行该词(这时便打印一个星号)。然后文本解释程序回答 OK; ④若在词典中找不到这样的字符串,文本解释程序便调用数字处理程序(叫做 “NUMBER”),若“NUMBER”发现它是一个数字则把它放入数字暂存区。 当你试图执行一个词典中尚不存在的话会出现什么现象呢?例如键入: XLERB <CR> 这时文本解释程序在词典中找不到 XLERB,便试图把它传给“NUMBER”。而它并非数字,“NUMBER”拒绝接受。因此文本解释程序回答该串名字并跟随一问号"?"。 在某些 FORTH 版本中,包括 PolyFORTH,编译程序并不是把定义的全名复制进词典,只是复制前三个字符和全名的字符个数。例如,在PolyFORTH中文本解释程序不能区别 STAG 和 STAR,因为这两个词都是由 4 个字符组成且前三个字符又都是 S-T-A。尽管如此,许多专业程序员还是喜欢采用三字符规则,这样节省内存。某些程序员和许多业余爱好者都欣赏自由选择任意名字。标准 79-FORTH 可以把多到 31 个字符的名字存入词典。 “:”也是一个词。现在解释一下文本解释程序对它的处理。如在: : STAR 42 EMIT ;<CR> 中出现了“:”冒号,这时: ①文本解释程序在输入流中发现了冒号,则把它指给“EXECUTE”,“EXECUTE”则说"请开始编译"; ②编译程序便把该定义翻译成词典形式并写入词典; ③当编译程序遇到分号时则停止编译; ④返回到文本解释程序,给出信息 OK。 四、如何命名 在 FORTH 中,一个词就是具有定义的一个字符或一组字符。几乎所有的字符都能用来命名词。只有少数几个字符串不能用来命名: return:回车符<CR>,因为计算机认为你已完成了输入; backspace:删除符<BS>,因为计算机认为你试图修改键入错误; space:空格“ ”,因为计算机把它作为一个词的结束; caret(↑或^):脱机符<ESC>;因为编辑程序(如果你正在使用的话)用之表示其它功能。 下面就是由两个标点符号组成的 FORTH 词名,它是“ .” ” ,只由小数点-双引号“dot-quote”组成。你能把它用于定义内部去打印一文本"串"。例如: : GREET ." Hello, I speak Forth " ;<CR>OK 这样我们就定义了一个名为 GREET 的词,它的定义仅由一个 FORTH 词 “ .” ”组成,“ .” ” 后面跟随的是要打印的文本。文本后面的引号将不打印,它只是表明文本的结束,称为"分界符"。在定义的结尾别忘了结束符 “;”分号。 执行 GREET 其结果如下: GREET<CR> Hello, I speakForth OK 注:对应学习C语言的第一个程序“你好,世界!”,FORTH程序是这样的: : HELLO CR .” Hello, World! “ ;<CR> 注:如果FORTH和计算机终端都支持中文,那么中文程序是这样的: : 你好 CR .” 你好,世界! “ ;<CR>
|