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. ----------Author: Ros Barrett, 1984