第四名:POSTPONE ---它是如何运作的?

时间:2015-07-26 12:25:55

标签: user-interface forth

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。

那是怎么回事?

2 个答案:

答案 0 :(得分:5)

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

在您的示例中,您定义

: GT4 POSTPONE GT1 ; IMMEDIATE

这里发生的事情如下:

    执行
  1. :,阅读GT4并创建新词
  2. POSTPONE执行编译语义,即编译GT1的编译语义 - 正如您在GForth中看到的那样。
  3. 执行
  4. ;,结束定义
  5. 执行
  6. IMMEDIATE,将最后定义的单词标记为立即。
  7. 仅当编译 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
    

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

答案 1 :(得分:1)

您引用的代码段执行以下操作:

  1. 评估-3/2(在编译时),并检查它是否为-2。
  2. 如果是,则存储0(假),否则在 IFFLOORED中存储-1(真),因此在评估时,它会将此值放在堆栈上。 (这是LITERAL的效果。)
  3. 评估IFFLOORED时,在推送堆栈上的值后,会出现IF - THEN表达式。当值为true时,意味着我们在一个内置环境中,所以我们想要注释掉该行的其余部分,这就是\所做的。
  4. 所以这里有一个棘手的部分 - \IMMEDIATE,即你不能在冒号定义中使用它,因为它将注释掉行的其余部分。您必须明确告诉编译器您要编译此函数,而不是执行它,这是POSTPONE所做的。