### 3.7 Delayed BREAK of a Loop

#### Delaying a BREAK from an IN Loop

We can ensure that rules with loops always prove the predicate by using a flag, say :IFBREAK, to determine whether one is to break out of the loop. The flag is initialised to FALSE outside the loop. Immediately after the loop statement the flag is tested and the loop is broken if the flag is TRUE. The flag is reset to TRUE when the jump test is satisfied:

`IF     :IFBREAK = FALSEAND    ?ITEM IN SETAND        ( :IFBREAK EQ FALSE OR BREAK ?ITEM )AND        <intermediate code>AND        ( <test on ?ITEM>                 AND :IFBREAK = TRUE                 AND <further code for successful ?ITEM>              OR TRUE            )THEN        <predicate ?ITEM>`

Note that if <test on ?ITEM> is satisfied on the last element of SET, the loop finishes normally without a BREAK and the predicate is last proved with ?ITEM as the last element of SET.

#### Protecting a Delayed Break from Empty Sets and Never-satisfied Tests

We can include tests for SET being empty and for <test on ?I> never being satisfied as follows:

`IF      :IFBREAK = FALSEAND     ?NUM = SIZEOF SETAND     ?NUMM = ?NUM - 1AND     ( ?NUM EQ 0              AND ?ITEM = "SET is empty"                   OR ?LOOP IN SET              AND ( :IFBREAK EQ FALSE OR BREAK ?LOOP )              AND ?ITEM = ?LOOP              AND <intermediate code>              AND ( <test on ?ITEM>                        AND :IFBREAK = TRUE                        AND <further code for successful ?ITEM>    /* See whether it’s the last item and haven’t found anything */                     OR ?I = INDEXOF SET(@)                        AND ?I EQ ?NUMM                        AND ?ITEM = "Not found"                   )         )THEN    <predicate ?ITEM>`

Note that the loop variable is changed to ?LOOP and that ?ITEM is a local variable which is set to ?LOOP on each iteration. This permits ?ITEM to be reset to "Not found" if <test on ?ITEM> is never satisfied.

#### Delayed BREAK from a WHILE Loop

The equivalent code for a WHILE loop executed ?NUM times is as follows:

`IF      :IFBREAK = FALSEAND     ( ?NUM LE 0              AND ?I = -2      /* Value indicates ?NUM = 0 */           OR ?NUM GT CNTLE(LOOP,1)              AND ERROR_EXIT "Increase CNTLE(LOOP,1) to " ?NUM                       OR WHILE ?J                  AND ( :IFBREAK EQ FALSE OR BREAK ?J )                  AND ?I = ?J                  AND <intermediate code>    /* See whether it’s the last iteration and haven’t found anything */                  AND ( ?I EQ ?NUM                            AND ?I = -1       /* Not Found */                            AND :IFBREAK = TRUE    /* Test on a normal iteration */                         OR <test on ?I>                            AND :IFBREAK = TRUE                            AND <further code for successful ?I>                         OR TRUE                       )         )THEN    <predicate ?I>`

If the test is satisfied for some ?I between 0 and ?NUM – 1, this returns with that value of ?I. If ?NUM is less than or equal to zero it returns with ?I = -2; if ?NUM is greater than zero and the test is never satisfied it returns with ?I = -1. If ?NUM is greater than the maximum loop count it calls an error exit routine to report the fact and stop.