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。
那是怎么回事?
答案 0 :(得分:5)
让我在这里回答,因为问题发生了很大变化。我仍然不确定我理解这个问题,但是:)
在您的示例中,您定义
: 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
如果您还有其他问题,可以参考这些测试。
答案 1 :(得分:1)
您引用的代码段执行以下操作:
IFFLOORED
中存储-1(真),因此在评估时,它会将此值放在堆栈上。 (这是LITERAL
的效果。)IFFLOORED
时,在推送堆栈上的值后,会出现IF
- THEN
表达式。当值为true时,意味着我们不在一个内置环境中,所以我们想要注释掉该行的其余部分,这就是\
所做的。所以这里有一个棘手的部分 - \
是IMMEDIATE
,即你不能在冒号定义中使用它,因为它将注释掉行的其余部分。您必须明确告诉编译器您要编译此函数,而不是执行它,这是POSTPONE
所做的。