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 = FALSE

AND    ?ITEM IN SET
AND        ( :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 = FALSE
AND     ?NUM = SIZEOF SET
AND     ?NUMM = ?NUM - 1

AND     ( ?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 = FALSE

AND     ( ?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.


Back                                Next
Comments