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

Dav*_*ven 5 user-interface forth

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

: IFFLOORED [ -3 2 / -2 = INVERT ] LITERAL IF POSTPONE \ THEN ;
Run Code Online (Sandbox Code Playgroud)

然后根据我们是使用浮动还是对称除法,将其用于有条件地定义各种单词:

IFFLOORED : T/MOD  >R S>D R> FM/MOD ;
Run Code Online (Sandbox Code Playgroud)

因此,IFFLOORED无论是noop还是\取决于表达式的结果.精细.通过这样做,我可以在我的线程解释器上轻松实现:

: POSTPONE ' , ; IMMEDIATE
Run Code Online (Sandbox Code Playgroud)

......现在IFFLOORED有效; 定义相当于: IFFLOORED -1 IF ['] \ EXECUTE THEN ;.

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

: GT1 123 ;
: GT4 POSTPONE GT1 ; IMMEDIATE
: GT5 GT4 ;
\ assertion here that the stack is empty
Run Code Online (Sandbox Code Playgroud)

相同的实现在这里不起作用.如果POSTPONE编译其字的引用,则GT4成为相当于: GT4 123 ;......但GT4就是眼前.因此,当GT5定义时,123被推入编译器的堆栈并GT5变成noop.但那不对; 测试套件期望调用GT5在堆栈上留下123.因此要使其工作,POSTPONE必须生成生成代码的代码:

: POSTPONE  ' LITERAL  ['] , LITERAL ;
Run Code Online (Sandbox Code Playgroud)

事实上,如果我玩gForth,我看到POSTPONE实际上是这样的:

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

<long number> compile, ;
Run Code Online (Sandbox Code Playgroud)

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

......但两个测试都通过gForth.

发生什么了?

vuk*_*ung 5

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

在您的示例中,您定义

: GT4 POSTPONE GT1 ; IMMEDIATE
Run Code Online (Sandbox Code Playgroud)

这里发生了什么,如下:

  1. :执行,阅读GT4和创建新单词
  2. POSTPONEGT1正如你在GForth中看到的那样,执行编译语义,即编译编译语义.
  3. ; 执行,结束定义
  4. IMMEDIATE 执行,将最后定义的单词标记为立即.

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

顺便说一句,根据标准,POSTPONE只有编译语义,并且解释语义是未定义的.

另请参阅GForth手册中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
Run Code Online (Sandbox Code Playgroud)

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

  • 哦,它看起来看看它是一个什么样的词!这完全有道理(一旦我完成了实现,它甚至可以工作)。谢谢! (3认同)
  • `POSTPONE`总是编译单词的编译语义.在"GT1"的情况下,它的编译语义是将编译调用到"GT1".在\ _是一个`IMMEDIATE`字的情况下,它的编译语义是将该行的其余部分视为注释.所以,基本上,`POSTPONE`会推迟下一个单词的执行 - 如果是立即执行,那么它会编译一个简单的调用; 如果它是一个简单的调用,那么它编译代码来编译它. (2认同)

vuk*_*ung 1

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

  1. 评估-3/2(在编译时),并检查它是否为-2。
  2. 如果是,则在 中 存储 0(假),否则存储 -1(真)IFFLOORED,因此在计算时,会将这个值放入堆栈中。(这是效果LITERAL。)
  3. 计算 时IFFLOORED,将值压入堆栈后,会出现一个IF-THEN表达式。当该值为 true 时,意味着我们不在地板环境中,因此我们想注释掉该行的其余部分,这就是所做的\

因此,棘手的部分来了 -\IMMEDIATE,您不能在冒号定义中使用它,因为它会注释掉该行的其余部分。你必须明确地告诉编译器你想要编译这个函数,而不是执行它,这就是它的作用POSTPONE