home *** CD-ROM | disk | FTP | other *** search
- Compiler Extensions
- ===================
-
- The compiler has been extended with extra features. Most of which are
- designed to make interfacing with the amiga operating system easier.
- Other features are designed to make programming in Modula-2 less annoying.
- Avoid using these extensions if you wish to develop portable modules.
-
- Underscore
- ==========
-
- The underscore is a valid 'letter'.
- eg, '_Turbo_Modula_2' is a legal identifier.
-
- SHORTCARD, SHORTINT AND SHORTREAL
- =================================
-
- The types SHORTINT, SHORTCARD & SHORTREAL are not normally
- predeclared in other Modula-2 compilers:
-
- SHORTCARD is predeclared as [0..255] (* byte sized cardinal *)
- SHORTINT is predeclared as [-128..127] (* byte sized integer *)
- SHORTREAL Motorola fast floating point.
-
- Conversion Rules
- ================
-
- Signed (integer) and unsigned(cardinal) numeric subrange types may be freely
- mixed in expressions. The following conversion rules apply:
-
- VAR
- shortint : SHORTINT ;
- shortcard : SHORTCARD ;
- integer : INTEGER ;
- ...
-
- shortcard+shortint => VAL(INTEGER,shortcard)+VAL(INTEGER,shortint)
- shortcard+integer => VAL(INTEGER,shortcard)+integer
- shortcard+longint => VAL(LONGINT,shortcard)+longint
-
- cardinal+shortint => VAL(LONGINT,cardinal)+VAL(LONGINT,shortint)
- cardinal+integer => VAL(LONGINT,cardinal)+VAL(LONGINT,integer)
- cardinal+longint => VAL(LONGINT,cardinal)+longint
-
- longcard+longint => VAL(LONGINT,longcard)+VAL(LONGINT,shortint)
- longcard+integer => VAL(LONGINT,longcard)+VAL(LONGINT,integer)
- longcard+longint => VAL(LONGINT,longcard)+longint
-
- shortint+integer => VAL(INTEGER,shortint)+integer
- shortint+longint => VAL(LONGINT,shortint)+longint
-
- shortcard+cardinal => VAL(CARDINAL,shortcard)+cardinal
-
- integer+longint => VAL(LONGINT,integer)+longint
-
- Where '+' could be any binary operator.
- The result type in each conversion should be obvious.
-
- Standard function ORD() always returns a LONGINT typed value.
- This may lead to unessacary coerctions, so its always better to use
- VAL() instead.
-
- Qualified import identifier aliasing
- ====================================
-
- An imported global module name may be aliased.
-
- IMPORT Graphics , Intuition ;
-
- VAR
- rp : Graphics.RastPortPtr ;
- win : Intuition.WindowPtr ;
-
- Can be rewritten:
-
- IMPORT G := Graphics , I := Intuition ;
-
- VAR
- rp : G.RastPortPtr ;
- win : I.WindowPtr ;
-
- In V1.2 of the compiler, idenfifiers imported in local modules can also
- be aliased.
-
- Imported library versions
- =========================
-
- When importing an Amiga library module ( Dos, Intuition, Graphics etc ),
- an optional version number can be specified:
-
- IMPORT Intuition{33} ;
-
- FROM Dos{36} IMPORT System ;
-
- The values 33 & 36 will be passed to Exec.OpenLibrary by Intuition.o & Dos.o
- If no version number is specified, zero is assumed.
-
- Intuition.o, Dos.o etc will cache the highest version opened so far
- in order to reduce calls to Exec.OpenLibrary.
-
- The version number must be a decimal literal (not an arbitrary expression)
- this simplifies the parser in programs like M2B.
-
- Structure assignment
- ====================
-
- It is possible to assign to an array or record structure in a single
- statement, the right hand side being a list of bracketed expressions.
-
- The syntax of the assignment statement is extended to:
-
- $ assignment = designator ":=" ass_rhs .
- $ ass_rhs = "["[asslist]"]" | expression.
- $ asslist = ass_rhs{,ass_rhs}
-
- VAR x : ARRAY [0..6] OF INTEGER ;
-
- x := [f(y),2,4,a,0,0,0] ; (* The expressions need NOT be constant *)
-
- Trailing elements/fields need not be assigned to,in which case they will
- be zeroed.Any automatically inserted compiler padding fields will also be 0.
-
- x := [f(y),2,4,a] ; (* same as above *)
-
- If a record contains variant fields then the compiler assumes (and type
- checks against) the first variant.In other words you can only assign to the
- first variant field(s).
-
- examples:
-
- VAR
- matrix = ARRAY [0..3],[0..2],[0..2] OF LONGINT ;
-
- PROCEDURE InitMatrix ;
- BEGIN
- matrix:=[[[7FFFH, 0, 0],[ 0,7FFFH, 0],[ 0, 0,7FFFH]],
- [[32642, 0,2856],[ 0,7FFFH, 0],[-2856, 0,32642]],
- [[32642,2856, 0],[-2856,32642, 0],[ 0, 0,7FFFH]],
- [[7FFFH, 0, 0],[ 0,32642,2856],[ 0,-2856,32642]]] ;
- END InitMatrix ;
-
- TYPE
- NewMenu = RECORD (* Gadtools structure *)
- nm_Type : SHORTCARD ;
- CASE : INTEGER OF
- | 0 : nm_Label : STRING ;
- | 1 : nm_Image : ImagePtr ;
- END ;
- nm_CommKey : STRING ;
- nm_Flags : BITSET ;
- nm_MutualExclude : LONGINT ;
- nm_UserData : ADDRESS ;
- END ;
-
- VAR
- demomenu : ARRAY [0..11] OF NewMenu ;
-
- BEGIN
- demomenu :=
- [
- [ NM_TITLE,"Project" ],
- [ NM_ITEM, "Run", "R", {}, 0, MENU_RUN ],
- [ NM_ITEM, "Step", "S", {}, 0, MENU_STEP ],
- [ NM_ITEM, NM_BARLABEL ],
- [ NM_ITEM, "Slower Horizontal", "1", {}, 0, MENU_HSLOW ],
- [ NM_ITEM, "Faster Horizontal", "2", {}, 0, MENU_HFAST ],
- [ NM_ITEM, "Slower Vertical", "3", {}, 0, MENU_VSLOW ],
- [ NM_ITEM, "Faster Vertical", "4", {}, 0, MENU_VFAST ],
- [ NM_ITEM, NM_BARLABEL ],
- [ NM_ITEM, "Quit", "Q", {}, 0, MENU_QUIT ],
- [ NM_END ]
- ] ;
-
- Open array heap variables
- =========================
-
- In Modula-2 it is possible to declare open arrays only as formal parameters.
- The compiler allows open arrays to be declared as pointer base types.
-
- VAR
- p : POINTER TO ARRAY OF CHAR ;
-
- Like formal parameters, the open array must be 1 dimensional.
-
- The NEW substitution mechanism has to be extended to allow declarations
- of such heap variables.
-
- NEW(p,exp) ; where exp is an integer/cardinal expression.
-
- This expands to ALLOCATE( p , exp*SIZE(p^[0]));
-
- There is no bounds checking associated with this type of array.
- It is not possible to do any operation on the open array,only individual
- elements may be accessed:
-
- The designator p^ may never appear on its own, the '^' must always be
- followed by a '[' eg p^[10].
-
- If the follow declarations exist:
-
- VAR
- x : POINTER TO ARRAY OF type ;
- y : ARRAY [low..hi] OF type ; (* normal array *)
-
- Then the assignment
-
- x := y ; is allowed. This is equivalent to
- x := ADR( y ) ;
-
- If the base type of the open array(x^[0]) is CHAR then,
-
- x := "help" ; is allowed and is equivalent to
- x := ADR("help") ;
-
- The SYSTEM.STRING type is predeclared as POINTER TO ARRAY OF CHAR.
- The array pointed to by a STRING variable should always be 0C terminated.
-
- This kind of pointer occurs in the C language, and so is quite useful
- when programming with the amiga OS and the Ansi C libraries. However it is
- not true to Modula's strong typing philosophy and therefore its
- indiscriminate use should be avoided.
-
- Pointer casting in selector lists
- =================================
-
- It is possible to insert type casts in variable selector lists:
-
- foo := bar(NewMenuPtr)^.nm_Label(ImagePtr) ;
-
- The syntax of the designator is extended to:
-
- $ designator = qualident {"."ident|"["ExpList"]"|"("qualident")"| "^" }.
-
- This method of casting is restricted to (and from) pointer types.
- It is very useful when using Intuitions BOOPSI system.
-
- Variable length argument lists
- ==============================
-
- A procedure may be declared to take a variable number of arguments.
- To declare such a procedure, the formal parameter list must end with '..':
-
- PROCEDURE VarArgsProc( x : INTEGER ; .. ) ;
- (* There must be at least 1 normal formal parameter *)
-
- There is no standard way of accessing the unknown parameters from Modula-2.
- This kind of declaration normally occur in Amiga OS & C interface modules.
- However you can declare them in implementation & program modules:
-
- PROCEDURE CreateGad( kind:LONGINT; VAR ng:GT.NewGadget; tag1:LONGINT; .. ) ;
- (* topazAttr, visualInfo, window, lastAdded are global variables *)
- BEGIN
- ng.ng_TextAttr := ADR( topazAttr ) ;
- ng.ng_VisualInfo := visualInfo ;
- INC( ng.ng_LeftEdge, window^.BorderLeft ) ;
- INC( ng.ng_TopEdge , window^.BorderTop ) ;
-
- lastAdded := GT.CreateGadgetA( kind, lastAdded, ng, ADR( tag1 ) )
- END CreateGad ;
-
- If a SHORTREAL or REAL actual corresponds to a '..' formal
- then the parameter is converted to a LONGREAL before being passed.
-
- Newline and tab characters
- ==========================
-
- String literals may contain newline (\n) & tab(\t) characters.
-
- InOut.WriteString("Hello\tworld\n");
-
- If '\' in a string is not followed by one of 't' 'n' '\' then the compiler
- will report an error.
- To represent '\' use '\\'.
-
- "\n" & "\t" are also legal character constants as well as strings.
-
- Exit codes
- ==========
-
- A return statement inside the initialization statement sequence of the root
- program module may contain an optional integer expression. This expression,
- if executed, will represent the return code for the program.
- If no expression is supplied, or if execution falls through, 0 is returned.
-
- MODULE foo ;
- ...
- BEGIN
- RETURN 20
- END foo.
-
- The standard AmigaDOS return codes are:
-
- 00: success
- 05: warning
- 10: something's wrong
- 20: complete or severe failure
-
- Alternatively StdLib.exit(X), will terminate the program with return code X.
-
- Coroutines
- ==========
-
- The pseudo module SYSTEM does not contain any coroutine facilities,
- instead the library module 'Coroutines' should be used
- (modula:m2lib/Coroutines.def).
-
- SHORTSET BITSET & LONGSET constants
- ===================================
-
- The compiler predefines 3 set types.
-
- SHORTSET = SET OF [0..07] ; SIZE = 1 Byte
- BITSET = SET OF [0..15] ; SIZE = 2 Byte
- LONGSET = SET OF [0..31] ; SIZE = 4 Byte
-
- The type of an unqualified set constant has been extended to support these
- types.
-
- {}, {0}, {0,1} ... {0..7} are compatible with SHORTSET,BITSET & LONGSET
- {8}, {8,9} ... {8..15} are compatible with BITSET & LONGSET
- {16} .. {16..31} are only LONGSETs
-
- By compatible I mean both expression compatible & assignment compatible.
-
- VAR
- shortset : SHORTSET ; bitset : BITSET ; longset : LONGSET ;
-
- shortset:= {1} (*valid*); shortset:= {8} (*wrong*); shortset:= {16}(*wrong*)
- bitset := {1} (*valid*); bitset := {8} (*valid*); bitset := {16}(*wrong*)
- longset := {1} (*valid*); longset := {8} (*valid*); longset := {16}(*valid*)
-
- INCL & EXCL
- ===========
-
- As well as the normal definitions of the standard procedures INCL/EXCL
- the second parameter of these procedures may be a set expression.
-
- example:
-
- INCL(bitset,{1,2}) is identical to bitset := bitset+{1,2}.
- EXCL(bitset,{1,2}) is identical to bitset := bitset-{1,2}.
-
- However the INCL/EXCL versions generate atomic code.
-
- BCPL pointers
- =============
-
- The DOS operating subsystem was partly implemented in the BCPL programming
- language, which used long word pointers,as opposed to normal byte pointers.
- It is possible to declare a BCPL long word pointer in Turbo Modula-2
-
- TYPE
- FileLockPtr = BCPL POINTER TO FileLock ; (* BCPL is a reserved keyword *)
-
- Instances of this pointer can be dereferenced as normal.
-
- The type SYSTEM.BADDRESS exists and is analogous to the normal
- SYSTEM.ADDRESS type.
-
- If an assignment to a BCPL pointer from an ADDRESS typed expression occurs
- then the compiler will automatically perform the necessary conversion:
-
- VAR lock : FileLockPtr ; v : FileLock ;
-
- lock := ADR(v) ; (* will work, but only if v is long word aligned *)
-
- The reverse assignment from a BADDRESS expression to a normal pointer will
- also be converted properly.
-
- You must be careful not to cast between the 2 different kinds of pointers
- as no conversion will take place. Instead there are 2 functions in the
- SYSTEM module that can be used.
-
- PROCEDURE SYSTEM.BTOA( bp : BADDRESS ) : ADDRESS ;
- PROCEDURE SYSTEM.ATOB( p : ADDRESS ) : BADDRESS ;
-
- The base variable of a BCPL pointer should always be long word aligned.
- Modula-2 global variables are always longword aligned as is the memory
- allocated using the StdLib.malloc & Storage.ALLOCATE functions.
-
- SHORTFLOAT & LONGFLOAT
- ======================
-
- As well as the normal FLOAT conversion function, which always converts
- to REAL, there are 2 other integer/cardinal->real conversion functions:
-
- SHORTFLOAT, converts an integer/cardinal into a SHORTREAL
- LONGFLOAT , converts an integer/cardinal into a LONGREAL
-
- Psuedo Module SYSTEM
- ====================
-
- The following types are declared in SYSTEM:
-
- ADDRESS
- BADDRESS see above
- BYTE
- WORD
- LONGWORD like BYTE & WORD except 32-bits long
-
- SHORTSET (also pervasive)
- BITSET (also pervasive)
- LONGSET (also pervasive)
- SHORTREAL (also pervasive)
- FFP Motoral Fast Floating Point (FFP=SHORTREAL)
- STRING see above
-
- Note that ADDRESS is internally declared as [0..2^31-1], however no
- range checking is ever applied on ADDRESS variables so its possible to
- assume all 32-bits.
- Be careful when mixing ADDRESS expressions with signed expressions, as the
- compiler will corece the ADDRESS to a LONGINT:
-
- address+longint => VAL(LONGINT,address)+longint
-
- If you want the result to be unsigned then you must corece the signed
- expression into ADDRESS or LONGCARD type using VAL:
-
- address+VAL(ADDRESS,longint)
-
- Functions declared in SYSTEM:
- -----------------------------
-
- ADR
- TSIZE
- BTOA see above
- ATOB see above
-
- OFFSET OFFSET( recordType , field ) : LONGINT
- Returns the byte offset of the field in the record.
-
- CAST CAST( TYPEid,expression) : TYPEid
- Performs a typecast: same as to TYPEid(expression).
- eg str := CAST(STRING,98)
- str := STRING(98)
-
- MAKEID MAKEID( STRING ) : LONGINT
- String should <= 4 characters.
-
- Comment Options
- ===============
-
- Unnested comments in your source code can be used to override command line
- options. The format is (* @X+ *) to enable an option or (* @X- *) to disable
- it. These comments should normally be placed at the top of your code.
-
- The options are:
-
- @C(+/-) Enable/Disable Large Code option.
- @D(+/-) Enable/Disable Large Data option.
- @B(+/-) Enable/Disable Array Bounds Checking.
- @R(+/-) Enable/Disable Range Checking.
- @V(+/-) Enable/Disable OVerflow Checking.
- @S(+/-) Enable/Disable Stack Checking.
- @Z(+/-) Enable/Disable Integer Divide by 0 Checking.
- @P(+/-) Enable/Disable Pointer Checking.
- @A(+/-) Enable/Disable Alternative BSS naming convention.
-
- There are also two other options which relate to individual procedures:
-
- @G See examples/src/Hook.mod
- @O See ansi-c/SetJmp.def
-
- Procedure switches should be placed between the procedure keyword & the
- procedure name:
-
- PROCEDURE (* @G *) CallBack( ) ;
- BEGIN ...
-
- The @G comment tells the compiler to generates code to set the A4 register
- to point to the global variable space when the procedure is entered
- (the old value is saved on entry an restored at exit), this is required
- if your program performs out of context calls when using the small data
- addressing model.
- You MUST use @G on procedures that are passed to the operating system
- for later invocation, eg Hook functions, CreateTask entry points etc.
- Unfortunately using @G means the program can not be made resident.
-
- The @O comement tells to the compiler not to allocate any locals to
- registers (not needed unless you use the SetJmp functions).
-
- When an open array is passed by value, the caller normally passes its
- address via the stack, its then the callees job to make a copy of it.
- The copying can be suppressed by using (* @N *) option, this option applies
- to a parameter list, it should be placed just afer the ':'
-
- PROCEDURE X( a , b : (*@N*) ARRAY OF CHAR ; c : ARRAY OF CHAR ) ;
- BEGIN
-
- In the above a & b will not be copied, while c will be.
-
- Use @N for efficiency if you know an open array value parameter will be
- strictly read-only. You must be careful, since it effectively converts
- value parameters into variable parameters, bypassing the compiler's normal
- safety checks. The PROGRAMMER must make sure not to make any assignments to
- such parameters, otherwise undesirable side effects may occur.
-
- The @G @O @N comments should only be used in a declaration for
- an implementation NOT in any forward declaration or definition module
- (in which case they will be ignored).
-
- DEFINITION FOR C MODULE'S
- =========================
-
- To make it easy to interface with code written in the 'C' language it
- is possible to declare non standard definition modules.
- There are 3 closely related kinds:
-
- 1.DEFINITION FOR C MODULE (eg StdLib.def)
-
- There is no corresponding implementation module.
- This kind of definition module normally contains a list of declarations
- which are defined in some C library or object file.
- A normal Modula-2 module that wishes to use the functions/variables
- declared in this kind of module simply imports them as normal.
- To enable correct linking however, the library or object files must be
- specified on the command line
-
- >m2b CallsX.mod X.o X.lib
-
- See examples/for_c/ for an example of calling a 'C' function.
-
- The library (c.lib) which contains all the function declared in
- StdLib.def,CType.def etc is automatically included by DCC,
- so we dont have to specify it on the command line.
-
- Note that function procedures declared in this kind of module can be
- treated as proper procedures (ie the function result can be ignored).
-
- 2.DEFINITION FOR AMIGALIB MODULE (eg Console.def)
-
- Mainly used to interface with AmigaDos devices (functions in amiga.lib).
- Like FOR C except all variable and strings declarations declared in the
- definition module are expected to be found in the coressponding Modula-2
- object file. For the compiler to generate such an object file there must
- be a corressonding implementation module,which is normally empty
- eg Console.mod or opens the device.
- The implementation module may contain procedure declaration which
- should only impelement macros not coded in the object file or library
- eg StdIO.mod .
-
- 3.DEFINITION FOR LIBRARY MODULE (eg GadTools.def)
-
- Used to open and interface to AmigaDos libraries.
- Identical to FOR AMIGALIB except when such a module is imported an
- optional library version number can be specified (see line 75 above).
- This version number can be read using the pervasive cardinal variable
- 'VERSION', for an example see GadTools.mod, and is noramlly passed to
- to function OpenLib, which inturn calls Exec.OpenLibrary.
- The initialisation body of an implementaion for library module must be
- capable of being called more than once i.e. with different versions
- arguments.
-
- Clean up code 'CLOSE'
- =====================
-
- In order to free any allocated resources (files, memory etc) a module may
- contain a CLOSE area:
-
- MODULE Test ;
-
- FROM Exec IMPORT AllocMem, FreeMem ;
-
- VAR
- x : POINTER TO INTEGER ;
-
- BEGIN
- x := AllocMem( 2 )
- CLOSE (* optional *)
- IF x # NIL THEN FreeMem( x ) END
- END Test.
-
- A CLOSE area is allowed in every module and is called when the program
- terminates (either succesfully or through a runtime error).
- The order in which the CLOSE statement sequences are called is the exact
- opposite to to the initialisation body calling order. i.e. the main modules
- CLOSE sequence is called first...
- A CLOSE statement sequence cannot be declared for procedures or local
- modules.
- The CLOSE mechanism is implemented using StdLib.atexit, which can be
- called directly if you prefer.
- Make sure that the CLOSE statements cannot fail (cause a run-time error),
- as this will result in an unbreakable loop.
- CLOSE is a reserved keyword.
-