This section gives an example of exception handling and briefly describes its runtime behavior. The module below is written in the ISO dialect of Modula-2 and can be compiled with the command line:
$ gm2 -g -fiso -fsoft-check-all lazyunique.mod
The option ‘-fsoft-check-all’ generates checks for NIL
pointer access violation. In turn this will call the exception handler.
MODULE lazyunique ; (*!m2iso+gm2*) FROM Storage IMPORT ALLOCATE ; FROM libc IMPORT printf, exit ; TYPE List = POINTER TO RECORD next : List ; value: INTEGER ; END ; Array = ARRAY [0..3] OF INTEGER ; CONST Unsorted = Array {0, 2, 1, 1} ; VAR head: List ;
PROCEDURE Display ; VAR p: List ; BEGIN p := head^.next ; printf ("\nunique data\n"); printf ("===========\n"); WHILE p # NIL DO printf ("%d\n", p^.value); p := p^.next END END Display ;
PROCEDURE Add (VAR p: List; val: INTEGER) ; BEGIN NEW (p) ; WITH p^ DO value := val ; next := NIL END END Add ;
PROCEDURE Unique (val: INTEGER) ; VAR p: List ; BEGIN printf ("new value %d\n", val); p := head ; (* The following line may cause an exception accessing next or value. *) WHILE p^.next^.value # val DO p := p^.next END EXCEPT (* Now fixup. Determine the source of the exception and retry. *) IF head = NIL THEN printf ("list was empty, add sentinal\n"); Add (head, -1) ; RETRY (* Jump back to the begin statement. *) ELSIF p^.next = NIL THEN printf ("growing the list\n"); Add (p^.next, val) ; RETRY (* Jump back to the begin statement. *) ELSE printf ("should never reach here!\n"); END END Unique ;
PROCEDURE unique ; VAR i: CARDINAL ; BEGIN FOR i := 0 TO HIGH (Unsorted) DO Unique (Unsorted[i]) END ; Display END unique ; BEGIN head := NIL ; unique END lazyunique.
new value 0 list was empty, add sentinal new value 0 growing the list new value 0 new value 2 growing the list new value 2 new value 1 growing the list new value 1 new value 1 unique data =========== 0 2 1