HELP CATCH                                             Ros Barrett, 1984

    catch(<procedure>, <catch_procedure>, <spec>);
    throw(<argument>);

The first argument, <procedure>, is a procedure, which is called
immediately. If, while this procedure is running, the procedure THROW is
called with an argument that matches <spec>, and if <catch_procedure> is
a procedure, control unwinds to this call of CATCH and <catch_procedure>
is run. The matching is done using MATCHES. (If <catch_procedure> is not
a procedure, it is simply left on the stack.) After this control returns
from the call of CATCH. If THROW'S argument does not match <spec>,
control unwinds until a call of CATCH whose <spec> does match is found.
This makes it possible to embed procedures which use CATCH and THROW
inside one another, and yet for each instance of THROW to be able to
specify which instance of CATCH it is aiming at.

Here is an example. The procedure TEST takes three arguments - a list of
lists of numbers, a number specifying a lower bound, and a number
specifying an upper bound. It immediately calls CATCH. The procedure
given to CATCH as argument, CHECKLIST, is run. CHECKLIST recursively
checks to see if any of the numbers in the tree fall outside the bounds
specified. If a number is outside the bounds then THROW is called. The
argument given to THROW in both cases matches the third argument of
CATCH, namely [NOGOOD ?CULPRIT ?REASON], so control unwinds to CATCH,
and the second argument of CATCH, the procedure CATCHER, is run.

    define checklist(tree, Lo, Hi);
        vars x;
        ;;; recursively check if elements of tree are in bounds
        if islist(tree) then              ;;; if argument is a tree
            for x in tree do              ;;; then check each component
               checklist(x, Lo, Hi)       ;;; which may itself be a tree
            endfor;
        elseif tree > Hi then             ;;; else see if it's too big
            throw([nogood ^tree toobig])  ;;; unwind to catch if so
        elseif tree < Lo then             ;;; see if it's too small
            throw([nogood ^tree toolow])  ;;; unwind to catch
        else
            tree =>                       ;;; OK - print out
        endif
    enddefine;

    define test(tree, Lo, Hi);
        vars culprit reason;

        define catcher();
            ;;; This will be run if a number is out of bounds
            [rejected ^culprit because ^reason] =>
        enddefine;

        ;;; recursively examine the tree and complain if necessary
        tree, Lo, Hi;
        ;;; Arguments for CHECKLIST put on stack
        catch(checklist, catcher, [nogood ?culprit ?reason])
    enddefine;

trace checklist throw test;

test([1 2 [2.5] 3], 0, 6);      ;;; All elements in bounds
>test [1 2 [2.5] 3] 0 6
!>checklist [1 2 [2.5] 3] 0 6
!!>checklist 1 0 6
** 1                            ;;; When CHECKLIST gets an OK number
                                ;;; it prints it out
!!<checklist
!!>checklist 2 0 6
** 2
!!<checklist
!!>checklist [2.5] 0 6
!!!>checklist 2.5 0 6
** 2.5
!!!<checklist
!!<checklist
!!>checklist 3 0 6
** 3
!!<checklist
!<checklist
<test

vars tree;
[3 [3.3 3.4 [3.45 2.6 [9]] [2 4.6]]] -> tree;
test(tree, 1, 3.4);
>test [3 [3.3 3.4 [3.45 2.6 [9]] [2 4.6]]] 1 3.4
!>checklist [3 [3.3 3.4 [3.45 2.6 [9]] [2 4.6]]] 1 3.4
!!>checklist 3 1 3.4
** 3
!!<checklist
!!>checklist [3.3 3.4 [3.45 2.6 [9]] [2 4.6]] 1 3.4
!!!>checklist 3.3 1 3.4
** 3.3
!!!<checklist
!!!>checklist 3.4 1 3.4
** 3.4
!!!<checklist
!!!>checklist [3.45 2.6 [9]] 1 3.4
!!!!>checklist 3.45 1 3.4
!!!!!>throw [nogood 3.45 toobig]
** [rejected 3.45 because toobig]
<test

The use of CATCH and THROW has enabled us to define CHECKLIST so that it
reacts immediately it finds something it doesn't like. We have not had
to worry about how control returns from CHECKLIST when this happens -
the call of THROW looks after it for us.

For other non-standard control structures, see HELP *CHAIN, *CHAINTO,
*CHAINFROM, *EXITTO, *EXITFROM, *JUMPOUT.

See also HELP
    *CALLER    - For accessing the stack of currently active procedures
    *INTERRUPT - On POP-11 interrupt procedures
    *CONTROL   - For a summary of control structures in POP-11

--- C.all/help/catch ---------------------------------------------------
--- Copyright University of Sussex 1987. All rights reserved. ----------
