John Heyes的ANS Forth测试套件包含以下定义:

: IFFLOORED [ -3 2 / -2 = INVERT ] LITERAL IF POSTPONE \ THEN ;


然后根据我们使用的是底数分割还是对称分割,使用它有条件地定义各种单词:

IFFLOORED : T/MOD  >R S>D R> FM/MOD ;


因此,根据表达式的结果,IFFLOORED的作用类似于noop或\。精细。这样做很容易在我的线程解释器上实现:

: POSTPONE ' , ; IMMEDIATE


...现在IFFLOORED起作用了;该定义等同于: IFFLOORED -1 IF ['] \ EXECUTE THEN ;

不幸的是,在测试套件的最下方是以下代码:

: GT1 123 ;
: GT4 POSTPONE GT1 ; IMMEDIATE
: GT5 GT4 ;
\ assertion here that the stack is empty


相同的实现在这里行不通。如果POSTPONE编译对单词的引用,则GT4等同于: GT4 123 ; ...,但是GT4是立即的。因此,当定义了GT5时,会将123压入编译器的堆栈,并且GT5变为noop。但这是不对的。测试套件期望调用GT5将123保留在堆栈中。因此,要使其正常工作,POSTPONE必须生成代码,该代码将生成代码:

: POSTPONE  ' LITERAL  ['] , LITERAL ;


而且,的确,如果我使用gForth,我会看到POSTPONE实际上是这样的:

: GT1 123 ;
: GT4 POSTPONE GT1 ; IMMEDIATE
SEE GT4

<long number> compile, ;


但是这两个定义不兼容。如果使用第二个定义,则第一个测试将失败(因为现在IFFLOORED尝试编译\而不是执行它)。如果使用第一个定义,则第二个测试将失败(因为GT4推送到编译器堆栈而不是编译文字推送)。

...但是两个测试都通过了gForth。

发生什么了?

最佳答案

让我在这里回答,因为问题发生了很大的变化。不过,我仍然不确定我是否理解这个问题:)

在您的示例中,您定义

: GT4 POSTPONE GT1 ; IMMEDIATE


在这里发生的是以下情况:


:被执行,读取GT4并创建新单词
执行POSTPONE的编译语义,即编译GT1的编译语义-正如您在GForth中所看到的。
;被执行,结束定义
IMMEDIATE被执行,将最后定义的单词标记为立即。


POSTPONE仅在编译GT4时被调用,并且不会出现在已编译的代码中。因此,当以后在GT5的定义中使用此直接词时,不需要POSTPONE的解释语义。

顺便说一下,根据the standardPOSTPONE仅具有编译语义,而解释语义是未定义的。

另请参见GForth manual中的POSTPONE教程。

编辑解释和编译语义的示例:

: TEST1 ." interpretation" ;  => ok
: TEST2 ." compilation" ; IMMEDIATE  => ok
: TEST3 TEST1 TEST2 ;  => compilation ok
TEST3  => interpretation ok
: TEST4 POSTPONE TEST1 ; IMMEDIATE  => ok
: TEST5 TEST4 ;  => ok
TEST5  => interpretation ok
: TEST6 POSTPONE TEST2 ; IMMEDIATE  => ok
TEST6  => compilation ok


如果您还有其他问题,可以参考这些测试。

08-27 05:48