Starting with
IF-THEN, a bit more detail for those new to this sort of thing:
At compile-time, IF ads a "conditional forward branch" to the word being created, traditionally called 0BRANCH. Then, during run-time, if the value on the Data Stack is false (flag is zero), the branch is taken ("branch on zero", therefore the zero). The target of the that branch will be added by THEN. But how does THEN know where to save the address IF jumps to? After the 0BRANCH has been compiled, the Compiler Pointer (CP) -- the pointer that tells Forth where we are in the memory -- marks where that address will have to go. HERE puts the CP on the Data Stack, so we do that,
during compile time. Then, we compile a dummy value (usually 0) to reserve the space we need.
The whole thing ends up looking like this in ANS Forth:
Code:
: IF POSTPONE 0BRANCH HERE 0 , ; IMMEDIATE
Note this is a compile-only word (in Tali Forth, there's an additional word COMPILE-ONLY that handles that; YFMV) and it is "immediate", so it is executed during compilation. However, POSTPONE blocks the execution of the following word, so 0BRANCH is compiled after all. Older Forths tend to use [COMPILE] here (I think). If POSTPONE is making your brain hurt, that's fine, it does that at first.
Anway, after compiling IF, we end up with a dummy value as the branch target and the address of that same dummy value on the stack. Sooner or later, we reach THEN.
Code:
: THEN HERE SWAP ! ; IMMEDIATE
Note that THEN doesn't actually compile anything at the location in memory where it is at. It's job is to help IF out of the mess it created. THEN assumes that the top of the Data Stack (TOS)
during compile time contains the address that IF provided. HERE again gives us the location of the CP, but this time we get the target of IF's jump. We SWAP it with the address from IF, and our ! ("store") saves it right behind the IF's 0BRANCH where it belongs. That finishes the IF-THEN construction.
The ELSE of
IF-ELSE-THEN can be coded like this:
Code:
: ELSE POSTPONE BRANCH HERE 0 , HERE ROT ! ; IMMEDIATE
If we have taken the IF branch, we have to jump over the alternative at this point, so we add the unconditional branch BRANCH, push the location of the next cell on the stack for THEN, and save a dummy value 0 (ANS Forth has its own name for this sequence, AHEAD). Now we have to tell IF where to land if we didn't continue after ELSE, which is right after the dummy value we just saved. Basically, this now a version of THEN with ROT instead of SWAP, because we're juggling one more thing on the stack. In fact, another version of ELSE you'll see is
Code:
: ELSE POSTPONE AHEAD SWAP THEN ; IMMEDIATE
Note the "hidden" second SWAP in THEN. I like the first version better because it seems slightly less confusing. ANS Forth uses 1 CS-ROLL instead of SWAP.
Finally we come to the THEN, which takes the address provided by the first part of ELSE (
not by IF any more!) and does the store thing to resolve that unconditional forward branch.
Those were cases 1 and 2. Now for the simple DO/LOOP stuff.