DO WHILE/UNTIL

A set of instructions may be executed repeatedly until some condition is true, by placing the UNTIL keyword after DO, and then following it with some conditional expression (as are used in conditional instructions). For example, here we repeat the loop until the variable answer does not have the value "NO".

/* I won't take no for an answer */
DO UNTIL answer \= "NO"
   PULL answer
END
Alternatively, a loop can be executed as long as some condition is true by placing the WHILE keyword after DO.
/* This loop repeats as long as there is no error */
DO WHILE error=0
   PULL a
   IF a="ERROR" THEN error=1
   ELSE SAY a
END
Using WHILE, if the expression is not true to start with, then the set of instructions within the loop will not be executed at all. Using UNTIL, the instructions within the loop will always be executed at least once. This is because UNTIL tests to see if the expression is true at the end of each loop's iteration, whereas WHILE tests to see if the expression is true at the start of each iteration.

Another important distinction is that with WHILE, the loop continues executing as long as the expression is true (ie, a false expression ends the loop), whereas with UNTIL, the loop continues as long as the expression is false (ie, a true expression ends the loop).

You can place a numeric value after DO in order to specify how many times to repeat the loop, and then also use the UNTIL or WHILE keywords to specify some condition that may prematurely end the loop. Of course, you can use a variable's value (or mathematical expression) to specify the repeat count.

/* I won't take NO for an answer unless it is typed three times */
DO 3 UNTIL answer \= "NO"
   PULL answer
END
You can also use a control variable along with the UNTIL or WHILE keywords.
/* Input upto 10 answers, but stop when empty string is entered */
DO n=1 TO 10 UNTIL answer==""
   PULL answer
   answers.n=answer
END


DO OVER

Reginald offers a DO OVER loop. DO OVER is a way to loop over all variables that use a certain stem, without knowing exactly how many, and what, tail names use that stem. For example, if you want to find out the names of all variables that use the stem "MyStem.", you can do:

DO i OVER MyStem.
   SAY "MyStem." || i
END
Each time around the loop, i will be set to the next tail name that uses "MyStem.". So, you can fetch the values of all variables using a given stem, for example:
MyStem.name = "Jeff"
MyStem.1 = 100
MyStem.first.second = "Some string"
DO i OVER MyStem.
   SAY MyStem.i
END
The first time through the DO OVER loop, the variable "i" is set to the value "name". That's because 'name' is the first tail that uses MyStem as its stem. So you actually SAY the value of MyStem.name and "Jeff" gets displayed. The second time through the DO OVER loop "i" is set to the value "1". That's because '1' is the second tail that uses MyStem as its stem. So you actually SAY the value of MyStem.1 and "100" gets displayed. The third time through the DO OVER loop, the variable "i" is set to the value "first.second". That's because 'first.second' is the third tail that uses MyStem as its stem. So you actually SAY the value of MyStem.first.second and "Some string" gets displayed. Then the DO OVER loop ends because there are no more tail names that use MyStem.

In other words, DO OVER can be used to enumerate all of the tails that use a given stem, and thereby access the values of each of those variables.

The only caveat is that there is no guaranteed order to enumerating the tails. For example, they are not enumerated in alphabetical order.