GNU Modula-2 language extensions#

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.

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.