This section introduces the GNU Modula-2 language extensions. The GNU Modula-2 compiler allows abstract data types to be any type, not just restricted to a pointer type providing the -fextended-opaque option is supplied See (Compiler options, gm2).
Declarations can be made in any order, whether they are types, constants, procedures, nested modules or variables.
GNU Modula-2 also allows programmers to interface to C and assembly language.
GNU Modula-2 provides support for the special tokens __LINE__, __FILE__, __FUNCTION__ and __DATE__. Support for these tokens will occur even if the -fcpp option is not supplied. A table of these identifiers and their data type and values is given below:
Scope GNU Modula-2 token Data type and example value anywhere __LINE__ Constant Literal compatible with CARDINAL, INTEGER and WORD. Example 1234 anywhere __FILE__ Constant string compatible with parameter ARRAY OF CHAR or an ARRAY whose SIZE is >= string length. Example "hello.mod" procedure __FUNCTION__ Constant string compatible with parameter ARRAY OF CHAR or an ARRAY whose SIZE is >= string length. Example "calc" module __FUNCTION__ Example "module hello initialization" anywhere __DATE__ Constant string compatible with parameter ARRAY OF CHAR or an ARRAY whose SIZE is >= string length. Example "Thu Apr 29 10:07:16 BST 2004" anywhere __COLUMN__ Gives a contant literal number determining the left hand column where the first _ appears in __COLUMN__. The left most column is 1.
The preprocessor cpp can be invoked via the -fcpp command line option. This in turn invokes cpp with the following arguments -traditional -lang-asm. These options preserve comments and all quotations. gm2 treats a # character in the first column as a preprocessor directive.
For example here is a module which calls FatalError via the macro ERROR.
MODULE cpp ; FROM SYSTEM IMPORT ADR, SIZE ; FROM libc IMPORT exit, printf, malloc ; PROCEDURE FatalError (a, file: ARRAY OF CHAR; line: CARDINAL; func: ARRAY OF CHAR) ; BEGIN printf("%s:%d:fatal error, %s, in %s\n", ADR(file), line, ADR(a), ADR(func)) ; exit(1) END FatalError ; #define ERROR(X) FatalError(X, __FILE__, __LINE__, __FUNCTION__) VAR pc: POINTER TO CARDINAL; BEGIN pc := malloc(SIZE(CARDINAL)) ; IF pc=NIL THEN ERROR('out of memory') END END cpp.
Another use for the C preprocessor in Modula-2 might be to turn on debugging code. For example the library module FormatStrings.mod uses procedures from DynamicStrings.mod and to track down memory leaks it was useful to track the source file and line where each string was created. Here is a section of FormatStrings.mod which shows how the debugging code was enabled and disabled by adding -fcpp to the command line.
FROM DynamicStrings IMPORT String, InitString, InitStringChar, Mark, ConCat, Slice, Index, char, Assign, Length, Mult, Dup, ConCatChar, PushAllocation, PopAllocationExemption, InitStringDB, InitStringCharStarDB, InitStringCharDB, MultDB, DupDB, SliceDB ; (* #define InitString(X) InitStringDB(X, __FILE__, __LINE__) #define InitStringCharStar(X) InitStringCharStarDB(X, __FILE__, __LINE__) #define InitStringChar(X) InitStringCharDB(X, __FILE__, __LINE__) #define Mult(X,Y) MultDB(X, Y, __FILE__, __LINE__) #define Dup(X) DupDB(X, __FILE__, __LINE__) #define Slice(X,Y,Z) SliceDB(X, Y, Z, __FILE__, __LINE__) *) PROCEDURE doDSdbEnter ; BEGIN PushAllocation END doDSdbEnter ; PROCEDURE doDSdbExit (s: String) ; BEGIN s := PopAllocationExemption(TRUE, s) END doDSdbExit ; PROCEDURE DSdbEnter ; BEGIN END DSdbEnter ; PROCEDURE DSdbExit (s: String) ; BEGIN END DSdbExit ; (* #define DBsbEnter doDBsbEnter #define DBsbExit doDBsbExit *) PROCEDURE Sprintf1 (s: String; w: ARRAY OF BYTE) : String ; BEGIN DSdbEnter ; s := FormatString(HandleEscape(s), w) ; DSdbExit(s) ; RETURN( s ) END Sprintf1 ;
It is worth noting that the overhead of this code once -fcpp is not present and -O2 is used will be zero since the local empty procedures DSdbEnter and DSdbExit will be thrown away by the optimization passes of the GCC backend.
GNU Modula-2 allows the last parameter to a procedure or function parameter to be optional. For example in the ISO library COROUTINES.def the procedure NEWCOROUTINE is defined as having an optional fifth argument (initProtection) which, if absent, is automatically replaced by NIL.
PROCEDURE NEWCOROUTINE (procBody: PROC; workspace: SYSTEM.ADDRESS; size: CARDINAL; VAR cr: COROUTINE; [initProtection: PROTECTION = NIL]); (* Creates a new coroutine whose body is given by procBody, and returns the identity of the coroutine in cr. workspace is a pointer to the work space allocated to the coroutine; size specifies the size of this workspace in terms of SYSTEM.LOC. The optional fifth argument may contain a single parameter which specifies the initial protection level of the coroutine. *)
The implementation module COROUTINES.mod implements this procedure using the following syntax:
PROCEDURE NEWCOROUTINE (procBody: PROC; workspace: SYSTEM.ADDRESS; size: CARDINAL; VAR cr: COROUTINE; [initProtection: PROTECTION]); BEGIN END NEWCOROUTINE ;
Note that it is illegal for this declaration to contain an initialiser value for initProtection. However it is necessary to surround this parameter with the brackets [ and ]. This serves to remind the programmer that the last parameter was declared as optional in the definition module.
Local procedures can be declared to have an optional final parameter in which case the initializer is mandatory in the implementation or program module.
GNU Modula-2 also provides additional fixed sized data types which are all exported from the SYSTEM module. See (The PIM system module, gm2). See (The ISO system module, gm2).