6.9.3 Counted Loops

The basic counted loop is:

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.

You can access the limit of the innermost loop with i' and i'-i with delta-i. E.g., running

: foo 7 5 ?do cr i . i' . delta-i . loop ; 

prints

5 7 2 
6 7 1

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 loop14. 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:

The counted-loop words are:

?DO ( compilation – do-sys ; run-time w1 w2 – | loop-sys  ) core-ext “question-do”

See Counted Loops.

+DO ( compilation – do-sys ; run-time n1 n2 – | loop-sys  ) gforth-0.2 “plus-do”

See Counted Loops.

U+DO ( compilation – do-sys ; run-time u1 u2 – | loop-sys  ) gforth-0.2 “u-plus-do”

See Counted Loops.

bounds ( u1 u2 – u3 u1 ) gforth-0.2 “bounds”

Given a memory block represented by starting address addr and length u in aus, produce the end address addr+u and the start address in the right order for u+do or ?do.

-[do ( compilation – do-sys ; run-time n1 n2 – | loop-sys  ) gforth-experimental “minus-bracket-do”

Start of a counted loop with negative stride; Skips the loop if n2<n1; such a counted loop ends with +loop where the increment is negative; it runs as long as I>=n1.

u-[do ( compilation – do-sys ; run-time u1 u2 – | loop-sys  ) gforth-experimental “u-minus-bracket-do”

Start of a counted loop with negative stride; Skips the loop if u2<u1; such a counted loop ends with +loop where the increment is negative; it runs as long as I>=u1.

-DO ( compilation – do-sys ; run-time n1 n2 – | loop-sys  ) gforth-0.2 “minus-do”

See Counted Loops.

U-DO ( compilation – do-sys ; run-time u1 u2 – | loop-sys  ) gforth-0.2 “u-minus-do”

See Counted Loops.

array>mem ( uelements uelemsize – ubytes uelemsize  ) gforth-experimental “array>mem”

ubytes=uelements*uelemsize

mem+do ( compilation – w xt do-sys; run-time addr ubytes +nstride –  ) gforth-experimental “mem-plus-do”

Starts a counted loop that starts with I as addr and then steps upwards through memory with nstride wide steps as long as I<addr+ubytes. Must be finished with loop.

mem-do ( compilation – w xt do-sys; run-time addr ubytes +nstride –  ) gforth-experimental “mem-minus-do”

Starts a counted loop that starts with I as addr+ubytes-ustride and then steps backwards through memory with -nstride wide steps as long as I>=addr. Must be finished with loop.

DO ( compilation – do-sys ; run-time w1 w2 – loop-sys  ) core “DO”

See Counted Loops.

FOR ( compilation – do-sys ; run-time u – loop-sys  ) gforth-0.2 “FOR”

See Counted Loops.

LOOP ( compilation do-sys – ; run-time loop-sys1 – | loop-sys2  ) core “LOOP”

See Counted Loops.

+LOOP ( compilation do-sys – ; run-time loop-sys1 n – | loop-sys2  ) core “plus-loop”

See Counted Loops.

-LOOP ( compilation do-sys – ; run-time loop-sys1 u – | loop-sys2  ) gforth-0.2 “minus-loop”

See Counted Loops.

NEXT ( compilation do-sys – ; run-time loop-sys1 – | loop-sys2  ) gforth-0.2 “NEXT”

See Counted Loops.

i ( R:n – R:n n ) core “i”

n is the index of the innermost counted loop.

j ( R:n R:w1 R:w2 – n R:n R:w1 R:w2 ) core “j”

n is the index of the next-to-innermost counted loop.

k ( R:n R:w1 R:w2 R:w3 R:w4 – n R:n R:w1 R:w2 R:w3 R:w4 ) gforth-0.3 “k”

n is the index of the third-innermost counted loop.

i' ( R:w R:w2 – R:w R:w2 w ) gforth-0.2 “i-tick”

The limit of the innermost counted loop

delta-i ( r:ulimit r:u – r:ulimit r:u u2 ) gforth-1.0 “delta-i”

u2=I'-I (difference between limit and index).

LEAVE ( compilation – ; run-time loop-sys –  ) core “LEAVE”

See Counted Loops.

?LEAVE ( compilation – ; run-time f | f loop-sys –  ) gforth-0.2 “question-leave”

See Counted Loops.

unloop ( R:w1 R:w2 – ) core “unloop”
DONE ( compilation do-sys – ; run-time –  ) gforth-0.2 “DONE”

resolves all LEAVEs up to the do-sys

The standard does not allow using CS-PICK and CS-ROLL on do-sys. Gforth allows it, except for the do-sys produced by MEM+DO and MEM-DO, but it’s your job to ensure that for every ?DO etc. there is exactly one UNLOOP on any path through the definition (LOOP etc. compile an UNLOOP on the fall-through path). Also, you have to ensure that all LEAVEs are resolved (by using one of the loop-ending words or DONE).


Footnotes

(14)

well, not in a way that is portable.