Exception handling (The GNU Modula-2 Compiler)

### 2.12 Exception handling ¶

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 sentinel\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 sentinel
    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