Next: Arbitrary control structures, Previous: Simple Loops, Up: Control Structures
limit start ?DO body LOOP
This performs one iteration for every integer, starting from start
and up to, but excluding limit. The counter, or index, can be
accessed with i
. For example, the loop:
10 0 ?DO i . LOOP
prints 0 1 2 3 4 5 6 7 8 9
The index of the innermost loop can be accessed with i
, the index
of the next loop with j
, and the index of the third loop with
k
.
i
R:n – R:n n core “i”
j
R:w R:w1 R:w2 – w R:w R:w1 R:w2 core “j”
k
R:w R:w1 R:w2 R:w3 R:w4 – w R:w R:w1 R:w2 R:w3 R:w4 gforth “k”
The loop control data are kept on the return stack, so there are some restrictions on mixing return stack accesses and counted loop words. In particuler, if you put values on the return stack outside the loop, you cannot read them inside the loop1. If you put values on the return stack within a loop, you have to remove them before the end of the loop and before accessing the index of the loop.
There are several variations on the counted loop:
LEAVE
leaves the innermost counted loop immediately; execution
continues after the associated LOOP
or NEXT
. For example:
10 0 ?DO i DUP . 3 = IF LEAVE THEN LOOP
prints 0 1 2 3
UNLOOP
prepares for an abnormal loop exit, e.g., via
EXIT
. UNLOOP
removes the loop control parameters from the
return stack so EXIT
can get to its return address. For example:
: demo 10 0 ?DO i DUP . 3 = IF UNLOOP EXIT THEN LOOP ." Done" ;
prints 0 1 2 3
?DO
loop is entered
(and LOOP
iterates until they become equal by wrap-around
arithmetic). This behaviour is usually not what you want. Therefore,
Gforth offers +DO
and U+DO
(as replacements for
?DO
), which do not enter the loop if start is greater than
limit; +DO
is for signed loop parameters, U+DO
for
unsigned loop parameters.
?DO
can be replaced by DO
. DO
always enters
the loop, independent of the loop parameters. Do not use DO
, even
if you know that the loop is entered in any case. Such knowledge tends
to become invalid during maintenance of a program, and then the
DO
will make trouble.
LOOP
can be replaced with n +LOOP
; this updates the
index by n instead of by 1. The loop is terminated when the border
between limit-1 and limit is crossed. E.g.:
4 0 +DO i . 2 +LOOP
prints 0 2
4 1 +DO i . 2 +LOOP
prints 1 3
+LOOP
is peculiar when n is negative:
-1 0 ?DO i . -1 +LOOP
prints 0 -1
0 0 ?DO i . -1 +LOOP
prints nothing.
Therefore we recommend avoiding n +LOOP
with negative
n. One alternative is u -LOOP
, which reduces the
index by u each iteration. The loop is terminated when the border
between limit+1 and limit is crossed. Gforth also provides
-DO
and U-DO
for down-counting loops. E.g.:
-2 0 -DO i . 1 -LOOP
prints 0 -1
-1 0 -DO i . 1 -LOOP
prints 0
0 0 -DO i . 1 -LOOP
prints nothing.
Unfortunately, +DO
, U+DO
, -DO
, U-DO
and
-LOOP
are not defined in ANS Forth. However, an implementation
for these words that uses only standard words is provided in
compat/loops.fs.
n FOR body NEXT
This is the preferred loop of native code compiler writers who are too
lazy to optimize ?DO
loops properly. This loop structure is not
defined in ANS Forth. In Gforth, this loop iterates n+1 times;
i
produces values starting with n and ending with 0. Other
Forth systems may behave differently, even if they support FOR
loops. To avoid problems, don't use FOR
loops.