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 ; ... shortint+shortcard => VAL(INTEGER,shortint)+VAL(INTEGER,shortcard) shortint+cardinal => VAL(LONGINT,shortint)+VAL(LONGINT,cardinal) shortint+integer => VAL(INTEGER,shortint)+integer shortint+longint => VAL(LONGINT,shortint)+longint shortcard+cardinal => VAL(CARDINAL,shortcard)+cardinal shortcard+integer => VAL(INTEGER,shortcard)+integer shortcard+longint => VAL(LONGINT,shortcard)+longint integer+cardinal => VAL(LONGINT,integer)+VAL(LONGINT,cardinal) integer+longint => VAL(LONGINT,integer)+longint cardinal+longint => VAL(LONGINT,cardinal)+longint Where '+' could be any binary operator. The result type in each conversion should be obvious. Qualified Import 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 ; 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 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: program was successful. 10: warning (non fatal 'error'). 20: fatal error. 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. 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