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 standard,
POSTPONE
仅具有编译语义,而解释语义是未定义的。另请参见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
如果您还有其他问题,可以参考这些测试。