“n FOR-NEXT runs n+1 loops by design”
Why and how to cope with:
eForth FOR .. NEXT
While it’s advisable to use the STM8 eForth
DO .. LEAVE .. LOOP/+LOOP structure instead of
FOR .. NEXT and its variants, the following discussion deals with the most main properties, idioms and limitations of the this “eForth-ism”.
Among “small Forth implemenations” the eForth
FOR .. NEXT construct is idiosyncratic, and some of its properties and idioms are rather difficult to understand.
Here is a the basic
FOR .. NEXT loop:
: test-for FOR I . NEXT ;
NEXT decrements the loop counter on the return stack (accessible with
R@) and loops while the counter is positive.
4 test-for prints
4 3 2 1 0,
0 test-for prints
-1 test-for prints
FOR .. NEXT properties are noteworthy:
- at least one iteration, with the loop counter equal to the input to
FORwill be performed
- the nuber of iterations is limited to 32768, and
- the loop count will be “one-too-many” compared to standard loop structures (e.g.
DO .. LOOP)
The most unusual feature eForth provides is the word
: test-aft1 ( n -- ) FOR \ first loop ." for" AFT \ following iterations ." aft" THEN \ all iterations I . NEXT ;
2 test-aft1 prints
for 2 aft 1 aft 0. Why one would need such a control structure is all but obvious. The eForth core implementation use of
AFT, however, shows that it not only works around the “one-too-many” iterations in
FOR .. NEXT, but it also provides loop count testing if the actual “loop clause code” is in the
AFT .. THEN block:
: test-aft2 ( n -- ) FOR AFT I . THEN NEXT ;
3 test-aft2 prints
2 1 0, and
0 test-aft2 or
-1 test-aft2 print nothing at all. This structure is widely used in the eForth core, e.g. in
TYPE. The effect is that input testing around
FOR .. NEXT, especially for
0 counts, isn’t needed.
A loop structure similar to
DO .. LEAVE .. LOOP can be implemented in “pure eForth” with an idiomatic combination of
FOR .. NEXT,
ELSE .. THEN:
: test-for-while ( n1 n2 -- ) FOR DUP I = NOT WHILE I . \ limit not reached NEXT ." end" ELSE ." limit" R> DROP \ remove the FOR loop counter THEN DROP ; \ drop limit
In this example,
5 10 test-for-while prints
10 9 8 5 6 limit, and
5 4 test-for-while prints
4 3 2 1 0 end.
WHILE puts a the address of its conditional branch target on the stack above the start address of
FOR the for loop (which is used when compiling
NEXT). During compilation,
ELSE then uses this address to make
WHILE exit to the code block delimited by
THEN. Note that the
ELSE clause is responsible of removing the loop counter from the return stack.
Note that the
FOR .. WHILE .. NEXT .. ELSE .. THEN idiom can’t be mixed with the
FOR .. AFT .. THEN .. NEXT idiom!