John Heyes' ANS Forth test suite contains the following definition:
: IFFLOORED [ -3 2 / -2 = INVERT ] LITERAL IF POSTPONE \ THEN ;
This is then used to conditionally define various words depending on whether we're using floored or symmetric division:
IFFLOORED : T/MOD >R S>D R> FM/MOD ;
So IFFLOORED
acts like either a noop or a \
depending on the result of the expression. Fine. That's easily implementable on my threaded interpreter by doing this:
: POSTPONE ' , ; IMMEDIATE
...and now IFFLOORED
works; the definition is equivalent to : IFFLOORED -1 IF ['] \ EXECUTE THEN ;
.
Unfortunately, further down the test suite is the following code:
: GT1 123 ;
: GT4 POSTPONE GT1 ; IMMEDIATE
: GT5 GT4 ;
\ assertion here that the stack is empty
The same implementation doesn't work here. If POSTPONE
compiles a reference to its word, then GT4
becomes the equivalent of : GT4 123 ;
... but GT4
is immediate. So when GT5
is defined, 123 is pushed onto the compiler's stack and GT5
becomes a noop. But that's not right; the test suite expects calling GT5
to leave 123 on the stack. So for this to work, POSTPONE
must generate code which generates code:
: POSTPONE ' LITERAL ['] , LITERAL ;
And, indeed, if I play with gForth, I see that POSTPONE
actually works like this:
: GT1 123 ;
: GT4 POSTPONE GT1 ; IMMEDIATE
SEE GT4
<long number> compile, ;
But these two definitions are not compatible. If I use the second definition, the first test fails (because now IFFLOORED
tries to compile \
rather than executing it). If I use the first definition, the second test fails (because GT4
pushes onto the compiler stack rather than compiling a literal push).
...but both tests pass in gForth.
So what's going on?
Let me answer here, as the question changed considerably. I am still not sure I understand the question, though :)
In your example, you define
: GT4 POSTPONE GT1 ; IMMEDIATE
What happens here, is the following:
:
is executed, reading GT4
and creating the new wordPOSTPONE
's compilation semantics is executed, which is to compile the compilation semantics of GT1
- as you have seen in GForth.;
is executed, ending the definitionIMMEDIATE
is executed, marking the last defined word as immediate.POSTPONE
is called only when compiling GT4
, and it does not appear in the compiled code. So when later using this immediate word in the definition of GT5
, the interpretation semantics of POSTPONE
is not needed.
By the way, according to the standard, POSTPONE
has only compilation semantics, and the interpretation semantics is undefined.
See also the POSTPONE
tutorial in the GForth manual.
EDIT Examples of interpretation and compilation semantics:
: 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
If you have any more questions, you can reference these tests.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With