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.
发生什么了?
让我在这里回答,因为问题发生了很大变化.我仍然不确定我理解这个问题,但:)
在您的示例中,您定义
: GT4 POSTPONE GT1 ; IMMEDIATE
Run Code Online (Sandbox Code Playgroud)
这里发生了什么,如下:
:执行,阅读GT4和创建新单词POSTPONEGT1正如你在GForth中看到的那样,执行编译语义,即编译编译语义.; 执行,结束定义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)
如果您还有其他问题,可以参考这些测试.
您引用的代码片段执行以下操作:
IFFLOORED,因此在计算时,会将这个值放入堆栈中。(这是效果LITERAL。)IFFLOORED,将值压入堆栈后,会出现一个IF-THEN表达式。当该值为 true 时,意味着我们不在地板环境中,因此我们想注释掉该行的其余部分,这就是所做的\。因此,棘手的部分来了 -\即IMMEDIATE,您不能在冒号定义中使用它,因为它会注释掉该行的其余部分。你必须明确地告诉编译器你想要编译这个函数,而不是执行它,这就是它的作用POSTPONE。