Forth入门(03):冒号定义,搭建FORTH高楼大厦的基本方法
—、一种有生命力的语言假设你是一位办公室管理人员并且刚刚雇用了一位热心的新助手。第一天你教给这位助手打印图件的正确格式(假定这位助手已掌握打字技术)。在当天结束时,你只需说"请打印这个"。第二天你对他讲解档案制度。你花了二上午时间来解释如何归档,下午你就只需说"请把这个归档"。到了周末你便可以用一种简记的形式同助手交谈了。"请发出这封信",意思包含"打印它,让我签发,照相复制,附本归档,邮寄原件"。这样,你和你的助手就能更愉快更有效地自由执行你的商业事务了。良好的组织和有效的通讯要求你:①对有用的任务加以定义并对它们命名;②把各个相关的任务组合成一些较大的任务,并给它们相应命名等等。FORTH 正是按上述方法(除了你不必说"请"之外)让你来组织你自己的过程并和计算机建立联系。 作为一个例子,我们设想用 FORTH 编程来控制一台由微机控制的洗衣机。在该例中主要命令被命名为 WASHER。下面是用 FORTH 书写的 WASHER 的定义::WASHER WASHSPIN RINSESPIN;在 FORTH 中,冒号表示一个新定义的开始。冒号后的第一个词 WASHER 是新过程的名称。其余的词 WASH、SPIN、RINSE 和 SPIN 组成该新过程的定义。最后的分号表示定义结束。组成 WASHER 定义的每一个词都必须是在洗衣机控制程序中已被定义过的词。例如,察看定义 RINSE::RINSE FILLAGITATEDRAIN ;可以看到它是由词 FILL、AGITATE 和 DRAIN 组成的。而且这些词又应是本例中其它地方已定义过的词。例如可以查到 FILL 的定义::FILL FAUCETSOPENTILL-FULLFAUCETSCLOSE ;在这个定义中,我们既涉及了对象(faucts、水龙头)又涉及了动作(open 和 close、开和关)。而且定义了词 TILL-FULL 去建立一个"延迟循环",它指示当从到达水平面时开关已被启动的时间,没有其它动作。如果我们顺着这些定义察看下去,最终将会发现它们都是由一组非常有用的、组成全部FORTH系统的基本命令定义的。在 PolyFORTH 中大约包含 300 条基本命令。这些命令中的许多命令本身也是由如同本例中的"冒号定义"所定义的,另一部分由特定机器的机器语言直接定义。在 FORTH 中,一条已定义的命令称为一个"词"。用其它词定义一个词的能力称为"扩展性"。这种扩展性导致了一种非常简单、结构天然严谨、功能无限扩展的程度设计格式。无论你的程序是流水运行,还是获取科学计算、商业管理或游戏中的数据,你都可以根据特定需要建立你自己的"有生命力的语言"——各种词。 二、人机会话FORTH 有许多独有的特点,其中之一就是简单地呼叫一个词的名字便可以执行它。若在终端键盘上操作,只要键入词的名字再按 RETURN 键即可。自然也可以在其它的定义中放入该词的名字,再由其它词来使用它。由于只要键入一命令,机器便可执行该命令,所以 FORTH 被称为"会话式"语言。首先我们给出一个你能亲自试验的例子,并显示出把一些简单的命令组合成一些功能极强的命令的步骤。在此我们将使用一些控制终端屏幕或打印机的简单 FORTH 词。现在让我们熟悉一下通过终端键盘与 FORTH "交谈"的技巧。请坐在你实际的或假想的终端前面。我们将假定你已请求别人为你装备了使用 FORTH 的所有软硬件,或者你了解如何装备。现在请按下键:RETURN这时计算机将回答: OKRETURN 键是你用来使 FORTH 知道你的请求的信息。OK 是 FORTH 回答它已完成你的请求而且没有出错的信息。在上面的情况下,你要求 FORTH 不进行任何工作,所以它遵从你的请求不做任何事情,只是回答 OK。(OK可能是大写字母,也可能是小写字母,这取决于你的终端)。现在键入:15SPACES如果你在键入过程中发生错误,可以按"backspace"键进行修改。方法是使光标回到发生错误的位置,重新键入正确的字符,然后继续。在一行键入正确后再按 RETURN 键。(一旦按下 RETURN 键后就无法再对本行进行修改了)。注:1)有的FORTH书刊称为"字"。为了不与存疑的"字长"相混淆,我们译为"词"(word),而且在本书中我们把内容中的一个字(18bit)称为一个"单元"(cell)。在本节中,我们利用符号 <CR> 来表明你必须按 RETURN 键的地方。例如:15SPACES <CR> OK当你按下 RETURN 键时,FORTH 随后打印出 15 个空格,再回打 OK,表示已处理了你的要求。现在键入:42EMIT <CR> *OK短语"42EMIT"告诉 FORTH 打印一个"*"号,因此 FORTH 打印出一个星号后再回答 OK。我们可以在同一行中键入多个命令,例如:15SPACES42EMIT 42EMIT<CR> * OK这时,FORTH 打印出 15 个空格和两个星号。请注意:对于键入的词或数,可以用任意多个空格分开。但是要使 FORTH 能把它们当作词或者是数来识别,至少要用一个空格分开。如果我们要多次使用短语:42EMIT我们可以把它定义为一个词"STAR"::STAR 42EMIT;<CR> OK其中"STAR"是名字,"42EMIT"是定义。请注意,必须把冒号和分号与邻近的词用空格隔开。另外,为了使 FORTH 定义易于为人们阅读,我们习惯于把定义的名字和内容用二个空格分开。当你已经键入上述定义并按了 RETURN 键后,FORTH 回答 OK,这表明 FORTH 已认可该定义并将记住它。现在键入:STAR <CR>* OKFORTH 便执行你的定义而打印一个星号。象 STAR 这样你自己定义的词和象“EMIT”这样系统中已定义的词之间并没有什么区别。下面介绍另一个系统定义的词“CR”,它在你的终端上执行换行。例如:CR <CR>OKFORTH 则先执行回车换行,再打印OK(在下一行)。如果你的FORTH系统中没有这个词,你可以自己立即定义它::CR13EMIT10 EMIT;现在请试试:CRSTARCR STARCRSTAR<CR>*** OK然后请把 CR放在定义中,如:
:MARGINCR30SPACES;<CR>OK现在我们就能键入: MARGINSTARMARGINSTARMARGIN STAR<CR>它将在离左边30个空格的竖线上打印3个星号。为了下面的需要我们把MARGINSTAR组合起来定义成一个词: :BLIP MARGINSTAR;<CR>OK 我们还需要定义在水平分析打印多个星号的词(我们将在后面解释它是如何工作的): :STARS 0DO STARLOOP;<CR>OK现在我们可以键入: 5STARS<CR>***** OK 或者 15STARS<CR>***********************************OK 或者要求打印任意多个星号。我们还需要定义一个词,它先执行MARGIN,然后再打印5个星号: :BARMARGIN5STARS; <CR>OK 现在我们可以键入: BARBLIP BARBLIPBLIPCR<CR>并得到一个由星星组成字母“F”(代表Forth),它应该是这样的:: ***** * ***** * * 最后一个步是把这个新的过程定义成词,称此词为“F”。:FBARBLIPBAR BLIPBLIPCR; <CR>OK通过上面的例子,你已经了解到简单的Forth命令可以成为更复杂的命名基础。当列表显示一个Forth应用程序时,我们可以看到它是由一系列功能逐步增长的定义组成,而不是由一个个依次执行的指令系列组成。 作为一个Forth应用的实际程序,我们把前面的实验应用程序列表如下(开头的数字是行号,第0行是注释行,FORTH用括号括起要注释的内容):0(LARGE LETTER F )1:STAR42EMIT ;2:STARS 0DOSTAR LOOP;3:MARGINCR30SPACES ;4:BLIPMARGINSTAR;5:BARMARGIN5STAR;6:FBARBLIPBAR BLIPBLIPCR; 三、词 典 FORTH 的每个词和它的定义都被登记在 FORTH 词典中。机器启动时,词典中已包含了许多词,这时,你自己定义的词也可以登记进词典。当你定义一个新词时,FORTH 便把你的定义翻译成词典形式写入词典条目。这个过程称为"编译"。例如,当你键入一行::STAR 42EMIT;<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 42EMIT ;<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 speakForthOK 注:对应学习C语言的第一个程序“你好,世界!”,FORTH程序是这样的::HELLOCR.”Hello, World!“;<CR>注:如果FORTH和计算机终端都支持中文,那么中文程序是这样的::你好 CR .” 你好,世界! “;<CR>
Forth语言以其简洁、灵活和高效著称,其核心设计理念之一便是通过“冒号定义”来构建程序。这种机制不仅赋予了Forth极高的模块化和可扩展性,还使其成为一种极具生命力的编程语言。本文将深入探讨Forth中的冒号定义机制,并通过实例分析其在实际应用中的优势。
冒号定义的基本概念
在Forth中,冒号定义(Colon Definition)是构建程序的基本方法。冒号(:)用于定义一个新词(Word),这个词可以是Forth中的任何操作或功能。定义结束时使用分号(;)表示。这种机制允许程序员将复杂的任务分解为一系列简单的步骤,并将这些步骤组合成更高层次的功能。
例如,假设我们需要编写一个程序来控制一台洗衣机。我们可以通过冒号定义来实现这一功能:
forth
: WASHER WASH SPIN RINSE SPIN ;
在这个例子中,WASHER是一个新定义的词,它由WASH、SPIN、RINSE和SPIN组成。每个组成词都必须在程序中事先定义过。这种层次化的定义方式使得程序结构清晰,易于维护和扩展。
冒号定义的层次化结构
冒号定义的强大之处在于其层次化结构。每个定义的词可以进一步分解为更基础的词,直到最底层的操作。例如,RINSE可以定义为:
forth
: RINSE FILL AGITATE DRAIN ;
而FILL又可以定义为:
forth
: FILL FAUCETS OPEN TILL-FULL FAUCETS CLOSE ;
通过这种层层分解的方式,程序员可以将复杂的任务逐步简化为一系列简单的操作。这不仅提高了代码的可读性,还使得程序的调试和维护变得更加容易。
冒号定义的实际应用
冒号定义在实际应用中具有广泛的适用性。以办公室管理为例,假设你是一位办公室管理人员,刚刚雇用了一位新助手。你可以通过冒号定义的方式,将日常任务分解为一系列简单的操作,并为每个操作命名。例如:
forth
: PRINT-DOCUMENT FORMAT PRINT ;
: FILE-DOCUMENT ARCHIVE STORE ;
: SEND-LETTER PRINT-DOCUMENT SIGN COPY FILE-DOCUMENT MAIL ;
在这个例子中,PRINT-DOCUMENT、FILE-DOCUMENT和SEND-LETTER分别代表打印文件、归档文件和发送信件。通过这种定义方式,你可以用简洁的指令来执行复杂的任务,从而提高工作效率。
冒号定义的优势
1. 模块化:冒号定义使得程序可以被分解为多个独立的模块,每个模块负责一个特定的功能。这种模块化设计使得程序结构清晰,易于理解和维护。
2. 可扩展性:通过冒号定义,程序员可以轻松地扩展程序的功能。只需定义新的词,并将其组合到现有的程序中,即可实现功能的扩展。
3. 高效性:Forth语言的解释器直接执行冒号定义,无需额外的编译步骤。这种直接执行的方式使得Forth程序具有极高的执行效率。
4. 灵活性:冒号定义允许程序员根据需要灵活地组合和重用代码。这种灵活性使得Forth语言在处理复杂任务时表现出色。
结论
Forth语言中的冒号定义机制是其核心设计理念之一,通过这种机制,程序员可以将复杂的任务分解为一系列简单的操作,并将这些操作组合成更高层次的功能。这种层次化、模块化的设计方式使得Forth程序具有极高的可读性、可维护性和可扩展性。无论是控制洗衣机还是管理办公室事务,冒号定义都能提供一种简洁、高效的解决方案。因此,掌握冒号定义是学习和使用Forth语言的关键步骤。
[本文内容由国芯人工智能辅助生成,仅供参考] 能做一期中文的视频培训课程吗
页:
[1]