body, table{font-family: 微软雅黑; font-size: 13.5pt}
table{border-collapse: collapse; border: solid gray; border-width: 2px 0 2px 0;}
th{border: 1px solid gray; padding: 4px; background-color: #DDD;}
td{border: 1px solid gray; padding: 4px;}
tr:nth-child(2n){background-color: #f8f8f8;}
地址解释程序是一些 CODE 词,计算机类型不同,这些 CODE 词也不同,故地址解释程序又往往称为内部解释程序。相应地,又把文本解释程序称为外部解释程序。
IP 解释指针 W 现行词指针 。 IP 通常指着在一个冒号定义中的下一个要被执行的词,而 W 则指着当前要执行的词(W 的内容为当前要执行的词的 cfa);
地址解释程序:【
在文本解释程序中通过 EXECUTE 调用内部解释程序。EXECUTE 初始化地址解释程序,它接过留在堆栈上的代码指针域地址 cfa ,然后间接转移执行由此地址所指的子程序。
CODE EXECUTE ( cfa - ) 执行编译地址(即 cfa )在参数栈顶的定义 W POP 把在堆栈上的 cfa 送入到现行词指针 W 中 0 [W] JMP 经由 W 进行一次间接转移 END-CODE |
内部解释程序由定义 NEXT、NEST 及 UNNEST所构成。他们是由主机的汇编语言或宏汇编语言编写的。
NEXT 是一个 CODE 词。执行 NEXT 就是执行由 IP 所指着的下一个词。在执行 NEXT 中要做三件事: 1、((IP)) -> W 使 W 指着由 IP 当前内容所指着的词; 2、(IP)+2 -> IP 使 IP 的内容递增 2; 3、间接转移执行由 W 所指着的词; 解释指针 IP (有时又称为指令指针)的值由 NEXT 来设置和更新,所以每一个 CODE 词的最后都无例外地一定要执行 NEXT 。执行 NEXT 就去执行由 IP 所指的下一个 cfa 所代表的子程序,同时更新 IP 的值指向再下一个地址,一直重复直到执行完毕一个定义中的所有编译地址。 |
NEST 在执行 NEST 之前,IP 含有待返回的地址,而 W 含有要被调用的冒号定义的 cfa 。执行 NEST 要做四件事: 1、(IP) -> 返回栈顶(即保存好的 IP 原来的内容); 2、(W)+2 -> W 使 W 指向要被调用的定义的 pfa (即参数域地址); 3、(W) -> IP 把所要执行的词的地址送入 IP; 4、执行 NEXT。 NEST 在不同的 FORTH 系统中可能有不同的名字,如(NEST)、DO_COLON等。NEST 所代表的子程序是所有的冒号定义在一开始执行时都要首先执行的共同子程序。 |
UNNEST 是一个 CODE 词。它把返回栈顶的首项移入到解释指针中,结束一冒号定义的执行和返回到它的调用者。执行 UNNEST 时要做两件事: 1、把返回堆栈顶第一个单元的内容送入 IP 中; 2、执行 NEXT ; UNNEST 在不同的 FORTH 版本中也可能有不同的名字,比如 ;S 、EXIT 等。在词典中的每一个冒号定义的最后一个成分一定是 UNNEST ,它来源于冒号源定义中最后的分号。 |
冒号定义的执行过程:
eg:
: NOTHING ;
: STEP1 DUP OVER NOTHIN + + ; // 用词 ' 可以求出每个词的 cfa 地址;
NOTHING | ^nest | ^unnest(14B) | |
66DE | 66E0 ( lfa ) | 66E8 | 66EA ( pfa ) |
STEP1 | ^NEST | ^DUP(3C4) | ^OVER(3E4) | ^NOTHING(66E8) | ^+(582) | ^+(582) | ^UNNEST(14B) |
66F2 | 66F6 | 66F8 | 66FA | 66FC | 66FE | 6700 | 6702 |
当执行 DUP 时,(IP)=66FA指向OVER,DUP词本身的最后一个成分是NEXT,于是当执行DUP的NEXT时发生: 1、((IP)) -> W ,也即IP的内容的内容进入到 W 中,于是 (W)=3E4,它是词 OVER 的 cfa; 2、(IP)+2 -> IP,于是 (IP)=66FC,指向词NOTHING; 3、执行 W 所指的词,即执行 OVER 。OVER 是一个 CODE 词,它的 cfa 单元的内容就是它的 pfa ,于是就跳去执行其词身内的机器指令。 |
执行 OVER 的最后一个成分又是 NEXT,当执行此 NEXT 时发生: 1、((IP)) -> W,于是 (W) = 66E8,它是 NOTHING 的 cfa; 2、(IP)+2 -> IP,于是 (IP) = 66FE,它指着第一个 +; 3、执行 W 所指的词 NOTHING; |
NOTHING 是以冒号定义,所以它的 cfa 单元的内容是 NEST 的地址,于是就跳去执行 NEST,执行 NEST 时发生: 1、(IP) -> 返回堆栈栈顶,返回地址 66FE 就被保存在返回栈中。 2、(W)+2 -> W,(W)=66EA,它是 NOTHING 的 pfa。 3、(W) -> IP,(IP)=66EA,指着 NOTHING 内的 UNNEST。 4、执行 NEXT 1)、((IP)) -> W,(W)=14B,它是 UNNEST 的地址。 2)、(IP)+2 -> IP,(IP)=66EC,这个地址是分号后的一个地址,没有任何意义,后面执行UNNEST会被修改,直接丢弃 3)、执行W所指的词,也即执行UNNEST |
执行 UNNEST 时发生: 1、返回栈顶的内容 -> IP,于是(IP)=66FE,指着 STEP1 内的第一个 +; //每执行一次UNNEST,程序执行嵌套就减少一层,返回到原来的调用层中。 2、执行 NEXT 1)、((IP)) -> W,(W) = 582 2)、(IP)+2 -> IP,(IP) = 6700,指着 STEP1 中的第二个 +; 2)、执行由W所指的词,也即此时 STEP1 中的第一个 + 被执行。 //由于 + 是CODE词,它不会进入更深一层的嵌套。 |
……等执行完STEP1的UNNEST之后就返回到STEP1的调用者,也就是返回到外部解释程序INTERPRET,由于执行完STEP1后输入流耗尽,于是跳转到FORTH循环中的外循环 QUIT 。在显示屏上打印出“ok”后,FORTH 又等待使用者从键盘上输入下一行命令。 |