本文是有关可编程计算器的eForth系列文章的结尾。 从这里开始 。输入语言“ Electronics MK-161”的命令仅占据文件eForth0.mkl的一半。 后半部分由表占据,表的开发与编写转换器的算法部分一样困难。 让我们尝试找出如何使用这些表。

Wirth教授教导说,“以小规模编程”包括开发两个同等重要的组成部分-算法和数据结构。
我们已经遇到了一个eForth数据结构。 这是位于字节存储器中的VCA(高级字)的主体。 四个处理程序以不同的方式解释“他们自己的” VCA的参数字段:
.DB DOVAR ; .DB … ; .DB DOCON ; .DW _ ; .DB DOCONM ; .DW _ ; .DB DOLST ; .DW 1, 2,… EXITT ;
以下相对简单的数据结构与TYPE“标准消息”相关联。
所有eForth消息均已编号并传输到廉价程序存储器中。 如果单词TYPE打印单个字母,则其代码可以是此类消息的编号,范围是0到7。
; TYPE .BASE tblTYPE: .DBB str7,str6, str5, str4, str3, str2, str1, str0
在扩展的MK语言中,.BASE伪命令为.DBB命令设置“基础”,该命令按顺序将str7,str6等的行偏移量放置在字节中。 相对于基本标签tblTYPE。 将0到7的数字添加到表地址,可以从中读取此偏移量。 将找到的偏移量添加到tblTYPE,我们得到所需行的地址。
字符串的第一个字节包含其长度。 eForth广泛使用了这种
计数线 。
我们还遇到了tblTokens表,该表列出了所有208个嵌入式单词的代码地址。 如果单词不是原始单词,则该表包含0。转到地址0将导致eForth重启并发出吱吱声。
还提到了表tblNames,指的是相同的208个单词的名称。 这些以计数线形式的名称存储在相同的“橡胶”程序存储器中。 当eForth运行时,tblNames表本身将不可用,但是其中包含的信息将不会丢失。 在编译时,eForth.f会将名称的地址传输到存储在十进制内存中的更方便的数据结构(请参见2)。
我还谈到了tblCHPUT,这是在计算器屏幕上显示字母时的控制代码关联表。 从tblKeyNum到tblKeyRusF的另外七个表将在不同键盘模式下按下的按钮的代码转换为8位字母代码。 负责活动键盘模式的子例程的地址在十进制寄存器ptrKbdInt中。
总体而言,eForth0.mkl文件中只有一个数据结构仍未汇编,这就是名称识别表。 让我们在主要课程结束后将它们留给甜点(请参阅5)-两个标题表存储在十进制内存中。 首先,我们将使用“填充”这些标题的工具武装自己。
1.使用标题:HEAD! 和HEAD @
HEAD! ( xt nfa r -- ) r, xt nfa. HEAD@ ( r -- xt nfa lex ) r, xt, nfa .
一个十进制寄存器MK-161可以存储12个小数位。 eForth使用该寄存器存储三个小数字,每个数字从0到9999。
用于存储这些数字的
三个“字段”分别称为A,B和C:AAAABBBBCCCC。 十进制符号仅指字段A。
HEAD @原语获取寄存器号,然后从那里将其拆分为字段,然后HEAD! 收集大量字段,并将结果“怪物”写入指定的寄存器。 但是有细微差别。
单词的“十进制标题”在字段A中包含其名字(nfa)的地址。 如果该地址为负,则名称存储在程序存储器中。 字段B包含单词令牌(xt)。 字段C称为词典。 它存储IMMEDIATE位和一个标志,该字仅用于编译。
HEAD @将标题拆分为多个部分。 堆栈的顶部是词典字段C,在其下方是名称字段A。通常在其中存储令牌的字段B位于最底部。
头! 重置字段C。
2.内联标题

208个内置单词(0到207)中每个单词的标题都从R44开始按顺序排列。 字段A始终包含一个负数,因为这些字的名称在程序存储器中进行了硬编码。
字段B和C是可编辑的。 因此,用户可以重新定义内置单词,并对其进行必要的立即更改(请参见4)。
3.用户标题

仅使用208个预定义名称可以节省字节存储空间,但异常无聊。 因此,我开发了另一个数据结构,其中选择名称的幻想仅限于32个字母。 此结构由32个
列表组成,每个
列表负责一定长度的用户单词。 这32个列表中的每一个都有一个个人标题。 列表本身跳过了十进制内存,但其标题始终存储在R301 ... R332中。
按名称长度对单词进行排序是161eForth的重要亮点。 当您按单词名称搜索单词时,排序会大大减少比较次数,从而加快了编译速度。 如果每个名称的长度已知,谁需要散列函数?
为简单起见,
列表的标题与单词的标题具有相同的结构,其中字段A,B和C相同。 这些字段的目的是不同的。 字段A包含列表中第一个寄存器的编号。 字段B包含提供给列表的寄存器数。 字段C存储其标题已经在列表中的单词数。
在工作开始时,字段C等于零;所有列表中都没有单词。 字段B为2,每个列表都从几个寄存器开始。 字段A表示从R333开始的2个寄存器的块。
每个列表包含单词的标题。 我们已经拆解了它们(请参阅第1节)。 在这里,名称(nfa)的地址可能为正,并指向计数线,该计数线通常存储在VCA主体的前面。 同样,字段B中的令牌是此名称后立即进入二进制存储器的代码字段(cfa)的地址。 有一个例外-
如果单词已经确定,则字段A将指向旧名称。 为什么要再次存储字符串? 二进制内存很昂贵。
当列表中的所有寄存器都已满(B = C)时,单词PUBLISH将提供另外5个空闲位置,将此数据结构推入正确的位置并调整列表标题中的链接(A)。
4.发布一个新词:WORK and PUBLISH
LAST ( -- a ) . WORK ( -- a ) . PUBLISH ( -- ) . $,n ( nfa -- ) , nfa. ?UNIQUE ( a -- a ) , .
事实证明,为MK-161开发的用于存储单词标题的数据结构实用且易于集成到eForth中。 当创建,常量或:创建一个新单词时,他们访问系统单词$,n以给定名称的单词创建标题。 $,n代表唯一性验证-我们创建一个新单词还是重新定义旧单词?
如果已经存在同名单词,UNIQUE会警告用户。 同时,在LAST系统变量中输入重新定义的标头的地址。 对于新单词,LAST被重置为零。
在任何情况下,$,n都会在WORK变量中建立一个新的标头-这是一个十进制寄存器,可以存储标头的12位。 如果未找到该名称,则该名称会包含在字典中的代码字段之前,就像86eForth和许多其他Forts中一样。
MK-161设法在没有“通讯字段”的情况下进行 ;这还节省了二进制内存。
PUBLISH原语完成单词的定义。 编译冒号时,从中调用PUBLISH;因此,不需要SMUDGE位。 复制WORK标头的位置由LAST变量确定。 如果LAST为零,则会在相应的列表中创建一个新的标头(请参见3)。 清单是否完整? 然后发布将向其中添加5个寄存器,其中四个用于将来。
运行PUBLISH后,LAST变量始终指向最后一个单词的标题。 这有助于通过更改词典字段来立即完成工作。
5.(FIND)和名称识别表
(FIND) ( a -- r T | a F ) r, a. FIND ( a -- a F | xt 1 | xt -1) . 1, IMMEDIATE.
原语(FIND)通过其名称来管理单词的搜索。 首先,他在具有先前已知名称的内置单词中搜索一个名称,然后检查具有所需名称长度的用户单词列表(请参阅3)。 名称识别表大大加快了这种“第一”的速度。 这是他们的工作方式。
在开头(FIND),它在tblLen数组中找到主关联表的地址,其中“准备”了所需长度的众所周知的名称。 在此表(FIND)中搜索名称的第一个字符。 在大多数情况下,这可以立即使您找到
所搜索单词的
标题寄存器号 -按首字母和长度。
碰巧几个相同长度的单词的首字母相同。 然后,而不是寄存器号(FIND),它偶然发现下一个关联表的地址(读取的号为300或更大),并且继续搜索第二个字母。 依此类推,直到找到该单词或确定没有该单词。
当然,在匹配第一个字母(FIND)之后,将验证整个名称。 但是,
识别表使eForth变得很快 。 今年春天,我在这些网站上投入了大量时间,现在它们节省了搜索时间。 其中的“键”甚至按字母顺序排序。 对不起,MK-161固件随地吐痰。
为了兼容起见,我实现了Fort ANS [4]中的FIND一词,该词信任“黑工作”原语(FIND)。 已经考虑过这个词吗?UNIQUE也正在通过(FIND)寻找其论点。
6.外部口译员
书籍[1]包含eForth的详尽描述,包括一个外部“文本”解释器。 是他以Fort语言执行或编译源文本的人。 在过去几十年中,已经出现了与其他Fort方言的文字解释器不同的观点[2],[3],但其中很少。
下面是从[1]中摘录的文本解释器的框图。 注意-此“解释器”具有编译模式! $ COMPILE一词负责将Forte文本编译为“缝制代码”,我们在第一篇文章中对此进行了详细介绍。 当执行$ INTERPRET时,输入的单词将立即执行-解释模式。 EVAL“计算”输入的整个字符串,为每个输入的单词调用这两个单词之一。

方框图之后,作者解密哪个方框。 这是她的翻译。 块名称通常与eForth单词名称匹配。 NAME这个词? 在我的实现中不存在,它已成功地由快速(FIND)替代(请参见5)。
本书还提供Windows版本中每个eForth单词的源代码,并带有简要说明。 我已经告诉过您MK-161的版本不同。 我的实现的源代码在存档中:
the-hacker.ru/2019/161eforth0.5b.zip最后,我将提到
MK-161语言中的单词
(PARSE)的实现-在Windows下是VCA。 调试花费了一周的时间,但它
使编译速度提高了一半 。 单词(PARSE)完成PARSE的所有“肮脏工作”,以将单个单词与输入文本流隔离。
除了通常的QUIT周期外,我对外部解释器的补充是两个词:已经提到的TLOAD并取自FILE的旧版本。 FILE一词将I / O转换为控制台,但从RS-232端口读取行以进行解释。 成功处理完每一行后,端口上将输出代码11的字母,从计算机下载的文件应以QUIT结束。
我还没有调试FILE这个词。 如果有人需要,请分享您的印象。
紧要关头的161eForth审查已经结束,但是Fort是一个非常灵活的工具,每个所有者都可以自定义。 即使您彻底弄清了一切,星球上某个地方的人也会想出另一个使您感到惊讶的技巧。
这是作者[1]的eForth的最后一句话:
26年来,我已经多次重写eForth。 在每个配音中,我都尝试使其更简单明了。 现在在86eForth v5.2中,我认为我已经达到了正确性,因此非常高兴。
正如爱因斯坦所说:
一切都应尽可能简单,但不要简单。
使86eForth v5.2更加容易,也许破坏了它或作为编程工具没有用。
文学作品
- 博士 丁陈汉森。 eForth和Zen-第3版,2017年。在Amazon Kindle上可用。
- Baranov S.N.,Nozdrunov N.R. Fort语言及其实现。 -L。:机械工程。 列宁格勒 系,1988。
- Semenov Yu.A. 用FORT语言编程。 -M .:无线电和通讯,1991年。
- ANS Forth标准。 X3.215-1994。 笔译
- SP-Forth文档 。
- Offete Enterprises(丁辰汉博士)是86eForth v5.2的作者,使用英语。
- Mikhail Pukhov用“ Moonwalker-1”程序编写的“ True Truth”的故事 ,在那里我得到了KDPV并热爱苏联计算器。