Top: Forth Index Prev: Making Decisions Next: Storage, Strings & Output

DO ... LOOPS

This type of loop is known as a definite loop. It will loop a specific number of times and then continue with the program. If you wanted to count to ten you could setup the following:

    ok 10 0 do i 1+ . cr loop
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
The two numbers before do are the limit and the index of the loop. The index is the number to start incrementing from, in this case zero, and the limit is the number of times the loop will repeat itself, in this case ten. Why 0...10? Because each iteration of the loop causes a test to be performed: Is i less than the limit?. Within a do...loop, i represents the current loop index. So we are checking to see if i<10 in the above example after every every carriage return (cr). If we had wanted the obvious 1..10 loop, the test would have to be i<=10, which requires two additional tests (one to check if i is less than ten and one to check if i is equal to ten). Plus, programmers tend to count to ten by starting at zero and going to nine because array indices start at zero.

The "." (dot) is a word which pops a number off of the stack and displays it on the screen (more about this and other types of output in 7. Strings, Fields And Output).

do ... loop do: ( limit index -- ) loop: ( -- ) Set up a finite loop, given the index range.

do ... +loop do: ( limit index -- ) +loop: ( n -- ) Set up a finite loop similar to a DO...LOOP except that the index will increase by n instead of one.

leave ( -- ) causes the DO...LOOP to end at the next loop or +loop.


BEGIN ... UNTIL

Another type of loop is the indefinite loop, or a loop which continues until a certain condition is met. The BEGIN...UNTIL loop always executes at least once. Counting to ten with a BEGIN...UNTIL loop:

    ok 0 begin 1+ dup . cr dup 10 = until
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
Not very pretty, but it works. This shows why you would use a DO...LOOP instead of a BEGIN...UNTIL. Now how about the reverse? A good example of when to use a BEGIN...UNTIL loop is when a condition changes all of sudden, such as waiting for a DSP card to finish processing:

    : init.board ( -- ) \ Run DSP program to intialize board. 
        initializeboard \ Load SPECTRUM's initialization code onto board
        h# 100 runprog  \ Start NIR setup subprogram running on dsp 56001 board
        begin
            readdspflag 0=  \ Wait until dsp program lowers its "run" flag
        until  ;
While the program is running on a DSP card, readdspflag will poll the DSP card, checking to see if the program is still running and will return true if it is. 0= determines whether the flag is equal to zero. So if the program has finished, 0= will return true and the loop will end.

begin ... until until: ( f -- ) Set up an indefinte loop, repeating until f is true.


BEGIN xxx WHILE yyy REPEAT

This loop acts a little differently than the BEGIN...UNTIL loop. It will always execute xxx at least once and if the flag to WHILE is true, it will execute yyy and start the loop over. It will continue to loop until the flag before WHILE is false.

An example of using a BEGIN xxx WHILE yyy REPEAT loop is to query the user for a number between 0 and 9, maybe as part of a menu selection process.

    : get-menu-item ( -- n )    \ Query user for a menu option.
        begin
            ." Enter the menu item you desire: "
            key dup emit cr ascii 0 - dup 0 9 between not
        while
            drop
            ." Not a valid menu number! Try again." cr cr
        repeat  ;
begin xxx while yyy repeat while: ( f -- ) Set up an indefinite loop which always executes xxx and executes yyy if f is true. The loop ends when f is false. Note that this loop reacts differently to the flag than BEGIN...UNTIL.


Top: Forth Index Prev: Making Decisions Next: Storage, Strings & Output