Extensions (The GNU Modula-2 Compiler)

### 2.10 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 constant 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 unless ‘`-fno-cpp`’ is supplied.

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.

#### 2.10.1 Optional procedure parameter ¶

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 initializer 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. See The ISO system module.