gm2(1)
โจ gm2(1) โจ
Okay bestie, this is the manual page for GNU Modula-2 ๐ the gm2(1) page, and it's giving everything you need to know about the compiler, the linker helpers, and the makefile tools ๐
โจ NAME โจ
gm2โ the GNU Modula-2 compiler, obviously ๐gm2lโ a GNU Modula-2 linker subcomponent ๐gm2lccโ another GNU Modula-2 linker subcomponent ๐gm2lgenโ yep, a GNU Modula-2 linker subcomponent too ๐gm2lsubโ the last linker subcomponent in the lineup ๐gm2mโ the GNU Modula-2 makefile generator ๐งh2defโ turns a 'C' header file into a Modula-2 definition file ๐ฆ
โจ DESCRIPTION โจ
๐ NOTE: This manual page might be out of date, so check the texinfo file.
Okay so GNU Modula-2 is a front end for GCC (the GNU Compiler Collection), see http://gcc.gnu.org/frontends.html ๐ GCC has a retargetable C compiler that's been ported to a huge number of architectures and operating systems. GNU Modula-2 uses the back end of GCC and swaps the C language front end out for a Modula-2 one ๐ซถ
The GNU Modula-2 front end can do a substantial amount of static analysis on your source code ๐ Check out -Wpedantic, -Wpedantic-param-names, -Wstudents, and -Wpedantic-cast for that.
And then there's runtime checking, which is literally so iconic ๐ญ It can check the bounds of subranges and array indexes, that functions actually execute a RETURN statement, that a pointer doesn't dereference a NIL pointer value, and that the expression inside a CASE statement is correctly matched ๐
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, but all the definition modules for all three library sets are included in this document โจ
GNU Modula-2 is also super tight with GCC ๐ง which means the code is excellent and the architecture and operating system coverage is excellent too. It also borrows a bunch of GCC features. For example, GNU Modula-2 can invoke the C preprocessor to handle conditional compilation ๐ Inlining of SYSTEM procedures, intrinsic functions, and memory copying routines also get exploited, and you can access assembly language using GCC syntax. Plus, GNU Modula-2 supports sets of any ordinal type, memory permitting ๐ฆ
Here's how it reads source code. It takes files containing either (1) definition modules, (2) implementation modules, or (3) a main body module ๐ซถ Definition modules usually use the standard extension .def, while implementation and main body modules usually use the standard extension .mod. If you're working with legacy code that was written for a different compiler, other extensions might be in play. GNU Modula-2 can be told to search for those extensions first, before it falls back to the standard ones. For example, you'd use the command line options -fdef=.d2 -fmod=.m2 ๐
Also, GNU Modula-2 imports definition modules by reading the definition module file every single time, kind of like how C includes .h header files ๐ธ Traditional Modula-2 compilers, on the other hand, would need every definition module compiled into a symbol file before anything could be imported from it. Lowkey a different energy ๐
๐ท Purpose
It's expected that the main purpose of GNU Modula-2 will be compiling legacy code ๐ฐ๏ธ Right now there are only a few commercial Modula-2 compilers that are actively maintained. Code that was written ten or fifteen years ago might still get compiled by older commercial compilers, possibly ones that aren't maintained anymore ๐
While 32 bit x86 is still around, these compilers can presumably run in compatibility mode (some of them only produced 16 bit code). Time is running out though, since the computing industry is switching over to 64 bit microprocessors โณ x86 emulation or 16 bit backwards compatibility is always an option, but it comes with some serious drawbacks ๐ฌ
For the older source to run natively, the source code will either have to be translated into another high level language, or you'll need a Modula-2 compiler that can target this new generation of microprocessors ๐ฅ
๐ Current State
Right now GNU Modula-2 (0.49) implements all PIM dialects of the language, and eventually it'll be fully compliant with ISO Modula-2 ๐ It has been built on i[3456]86 GNU/Linux, i[3456]86 BSD, Opteron LP64 GNU/Linux, and sparc GNU/Linux systems. It's also been built as a cross compiler for MinGW and StrongARM GNU/Linux ๐
GNU Modula-2 builds and passes all of its regression tests on Debian Pure 64 (LP64 architecture), 64 bit Solaris, 32 bit x86 GNU/Linux (Suse 9.1, Debian, stable and unstable), and 32 bit x86 FreeBSD ๐
Work is underway to build and test it on DARWIN/i386 and DARWIN/powerpc ๐ฆ
And there's even a project to extend GNU Modula-2 with object oriented constructs similar to Objective-C, called 'Objective Modula-2', or objM2 for short ๐งโจ
โจ OPTIONS โจ
This section covers the compiler's command line options that are specific to GNU Modula-2 ๐ A bunch of the standard options are documented here too. For details on generic options, check the manual page for gcc (The GNU C Compiler) and the other members of the GNU Compiler Collection ๐ซถ
๐ Overall Options
--helpโ prints (on the standard output) a description of the command line options gm2 understands ๐ If-vis also specified, then--helpgets passed on to the various processes gm2 invokes, so they can show the command line options they accept. If-fis also specified, then command line options with no documentation attached will get displayed too ๐--target-helpโ prints (on the standard output) a description of the target specific command line options for each tool ๐ฏ--versionโ displays the version number and copyrights of the invoked GCC ๐ธ-cโ compiles and assembles the source files, but does not link ๐ โโ๏ธ The linking stage simply doesn't happen, so the ultimate output is an object file for each source file ๐ฆ-Eโ stops after the preprocessing stage and doesn't run the compiler proper โจ The output is preprocessed source code, which gets sent to the standard output ๐ค-gโ inserts debugging symbols into the object files and the executable ๐ NOTE: when you're using the debugger, it may help to not optimize at a high level ๐-Ipathโ adds an include path ๐บ๏ธ The GNU Modula-2 compiler needs to import symbols from definition module files, so it includes the definition file rather than reading a symbol file ๐-Onโ sets the optimization level and kind ๐ฅ-Osoptimizes for size, which is great if you want small executables ๐-O,-O1,-O2, ...,-O6optimize for speed, with increasingly powerful techniques like loop unrolling and reordering of code ๐ When you're debugging, only use-O, or at the most-O1๐ซถ-o fileโ places the output infile(yes, the file is called file ๐ญ) This applies no matter what kind of output is being produced, whether it's an executable file, an object file, an assembler file, or preprocessed C code ๐
Since only one output file can be specified, it doesn't make sense to use -o when compiling more than one input file, unless you're producing an executable file as the output ๐
โโ๏ธ
If you don't specify -o, the default is to put an executable file in a.out, the object file for source.suffix in source.o, its assembly language file in source.s, and all preprocessed C source on standard output ๐
-Sโ preprocesses and compiles the source code but doesn't assemble it ๐งฉ The temporary assembly language file isn't deleted. It stops after the compilation proper stage and doesn't assemble, so the output is an assembly language code file for each non-assembler input file you gave it ๐-vโ verbosely displays all calls to subsidiary programs, like the C preprocessor and the GNU Modula-2 compiler and linker ๐ข It also prints the version of the compiler and which specs file it's using ๐ค-fcppโ preprocesses the source withcpp -lang-asm -traditional-cpp๐ง If-fcppis supplied, then all the definition modules and implementation modules that get parsed will be preprocessed bycpp๐-fdef=โ recognizes the suffix you specify as a definition module filename ๐ The default definition module filename suffix is.def. If you use this option, GNU Modula-2 will still fall back to.defif a requested definition module isn't found ๐ซถ-fmod=โ recognizes the suffix you specify as implementation and module filenames ๐ธ The default implementation and module filename suffix is.mod. If you use this option, GNU Modula-2 will still fall back to.modif it needs to read an implementation module and the suffixed filename doesn't exist. This option and-fdef=both also work with the-fmakealloption ๐-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 it can be resolved when compiling the module that imports the opaque type ๐-fmakeallโ generates a temporary makefile, then builds all the dependent modules and links them ๐๏ธ-fmakelistโ this option is only applicable when linking a program module โจ The compiler generates amodulename.lstfile, which lists the initialization order of all the modules that are going to be linked ๐ The actual link doesn't happen. The GNU Modula-2 linker scans allIMPORTs, generates a list of dependencies, and produces an ordered list for initialization โก It'll probably get the order wrong if your project has cyclic dependencies, but the.lstfile is plain text, so you can modify it if you need to ๐ Once the.lstfile exists, the compiler can use it to link your project through the-fuselistoption ๐ It has no effect if the-coption is present ๐-fsourcesโ displays the path to the source of each module ๐บ๏ธ-fstatisticsโ generates quadruple information: the number of quadruples generated, and the number of quadruples remaining after optimization ๐ Quadruples are the intermediate language the GNU Modula-2 compiler uses internally ๐ค-fuselistโ as long asgm2has been told to link the program module, this option uses the filemodulename.lstfor the initialization order of modules ๐ซถ-Wverbose-unboundedโ okay so this one's a total tattletale ๐ซฃ It tells you which nonVARunbounded parameters are gonna get passed by reference. It only says anything if you also pass-funbounded-by-referenceon the command line, so pair them up, bestie ๐-funbounded-by-referenceโ the glow-up option โจ It tries to pass nonVARunbounded parameters by reference, which skips the implicit copy inside the callee procedure. GNU Modula-2 only lets unbounded parameters go by reference if, inside the callee, they're not written to, no address is calculated on the array, and they aren't passed as aVARparameter. Those rules are non-negotiable ๐ โโ๏ธ
NOTE: It's possible to write code that breaks this optimization, so use it carefully!! For example, you could 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. Chaos ๐
Due to the dangerous nature of this option, it is not enabled when the -O option is specified. Hard pass on mixing these ๐
โจ Runtime Checking Options โจ
-fboundsโ tells the compiler to generate code that checks the bounds of subranges and array indexes ๐ง-freturnโ generates code that checks functions always exit with aRETURNand never just fall out the end ๐ซถ-fnilโ generates code that catches, at runtime, any attempt to access data through aNILpointer value ๐จ-fcaseโ generates code that detects at runtime whether aCASEstatement needs anELSEclause when you didn't write one. It adds an implicitELSEto anyCASEstatements that don't define one. It just prints an error message and exits with an error code ๐ญ-fsoft-check-allโ turns on all the runtime checks ๐ฅ It's the same as invoking GNU Modula-2 with-fbounds, -freturn, -fnil, -fcase, -frange, ,-findex, -fwholediv
โจ Style Checking Options โจ
-Wstudentsโ checks for bad programming style ๐ This one's aimed at new Modula-2 users, because it looks for situations that might cause confusion and therefore mistakes. It checks whether variables of the same name are declared in different scopes, and whether variables look like keywords. Experienced users might find it too aggressive ๐-Wpedanticโ main character energy for the compiler ๐ It forces the compiler to reject nestedWITHstatements referencing the same record type, and doesn't allow multiple imports of the same item from a module. It also checks that:- procedure variables are written to before they're read
- variables aren't only written to but also read from
- variables are declared and used
If the compiler runs into a variable being read before it's written, it terminates with a message. It also checks that FOR loop indices aren't used outside the end of the loop without being reset ๐ซฃ
-Wpedantic-param-namesโ checks procedure parameter names in the definition module against their implementation module counterparts. This isn't necessary in ISO or PIM versions of Modula-2, but it can be extremely useful, as long as you're doing it on purpose ๐-Wpedantic-castโ warns if the ISO system function is used and the size of the variable is different from the size of the type. It's legal in ISO Modula-2, but it can be dangerous ๐ Some users may preferVALin these situations, and useCASTexclusively for type changes on objects that have the same size ๐ฆ
โจ Language Dialect Options โจ
-fisoโ turns on ISO standard features ๐ธ Right now it enables the ISOSYSTEMmodule and alters the default library search path so the ISO libraries get searched before the PIM libraries. It also affects how theDIVandMODoperators behave.-fpimโ turns on PIM standard features ๐ Right now it enables the PIMSYSTEMmodule and determines which identifiers are pervasive (declared in the base module). If no other-fpim[234]switch is used, division and modulus behave as defined in PIM4. (See LANGUAGE DIALECTS.)-fpim2โ turns on PIM-2 standard features ๐ง Right now it removesSIZEfrom being a pervasive identifier (declared in the base module) and placesSIZEin theSYSTEMmodule instead. It also affects howDIVandMODbehave.-fpim3โ turns on PIM-3 standard features. Right now it only affects how theDIVandMODoperators behave.-fpim4โ turns on PIM-4 standard features. Right now it only affects how theDIVandMODoperators behave.-fpositive-mod-floor-divโ forces theDIVandMODoperators to behave as PIM4 defines them ๐ All modulus results come out positive, and division results get rounded to the floor.
NOTE: Check out the LANGUAGE DIALECTS section for a table describing these results ๐
โจ Library Search Path Options โจ
-flibs=ulmโ tweaks the default library search path so the University of Ulm libraries get searched before the other PIM libraries ๐-flibs=pimโ tweaks the default library search path so the PIM libraries get searched before any others. This is the default, bestie ๐-flibs=pim-coroutineโ tweaks the default library search path so the PIMSYSTEMmodule that provides coroutine support gets searched before the base PIM libraries. This directory also includes lots of coroutine-related libraries ๐ง-flibs=isoโ tweaks the default library search path so the ISO libraries get searched before any others. You don't need this if you already specified-fiso๐ซถ-flibs=logitechโ tweaks the default library search path so the Logitech compatible libraries get searched before the base PIM libraries โญ-flibs=minโ tweaks the default library search path so the minimal set of runtime libraries gets searched before any others. Super useful if you're targeting a small memory embedded device ๐
๐ LANGUAGE DIALECTS ๐
Okay so this section is all about the dialects GNU Modula-2 understands ๐ง It also breaks down how the dialects differ from each other, and which command line switches control dialect behavior. Let's get into it ๐
The GNU Modula-2 compiler is based on the language as defined in:
- PIM2 โ ยดProgramming in Modula-2ยด, 2nd Edition, Springer Verlag, 1982, 1983 by Niklaus Wirth,
- PIM3 โ ยดProgramming in Modula-2ยด, 3rd Corrected Edition, Springer Verlag, 1985 by Niklaus Wirth, and
- PIM4 โ ยดProgramming in Modula-2ยด, 4th Edition, Springer Verlag, 1988, by Niklaus Wirth.
- ISO โ The International Standards Organization's ISO/IEC 10514-1:1996 Information Technology -- Programming Languages -- Part-1: Modula-2, Base Language
It also includes ISO M2 features and GNU Modula-2 extensions ๐ฆ Currently GNU Modula-2 (0.49) implements all PIM dialects of the language. Eventually, GNU Modula-2 will be fully compliant with the ISO Modula-2 Base Language. It supports neither ISO Modula-2 Generics, nor ISO Object Oriented Modula-2 ๐ โโ๏ธ
The command line switches -fpim2, -fpim3, -fpim4, and -fiso can be used to force mutually exclusive features. However, by default the compiler won't aggressively fail if a non mutually exclusive feature is used from another dialect. For example, it's possible to specify -fpim2 and still utilize 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. So 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. It's vital that users choose their dialects with care when these language features are used ๐ซข
๐ Integer Division, Remainder and Modulus ๐
The most dangerous set of mutually exclusive features in the four dialects supported by GNU Modula-2 is the INTEGER division, remainder and modulus arithmetic operators. It's important to note that the same source code can be compiled to give different runtime results depending on these switches! The reference manuals for the various Modula-2 dialects are quite clear about this behavior, 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 pg24 of PIM2, pg27 of PIM3, pg29 of PIM4, and pg201 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 ๐ธ
๐ฆ The PIM SYSTEM Module ๐ฆ
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 ๐ง
DEFINITION MODULE SYSTEM ;
EXPORT QUALIFIED (* the following are built into the compiler: *)
ADDRESS, WORD, BYTE, BITSET, ADR, TSIZE, SIZE ;
END SYSTEM.
๐ง 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, BYTE, WORD, BITSET, ADDRESS,
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; (* 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: INTEGER) ;
(*
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: INTEGER) ;
(*
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: INTEGER) ;
(*
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: INTEGER) ;
END SYSTEM.
โจ GM2 LANGUAGE EXTENSIONS โจ
okay so this whole section is the GNU Modula-2 language extensions ๐ and it's lowkey the best part ๐ฅ
๐ฆ Abstract Types ๐ฆ
ok so the GNU Modula-2 compiler lets abstract data types be any type ๐คฏ, not just a pointer type... but only if you pass the -fextended-opaque command line option โจ
๐ Declaration Order ๐
declarations can be made in any order ๐ whether they're types, constants, procedures, nested modules or variables. no stress about who goes first ๐
๐ Interfacing to C ๐
GNU Modula-2 also lets you hook up with C and assembly language ๐ซถ
the compiler tries its absolute best to use the C calling convention wherever it can ๐
but some parameters have no C equivalent, so a language-specific method gets used instead. for example, unbounded arrays get passed as a struct void *address, unsigned int high ๐ and the contents of these arrays are copied by callee functions when they're declared as non VAR parameters ๐ญ. the VAR equivalent unbounded array parameters need no copy, but they still use the struct representation ๐
the recommended method for interfacing GNU Modula-2 to C is telling the definition module that the implementation is in the C language ๐. you do this with the tokens DEFINITION MODULE FOR โCโ'.
DEFINITION MODULE FOR "C" libprintf ;
EXPORT UNQUALIFIED printf ;
PROCEDURE printf (a: ARRAY OF CHAR; ...) ;
END libprintf.
the UNQUALIFIED keyword in the definition module tells GNU Modula-2 not to prefix the module name to exported references in the object file ๐
the printf declaration says the first parameter semantically matches ARRAY OF CHAR, but since the module is for the C language it gets mapped onto 'char *' ๐ง. the token ... means a variable number of arguments (varargs), and all the parameters passed there get 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 world0)
END hello.
and it can be compiled by: gm2 -fmakeall -g -I. hello.mod -lc.
in reality the -lc is redundant, because libc is always included in the linking process ๐. it's only shown here to emphasize that the C library or object file containing printf must be present ๐ซถ
๐ ๏ธ Interfacing 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 below ๐ 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;
๐ Special Tokens ๐
GNU Modula-2 provides support for the special tokens __LINE__, __FILE__, __FUNCTION__, and __DATE__ ๐ง. support for these tokens happens even if the -fcpp option is not supplied โจ
here's the lowdown on these identifiers, their data types, and their values ๐
- Scope
anywhereโ__LINE__is a constant literal compatible withCARDINAL,INTEGERandWORD. Example1234๐ __FILE__(anywhere) ๐ A constant string that works with a parameter ofARRAY OF CHAR, or with an ARRAY whose SIZE is >= string length. Example:"hello.mod"__FUNCTION__(procedure scope) โจ Another constant string, compatible withARRAY OF CHARor an ARRAY whose SIZE is >= string length. Example:"calc"__FUNCTION__(module scope) ๐ง Example:"module hello initialization"__DATE__(anywhere) ๐ Constant string, compatible withARRAY OF CHARor an ARRAY whose SIZE is >= string length. Example:"Thu Apr 29 10:07:16 BST 2004"
โจ Preprocessor โจ
Okay so the preprocessor, cpp, can be summoned with the -fcpp command line option ๐ฎ. That runs cpp with -traditional -lang-asm, and those two options keep comments and all quotations intact. Main character preservation energy ๐
. gm2 treats a # in the first column as a preprocessor directive, so keep that in mind ๐ซถ.
Here's a little module that calls FatalError through the ERROR macro ๐ธ
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 %s0,
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.
๐ฆ Optional procedure parameter ๐ฆ
GNU Modula-2 lets the last parameter to a procedure or function be optional ๐. You make it happen by wrapping the last formal parameter in square brackets and giving it an initializer (a constant assignment).
For example, in the ISO library COROUTINES.def, NEWCOROUTINE is defined with an optional fifth argument (initProtection) which, if it's absent, is automatically replaced by NIL ๐
PROCEDURE NEWCOROUTINE (procBody: PROC; workspace: SYSTEM.ADDRESS;
size: CARDINAL; VAR cr: COROUTINE;
[initProtection: PROTECTION = NIL]);
The implementation module COROUTINES.mod implements this procedure using this syntax:
PROCEDURE NEWCOROUTINE (procBody: PROC; workspace: SYSTEM.ADDRESS;
size: CARDINAL; VAR cr: COROUTINE;
[initProtection: PROTECTION]);
BEGIN
END NEWCOROUTINE ;
๐ซ Heads up, bestie: it is illegal for this declaration to contain an initializer value forinitProtection. You still have to wrap that parameter in[and], though, because it reminds 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 that case, the initializer is mandatory in the implementation or program module ๐
๐ Builtins ๐
This section covers the built-in constants and functions in GNU Modula-2 โจ. The following compiler constants can be accessed using the __ATTRIBUTE__ and __BUILTIN__ keywords. They aren't part of the Modula-2 language, and they may differ depending on the target architecture, but they give common libraries a way to interface with a different underlying architecture ๐งฉ.
The built-in constants are BITS_PER_UNIT, BITS_PER_WORD, BITS_PER_CHAR, and UNITS_PER_WORD. They get integrated into GNU Modula-2 through an extension to the ConstFactor rule:
ConstFactor := ConstQualidentOrSet | Number | ConstString |
"(" ConstExpression ")" | "NOT" ConstFactor |
ConstAttribute =:
ConstAttribute := "__ATTRIBUTE__" "__BUILTIN__" "(" "(" Ident ")" ")" =:
Here's 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 of them are declared in DEFINITION MODULEs and get imported as and when they're needed. You declare them in definition modules with the __BUILTIN__ keyword. Here's a bit of the ISO library LongMath.def that shows this off ๐
PROCEDURE __BUILTIN__ sqrt (x: LONGREAL): LONGREAL;
(* Returns the square root of x *)
This tells us the function sqrt will be implemented using the gcc built-in math library. If gcc can't use the built-in function (for example, if the programmer requested the address of sqrt), then code gets generated to call the alternative function implemented in the IMPLEMENTATION MODULE ๐ซ
Sometimes a function exported from the DEFINITION MODULE has a different name from the built-in function inside gcc. In those 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 it's written like this ๐ฆ
PROCEDURE __ATTRIBUTE__ __BUILTIN__ ((sqrtl)) sqrt
(x: LONGREAL) : LONGREAL;
(* Returns the positive square root of x *)
The following module, Builtins.def, lists every built-in function you can access in GNU Modula-2. It also defines the parameters and return value for each function ๐
DEFINITION MODULE Builtins ;
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__ 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__ 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.
Even though this module exists and will generate inline code if optimization flags are passed to GNU Modula-2, you should really use the same functions from more generic libraries ๐ The built-in mechanism gets applied to those generic libraries where it makes sense.
๐ฃ NOTE: for the mathematical routines to be inlined, you need to specify the -ffast-math -O options.
โจ LIBRARIES โจ
Nothing is listed under this heading in the original page, so there's nothing for me to add here ๐
๐ EXAMPLES ๐
This section shows how to compile and link a simple 'hello world' program ๐ It gives you a few examples of using the different options we talked about above.
Say the file "hello.mod" contains this code ๐ง
MODULE Hello;
FROM StrIO IMPORT WriteString, WriteLn;
BEGIN
WriteString('hello world');
WriteLn;
END Hello.
You should be able to compile it with gm2 -c hello.mod and link it with gm2 hello.mod. The result should be an a.out file created in your directory โจ
Or you can compile it with gm2 -g -I. -fmakeall hello.mod ๐ซถ
๐ธ FILES ๐ธ
Nothing is listed under this heading either, bestie ๐
๐ ENVIRONMENT ๐
Same deal here: the original page has nothing under this heading ๐
๐ฎ CONFORMING TO ๐ฎ
The GNU Modula-2 compiler is based on the language as defined in these three books ๐
- 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)
- Programming in Modula-2, 4th Edition, Springer Verlag, 1988 (PIM4)
It also includes ISO M2 features and GNU Modula-2 extensions ๐
๐ BUGS ๐
Nothing is listed under this heading in the original, so no bugs were documented here ๐
๐ COPYRIGHT ๐
Nothing is listed under this heading in the original either.
๐ LICENCE ๐
The GNU Modula-2 compiler and associated software is released under the GNU PUBLIC LICENCE (GPL), which should be available in a file named COPYING ๐ซถ
The runtime libraries (pim, iso, and Logitech Compatable) are released under the LESSER GNU PUBLIC LICENCE (LGPL). That one lets any user link against the runtime libraries without invoking all the clauses of the full GPL ๐ฆ
The Ulm library is released under the GPL.
๐ AUTHOR ๐
This manual page was written (using the documentation from the texinfo files) by Peter P. Eiserloh โจpeter@eiserloh.orgโฉ ๐ง
๐ SEE ALSO ๐
The many fine books about Modula-2 ๐
The GNU Modula-2 web site at โจhttp://www.nongnu.org/gm2โฉ ๐
Bestie, that's the whole page! ๐ It's from the GM2 manual, dated 27-Nov-2005. Stay iconic and keep compiling ๐ซถโจ
๐ฆ where this page comes from
- ubuntu jammy: gm2-9-sparc64-linux-gnu 9.4.0-1ubuntu1cross1
- ubuntu jammy: gm2-9-sparc64-linux-gnu 9.5.0-1ubuntu1~22.04cross1
- ubuntu noble: gm2-9-sparc64-linux-gnu 9.5.0-6ubuntu2cross1
- Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms