User interface 第四:推迟——它是如何工作的?
John Heyes的第四套测试套件包含以下定义:User interface 第四:推迟——它是如何工作的?,user-interface,forth,User Interface,Forth,John Heyes的第四套测试套件包含以下定义: : IFFLOORED [ -3 2 / -2 = INVERT ] LITERAL IF POSTPONE \ THEN ; 然后,根据我们使用的是floored还是对称除法,它被用于有条件地定义各种单词: IFFLOORED : T/MOD >R S>D R> FM/MOD ; 因此,ifflored的作用类似于noop或\,具体取决于表达式的结果。好的通过执行以下操作,可以在我的线程解释器上轻松实现: : POST
: IFFLOORED [ -3 2 / -2 = INVERT ] LITERAL IF POSTPONE \ THEN ;
然后,根据我们使用的是floored还是对称除法,它被用于有条件地定义各种单词:
IFFLOORED : T/MOD >R S>D R> FM/MOD ;
因此,ifflored
的作用类似于noop或\
,具体取决于表达式的结果。好的通过执行以下操作,可以在我的线程解释器上轻松实现:
: POSTPONE ' , ; IMMEDIATE
…现在,ifflored
工作了;该定义相当于:ifflored-1 IF[']\EXECUTE THEN代码>
不幸的是,测试套件的下面是以下代码:
: GT1 123 ;
: GT4 POSTPONE GT1 ; IMMEDIATE
: GT5 GT4 ;
\ assertion here that the stack is empty
同样的实现在这里不起作用。如果delay
编译了对其单词的引用,那么GT4
就相当于:GT4 123代码>。。。但是GT4是即时的。因此,当定义GT5
时,123被推到编译器堆栈上,GT5
成为noop。但这是不对的;测试套件期望调用GT5
将123留在堆栈上。因此,要使其工作,delay
必须生成生成代码的代码:
: POSTPONE ' LITERAL ['] , LITERAL ;
事实上,如果我玩gForth,我会发现delay
实际上是这样工作的:
: GT1 123 ;
: GT4 POSTPONE GT1 ; IMMEDIATE
SEE GT4
<long number> compile, ;
:GT1 123;
:GT4推迟GT1;立即的
见GT4
编译;
但这两个定义并不兼容。如果使用第二个定义,第一个测试将失败(因为现在ifflored
尝试编译\
,而不是执行它)。如果使用第一个定义,第二个测试将失败(因为GT4
将推送到编译器堆栈上,而不是编译文本推送)
…但这两项测试都通过了
发生了什么事?您引用的代码片段做了以下事情:
计算-3/2(在编译时),并检查它是否为-2
如果是,则存储一个0(false),否则将-1(true)存储在ifflored
中,因此在对其求值时,它会将该值放在堆栈上。(这是LITERAL
的效果)
计算IFFLOORED
时,在堆栈上按下值后,会出现IF
-然后表达式。当该值为true时,意味着我们不在一个铺满地板的环境中,因此我们希望注释掉该行的其余部分,这就是\
所做的
所以这里有一个棘手的部分-\
是立即的
,也就是说,您不能在冒号定义中使用它,因为它会注释掉行的其余部分。您必须明确地告诉编译器您想要编译这个函数,而不是执行它,这就是推迟所做的。让我在这里回答,因为问题发生了很大的变化。不过,我仍然不确定我是否理解这个问题:)
在您的示例中,您定义了
: GT4 POSTPONE GT1 ; IMMEDIATE
这里发生的情况如下:
执行:
,读取GT4
并创建新词
执行delay
的编译语义,即编译GT1
的编译语义,如您在GForth中所看到的
执行代码>,结束定义
执行IMMEDIATE
,将最后定义的单词标记为IMMEDIATE
只有在编译GT4
时才调用delay
,它不会出现在编译后的代码中。因此,当以后在GT5
的定义中使用这个直接词时,不需要delay
的解释语义
顺便说一下,根据,delay
只有编译语义,而解释语义是未定义的
另请参见中的推迟
教程
编辑解释和编译语义示例:
: 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
如果您还有任何问题,您可以参考这些测试。很抱歉,您完全错过了我问题的重点---我理解iFloored
的工作原理;这是我感到困惑的事。我更新了这个问题,希望能让它更清楚我想知道什么。是的,我都知道!我不明白的是delay
在这种情况下和ifflored
情况下是如何工作的GT4
最终成为一个单词,当调用它时,编译对GT1
的调用。但是ifflored
最终成为一个单词,当被调用时,它执行对\的调用。delay
如何同时做到这两个呢?delay
总是编译单词的编译语义。在GT1
的情况下,它的编译语义是编译对GT1
的调用。而在\的情况下,作为一个立即
单词,它的编译语义是将行的其余部分视为注释。因此,本质上,delay
延迟下一个单词的执行-如果它是立即的,那么它编译一个对它的简单调用;如果它是一个简单的调用,那么它会编译代码来编译它。哦,它会看看它是什么类型的单词!这完全有道理(一旦我完成了实现,它甚至可以工作)。谢谢