[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

makeinfo texinfo-format-buffer

1. Using GNU Modula-2

This document contains the user and design issues relevant to the Modula-2 front end to gcc. Throughout this document the GNU Modula-2 front end is often referred to as `gm2-0.63' or `gm2' for short. This corresponds to GCC version 4.1.2 and GNU Modula-2 version 0.63.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.1 What is GNU Modula-2

GNU Modula-2 is a front end http://gcc.gnu.org/frontends.html for GCC. GCC is a retargetable C compiler which has been ported to a large number of architectures and operating systems. GNU Modula-2 utilizes the back end of GCC and replaces the C language front end with a Modula-2 front end. Consequently GNU Modula-2 has been built on i[3456]86 GNU/Linux, i[3456]86 BSD, Opteron LP64 GNU/Linux and sparc GNU/Linux systems. It has also been built as a cross compiler for MinGW and StrongARM GNU/Linux.

The GNU Modula-2 compiler is based on the language as defined in 'Programming in Modula-2' 2nd Edition, Springer Verlag, 1982, 1983 by Niklaus Wirth (PIM2), 'Programming in Modula-2', 3rd Corrected Edition, Springer Verlag, 1985 (PIM3) and 'Programming in Modula-2', 4th Edition, Springer Verlag, 1988 (PIM4) http://freepages.modula2.org/report4/modula-2.html. It also includes ISO M2 features and GNU Modula-2 extensions. Currently GNU Modula-2 (0.63) implements all PIM dialects of the language, eventually GNU Modula-2 will be fully compliant with ISO Modula-2.

There are currently three sets of libraries. The 'Programming in Modula-2' libraries, the 'University of ULM libraries' and the ISO libraries. The ISO libraries are still being written, however all definition modules for the three library sets are contained within this document.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.2 Why use GNU Modula-2

This section is not designed to generate a language war, but rather map out some of the advantages of using GNU Modula-2 rather than translate Modula-2 sources into another language.

It is expected that the primary purpose of GNU Modula-2 will be to compile legacy code. Currently there are only a few commercial Modula-2 compilers being actively maintained. Code which was written ten or fifteen years ago may still be compiled by older commercial (possibly unmaintained) compilers. While the 32 bit x86 remains these compilers presumably can be run in compatibility mode (some compilers only produced 16 bit code). Time is running out as the computing industry is switching to 64 microprocessors. While x86 emulation or 16 bit backwards compatibility is always possible it has some serious drawbacks. In order for the older source to run natively the source code will either have to be translated into another high level language or alternatively a Modula-2 compiler which can target these new generation of microprocessors will have to be acquired. GNU Modula-2 builds and passes all its regression tests on Debian Pure 64 (LP64 architecture), 64 bit Solaris, 32 bit x86 GNU/Linux (Suse, Debian, stable and unstable) and 32 bit x86 FreeBSD.

GNU Modula-2 also has the advantage of being closely tied to GCC. Not only does this produce excellent code and excellent architectural and operating system coverage but it also utilises many of the GCC features. For example GNU Modula-2 can invoke the C preprocessor to manage conditional compilation; in-lining of SYSTEM procedures, intrinsic functions, memory copying routines are also exploited; access to assembly language using GCC syntax is also provided. GNU Modula-2 also support sets of any ordinal type (memory permitting).

GNU Modula-2 was based on a Modula-2 front end which performed a substantial amount of static analysis of the source code (see `-Wpedantic', `-Wpedantic-param-names', `-Wstudents' and `-Wpedentic-cast'.

Finally runtime checking has been implemented and can check: bounds of subranges and array indexes, functions execute a RETURN statement, a pointer does not dereference a NIL pointer value and that the expression within a CASE statement is correctly matched.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.3 Release map

This section attempts to give an idea of which releases points are likely in the future. Clearly this is a fairly fluid release map but hopefully it is more helpful than omitting it altogether. Please note that this is not set in stone and if you (the users) wish to see something different please email gaius@gnu.org with your ideas. Also please note that the actual release numbers do not have any correlation to the estimated time of release. For example please do not misunderstand that GM2-1.0 will take twice as long as GM2-0.5 to appear. It is worthing noting that some of the later points in the release life have already been addressed (in part) but are not yet complete.

0.50

compatible with gcc-3.3.6. GNU Modula-2 is stable and passes all regression tests on LP64 Opteron and 32 bit x86 GNU/Linux. The compiler is PIM-234 compatible (use `-fpim2', `-fpim3' and `-fpim4' to force mutually exclusive PIM features).

It is also able to compile the University of Ulm libraries which are now distributed as part of GNU Modula-2. To reference these libraries use the `-flibs=ulm' compiler switch.

0.60

many Logitech compatible libraries will be provided, which will be available when invoked by `-fpim'.

0.80

a full set of ISO libraries will have been implemented. GNU Modula-2 will be sufficiently ISO compliant to compile the libraries but will not yet be able to fully conform to the ISO Modula-2 standard.

1.0

GNU Modula-2 will be fully ISO compliant.

There will be releases inbetween those outlined above and these releases may occur when GNU Modula-2 builds using a different GCC source tree. It is a goal that backward compatibility to gcc-3.3.6 will be provided as far as it is possible. Releases will also occur if a key component of ISO Modula-2 is implemented (for example exception handling, complex types or `FINALLY' is implemented).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.4 Compiler options

This section describes the compiler options specific to GNU Modula-2 for generic flags details see See (gcc)Invoking GCC.

-fmakeall

generate a temporary makefile and build all dependent modules and link.

-fbounds

generate code to check the bounds of subranges and array indexes.

-freturn

generate code to check that functions always exit with a RETURN and do not fall out at the end.

-fnil

turns on runtime checking to detect accessing data through a NIL value pointer.

-fcase

turns on runtime checking to check whether a CASE statement requires an ELSE clause when on was not specified.

-fcheck-all

turns on all runtime checks. This is the same as invoking GNU Modula-2 using the command options -fbounds -freturn -fnil -fcase.

-v

display all calls to subsidiary programs, such as the C preprocessor, the GNU Modula-2 linker and compiler.

-fstatistics

generates quadruple information: number of quadruples generated, number of quadruples remaining after optimisation.

-fmakelist

this option is only applicable when linking a program module. The compiler will generate a `modulename.lst' file which contains a list indicating the initialisation order of all modules which are to be linked. The actual link does not occur. The GNU Modula-2 linker scans all IMPORTs, generates a list of dependencies and produces an ordered list for initialisation. It will probably get the order wrong if your project has cyclic dependencies, but the `.lst' file is plain text and can be modified if required. Once the `.lst' file is created it can be used by the compiler to link your project via the `-fuselist' option. It has no effect if the `-c' option is present.

-fuselist

providing `gm2' has been told to link the program module this option uses the file `modulename.lst' for the initialisation order of modules.

-fcpp

preprocess the source with `cpp -lang-asm -traditional-cpp' For further details about these options see See (cpp)Invocation. If `-fcpp' is supplied then all definition modules and implementation modules which are parsed will be preprocessed by `cpp'.

-fiso

turn on ISO standard features. Currently this enables the ISO SYSTEM module and alters the default library search path so that the ISO libraries are searched before the PIM libraries. It also effects the behaviour of DIV and MOD operators. See See (gm2)Dialect.

-fpim

turn on PIM standard features. Currently this enables the PIM SYSTEM module and determines which identifiers are pervasive (declared in the base module). If no other `-fpim[234]' switch is used then division and modulus operators behave as defined in PIM4. See See (gm2)Dialect.

-fpim2

turn on PIM-2 standard features. Currently this removes SIZE from being a pervasive identifier (declared in the base module). It places SIZE in the SYSTEM module. It also effects the behaviour of DIV and MOD operators. See See (gm2)Dialect.

-fpim3

turn on PIM-3 standard features. Currently this only effects the behaviour of DIV and MOD operators. See See (gm2)Dialect.

-fpim4

turn on PIM-4 standard features. Currently this only effects the behaviour of DIV and MOD operators. See See (gm2)Dialect.

-fpositive-mod-floor-div

forces the DIV and MOD operators to behave as defined by PIM4. All modulus results are positive and the results from the division are rounded to the floor. See See (gm2)Dialect.

-flibs=ulm

modifies the default library search path so that the University of Ulm libraries are searched before the other PIM libraries.

-flibs=pim

modifies the default library search path so that the PIM libraries are searched before any others (the default).

-flibs=min

modifies the default library search path so that the absolute minimum of Modula-2 runtime libraries are loaded (a stripped down M2RTS, SYSTEM and libc).

-flibs=iso

modifies the default library search path so that the ISO libraries are searched before any others (not needed if `-fiso' was specified).

-flibs=logitech

modifies the default library search path so that the Logitech compatible libraries are searched before the base PIM libraries.

-flibs=pim-coroutine

modifies the default libraries search path so that the PIM SYSTEM module providing coroutine support is searched before the base PIM libraries. This directory also includes many coroutine related libraries.

-fextended-opaque

allows opaque types to be implemented as any type. This is a GNU Modula-2 extension and it requires that the implementation module defining the opaque type is available so that it can be resolved when compiling the module which imports the opaque type.

-fsources

displays the path to the source of each module.

-fdef=

recognise the specified suffix as a definition module filename. The default implmentation and module filename suffix is `.def'. If this option is used GNU Modula-2 will still fall back to this default if a requested definition module is not found.

-fmod=

recognise the specified suffix as implementation and module filenames. The default implmentation and module filename suffix is `.mod'. If this option is used GNU Modula-2 will still fall back to this default if it needs to read an implmentation module and the specified suffixed filename does not exist. Both this option and -fdef= also work with the -fmakeall option.

-fxcode

issues all errors and warnings in the `Xcode' format.

-funbounded-by-reference

enable optimization of unbounded parameters by attempting to pass non VAR unbounded parameters by reference. This optimization avoids the implicit copy inside the callee procedure. GNU Modula-2 will only allow unbounded parameters to be passed by reference if, inside the callee procedure, they are not written to, no address is calculated on the array and it is not passed as a VAR parameter. Note that it is possible to write code to break this optimization, therefore this option should be used carefully. For example it would be possible to take the address of an array, pass the address and the array to a procedure, read from the array in the procedure and write to the location using the address parameter.

Due to the dangerous nature of this option it is not enabled when the -O option is specified.

-Wverbose-unbounded

inform the user which non VAR unbounded parameters will be passed by reference. This only produces output if the option `-funbounded-by-reference' is also supplied on the command line.

-Wstudents

checks for bad programming style. This option is aimed at new users of Modula-2 in that it checks for situations which might cause confusion and thus mistakes. It checks whether variables of the same name are declared in different scopes and whether variables look like keywords. Experienced users might find this option too aggressive.

-Wpedantic

forces the compiler to reject nested WITH statements referencing the same record type. Does not allow multiple imports of the same item from a module. It also checks that: procedure variables are written to before being read; variables are not only written to but read from; variables are declared and used. If the compiler encounters a variable being read before written it will terminate with a message. It will check that FOR loop indices are not used outside the end of this loop without being reset.

-Wpedantic-param-names

procedure parameter names are checked in the definition module against their implementation module counterpart. This is not necessary in ISO or PIM versions of Modula-2, but it can be extremely useful, as long as code is intentionally written in this way.

-Wpedantic-cast

warns if the ISO system function is used and if the size of the variable is different from that of the type. This is legal in ISO Modula-2, however it can be dangerous. Some users may prefer to use VAL instead in these situations and use CAST exclusively for changes in type on objects which have the same size.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.5 Example compile and link

This section describes how to compile and link a simple hello world program. It provides a few examples of using the different options mentioned in See (gm2)Compiler options. Assuming that you have a file called `hello.mod' in your current directory which contains:

 
MODULE hello ;

FROM StrIO IMPORT WriteString, WriteLn ;

BEGIN
   WriteString('hello world') ; WriteLn
END hello.

You should be able to compile it by: `gm2 -c -g -I. hello.mod' and link via: `gm2 -g -I. hello.mod'. The result should be an `a.out' file created in your directory.

Alternatively it may be compiled by:

`gm2 -g -I. -fmakeall hello.mod' (1)


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.6 Elementary data types

This section describes the elementary data types supported by GNU Modula-2. It also describes the relationship between these data types and the equivalent C data types.

The following data types are supported: INTEGER, LONGINT, SHORTINT, CARDINAL, LONGCARD, SHORTCARD, BOOLEAN, REAL, LONGREAL, SHORTREAL, and CHAR.

An equivalence table is given below:

 
GNU Modula-2              GNU C
======================================
INTEGER                   int
LONGINT                   long long int
SHORTINT                  short int
CARDINAL                  unsigned int
LONGCARD                  long long unsigned int
SHORTCARD                 short unsigned int
BOOLEAN                   int
REAL                      double
LONGREAL                  long double
SHORTREAL                 float
CHAR                      char

Note that GNU Modula-2 also supports fixed sized data types which are exported from the SYSTEM module. See (gm2)The PIM system module. See (gm2)The ISO system module.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.7 Permanently accessible base procedures.

This section describes the procedures and functions which are always visible.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.7.1 Standard procedures and functions common to PIM and ISO

The following procedures are implemented and conform with Programming in Modula-2 and ISO Modula-2: NEW, DISPOSE, INC, DEC, INCL, EXCL and HALT. The standard functions are: HIGH, CAP, ABS, ODD, VAL, CHR, MIN, MAX. All these functions and procedures (except HALT, NEW, DISPOSE and, under non constant conditions, LENGTH) generate in-line code for efficiency.

 
(*
   NEW - the procedure NEW is replaced by:
         ALLOCATE(p, TSIZE(p^)) ;
         The user is expected to import the procedure ALLOCATE
         (normally found in the module, Storage.)

         In:  a variable p: of any pointer type.
         Out: variable, p, is set to some allocated memory
              which is large enough to hold all the contents of p^.
*)

PROCEDURE NEW (VAR p:<any pointer type>) ;
 
(*
   DISPOSE - the procedure DISPOSE is replaced by:
             DEALLOCATE(p, TSIZE(p^)) ;
             The user is expected to import the procedure DEALLOCATE
             (normally found in the module, Storage.)

             In:  a variable p: of any pointer type which has been
                  initialized by a call to NEW.
             Out: the area of memory
                  holding p^ is returned to the system.
                  Note that the underlying procedure DEALLOCATE
                  procedure in module Storage will assign p to NIL.
*)

PROCEDURE DISPOSE (VAR p:<any pointer type>) ;
 
(*
   INC - can take one or two parameters. If supplied with one
         parameter it adds 1 to the variable, v.
         If two parameters are supplied then the value, a, is
         added to, v.
*)

PROCEDURE INC (VAR v: <any base type>; [a: <any base type> = 1]) ;
 
(*
   DEC - can take one or two parameters. If supplied with one
         parameter it subtracts 1 from the variable, v.
         If two parameters are supplied then the value, a, is
         subtracted from, v.
*)

PROCEDURE DEC (VAR v: <any base type>; [a: <any base type> = 1]) ;
 
(*
   INCL - includes bit element, e, to a set type, s.
*)

PROCEDURE INCL (VAR s: <any set type>; e: <element of set type s>) ;
 
(*
   EXCL - excludes bit element, e, from a set type, s.
*)

PROCEDURE EXCL (VAR s: <any set type>; e: <element of set type s>) ;
 
(*
   HALT - will call the HALT procedure inside the module M2RTS.
          Users can replace M2RTS.
*)

PROCEDURE HALT ;

The following define the standard set of functions which conform with Programming in Modula-2 and ISO Modula-2.

 
(*
   HIGH - returns the last accessible index of an parameter declared as
          ARRAY OF CHAR. Thus

          PROCEDURE foo (a: ARRAY OF CHAR) ;
          VAR
             c: CARDINAL ;
          BEGIN
             c := HIGH(a)
          END foo ;

          BEGIN
             foo('hello')
          END

          will cause the local variable, c, to contain the value 4
*)

PROCEDURE HIGH (a: ARRAY OF CHAR) : CARDINAL ;
 
(*
   CAP - returns the capital of character, ch, providing
         ch lies within the range 'a'..'z'. Otherwise, ch,
         is returned unaltered.
*)

PROCEDURE CAP (ch: CHAR) : CHAR ;

 
(*
   ABS - returns the positive value of, i.
*)

PROCEDURE ABS (i: <any signed type>) : <any signed type> ;

 
(*
   VAL - converts data, i, of <any simple data type 2> to
         <any simple data type 1> and returns this value.
         No range checking is performed during this conversion.
*)

PROCEDURE VAL (<any simple data type 1>,
               i: <any simple data type 2>) : <any simple data type 1> ;

 
(*
   CHR - converts a value of a <whole number type> into a CHAR.
         CHR(x) is shorthand for VAL(CHAR, x).
*)

PROCEDURE CHR (x: <whole number type>) : CHAR ;

 
(*
   ODD - returns TRUE if the value is not divisible by 2.
*)

PROCEDURE ODD (x: <whole number type>) : BOOLEAN ;

 
(*
   MIN - returns the lowest legal value of an ordinal type.
*)

PROCEDURE MIN (t: <ordinal type>) : <ordinal type> ;

 
(*
   MAX - returns the largest legal value of an ordinal type.
*)

PROCEDURE MAX (t: <ordinal type>) : <ordinal type> ;


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.7.2 ISO specific standard procedures and functions

The standard function LENGTH is specific to ISO Modula-2 and is defined as:

 
(*
   LENGTH - returns the length of string, a.
*)

PROCEDURE LENGTH (a: ARRAY OF CHAR) : CARDINAL ;

This function is evaluated at compile time, providing that string a is a constant. If a cannot be evaluated then a call is made to M2RTS.Length.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.8 GNU Modula-2 supported dialects

This section describes the dialects understood by GNU Modula-2. It also describes the differences between the dialects and any command line switches which determine dialect behaviour.

The GNU Modula-2 compiler is based on the language as defined in 'Programming in Modula-2' 2nd Edition, Springer Verlag, 1982, 1983 by Niklaus Wirth (PIM2), 'Programming in Modula-2', 3rd Corrected Edition, Springer Verlag, 1985 (PIM3) and 'Programming in Modula-2', 4th Edition, Springer Verlag, 1988 (PIM4). It also includes ISO M2 features and GNU Modula-2 extensions. Currently GNU Modula-2 (0.63) implements all PIM dialects of the language, eventually GNU Modula-2 will be fully compliant with ISO Modula-2.

The command line switches `-fpim2', `-fpim3', `-fpim4' and `-fiso' can be used to force mutually exclusive features. However by default the compiler will not agressively fail if a non mutually exclusive feature is used from another dialect. For example it is possible to specify `-fpim2' and still utilise `DEFINITION' `MODULES' which have no export list.

Some dialect differences will force a compile time error, for example in PIM2 the user must IMPORT SIZE from the module SYSTEM, whereas in PIM3 and PIM4 SIZE is a pervasive function. Thus compiling PIM4 source code with the `-fpim2' switch will cause a compile time error. This can be fixed quickly with an additional IMPORT or alternatively by compiling with the `-fpim4' switch.

However there are some very important differences between the dialects which are mutually exclusive and therefore it is vital that users choose the dialects with care when these language features are used.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.8.1 Integer division, remainder and modulus

The most dangerous set of mutually exclusive features found in the four dialects supported by GNU Modula-2 are the INTEGER division, remainder and modulus arithmetic operators. It is important to note that the same source code can be compiled to give different runtime results depending upon these switches! The reference manual for the various dialects of Modula-2 are quite clear about this behaviour and sadly there are three distinct definitions.

The table below illustrates the problem when a negative operand is used.

 
                  Pim2/3          Pim4                ISO
               -----------    -----------    ----------------------
lval    rval   DIV     MOD    DIV     MOD    DIV    MOD    /    REM
 31      10      3       1      3       1      3      1     3     1
-31      10     -3      -1     -4       9     -4      9    -3    -1
 31     -10     -3       1     -3       1     Exception    -3     1
-31     -10      3      -1      4       9     Exception     3    -1

See also P24 of PIM2, P27 of PIM3, P29 of PIM4 and P201 of the ISO Standard. At present all dialect division, remainder and modulus are implemented as above, apart from the exception calling in the ISO dialect. Instead of exception handling the results are the same as the PIM4 dialect. This is a temporary implementation situation.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.9 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 (gm2)Compiler options.

Declarations can be made in any order, whether they are types, constants, procedures, nested modules or variables (see See section Passes.)

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 column of the
                                    first token on the line.

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) ;
VAR
   r: INTEGER ;
BEGIN
   r := 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.

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.9.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 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 (gm2)The PIM system module. See (gm2)The ISO system module.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.10 GNU Modula-2 language extensions

This section discuss the issues surrounding assignment, expression and parameter compatibility, their effect of the additional fixed sized datatypes and also their effect of runtime checking. The data types supported by the compiler are:

 
GNU Modula-2              scope      switches
=============================================
INTEGER                   pervasive
LONGINT                   pervasive
SHORTINT                  pervasive
CARDINAL                  pervasive
LONGCARD                  pervasive
SHORTCARD                 pervasive
BOOLEAN                   pervasive
REAL                      pervasive
LONGREAL                  pervasive
SHORTREAL                 pervasive
CHAR                      pervasive

BITSET                    SYSTEM
LOC                       SYSTEM     -fiso
BYTE                      SYSTEM
WORD                      SYSTEM
ADDRESS                   SYSTEM

The following extensions are supported for
most architectures (please check SYSTEM.def).
=============================================
INTEGER8                  SYSTEM
INTEGER16                 SYSTEM
INTEGER32                 SYSTEM
INTEGER64                 SYSTEM
CARDINAL8                 SYSTEM
CARDINAL16                SYSTEM
CARDINAL32                SYSTEM
CARDINAL64                SYSTEM
BITSET8                   SYSTEM
BITSET16                  SYSTEM
BITSET32                  SYSTEM
WORD16                    SYSTEM
WORD32                    SYSTEM
WORD64                    SYSTEM
REAL32                    SYSTEM
REAL64                    SYSTEM
REAL96                    SYSTEM
REAL128                   SYSTEM

The compiler categorises compatibility between all these types into three components: assignment, parameter and expression.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.10.1 Assignment compatibility

This section discusses the assignment issues surrounding assignment compatibility of fundamental types. Obviously compatibility exists between the same sized types. Same type family of different sizes are also compatible as long as the MAX(type) and MIN(type) is known. So for example this includes the INTEGER family, CARDINAL family and the REAL family. The reason for this is that when the assignment is performed the compiler will check to see that the expression (on the right of the :=) lies within the bounds of the designator type (on the left hand side of the :=). Thus these ordinal types can be assignment compatible. However it does mean that WORD32 is not compatible with WORD16 as WORD32 does not have a minimum or maximum value and therefore cannot be checked. The compiler does not know which of the two bytes from WORD32 should be copied into WORD16 and which two should be ignored. Currently the types BITSET8, BITSET16 and BITSET32 are assignment incompatible. However this restriction maybe lifted when further runtime checking is achieved.

Modula-2 does allow INTEGER to be assignment compatible with WORD as they are the same size. Likewise GNU Modula-2 allows INTEGER16 to be compatible with WORD16 and the same for the other fixed sized types and their sized equivalent in either WORDn, BYTE or LOC types. However it prohibits assignment between WORD and WORD32 even though on many systems these sizes will be the same. The reasoning behind this rule is that the extended fixed sized types are meant to be used by applications requiring fixed sized data types and it is more portable to forbid the bluring of the boundaries between fixed sized and machine dependant sized types.

Intemediate code runtime checking is always generated by the front end. However this intemediate code is only translated into actual code if the appropriate command line switches are specified. This allows the compiler to perform limited range checking at compile time. In the future it will allow the extensive GCC optimisations to propagate constant values through to the range checks which if they are found to exceed the type bounds will result in a compile time error message.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.10.2 Expression compatibility

According to the various Modula-2 standards INTEGER and CARDINAL types are not expression compatible (http://freepages.modula2.org/report4/modula-2.html and ISO Modula-2). This is rule is also extended across the fixed sized data types.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.10.3 Parameter compatibility

Parameter compatibility is divided into two arenas, pass by value and pass by reference (VAR). In the case of pass by value the rules are exactly the same as assignment. However in the second case, pass by reference, the actual parameter and formal parameter must be the same size and family. Furthermore INTEGER and CARDINALs are not treated as compatible in the pass by reference case.

The types BYTE, LOC and WORD and sized their derivitives are assignment and parameter compatible with any data type of the same size.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.11 Unbounded by reference

This section documents a GNU Modula-2 compiler switch which implements a language optimisation surrounding the implementation of unbounded arrays. In GNU Modula-2 the unbounded array is implemented by utilising an internal structure struct {dataType *address, unsigned int high}. So given the Modula-2 procedure declaration:

 
PROCEDURE foo (VAR a: ARRAY OF dataType) ;
BEGIN
   IF a[2]= (* etc *)
END foo ;

it is translated into GCC trees, which can be represented in their C form thus:

 
void foo (struct {dataType *address, unsigned int high} a)
{
   if (a.address[2] == /* etc */
}

Whereas if the procedure foo was declared as:

 
PROCEDURE foo (a: ARRAY OF dataType) ;
BEGIN
   IF a[2]= (* etc *)
END foo ;

then it is implemented by being translated into the following GCC trees, which can be represented in their C form thus:

 
void foo (struct {dataType *address, unsigned int high} a)
{
   dataType *copyContents = (dataType *)alloca (a.high+1);
   memcpy(copyContents, a.address, a.high+1);
   a.address = copyContents;

   if (a.address[2] == /* etc */
}

This implementation works, but it makes a copy of each non VAR unbounded array when a procedure is entered. If the unbounded array is not changed during procedure foo then this implementation will be very inefficient. In effect Modula-2 lacks the REF keyword of Ada. Consequently the programmer maybe tempted to sacrifice semantic clarity for greater efficiency by declaring the parameter using the VAR keyword in place of REF.

The -funbounded-by-reference switch instructs the compiler to check and see if the programmer is modifying the content of any unbounded array. If it is modified then a copy will be made upon entry into the procedure. Conversely if the content is only read and never modified then this non VAR unbounded array is a candidate for being passed by reference. It is only a candidate as it is still possible that passing this parameter by reference could alter the meaning of the source code. For example consider the following case:

 
PROCEDURE StrConCat (VAR a: ARRAY OF CHAR; b, c: ARRAY OF CHAR) ;
BEGIN
   (* code which performs string a := b + c *)
END StrConCat ;

PROCEDURE foo ;
VAR
   a: ARRAY [0..3] OF CHAR ;
BEGIN
   a := 'q' ;
   StrConCat(a, a, a)
END foo ;

In the code above we see that the same parameter, a, is being passed three times to StrConCat. Clearly even though parameters b and c are never modified it would be incorrect to implement them as pass by reference. Therefore the compiler checks to see if any non VAR parameter is type compatible with any VAR parameter and if so it generates runtime procedure entry checks to determine whether the contents of parameters b or c matches the contents of a. If a match is detected then a copy is made and the address in the unbounded structure is modified.

The compiler will check the address range of each candidate against the address range of any VAR parameter, providing they are type compatible. For example consider:

 
PROCEDURE foo (a: ARRAY OF BYTE; VAR f: REAL) ;
BEGIN
   f := 3.14 ;
   IF a[0]=BYTE(0)
   THEN
      (* etc *)
   END
END foo ;

PROCEDURE bar ;
BEGIN
   r := 2.0 ;
   foo(r, r)
END bar ;

Here we see that although parameter, a, is a candidate for the passing by reference, it would be incorrect to use this transformation. Thus the compiler detects that parameters, a and f are type compatible and will produce runtime checking code to test whether the address range of their respective contents intersect.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.12 Interfacing GNU Modula-2 to C

The GNU Modula-2 compiler tries to use the C calling convention wherever possible however some parameters have no C equivalent and thus a language specific method is used. For example unbounded arrays are passed as a struct {void *address, unsigned int high} and the contents of these arrays are copied by callee functions when they are declared as non VAR parameters. The VAR equivalent unbounded array parameters need no copy, but still use the struct representation.

The recommended method of interfacing GNU Modula-2 to C is by telling the definition module that the implementation is in the C language. This is achieved by using the tokens DEFINITION MODULE FOR "C". Here is an example which can be found in the source tree `gcc-version/gcc/gm2/examples/callingC/libprintf.def'

 
DEFINITION MODULE FOR "C" libprintf ;

EXPORT UNQUALIFIED printf ;

PROCEDURE printf (a: ARRAY OF CHAR; ...) ;

END libprintf.

the UNQUALIFIED keyword in the definition module informs GNU Modula-2 not to prefix the module name to exported references in the object file.

The printf declaration states that the first parameter semantically matches ARRAY OF CHAR but since the module is for the C language it will be mapped onto char *. The token ... indicates a variable number of arguments (varargs) and all parameters passed here are mapped onto their C equivalents. Arrays and constant strings are passed as pointers.

The hello world program can be rewritten as:

 
MODULE hello ;

FROM libprintf IMPORT printf ;

BEGIN
   printf("hello world\n")
END hello.

and it can be compiled by:

`gm2 -fmakeall -g -I. hello.mod -lc'

In reality the `-lc' is redundant as libc is always included in the linking process. It is shown here to emphasize that the C library or object file containing printf must be present.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.13 Semi-automatic translation of C header files

The tool `h2def' can be used to semi-automatically generate DEFINITION MODULE FOR "C" modules. The tool takes as input a C header file and generates as output a corresponding textual definition module. While the tool will not automatically translate complex C header files it will generate definition modules for simple header files.

For example consider the following excerpt from the header file (`vga.h'):

 
/* blit flags */
#define HAVE_BITBLIT 1
#define HAVE_FILLBLIT 2
#define HAVE_IMAGEBLIT 4
#define HAVE_HLINELISTBLIT 8
#define HAVE_BLITWAIT 16

    typedef struct {
	int width;
	int height;
	int bytesperpixel;
	int colors;
	int linewidth;		/* scanline width in bytes */
	int maxlogicalwidth;	/* maximum logical scanline width */
	int startaddressrange;	/* changeable bits set */
	int maxpixels;		/* video memory / bytesperpixel */
	int haveblit;		/* mask of blit functions available */
	int flags;		/* other flags */

	/* Extended fields: */

	int chiptype;		/* Chiptype detected */
	int memory;		/* videomemory in KB */
	int linewidth_unit;	/* Use only a multiple of this as parameter for set_logicalwidth and
				   set_displaystart */
	char *linear_aperture;	/* points to mmap secondary mem aperture of card (NULL if unavailable) */
	int aperture_size;	/* size of aperture in KB if size>=videomemory. 0 if unavail */
	void (*set_aperture_page) (int page);
	/* if aperture_size<videomemory select a memory page */
	void *extensions;	/* points to copy of eeprom for mach32 */
	/* depends from actual driver/chiptype.. etc. */
    } vga_modeinfo;

    extern vga_modeinfo *vga_getmodeinfo(int mode);
    extern int vga_getdefaultmode(void);
    extern int vga_getcurrentmode(void);
    extern int vga_getcurrentchipset(void);
    extern char *vga_getmodename(int mode);

Using the following command line h2def vga.h will generate the module below:

 
DEFINITION MODULE FOR "C" vga ;

CONST
     HAVE_BITBLIT =  1 ;
     HAVE_FILLBLIT =  2 ;
     HAVE_IMAGEBLIT =  4 ;
     HAVE_HLINELISTBLIT =  8 ;
     HAVE_BLITWAIT =  16 ;

TYPE
     vga_modeinfo =   RECORD
                         width: INTEGER ;
                         height: INTEGER ;
                         bytesperpixel: INTEGER ;
                         colors: INTEGER ;
                         linewidth: INTEGER ;
                         maxlogicalwidth: INTEGER ;
                         startaddressrange: INTEGER ;
                         maxpixels: INTEGER ;
                         haveblit: INTEGER ;
                         flags: INTEGER ;
                         chiptype: INTEGER ;
                         memory: INTEGER ;
                         linewidth_unit: INTEGER ;
                         linear_aperture: POINTER TO CHAR ;
                         aperture_size: INTEGER ;
                         set_aperture_page:  PROCEDURE (INTEGER) ;
                         extensions: ADDRESS ;
                      END ;
    
 PROCEDURE vga_getmodeinfo (mode: INTEGER) : ADDRESS ;
 PROCEDURE vga_getdefaultmode () : INTEGER ;
 PROCEDURE vga_getcurrentmode () : INTEGER ;
 PROCEDURE vga_getcurrentchipset () : INTEGER ;
 PROCEDURE vga_getmodename (mode: INTEGER) : ADDRESS ;

END vga.

The main limitation of h2def is in the preprocessing handling. It does not understand the C preprocessor token constructor directives # and ##. Also it will not combine successive string tokens.

Support for the #define mechanism is limited. Initially the macro is parsed to check whether it is a constant expression. If it fails it is reassigned as a macro definition. A macro which contains C statement code cannot be translated into a definition module. These macros and all dependents are poisoned and are not translated. At present it does not understand macros with arguments.

The `-I' option to h2def allows include directories to be specified and the `-C' option states that a macro definition must be computed at compile time. For example consider the following header file called ifdef.h:

 
#if !defined(FOOBAR)
# define FOOBAR
# define MAXIMUM 1000
#else
# define MAXIMUM 2000
#endif

which if processed by h2def -CFOOBAR ifdef.h yields the following code:

 
DEFINITION MODULE FOR "C" ifdef ;

# if (!(defined(FOOBAR)))
CONST
   MAXIMUM = 1000 ;
# else
   MAXIMUM = 2000 ;
# endif
     
END ifdef.

The `-a' option provides a method whereby the C parameter construct sometype *foo is translated in Modula-2 as foo: ARRAY OF sometype.

Normally output for h2def will require some manual intervention. Some header files need more help than others, for example the GNU/Linux svga header file vga.h requires a little help whereas the GNU pthread file pthread.h requires more. Nevertheless the effort required is considerably less than writing the modules by hand.

The `-e' option will emit an error message if a C syntax error is encountered. The `-p' option generate a comment for every occurance of an object which cannot be translated into Modula-2.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.14 Interface to assembly language

The interface for GNU Modula-2 to assembly language is almost identical to GNU C. The only alterations are that the keywords asm and volatile are in capitals, following the Modula-2 convention.

A simple, but highly non optimal, example is given below. Here we want to add the two CARDINALs foo and bar together and return the result.

 
PROCEDURE Example (foo, bar: CARDINAL) : CARDINAL ;
VAR
   myout: CARDINAL ;
BEGIN
   ASM VOLATILE ("movl %1,%%eax; addl %2,%%eax; movl %%eax,%0"
      : "=g" (myout)           (* outputs *)
      : "g" (foo), "g" (bar)   (* inputs  *)
      : "eax") ;               (* we trash *)
   RETURN( myout )
END Example ;

For a full description of this interface we refer the reader to the GNU C manual.

See (gcc)Extended Asm.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.15 Accessing GNU Modula-2 Built-ins

This section describes the built-in constants and functions defined in GNU Modula-2. The following compiler constants can be accessed using the __ATTRIBUTE__ __BUILTIN__ keywords. These are not part of the Modula-2 language and they may differ depending upon the target architecture but they provide a method whereby common libraries can interface to a different underlying architecture.

The built-in constants are: BITS_PER_UNIT, BITS_PER_WORD, BITS_PER_CHAR and UNITS_PER_WORD. They are integrated into GNU Modula-2 by an extension to the ConstFactor rule:

 
ConstFactor := ConstQualidentOrSet | Number | ConstString |
               "(" ConstExpression ")" | "NOT" ConstFactor |
               ConstAttribute =:

ConstAttribute := "__ATTRIBUTE__" "__BUILTIN__" "(" "(" Ident ")" ")" =:

Here is an example taken from the ISO library SYSTEM.def:

 
CONST
   BITSPERLOC    = __ATTRIBUTE__ __BUILTIN__ ((BITS_PER_UNIT)) ;
   LOCSPERWORD   = __ATTRIBUTE__ __BUILTIN__ ((UNITS_PER_WORD)) ;

Built-in functions are transparent to the end user. All built-in functions are declared in DEFINITION MODULEs and are imported as and when required. Built-in functions are declared in definition modules by using the __BUILTIN__ keyword. Here is a section of the ISO library LongMath.def which demonstrates this feature.

 
PROCEDURE __BUILTIN__ sqrt (x: LONGREAL): LONGREAL;
  (* Returns the square root of x *)

This indicates that the function sqrt will be implemented using the gcc built-in maths library. If gcc cannot utilise the built-in function (for example if the programmer requested the address of sqrt) then code is generated to call the alternative function implemented in the IMPLEMENTATION MODULE.

Sometimes a function exported from the DEFINITION MODULE will have a different name from the built-in function within gcc. In such cases the mapping between the GNU Modula-2 function name and the gcc name is expressed using the keywords __ATTRIBUTE__ __BUILTIN__ ((Ident)). For example the function sqrt in LongMath.def maps onto the gcc built-in function sqrtl and this is expressed as:

 
PROCEDURE __ATTRIBUTE__ __BUILTIN__ ((sqrtl)) sqrt
                                    (x: LONGREAL) : LONGREAL;
  (* Returns the positive square root of x *)

The following module Builtins.def enumerates the list of built-in functions which can be accessed in GNU Modula-2. It also serves to define the parameter and return value for each function:

 
DEFINITION MODULE Builtins ;

(*
    Description: provides a convenient place to list all the GNU Modula-2
                 built-in functions. These functions should be copied into
                 more generic modules.

                 For example the mathematical functions can be applied to
                 gm2-iso/LongMath. But each built-in function is here for
                 reference.
*)

FROM SYSTEM IMPORT ADDRESS ;

PROCEDURE __BUILTIN__ sinf (x: SHORTREAL) : SHORTREAL ;
PROCEDURE __BUILTIN__ sin (x: REAL) : REAL ;
PROCEDURE __BUILTIN__ sinl (x: LONGREAL) : LONGREAL ;

PROCEDURE __BUILTIN__ cosf (x: SHORTREAL) : SHORTREAL ;
PROCEDURE __BUILTIN__ cos (x: REAL) : REAL ;
PROCEDURE __BUILTIN__ cosl (x: LONGREAL) : LONGREAL ;

PROCEDURE __BUILTIN__ sqrtf (x: SHORTREAL) : SHORTREAL ;
PROCEDURE __BUILTIN__ sqrt (x: REAL) : REAL ;
PROCEDURE __BUILTIN__ sqrtl (x: LONGREAL) : LONGREAL ;

PROCEDURE __BUILTIN__ fabsf (x: SHORTREAL) : SHORTREAL ;
PROCEDURE __BUILTIN__ fabs (x: REAL) : REAL ;
PROCEDURE __BUILTIN__ fabsl (x: LONGREAL) : LONGREAL ;

PROCEDURE __BUILTIN__ logf (x: SHORTREAL) : SHORTREAL ;
PROCEDURE __BUILTIN__ log (x: REAL) : REAL ;
PROCEDURE __BUILTIN__ logl (x: LONGREAL) : LONGREAL ;

PROCEDURE __BUILTIN__ expf (x: SHORTREAL) : SHORTREAL ;
PROCEDURE __BUILTIN__ exp (x: REAL) : REAL ;
PROCEDURE __BUILTIN__ expl (x: LONGREAL) : LONGREAL ;

PROCEDURE __BUILTIN__ alloca (i: CARDINAL) : ADDRESS ;
PROCEDURE __BUILTIN__ memcpy (dest, src: ADDRESS; n: CARDINAL) : ADDRESS ;
PROCEDURE __BUILTIN__ index (s: ADDRESS; c: INTEGER) : ADDRESS ;
PROCEDURE __BUILTIN__ rindex (s: ADDRESS; c: INTEGER) : ADDRESS ;
PROCEDURE __BUILTIN__ memcmp (s1, s2: ADDRESS; n: CARDINAL) : INTEGER ;
PROCEDURE __BUILTIN__ memset (s: ADDRESS; c: INTEGER; n: CARDINAL) : ADDRESS ;
PROCEDURE __BUILTIN__ memmove (s1, s2: ADDRESS; n: CARDINAL) : ADDRESS ;
PROCEDURE __BUILTIN__ strcat (dest, src: ADDRESS) : ADDRESS ;
PROCEDURE __BUILTIN__ strncat (dest, src: ADDRESS; n: CARDINAL) : ADDRESS ;
PROCEDURE __BUILTIN__ strcpy (dest, src: ADDRESS) : ADDRESS ;
PROCEDURE __BUILTIN__ strncpy (dest, src: ADDRESS; n: CARDINAL) : ADDRESS ;
PROCEDURE __BUILTIN__ strcmp (s1, s2: ADDRESS) : INTEGER ;
PROCEDURE __BUILTIN__ strncmp (s1, s2: ADDRESS; n: CARDINAL) : INTEGER ;
PROCEDURE __BUILTIN__ strlen (s: ADDRESS) : INTEGER ;
PROCEDURE __BUILTIN__ strstr (haystack, needle: ADDRESS) : ADDRESS ;
PROCEDURE __BUILTIN__ strpbrk (s, accept: ADDRESS) : ADDRESS ;
PROCEDURE __BUILTIN__ strspn (s, accept: ADDRESS) : CARDINAL ;
PROCEDURE __BUILTIN__ strcspn (s, accept: ADDRESS) : CARDINAL ;
PROCEDURE __BUILTIN__ strchr (s: ADDRESS; c: INTEGER) : ADDRESS ;
PROCEDURE __BUILTIN__ strrchr (s: ADDRESS; c: INTEGER) : ADDRESS ;

PROCEDURE __BUILTIN__ huge_val (r: REAL) : REAL ;
PROCEDURE __BUILTIN__ huge_valf (s: SHORTREAL) : SHORTREAL ;
PROCEDURE __BUILTIN__ huge_vall (l: LONGREAL) : LONGREAL ;

END Builtins.

Although this module exists and will result in the generation of in-line code if optimization flags are passed to GNU Modula-2, users are advised to utilize the same functions from more generic libraries. The built-in mechanism will be applied to these generic libraries where appropriate. Note for the mathematical routines to be in-lined you need to specify the `-ffast-math -O' options.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.16 The PIM system module

 
DEFINITION MODULE SYSTEM ;

(*
   Description: Implements the SYSTEM dependent module
                in the Modula-2 compiler.
*)

EXPORT QUALIFIED BITSPERBYTE, BYTESPERWORD,
                 LOC, WORD, BYTE, ADDRESS, BITSET,
                 INTEGER8, INTEGER16, INTEGER32, INTEGER64,
                 CARDINAL8, CARDINAL16, CARDINAL32, CARDINAL64,
                 WORD16, WORD32, WORD64, BITSET8,
                 BITSET16, BITSET32, REAL32, REAL64,
                 REAL96, REAL128,
                 ADR, TSIZE, SIZE, ROTATE, SHIFT ;

CONST
  BITSPERBYTE   = __ATTRIBUTE__ __BUILTIN__ ((BITS_PER_UNIT)) ;
  BYTESPERWORD  = __ATTRIBUTE__ __BUILTIN__ ((UNITS_PER_WORD)) ;


(* all the following types are declared internally to gm2
TYPE
   LOC ;
   WORD ;
   BYTE ;
   ADDRESS ;
   BITSET ;
   INTEGER8 ;
   INTEGER16 ;
   INTEGER32 ;
   INTEGER64 ;
   CARDINAL8 ;
   CARDINAL16 ;
   CARDINAL32 ;
   CARDINAL64 ;
   WORD16 ;
   WORD32 ;
   WORD64 ;
   BITSET8 ;
   BITSET16 ;
   BITSET32 ;
   REAL32 ;
   REAL64 ;
   REAL96 ;
   REAL128 ;
*)


(*
   all the functions below are declared internally to gm2
   ====================================================

PROCEDURE ADR (VAR v: <anytype>): ADDRESS;
  (* Returns the address of variable v. *)

PROCEDURE SIZE (v: <type>) : CARDINAL;
  (* Returns the number of BYTES used to store a v of
     any specified <type>.
  *)

PROCEDURE TSIZE (<type>) : CARDINAL;
  (* Returns the number of BYTES used to store a value of the
     specified <type>.
  *)

PROCEDURE ROTATE (val: <a set type>;
                  num: INTEGER): <type of first parameter>;
  (* Returns a bit sequence obtained from val by rotating up or down
     (left or right) by the absolute value of num.  The direction is
     down if the sign of num is negative, otherwise the direction is up.
  *)

PROCEDURE SHIFT (val: <a set type>;
                 num: INTEGER): <type of first parameter>;
  (* Returns a bit sequence obtained from val by shifting up or down
     (left or right) by the absolute value of num, introducing
     zeros as necessary.  The direction is down if the sign of
     num is negative, otherwise the direction is up.
  *)
*)

(* The following procedures are invoked by GNU Modula-2 to
   shift non word sized set types. They are not strictly part
   of the core PIM Modula-2, however they are used by
   GNU Modula-2 to implement the SHIFT procedure defined above,
   which are in turn used by the Logitech compatible libraries.
   In any event users may find them useful.
*)

(*
   ShiftVal - is a runtime procedure whose job is to implement
              the SHIFT procedure of ISO SYSTEM. GNU Modula-2 will
              inline a SHIFT of a single WORD sized set and will only
              call this routine for larger sets.
*)

PROCEDURE ShiftVal (VAR s, d: ARRAY OF BITSET;
                    SetSizeInBits: CARDINAL;
                    ShiftCount: INTEGER) ;


(*
   ShiftLeft - performs the shift left for a multi word set.
               This procedure might be called by the back end of
               GNU Modula-2 depending whether amount is known at compile
               time.
*)

PROCEDURE ShiftLeft (VAR s, d: ARRAY OF BITSET;
                     SetSizeInBits: CARDINAL;
                     ShiftCount: CARDINAL) ;

(*
   ShiftRight - performs the shift left for a multi word set.
                This procedure might be called by the back end of
                GNU Modula-2 depending whether amount is known at compile
                time.
*)

PROCEDURE ShiftRight (VAR s, d: ARRAY OF BITSET;
                     SetSizeInBits: CARDINAL;
                     ShiftCount: CARDINAL) ;


(*
   RotateVal - is a runtime procedure whose job is to implement
               the ROTATE procedure of ISO SYSTEM. GNU Modula-2 will
               inline a ROTATE of a single WORD (or less)
               sized set and will only call this routine for larger sets.
*)

PROCEDURE RotateVal (VAR s, d: ARRAY OF BITSET;
                     SetSizeInBits: CARDINAL;
                     RotateCount: INTEGER) ;


(*
   RotateLeft - performs the rotate left for a multi word set.
                This procedure might be called by the back end of
                GNU Modula-2 depending whether amount is known at compile
                time.
*)

PROCEDURE RotateLeft (VAR s, d: ARRAY OF BITSET;
                      SetSizeInBits: CARDINAL;
                      RotateCount: CARDINAL) ;


(*
   RotateRight - performs the rotate right for a multi word set.
                 This procedure might be called by the back end of
                 GNU Modula-2 depending whether amount is known at compile
                 time.
*)

PROCEDURE RotateRight (VAR s, d: ARRAY OF BITSET;
                       SetSizeInBits: CARDINAL;
                       RotateCount: CARDINAL) ;


END SYSTEM.

The different dialects of Modula-2 PIM-[234] and ISO Modula-2 declare the function SIZE in different places. PIM-[34] and ISO Modula-2 declare SIZE as a pervasive function (declared in the base module). PIM-2 defined SIZE in the SYSTEM module (as shown above).

GNU Modula-2 allows users to specify the dialect of Modula-2 by using the -fiso and -fpim2 command line switches.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.17 The ISO system module

 
DEFINITION MODULE SYSTEM;

  (* Gives access to system programming facilities that are probably
     non portable. *)

  (* The constants and types define underlying properties of storage *)

EXPORT QUALIFIED BITSPERLOC, LOCSPERWORD,
                 LOC, ADDRESS, BYTE, WORD, INTEGER8,
                 INTEGER16, INTEGER32, INTEGER64, CARDINAL8,
                 CARDINAL16, CARDINAL32, CARDINAL64, WORD16,
                 WORD32, WORD64, BITSET8, BITSET16,
                 BITSET32, REAL32, REAL64, REAL96,
                 REAL128,
                 ADDADR, SUBADR, DIFADR, MAKEADR, ADR, ROTATE,
                 SHIFT, CAST, TSIZE,

                 (* Internal GM2 compiler functions *)
                 ShiftVal, ShiftLeft, ShiftRight,
                 RotateVal, RotateLeft, RotateRight ;

CONST
                  (* <implementation-defined constant> ; *)
  BITSPERLOC    = __ATTRIBUTE__ __BUILTIN__ ((BITS_PER_UNIT)) ;
                  (* <implementation-defined constant> ; *)
  LOCSPERWORD   = __ATTRIBUTE__ __BUILTIN__ ((UNITS_PER_WORD)) ;
                  (* <implementation-defined constant> ; *)
  LOCSPERBYTE = 8 DIV BITSPERLOC ;

(*
   all the objects below are declared internally to gm2
   ====================================================

TYPE
   LOC ;
   ADDRESS ;
   BYTE ;
   WORD ;
   INTEGER8 ;
   INTEGER16 ;
   INTEGER32 ;
   INTEGER64 ;
   CARDINAL8 ;
   CARDINAL16 ;
   CARDINAL32 ;
   CARDINAL64 ;
   WORD16 ;
   WORD32 ;
   WORD64 ;
   BITSET8 ;
   BITSET16 ;
   BITSET32 ;
   REAL32 ;
   REAL64 ;
   REAL96 ;
   REAL128 ;

TYPE
  LOC; (* A system basic type. Values are the uninterpreted
          contents of the smallest addressable unit of storage *)
  ADDRESS = POINTER TO LOC;
  WORD = ARRAY [0 .. LOCSPERWORD-1] OF LOC;

  (* BYTE and LOCSPERBYTE are provided if appropriate for machine *)

TYPE
  BYTE = ARRAY [0 .. LOCSPERBYTE-1] OF LOC;

PROCEDURE ADDADR (addr: ADDRESS; offset: CARDINAL): ADDRESS;
  (* Returns address given by (addr + offset), or may raise
     an exception if this address is not valid.
  *)

PROCEDURE SUBADR (addr: ADDRESS; offset: CARDINAL): ADDRESS;
  (* Returns address given by (addr - offset), or may raise an
     exception if this address is not valid.
  *)

PROCEDURE DIFADR (addr1, addr2: ADDRESS): INTEGER;
  (* Returns the difference between addresses (addr1 - addr2),
     or may raise an exception if the arguments are invalid
     or address space is non-contiguous.
  *)

PROCEDURE MAKEADR (high: <some type>; ...): ADDRESS;
  (* Returns an address constructed from a list of values whose
     types are implementation-defined, or may raise an
     exception if this address is not valid.

     In GNU Modula-2, MAKEADR can take any number of arguments
     which are mapped onto the type ADDRESS. The first parameter
     maps onto the high address bits and subsequent parameters map
     onto lower address bits. For example:

     a := MAKEADR(BYTE(0FEH), BYTE(0DCH), BYTE(0BAH), BYTE(098H),
                  BYTE(076H), BYTE(054H), BYTE(032H), BYTE(010H)) ;

     then the value of, a, on a 64 bit machine is: 0FEDCBA9876543210H

     The parameters do not have to have the same type, but constants
     _must_ be typed.
  *)

PROCEDURE ADR (VAR v: <anytype>): ADDRESS;
  (* Returns the address of variable v. *)

PROCEDURE ROTATE (val: <a packedset type>;
                  num: INTEGER): <type of first parameter>;
  (* Returns a bit sequence obtained from val by rotating up or down
     (left or right) by the absolute value of num.  The direction is
     down if the sign of num is negative, otherwise the direction is up.
  *)

PROCEDURE SHIFT (val: <a packedset type>;
                 num: INTEGER): <type of first parameter>;
  (* Returns a bit sequence obtained from val by shifting up or down
     (left or right) by the absolute value of num, introducing
     zeros as necessary.  The direction is down if the sign of
     num is negative, otherwise the direction is up.
  *)

PROCEDURE CAST (<targettype>; val: <anytype>): <targettype>;
  (* CAST is a type transfer function.  Given the expression
     denoted by val, it returns a value of the type <targettype>.
     An invalid value for the target value or a
     physical address alignment problem may raise an exception.
  *)

PROCEDURE TSIZE (<type>; ... ): CARDINAL;
  (* Returns the number of LOCS used to store a value of the
     specified <type>.   The extra parameters, if present,
     are used to distinguish variants in a variant record.
  *)
*)


(* The following procedures are invoked by GNU Modula-2 to
   shift non word set types. They are not part of ISO Modula-2
   but are used by GNU Modula-2 to implement the SHIFT procedure
   defined above. *)

(*
   ShiftVal - is a runtime procedure whose job is to implement
              the SHIFT procedure of ISO SYSTEM. GNU Modula-2 will
              inline a SHIFT of a single WORD sized set and will only
              call this routine for larger sets.
*)

PROCEDURE ShiftVal (VAR s, d: ARRAY OF BITSET;
                    SetSizeInBits: CARDINAL;
                    ShiftCount: INTEGER) ;


(*
   ShiftLeft - performs the shift left for a multi word set.
               This procedure might be called by the back end of
               GNU Modula-2 depending whether amount is known at compile
               time.
*)

PROCEDURE ShiftLeft (VAR s, d: ARRAY OF BITSET;
                     SetSizeInBits: CARDINAL;
                     ShiftCount: CARDINAL) ;

(*
   ShiftRight - performs the shift left for a multi word set.
                This procedure might be called by the back end of
                GNU Modula-2 depending whether amount is known at compile
                time.
*)

PROCEDURE ShiftRight (VAR s, d: ARRAY OF BITSET;
                     SetSizeInBits: CARDINAL;
                     ShiftCount: CARDINAL) ;


(*
   RotateVal - is a runtime procedure whose job is to implement
               the ROTATE procedure of ISO SYSTEM. GNU Modula-2 will
               inline a ROTATE of a single WORD (or less)
               sized set and will only call this routine for larger sets.
*)

PROCEDURE RotateVal (VAR s, d: ARRAY OF BITSET;
                     SetSizeInBits: CARDINAL;
                     RotateCount: INTEGER) ;


(*
   RotateLeft - performs the rotate left for a multi word set.
                This procedure might be called by the back end of
                GNU Modula-2 depending whether amount is known at compile
                time.
*)

PROCEDURE RotateLeft (VAR s, d: ARRAY OF BITSET;
                      SetSizeInBits: CARDINAL;
                      RotateCount: CARDINAL) ;


(*
   RotateRight - performs the rotate right for a multi word set.
                 This procedure might be called by the back end of
                 GNU Modula-2 depending whether amount is known at compile
                 time.
*)

PROCEDURE RotateRight (VAR s, d: ARRAY OF BITSET;
                       SetSizeInBits: CARDINAL;
                       RotateCount: CARDINAL) ;


END SYSTEM.

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2. Obtaining GNU Modula-2.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.1 Warning

This code is currently in development and it is not yet complete. Nevertheless the compiler is sufficiently stable to support itself on Debian GNU/Linux x86 systems. The PIM libraries are complete but the ISO libraries and ISO language features are still in development. Patches and development volunteers highly welcome! See section Contributing to GNU Modula-2.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.2 Getting GNU Modula-2

The easiest way to obtain GNU Modula-2 is to install i386, amd64 or ppc64 Debian GNU/Linux and then add these repository descriptions to your `/etc/apt/sources.list' file.

 
#
#  GNU Modula-2 repo
#

deb http://floppsie.comp.glam.ac.uk/debian/ etch main non-free contrib
deb-src http://floppsie.comp.glam.ac.uk/debian/ etch main non-free contrib

Now as root type:

 
$ apt-get update
$ apt-get install gm2-doc gm2

As a normal user you can obtain the source code via:

 
$ apt-get source gm2

If you are not running Debian GNU/Linux then you can either download the source tarball and build it manually or checkout the latest sources using CVS and combine them with the appropriate gcc tarball and then finally build it manually.

Combined GNU Modula-2 and patched GCC tarballs exist at http://floppsie.comp.glam.ac.uk/pub/c. Search for files which look like `gm2+gcc-version.tar.gz'. For example you should be able to download the latest version of GNU Modula-2 and GCC using these commands.

 
$ wget http://floppsie.comp.glam.ac.uk/download/c/gcc-4.1.2+gm2-cvs-latest.tar.gz
$ tar zxf gcc-4.1.2+gm2-cvs-latest.tar.gz

On a GNU/Linux system you should also be able to build it using these commands. The following commands assume your shell is `/bin/bash'. To build GNU Modula-2 type:

 
$ mkdir -p $HOME/opt
$ mkdir -p build-4.1.2
$ cd build-4.1.2
$ ../gcc-4.1.2+gm2-cvs-latest/configure --enable-languages=c,gm2 \
     --disable-multilib --enable-checking=all --prefix=$HOME/opt
$ make

To install GNU Modula-2, after a successful build, type:

 
$ make install
$ cd ..

Now you should be able to perform:

 
$ export PATH=$HOME/opt/bin:$PATH
$ cd gcc-4.1.2/gcc/gm2/examples/hello
$ make

which will create an `a.out' for the infamous hello world example.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.3 Development sources via CVS

Development sources can be downloaded via CVS but they must be grafted carefully onto an existing GCC release. The notes in this section document how this is achieved, however a prepared CVS and GCC release is available here http://floppsie.comp.glam.ac.uk/download/c/gcc-4.1.2+gm2-cvs-latest.tar.gz and it is created each night.

If you want to obtain the latest sources via CVS then type the following:

 
$ cvs -z3 -d:pserver:anoncvs@cvs.sv.gnu.org:/sources/gm2 co gm2

This will checkout a copy of GNU Modula-2 into one subdirectory, `gm2'. This version of GNU Modula-2 needs to be placed inside the GCC source tree in the position gcc-4.1.2/gcc before GNU Modula-2 can be built. Please check the GNU Modula-2 homepage http://www.nongnu.org/gm2 for details about which GCC releases are supported by GNU Modula-2.

Once you have downloaded the correct GCC release from http://gcc.gnu.org or a mirror site you should unpack the GCC archive. Assuming that both the `gcc-4.1.2' and `gm2' dicectories are at the same level, you can graft `gm2' onto `gcc-4.1.2' by:

 
$ mv gm2 gcc-4.1.2/gcc

If the directory `gcc-4.1.2/gcc/gm2/patches/gcc/4.1.2' exists then the patch files inside that directory can be applied to the `gcc-4.1.2' tree. This is done via:

 
$ cd gcc-4.1.2
$ if [ -d gcc/gm2/patches/gcc/4.1.2 ] ; then
     for i in gcc/gm2/patches/gcc/4.1.2/* ; do
        if [ -f $i ] ; then
           patch -p1 < $i
        fi
     done
  fi

Note that if you download a tarball from http://floppsie.comp.glam.ac.uk then any patching will have already been applied. See section Obtaining GNU Modula-2..


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.4 Stress testing GM2

Currently there are two automated methods to test GNU Modula-2. The first method is `make gm2.paranoid' in which gm2 builds itself and finally the test runs both parent and child generations of the compiler and compares the output. Be warned that this test can take some time to execute. This test is invoked by:

 
$ cd host-build/gcc ; make gm2.paranoid

The second method used to test GNU Modula-2 is to run the regression test suite. The GNU Modula-2 regression test suite is available for download. To install and run the GNU Modula-2 regression suite you need to have installed the `dejagnu' and `expect' packages. Note that you need to ensure that you have at least the following releases of dejagnu components:

 
$ runtest --version

Expect version is	5.42.1
Tcl version is		8.4
Framework version is	1.4.4

otherwise some of the tests may not run.

If you have downloaded the combined GCC and GNU Modula-2 tarball http://floppsie.comp.glam.ac.uk/download/c/gcc-4.1.2+gm2-cvs-latest.tar.gz then this will also contain the GNU Modula-2 testsuite. In this case you can skip over the following `cvs' and `tar' commands.

However if you have downloaded GNU Modula-2 using CVS then you will also need to download and position the testsuite. Assuming that the root of the GCC source tree is in the current working directory you can use the following commands to install the test suite:

 
$ cvs -z3 -d:pserver:anoncvs@cvs.sv.gnu.org:/sources/gm2 co testsuite
$ tar cf - testsuite | ( cd gcc-version/gcc ; tar xf - )

Do not simply move the directory `testsuite' into `gcc-version/gcc' as the GNU Modula-2 regression tests have to be overlaid on top of the gcc testsuite.

Thereafter you can run the GNU Modula-2 testsuite by:

 
$ cd host-build/gcc
$ make check-gm2

Depending on the speed of your computer these tests may take a while to complete.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.5 Building GNU Modula-2 under FreeBSD

[This section is out of date].

When building GNU Modula-2 under FreeBSD, there are essentially three issues that need to be addressed.

The first, is the system shell, `/bin/sh'. GNU Modula-2's build script uses some `bash' constructs that are not understood by `sh'. Therefore `bash' must be installed and this can be obtained from the ports package collection (ports:shells/bash).

The second, is the compiler used to bootstrap GNU Modula-2. On FreeBSD4.x the system compiler is from the 2.95.x generation, and should work without problems. On 5-RELEASE and 6-CURRENT, the system compiler is from the 3.4.x generation or greater, and it is known to create a faulty GNU Modula-2 compiler. Therefore you will need to install an earlier gcc on your machine. Known to work are gcc 3.2.3 (ports:lang/gcc32), gcc 3.3.4, 3.3.5 and 3.3.6 (ports:lang/gcc33).

Finally, `gmake' is required.

It is recommended that the same options are used to configure GNU Modula-2 as those suggested in the ports collection. A number of options are not relevant for building GNU Modula-2 and these can be safely omitted. The only two which apply directly to GNU Modula-2's build process are --with-system-zlib and --disable-nls.

The example below assumes that gcc-3.2.3 is installed (from the ports collection) and the compiler is called `gcc32'. The example assumes that the bash shell has been installed (as described above).

 
  mkdir host-build
  cd host-build
  env CONFIG_SHELL=/usr/local/bin/bash CC=gcc32 ../gcc-version/configure
      --with-system-zlib --disable-nls --enable-languages=c,gm2
  gmake

If you choose to install the generated compiler, you are urged to make use of the name rewriting options of configure (--program-prefix and --program-suffix work fine), and to avoid possible conflicts with a port that installs it's own gcc, you may also want to add --host. Here is the author of this section's full configure line:

 
  env CONFIG_SHELL=/usr/local/bin/bash CC=gcc32 ../gcc-version/configure
      --with-system-zlib --disable-nls --enable-languages=c,gm2
      --program-prefix=m2 --host=i386-gm2bld-freebsd5.3

[