* Extensions:: GNU Modula-2 language extensions.
* Type compatibility:: Data type compatibility.
* Unbounded by reference::Explanation of a language optimization.
+* Exception handling:: Example of exception handling.
* Building a shared library:: How to build a shared library.
* Interface for Python:: How to produce swig interface files.
* Producing a Python module:: How to produce a Python module.
@xref{The PIM system module}.
@xref{The ISO system module}.
-@node Type compatibility, Unbounded by reference, Extensions, Using
+@node Type compatibility, Exception handling, Extensions, Using
@section Type compatibility
This section discuss the issues surrounding assignment, expression
derivatives are assignment and parameter compatible with any data type
of the same size.
-@node Unbounded by reference, Building a shared library, Type compatibility, Using
+@node Exception handling, Unbounded by reference, Type compatibility, Using
+@section 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:
+
+@example
+$ gm2 -g -fiso -fsoft-check-all lazyunique.mod
+@end example
+
+The option @samp{-fsoft-check-all} generates checks for @code{NIL}
+pointer access violation. In turn this will call the exception handler.
+
+@example
+@group
+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 ;
+@end group
+@end example
+
+@example
+@group
+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 ;
+@end group
+@end example
+
+@example
+@group
+PROCEDURE Add (VAR p: List; val: INTEGER) ;
+BEGIN
+ NEW (p) ;
+ WITH p^ DO
+ value := val ;
+ next := NIL
+ END
+END Add ;
+@end group
+@end example
+
+@example
+@group
+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 ;
+@end group
+@end example
+
+@example
+@group
+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.
+@end group
+@end example
+
+@example
+@group
+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
+@end group
+@end example
+
+@node Unbounded by reference, Building a shared library, Exception handling, Using
@section Unbounded by reference
This section documents a GNU Modula-2 compiler switch which implements
Both examples generate exactly the same code. It is worth noting that
the specifier ``rm'' indicates that the operand can be either a
register or memory. Of course you must choose an instruction which
-can take either, but this allows the compiler to take make more
-efficient choices depending upon the optimization level given to the
-compiler.
+can take either, but this allows the compiler to make more
+efficient choices depending upon the optimization level.
@node Alignment, Packed, Assembly language, Using
@section Data type alignment
@include m2/SYSTEM-iso.texi
-The data types @code{CSIZE_T} and @code{CSSIZE_T} are also exported from
-the @code{SYSTEM} module. The type @code{CSIZE_T} is unsigned and is
-mapped onto the target C data type @code{size_t} whereas the type
-@code{CSSIZE_T} is mapped onto the signed C data type @code{ssize_t}.
+The data types @code{CSIZE_T}, @code{CSSIZE_T} and @code{COFF_T} are
+also exported from the @code{SYSTEM} module. The type @code{CSIZE_T}
+is unsigned and is mapped onto the target C data type @code{size_t}
+whereas the type @code{CSSIZE_T} is mapped onto the signed C data type
+@code{ssize_t}. The default size for the signed type @code{COFF_T} is
+the same as @code{CSSIZE_T} and this can be overridden by the
+@code{-fm2-file-offset-bits=} command line option.
It is anticipated that these should only be used to provide cross
platform definition modules for C libraries.
--- /dev/null
+(* Copyright (C) 2025 Free Software Foundation, Inc. *)
+(* This file is part of GNU Modula-2.
+
+GNU Modula-2 is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GNU Modula-2 is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with gm2; see the file COPYING. If not, write to the Free Software
+Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *)
+
+MODULE except9 ;
+
+FROM libc IMPORT printf ;
+FROM Storage IMPORT ALLOCATE, DEALLOCATE ;
+FROM SYSTEM IMPORT ADR, WORD ;
+
+
+PROCEDURE fly (debug: BOOLEAN) ;
+BEGIN
+ printf("fly main body\n") ;
+ IF 4 DIV ip^ = 4
+ THEN
+ printf("yes it worked\n")
+ ELSE
+ printf("no it failed\n")
+ END
+END fly ;
+
+(*
+ * a GNU M2 version of the Modula-2 example given in the ISO standard.
+ * This is a hand translation of the equivalent except.c file in this
+ * directory which is written to prove that the underlying runtime system
+ * will work with the GCC exception handling trees.
+ *)
+
+PROCEDURE tryFlying (debug: BOOLEAN) ;
+BEGIN
+ printf("tryFlying main body\n");
+ fly (debug) ;
+EXCEPT
+ printf("inside tryFlying exception routine\n") ;
+ IF (ip#NIL) AND (ip^=0)
+ THEN
+ ip^ := 1 ;
+ RETRY
+ END
+END tryFlying ;
+
+
+PROCEDURE keepFlying (debug: BOOLEAN) ;
+BEGIN
+ printf("keepFlying main body\n") ;
+ tryFlying (debug) ;
+EXCEPT
+ printf("inside keepFlying exception routine\n") ;
+ IF ip=NIL
+ THEN
+ NEW(ip) ;
+ ip^ := 0 ;
+ RETRY
+ END
+END keepFlying ;
+
+
+VAR
+ ip: POINTER TO INTEGER ;
+BEGIN
+ ip := NIL ;
+ keepFlying (FALSE) ;
+ printf("all done\n")
+END except9.
--- /dev/null
+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.