3.1  Megamax Modula: Sprachumfang                                     3 -  1
________________________________________________________


3.  Programmieren in Megamax Modula-2

3.1     Sprachumfang

In diesem Kapitel wird detailliert beschrieben, welchen 'Dialekt' von Modula-2
der Megamax Modula-Compiler bersetzt und wo es bei anderen Compilern
Abweichungen geben kann. Bevor wir damit anfangen, wollen wir aber kurz
erzhlen, warum dieses Kapitel eigentlich ntig ist  (wenn  Sie's  eilig  haben,
drfen Sie auf der nchsten Seite weiterlesen).


Der Wirth'sche Standard (PIM-Standard)

Schn wr's ja, wenn jeder unter 'Modula-2' ganz genau die gleiche Program~
miersprache verstehen wrde: Programme knnten ohne nderung von anderen
Rechnern bernommen werden; wer auf einem Computer Modula gelernt hat,
knnte jederzeit einen anderen programmieren... Die erste Definition von Modula-2
von Niklaus Wirth war tatschlich schn genau festgelegt. Trotzdem waren
nicht alle Benutzer mit dieser Definition einverstanden: Sie war nmlich ma~
geschneidert fr Wirths 'Lilith'-Computer, der z. B. nur 16 Bit-Adressen kannte
und keine Bytes adressieren mochte (also auch ASCII-Zeichen grozgig in 16
Bit-Worten unterbrachte).

Von  verschiedenen  Anwendern,  die  Modula-2  auch  auf  anderen  Computern
verwenden  wollten,  lie  sich  N.  Wirth  schlielich  berzeugen,  da  die
Sprachdefinition etwas flexibler auf die jeweils vorhandene Hardware angepat
werden mte: Fr die 68000-CPU brauchen wir eben 32 Bit-Adressen, mit
denen wir auch rechnen wollen; ASCII-Zeichen sollten hier in Bytes gespeichert
werden. Bei dieser Erweiterung der Sprachdefinition entschlo man sich, auch
gleich einige andere Kleinigkeiten zu ndern. Das Ergebnis war die 'Revision'
von Modula-2. Dann kam  eine  dritte  Auflage  des  Buchs  Programmieren  in
Modula-2, die nun allgemein als der aktuelle Standard betrachtet wird (man
bezeichnet in  auch  nach  der  dritten  Auflage  als  PIM-3  Standard).  Jngst
erschien noch eine  vierte  Auflage,  die  aber  weniger  anerkannt  wurde,  vor
allem,  weil  sie  einige  gravierende  nderungen  (Strings,  INTEGER)  mit  sich
brachte. brigens sttzt sich auch der ISO-Standard (s.u.) auf PIM-3.

Auf diese Weise gibt es also in verschiedenen Modula-Implementationen nicht
nur  kleine  Abweichungen  je  nach  Zielrechner,  sondern  auch  noch  mehrere
PIM-Revisionen. Zudem verfgen viele Compiler, auch Megamax, ber eigene
Erweiterungen in der Sprache.

Wollen Sie also portabel programmieren, damit Ihre Programme spter auch
auf anderen Compilern oder Rechnern mit wenig oder gar keinem Aufwand zum
Laufen zu bringen sind, mssen Sie sich ber den PIM3-Standard  und  die
speziellen Erweiterungen im klaren  sein.  Aber  zuvor  noch  ein  Vorgriff  auf
einen neuen Standard, der das alles lsen soll:
3.1  Megamax Modula: Sprachumfang                                     3 -  2
________________________________________________________


Der ISO-Standard

In naher Zukunft (ca. Anfang '91) wird ein  internationaler  Modula-Standard
definiert sein (der sogenannte ISO-Standard). Darin wird versucht, sowohl die
verschiedenen Revisionen und Ungenauigkeiten von N.Wirth zu klren, als auch
Sprache  und  Bibliotheken  an  die  Erfordernisse  der  realen  Computerwelt
anzupassen.  Nur  wenige  Erweiterungen  wurden  aufgenommen,  weil  man
erstmal Wirths Modula standardisieren wollte, anstatt gleich eine neue Sprache
zu schaffen. Allerdings waren einige nderungen an der Sprache notwendig,
um  beispielsweise  die  Idee  der  Verdeutlichung  von  unportablen,  rechner~
abhngigen Elementen durch Importe aus dem Modul SYSTEM konsequent zu
Ende zu fhren: Typen-Wandlung ist demnach nicht mehr implizit durch die
Funktionsschreibweise von Typen (Bsp: INTEGER (TRUE) ) sondern nur noch
mit Hilfe der Funktion CAST aus SYSTEM mglich. Ebenso wird BITSET aus
SYSTEM kommen, statt den diversen WORD und BYTE-Jokertypen wird es nun
LOC geben usw.

Wichtig ist auch folgendes: Als Standard-Typen fr ganze Zahlen werden nur
noch INTEGER und CARDINAL existieren, extra Long-Typen wie LONGCARD/
LONGINT sind nicht vorgesehen. Dies hat den Vorteil, da man sich nicht beim
Portieren  auf  einen  anderen  Rechner  mit  diesen  an  sich  gleichen  Typen
herumschlagen mu - man verwendet immer automatisch den grtmglichen
Bereich, den der Rechner bietet. Wenn der zu gering ist, ist das Programm
dort sowieso nicht anwendbar.

Damit die Effizienz bei Rechnern wie Atari ST oder IBM PC nun nicht absinkt,
wird  empfohlen,  in  Zukunft  mglichst  Unterbereichs-Typen  zu  verwenden.
Werden beispielweise nur Bereiche von 0 bis 1000 bentigt, deklariere man die
Variablen entsprechend und der Compiler ist dann in der Lage, wie gewnscht
intern mit 16 Bit-Zahlen (also den bisherigen SHORTCARDs) zu rechnen - die
Effizienz bleibt erhalten, kann teilweise sogar steigen.

Fr besondere Flle, in denen unbedingt feste Gren bentigt werden, drfen
Compiler bisherige Typen wie SHORTINT oder LONGCARD dann aus SYSTEM
exportieren.

Wir  Megamax-Entwickler  sind  selbst  im  DIN-Arbeitskreis,  der  deutschen
Abteilung fr die ISO-Normungsgruppe, engagiert und sind deshalb immer auf
dem laufenden. Wir haben schon jetzt einige der ISO-Erweiterungen vorweg~
genommen,  und  zwar  nur  soweit,  da  sie  sich  nicht  mit  dem  bisherigen
PIM-Standard bzw. den Megamax-Erweiterungen beien.

Erst,  wenn  der  Standard  offiziell  wird,  werden  wir  ein  neues,  vollstndig
ISO-konformes System fertigstellen und ausliefern. Dann mssen Sie nochmals
mit nderungen rechnen, dafr aber zum letzten Mal. Wir werden uns zudem
3.1  Megamax Modula: Sprachumfang                                     3 -  3
________________________________________________________


bemhen,  optional  die  alten,  bisherigen  Konventionen  beizubehalten,  um  bei
schon vorhandenen Programmen den  Anpassungsaufwand  mglichst  klein  zu
halten.


Standard gegen Erweiterungen

Nun erfahren Sie, wie Sie beides auseinander halten knnen. Das beste wre
natrlich, Sie lesen das Buch PIM-3 besonders aufmerksam und auch zwischen
den Zeilen. Dann warten Sie noch auf den ISO-Standard, lernen den  auch
kennen, und schon kennen Sie alle Tcken. Wir haben das aber schon fr Sie
durchgemacht und greifen Ihnen deshalb unter die Arme.

Im gesamten Kapitel 3, das als Referenz zur Sprache des Megamax-Compilers
dient, heben wir alle besonderen ISO- bzw. Megamax-Erweiterungen durch den
Hinweis  ISO-Erweiterung  bzw.  Megamax-Erweiterung  in  der  Beschreibung
hervor.

Megamax-Erweiterungen sind selbstverstndlich schwerer portabel, wenn auch
viele dieser Besonderheiten bei anderen Compilern ebenfalls als Erweiterung zu
finden  sind  (Bsp:  REF-Parameter),  whrend  ISO-Erweiterungen  in  Zukunft
sicher kein Portierungs-Problem mehr sein drften. ISO-Erweiterungen  sind
bis zum ISO-Standard ansonsten als Megamax-Erweiterungen zu verstehen.

Lediglich die Datentypen LONGCARD/LONGINT werden nicht hervorgehoben, sie
sind praktisch bei jedem 16/32 Bit-Compiler vorhanden.

Der Inline-Assembler (Kapitel 4) ist selbstverstndlich auch  eine  Megamax-
Erweiterung, ebenso sind die Compiler-Direktiven speziell auf das Megamax-
System zugeschnitten und deshalb nicht ohne weiteres portabel!
3.1  Megamax Modula: Sprachumfang                                     3 -  4
________________________________________________________


bersicht ber Einschrnkungen, Abweichungen und Erweiterungen

Megamax  Modula-2  erfllt  den  Modula-Standard  nach  "Programmieren  in
Modula-2", 3. Auflage, mit folgenden Unterschieden:

Einschrnkungen
    * TSIZE erlaubt zwar sog. Tag-Felder, ignoriert sie z.Zt. aber.
    * Durch den 1-Pass Compiler sind teilweise FORWARD-Deklarationen ntig,
      alle anderen Bezeichner mssen vor ihrer Benutzung deklariert werden
      (implizite Forward-Deklarationen sind jedoch bei POINTER TO sowie bei
      Parametern von Prozedurtypen erlaubt).
Erweiterungen
    * Diverse  Erweiterungen  aus  dem  kommenden  internationalen  ISO-
      Standard fr Modula-2, z.B. LOC, INT, BITNUM, LENGTH.
    * Aggregate (Datenverbunde von Feldern und Records in einem Stck).
    * Mehrdimensionale offene Felder (Open Arrays)
    * Deklaration von Register-Variablen
    * Funktionen LONG und SHORT.
    * REF-Parameter (auch sog. CONST-Parameter)
    * SYSTEM-Funktionen CODE, LOAD, STORE, DEREF
    * Datentypen LONGCARD, LONGINT, SHORTCARD, SHORTINT, BYTE.
    * Funktionsprozeduren knnen beliebig groe Datenstrukturen zurckgeben.
    * Bezeichner drfen den Unterstrich (" ") enthalten.
                                             _
    * Variablen sind auf feste Adressen ablegbar.
    * Bedingte Compilierung.
    * Direktes Einbinden von Assembler-Instruktionen mglich.
    * EXPORT in Def-Modulen weiterhin mglich (s. PIM, 1. & 2. Auflage).
    * Long-Konstanten mit "D" oder "L" als Kennung optional.
    * Hexadezimale Werte auch durch Anfhren von "$" mglich.

Datengren
    * Grenbeschrnkungen:
         - Kontrollstrukturen im Code (IF - END, WITH - END, usw.) knnen
           maximal  32  KB  Lnge  haben.  Bedingt  dadurch  sind  Prozeduren
           meist auf diese Gre beschrnkt.
         - SETs erlauben bis zu 65536 Elemente.
         - String-Konstanten fassen bis zu 256 Zeichen.
         - Die  formalen  Parameter  knnen  bis  zu  32  KB  auf  dem  Stack
           belegen, Open Arrays sind jedoch unbeschrnkt.
    * Ansonsten gibt es keine Beschrnkungen, insbesondere bei
         - Modulen,
         - strukturierten Daten (ARRAYs & RECORDs)
         - VAR-Parametern und Open Arrays (auch by value),
         - lokalen Variablen & Stack,
         - Rckgabe von Strukturen bei Funktionen,
         - Aufzhlungen (maximal 65536 Elemente),
         - Konstanten (auch Aggregate).
3.1  Megamax Modula: Sprachumfang                                     3 -  5
________________________________________________________


Standardprozeduren

Hinweise:
  NumberType  sind alle Ganzzahl-Typen (CARDINAL, INTEGER, usw.)
  OrdinalType   sind die Ganzzahlen, sowie CHAR, BOOLEAN und Aufzhlungen
  ScalarType   nennen wir Ordinale plus POINTER

ABS (x: INTEGER/LONGINT/ REAL): ArgumentType;
    Liefert den Absolutwert (Betrag) des Arguments. Das Ergebnis ist vom
    gleichen Typ wie das Argument.

CAP (ch: CHAR): CHAR;
    Konvertiert Kleinbuchstaben in die entsprechenden Grobuchstaben (auch die
                                                                   >
    landesspezifischen Umlaute werden bercksichtigt - z.B.  -  ).

CHR (c: CARDINAL): CHAR;
    Liefert das Zeichen mit der Ordnungszahl c.

DEC (VAR x: ScalarType; n: NumberType);
    Vermindert x um n. Fehlt n, wird 1 dafr eingesetzt. Der Typ von x kann
    jeder Skalar sein, d.h. INTEGER/CARDINAL, entsprechende LONG-Typen,
    Unterbereiche  davon,  Aufzhlungstypen,  CHAR,  BOOLEAN  und  POINTER
    (Megamax-Erweiterung) (POINTER werden immer um n und nicht etwa um
     die  Elementgre  vermindert).  Ist  x  INTEGER  oder  LONGINT,  mu  n
     ebenfalls von einem dieser Typen sein, ansonsten ist ein CARDINAL oder
     LONGCARD gefordert.

DISPOSE (VAR x: PointerType);
    Gibt mit NEW belegten Speicher wieder frei. DISPOSE wird vom Compiler
    durch DEALLOCATE (x, SIZE (x^)) ersetzt (s. a. NEW).

EXCL (VAR s: SetType; i: OrdinalType);
    Entfernt Element i aus der Menge s.

FLOAT (x: NumberOrRealType): REAL;
    Liefert  die  Darstellung  des  Wertes  x  als  REAL.  Nach  PIM  sind  nur
    CARDINALs als Argument erlaubt, wir erlauben aber auch INTEGER und
    Reals (ISO-Erweiterung).

HALT;
    Beendet  die  Programmausfhrung  mit  Anzeige  einer  Fehlerbox  wie  bei
    Laufzeitfehlern. Dem Aufrufer wird die irregulre Beendigung durch einen
    'ExitCode' angezeigt. (siehe Kapitel 5).
3.1  Megamax Modula: Sprachumfang                                     3 -  6
________________________________________________________


HIGH (x: OpenArray): CARDINAL/LONGCARD;
    In  Prozeduren,  wenn  x  Parameter  vom  Typ  'ARRAY  OF  ...'  bzw.
     'LONGARRAY OF ...' ist: Obere Indexgrenze des Feldes x, also Elementzahl
    - 1.

INC (VAR x: ScalarType; n: NumberType);
    Siehe Beschreibung zu DEC, x wird jedoch um n erhht.

INCL (VAR s: SetType; i: OrdinalType);
    Fgt Element i in die Menge s ein.

INT (x: OrdinalOrRealType): SHORTINT/LONGINT;
    ISO-Erweiterung
    Analog zu der Funktion ORD wird hier ein vorzeichenbehafteter Wert von x
    geliefert. Ist x ein 4-Byte-Typ, wird  ein  LONGINT,  sonst  ein  INTEGER
    geliefert. Ist x vom Typ BYTE, wird x als vorzeichenbehafteter Wert von
    -128 bis +127 interpretiert und entsprechend zurckgegeben (Megamax-
    Erweiterung).

LENGTH (string: ARRAY OF CHAR): SHORTCARD/LONGCARD;
    ISO-Erweiterung
    Entspricht der Funktion Length des Moduls Strings. Ist allerdings schneller
    und kann auch in CONST-Anweisungen verwendet werden.

LFLOAT (x: NumberOrRealType): LONGREAL;
    Liefert die Darstellung des Wertes x als LONGREAL.

LONG (x: ShortType): LongType;
    Megamax-Erweiterung (aber bei vielen Compilern vorhanden)
    Wandelt einen Ausdruck von 16 Bit-Darstellung in 32 Bit-Darstellung (bzw.
    von 8 nach 16 Bit). Die erlaubten Argumente und zugehrigen Ergebnistypen:
    CARDINAL  >>  LONGCARD           INTEGER >>  LONGINT
    WORD      >>  LONGWORD          BYTE     >>  WORD
    REAL       >>  LONGREAL

MAX (OrdinalType): OrdinalType;
    Ergibt den maximalen Wert des Typs 'OrdinalType'. Kann auch auf REAL
    und LONGREAL angewendet werden (Megamax-Erweiterung).

NEW (VAR x: PointerType);
    Reserviert Speicher fr x^. NEW wird vom Compiler  durch  ALLOCATE
    (x, SIZE (x^)) ersetzt (die sichtbare ALLOCATE-Funktion wird verwendet -
    ggf. mu ALLOCATE aus Storage importiert werden!).
3.1  Megamax Modula: Sprachumfang                                     3 -  7
________________________________________________________


MIN (OrdinalType): OrdinalType;
    Ergibt den minimalen Wert des Typs 'OrdinalType'. Kann auch auf REAL
    und LONGREAL angewendet werden (Megamax-Erweiterung), liefert dann
    den zu 0.0 kleinsten verschiedenen Wert.

ODD (x: OrdinalType): BOOLEAN;
    ODD (x) = "x ist ungerade". x kann von jedem ordinalen Typ sein.

ORD (x: OrdinalType): CARDINAL/LONGCARD;
    Liefert den Ordnungswert von x. x kann von jedem skalaren Typ  sein,
    siehe unter 'INC'. Das erste Element eines Aufzhlungstyps hat die Ordnungs~
    zahl Null. Bei Anwendung auf CHAR ergibt sich der jeweilige ASCII-Wert,
    bei einem BYTE-Typ wird der Wert zw. 0 und 255 geliefert (Megamax-
    Erweiterung).

SHORT (x: LongType): ShortType;
    Megamax-Erweiterung (aber bei vielen Compilern vorhanden)
    Wandelt einen Ausdruck von 32 Bit-Darstellung in 16 Bit-Darstellung (bzw.
    von 16 nach 8 Bit). Ist das Argument in dem verkrzten Typ nicht darstell~
    bar, wird ein Laufzeitfehler (berlauf) ausgelst. Die erlaubten Argumente
    und zugehrigen Ergebnistypen:
    LONGCARD  >>  CARDINAL            LONGINT  >>  INTEGER
    LONGWORD >>  WORD                WORD     >>  BYTE
    INTEGER     >>  BYTE (-128..127)     CARDINAL >>  BYTE (0..255)
    LONGREAL  >>  REAL

SIZE (VAR x: AnyType / t: AnyType): LONGCARD;
    Liefert Gre (Speicherbedarf) der Variablen x oder des Typs t in Bytes.

TRUNC (x: REAL): LONGCARD;
    Ergibt  ganzzahligen  Anteil  von  x.  Bei  Anwendung  auf  Werte,  die  als
    LONGCARD  nicht  darstellbar  sind,  wird  ein  Laufzeitfehler  (berlauf)
                 >>
    ausgelst.     Fr negative Werte ist VAL (LONGINT, x) zu verwenden.

VAL (OrdinalOrRealType; x: OrdinalOrRealType): OrdinalOrRealType;
    Die  VAL-Funktion  erlaubt  die  Wandlung  eines  Ausdrucks  <x>  in  den
    entsprechenden Wert des angegebenen Zieltyps  (erstes  Argument).  Fr
    Ausdruck und Zieltyp sind alle ordinalen Datentypen und Reals zulssig. Ist
    die Bereichsprfung aktiviert, wird bei Konvertierung des Werts auf einen
    kleineren Wertebereich Code erzeugt, der dann ggf. einen Fehler anzeigt.
3.1  Megamax Modula: Sprachumfang                                     3 -  8
________________________________________________________


Standardtypen: Gre und Wertebereich

Typ                  Gre/Byte    Wertebereich
SHORTINT          2               - 2^15  ..  2^15 - 1
SHORTCARD        2                     0  ..  2^16 - 1
LONGCARD         4                     0  ..  2^32- 1
LONGINT            4               - 2^31  ..  2^31 - 1
REAL                4               +/-2.71E-20 .. +/-9.22E+18
LONGREAL          8               +/-4.57E-1240 .. +/-1.75E+1240
CHAR               1               CHR (0) ..  CHR (255)
BOOLEAN           2               TRUE, FALSE
Aufzhlungen        2               maximal 65536 Elemente
BITSET              2               SET OF  0..15 
SET OF ...          1 bis 8192      wie LONGINT, aber max. 65536 Elemente.

Die  Typen  INTEGER  und  CARDINAL  werden  wahlweise  auf  SHORTCARD/
SHORTINT oder LONGCARD/LONGINT abgebildet.


Standardkonstanten (Megamax-Erweiterung)

MaxCard        =   2^16 - 1      =          65535
MaxInt          =   2^15 - 1      =          32767
MinInt           = - 2^ 15         =        - 32768
MaxLCard       =   2^32 - 1     =   4294967295
MaxLInt         =   2^31 - 1     =   2147483647
MinLInt          = - 2^31          = - 2147483648

Diese Konstanten  knnen  jedoch  auch  durch  die  Funktionen  MIN  und  MAX
ermittelt werden und  sollten  in  Hinblick  auf  den  ISO-Standard  nicht  mehr
benutzt werden.


Typen CARDINAL und INTEGER

Normalerweise  sind  diese  Typen  mit  SHORTCARD  und  SHORTINT  (s.u.)
identisch. Das heit, jeweils beide Namen knnen bei Bedarf gemischt werden.
Sie belegen dann jeweils zwei Byte (16 Bit). Wahlweise knnen sie auch auf
LONGCARD  bzw.  LONGINT  abgebildet  werden,  indem  die  Direktive  $I+
verwendet wird (siehe Kap 3.4). Sie haben dann deren greren Wertebereich
(32 Bit) und belegen 4 Byte.

Compiler-intern werden bei Verwendung von INTEGER/CARDINAL diese Typen
immer sofort in einen der SHORT-/LONG-Typen umdefiniert, je nach aktueller
Einstellung der Direktiven. Wird beispielsweise ein Definitionsmodul bersetzt,
whrend  CARDINAL  auf  LONGCARD  abgebildet  wird,  sind  alle  darin  mit
CARDINAL definierten Datentypen im Folgenden auf jeden Fall kompatibel zu
3.1  Megamax Modula: Sprachumfang                                     3 -  9
________________________________________________________


LONGCARD und nur dann kompatibel zu CARDINAL, sofern die entsprechende
Abbildung ber die Compiler-Direktive ($I+) gewhlt ist.

Die Bibliotheken des Megamax-Systems sind alle mit der Standardeinstellung
bersetzt  worden  ($I-),  das  heit,  CARDINAL  entspricht  SHORTCARD  und
INTEGER entspricht SHORTINT.

Anwendung findet diese Option beispielsweise, wenn Module von einem Modula-
System portiert werden, wo INTEGER und CARDINAL einen greren Werte~
bereich als 16 Bit aufwiesen (meist dann 32 Bit). Dann knnen diese Module
einfach ohne nderung mit der Direktive fr die  LONG-Abbildung  bersetzt
werden,  ohne  da  Bereichsberlufe/-beschrnkungen  befrchtet  werden
mssen.


Typen SHORTCARD und SHORTINT

Diese Typen entsprechen CARDINAL und INTEGER  bei  den  meisten  16-Bit-
Rechnern.  Sie  belegen  immer  zwei  Byte  und  haben  16  signifikante  Bits.
Normalerweise sind INTEGER und CARDINAL auf diese Typen abgebildet, das
heit, da sie identisch sind.

Wertebereich SHORTINT:     -32768 .. 32767
Wertebereich SHORTCARD:         0 .. 65535


Typen LONGCARD und LONGINT

Analog  zu  SHORTINT  und  SHORTCARD  sind  die  Typen  LONGINT  und
LONGCARD zum Rechnen mit 32 Bit-Zahlen definiert. Alle Operationen, die auf
INTEGER  bzw.  CARDINAL  mglich  sind,  sind  auch  mit  LONGINTs  bzw.
LONGCARDs zulssig. Konstanten dieser Typen sind durch ein nachgestelltes L
gekennzeichnet, z. B. -127L, 0L, 12345678L. (Im letzten Fall darf das L auch
fehlen, da der Wertebereich die Zahl eindeutig als Long-Typ identifiziert.) Statt
L kann wahlweise ein D als Suffix verwendet werden, wie in einigen anderen
Modula-Implementationen vorgeschrieben.

Wertebereich LONGINT:    -2147483648 .. 2147483647
Wertebereich LONGCARD:             0L .. 4294967295

Beachten   Sie   bitte,   da   die   LONG-Typen   nicht   kompatibel   zu   den
entsprechenden 16 Bit-Typen INTEGER und CARDINAL sind, da also in einem
arithmetischen Ausdruck 32- und 16-Bit-Typen nicht vermischt werden drfen.
Lediglich Konstanten sind kompatibel zu beiden Gren. Die Umwandlung von
Variablen, Funktionsergebnissen usw, kann mit der VAL-Funktion geschehen (s.
3.2). Bequemer ist die Verwendung der Funktionen SHORT und LONG, die im
folgenden Absatz beschrieben werden.
3.1  Megamax Modula: Sprachumfang                                     3 - 10
________________________________________________________


Bei Zuweisungen sind die Kompatibilittsforderungen gelockert: Die Zuweisung
eines 16-Bit-Wertes auf eine 32-Bit-Variable ist ohne weiteres mglich. In der
umgekehrten Richtung knnte ein berlauf auftreten, der erst zur Laufzeit des
Programms   feststellbar   ist.   Um   zu   verhindern,   da   eine   ungewollte
Vermischung der 16- und 32-Bit-Typen zu unerwarteten Laufzeitfehlern fhrt,
verlangt der Compiler hier die explizite Anpassung mittels der SHORT- oder
der VAL-Funktion. Dies kann jedoch ber eine Compiler-Direktive unterbunden
werden  (s.  Kapitel  ber  die  Compiler-Direktiven).  Dann  lt  der  Compiler
Zuweisungen von 32- auf 16-Bit-Typen zu und generiert dazu Code, der bei
einem  zu  groen  Wert  einen  Laufzeitfehler  meldet  (sofern  nicht  die
Generierung von Bereichsprfungen deaktiviert ist).


Typen REAL und LONGREAL

hnlich wie SHORTINT  und  LONGINT,  sind  auch  die  beiden  Real-Typen  zu
unterscheiden. REAL hat einen sehr kleinen Wertebereich, Berechnungen damit
sind dafr aber deutlich schneller (nur bei den Grundrechenarten!) als die mit
den viel genaueren LONGREALs. REALs haben nur 24 Bits fr die Mantisse
(incl. Vorzeichen), so da beachtet werden mu, da Rundungsfehler  schon
beim  Umwandeln  von  LONGINT-Werten  auftreten  knnen.  brigens  gilt
allgemein fr Real-Typen, da immer kleine Rundungsfehler bei Berechnungen
zu erwarten sind. So sollten Sie beispielsweise nie auf den Wert Null (0.0)
direkt vergleichen, sondern besser ein Intervall abfragen (also  z.B.  IF  ABS
(real) < 0.001 statt IF real = 0.0).

In Ausdrcken  knnen  REALs  und  LONGREALs  nicht  gemischt  werden,  sie
mssen mit der VAL-Funktion oder FLOAT/LFLOAT einander angepat werden.
Nur Real-Konstanten passen sich immer automatisch an den bentigten Typ an.

Zuweisungen lt Megamax Modula-2 zwischen beiden Typen beliebig zu. Der
ISO-Standard dagegen  wird  hierzu  immer  die  Konvertierung  mit  der  VAL-
Funktion oder FLOAT/LFLOAT verlangen. Wir haben hier die Lockerung, weil
die   Megamax-Bibliothek   z.Zt.   die   Real-Funktionen   ausschlielich   mit
LONGREAL-Parametern versehen hat und eine Handhabung von Variablen des
REAL-Typs sonst sehr umstndlich wre.


Funktionen SHORT und LONG

Megamax-Erweiterung (aber bei vielen Compilern vorhanden)

Die   Funktionen   wandeln   zwischen   Paaren   von   Datentypen,   die   zwar
unterschiedliche  Lngen  haben,  aber  jeweils  sich  entsprechende  innere
Struktur. Es gibt fnf solcher Paare:
3.1  Megamax Modula: Sprachumfang                                     3 -  11
________________________________________________________


SHORT (LONGINT)    = SHORTINT;       LONG (SHORTINT)   = LONGINT;
SHORT (LONGCARD)  = SHORTCARD;     LONG (SHORTCARD)= LONGCARD;
SHORT (LONGWORD) = WORD;            LONG (WORD)       = LONGWORD;
SHORT (WORD)       = BYTE;             LONG (BYTE)        = WORD;
SHORT (LONGREAL)  = REAL;             LONG (REAL)        = LONGREAL;

Die SHORT-Funktion erzeugt bei aktivierter Bereichsprfung (siehe Compiler-
Direktiven)  zustzlichen  Code,  der  beim  Krzen  von  Werten  der  Typen
LONGCARD,  LONGINT  und  LONGREAL  prft,  ob  der  Wert  in  die  kleinere
Darstellung pat. Wenn nicht, wird dann ein Laufzeitfehler angezeigt.

Beim Krzen von LONGWORD und WORD werden jeweils die hherwertigen
Bits/Bytes  abgeschnitten,  entsprechend  werden  von  der  LONG-Funktion  bei
BYTE und WORD die oberen Bits/Bytes mit Null aufgefllt.


Kompatibilitt von ADDRESS, POINTER, LONGCARD, Opaque

Adressen und Zeiger (POINTER) werden als 32-Bit-Werte dargestellt. Daher
ist der Typ ADDRESS (s. 3.2) nicht mit CARDINAL, sondern mit LONGCARD
kompatibel;  dies  erlaubt  das  Rechnen  mit  Speicheradressen  im  gesamten
adressierbaren  Bereich.  Opaque-Typen  (Typen,  deren  genaue  Definition  in
einem   Definitionsmodul   verschwiegen   wird)   knnen   als   32-Bit-Typen
implementiert werden; insbesondere ist also eine Implementation als POINTER
mglich.


Angaben von Speichergren

Ebenso  wie  die  Adressen  werden  auch  die  Lngen  von  Speicherbereichen
immer  als  32-Bit-Zahl,  also  als  LONGCARD,  angegeben.  Das  gilt  fr  die
Standardfunktion SIZE, fr einige Prozeduren aus dem SYSTEM-Modul (s. 3.2)
und auch fr zahlreiche Prozeduren der Megamax-Bibliothek.

Beispiel:
    PROCEDURE SIZE (VAR v: AnyType): LONGCARD;


Funktionen MIN und MAX

Die Standardfunktionen MIN und MAX akzeptieren als Argument jeden skalaren
Typ sowie REAL und LONGREAL. Sie liefern den minimalen bzw. maximalen
Wert des Typs.

Achtung: MIN (REAL) liefert den betragsmig kleinsten darstellbaren Wert; die
absolut kleinste darstellbare Realzahl ist -MAX(REAL).
3.1  Megamax Modula: Sprachumfang                                     3 - 12
________________________________________________________


Exportlisten in Definitionsmodulen, PERVASIVE Export, lokale Module

In der revidierten Modula-Syntax drfen Definitionsmodule keine EXPORT-Listen
mehr enthalten. Alle  Bezeichner,  die  im  Definitionsmodul  deklariert  werden,
werden  qualifiziert  exportiert.  Diese  Konvention  wird  auch  vom  Megamax
Modula-Compiler eingehalten.

Der Megamax-Compiler erlaubt jedoch weiterhin die Angabe einer EXPORT-
Liste, so da Definitionsmodule nach dem alten Standard unverndert bersetzt
werden knnen. Wird eine EXPORT-Liste spezifiziert, so bleiben alle dort nicht
aufgefhrten Bezeichner nach auen unsichtbar.

Durch  eine  Export-Liste  mit  dem  Schlsselwort  PERVASIVE  werden  die
aufgefhrten  Bezeichner  so  exportiert,  da  ein  Import  des  Moduls  die
Bezeichner berall sichbar werden lt, also auch automatisch in den lokalen
Modulen. Das Runtime-Modul wendet dies an, um seine Hilfsfunktionen berall
hin  sichtbar  zu  machen.  Der  Compiler  erzeugt  lediglich  automatisch  die
Anweisung IMPORT Runtime (sofern nicht $N+ verwendet wird) und schon ist
beispielsweise HALT aus Runtime berall sichtbar.

Exportierte Prozeduren, die dann erst in einem lokalen Modul implementiert
werden  sollen,  knnen  sowohl  aus  dem  lokalen  Modul  exportiert  als  auch
umgekehrt importiert werden. Die erste Lsung ist die allgemein verbreitete,
die andere wird beibehalten, da der alte Megamax-Compiler nur sie zulie.

Beispiele fr die mglichen Importe/Exporte bei lokalen Modulen finden Sie in
der Datei LOCALMOD.M im DEMO-Ordner.


Syntax eines Variant-Records

Die Syntax eines Variant-Records lautet seit PIM-3 nicht mehr

   FieldList = .. | CASE  ident ":"  qualident OF ..    sondern
   FieldList = .. | CASE  ident  ":" qualident OF .. .

Wenn Sie also keinen Feldnamen (ident) fr das Auswahlfeld angeben, mu
trotzdem ein ":" vor dem Typ des Auswahlfeldes stehen.  Das  erlaubt  eine
eindeutige Erkennung, ob ein Feldname vorhanden ist oder nicht. Beispiele:

   RECORD                                    RECORD
      CASE : BOOLEAN OF                      CASE male: BOOLEAN OF
          TRUE:    r: REAL |                        TRUE: rank: CARDINAL |
        FALSE: lo, hi: LONGCARD                  FALSE: maidenname: Name
      END                                       END
   END;                                       END;
3.1  Megamax Modula: Sprachumfang                                     3 - 13
________________________________________________________


Unterbereichs-Deklaration

Gem  der  neuen  Modula-Syntax  (PIM-3)  kann  bei  der  Deklaration  von
Unterbereichstypen  der  Basistyp  explizit  angegeben  werden.  Insbesondere
erlaubt dies, Unterbereichen den Typ INTEGER oder LONGINT zu geben, auch
wenn sie keine negativen Elemente enthalten. Die neue Syntax lautet

SubrangeType =  qualident  " " ConstExpression ".." ConstExpression " "
Beispiel:   TYPE  PosInt  =  INTEGER  0 .. MaxInt ;


FORWARD-Deklaration

Der Megamax Modula-bersetzer ist ein Ein-Pass-Compiler. Soll eine Prozedur
aufgerufen werden, bevor sie deklariert wurde, ist deshalb eine FORWARD-
Deklaration erforderlich, die dem Compiler die vorgesehene Parameterliste der
Prozedur mitteilt. Ihre Syntax lautet

ForwardDeclaration =   ( FORWARD ident  FormalParameters  )
                       | ( PROCEDURE ident  FomalParameters  ; FORWARD )

Die erste Formulierung stammt vom Gepard-Modula-Compiler, die zweite ist
die  allgemein  bei  Ein-Pass-Compilern  bliche  Form  (Pascal-Syntax).  Wir
empfehlen daher die Verwendung der zweiten Form, die in Zukunft auch von
allen Modula-Compilern nach ISO-Norm verstanden wird.

Bei der spteren Implementation der Prozedur mu der komplette Prozedurkopf
mit Parameterliste nochmals wiederholt werden (wie das auch bei Prozeduren
erforderlich ist, die im Definitionsmodul deklariert wurden). Beispiel:

PROCEDURE  SagHallo (wie: ARRAY OF CHAR; wann: CARDINAL);
   FORWARD;
 ...
     (* von hier an kann SagHallo nun benutzt werden *)
PROCEDURE  SagHallo (wie: ARRAY OF CHAR; wann: CARDINAL);
   BEGIN ...
   END SagHallo;


Externe Variable

Megamax-Erweiterung (auch bei vielen anderen Compilern anzutreffen)

Normalerweise hat man keine Einflu darauf, wo Compiler und Linker die Vari~
ablen (ebenso wie den Programmcode) ablegen. Man greift einfach darauf zu.
3.1  Megamax Modula: Sprachumfang                                     3 - 14
________________________________________________________


Fr systemnahe Programmierung ist es oft wnschenswert, auf feste Spei~
cherstellen zuzugreifen. Die gngige Methode ist dabei, einen POINTER auf den
gewnschten Datentyp zu deklarieren und dann die Adresse darauf zuzuweisen.
Dann kann ber den Pointer zugegriffen werden. Einfacher ist es bei Megamax
Modula:  Variablen  werden  einfach  feste  Adressen  zugewiesen,  indem  beim
Deklarieren der Variablen hinter dem Namen und  vor  dem  Doppelpunkt  die
Adresse in eckigen Klammern angegeben wird. Beispiel:

  VAR palmode  $448 : CARDINAL; (* 0: NTSC (60Hz), sonst: PAL (50Hz) *)
        farbTabelle $FF8240 : ARRAY  0..15  OF WORD;

Fast alle interessanten und dokumentierten Systemadressen von Registern und
Variablen des TOS sind normalerweise zugriffsgeschtzt, d.h. da beim Zugriff
darauf ein Bus-Fehler (Zugriff auf unbekannte Adresse) ausgelst wird. Um
dies zu umgehen, mu man in den Supervisor-Modus gelangen,  z.B.  durch
Calls.CallSupervisor. Eine andere, einfachere Lsung wre, die Funktionen aus
SysUtil1 zu verwenden.


Funktions-Prozeduren

ISO-Erweiterung

Damit sind Prozeduren gemeint, die  ein  Ergebnis  als  Funktionswert  liefern.
Entgegen  Wirths  Einschrnkung,  nur  einfache  Datentypen  als  Ergebnis  zu
liefern, kann der Megamax-Compiler jeglichen Datentyp zurckgeben. So sind
grere  Strukturen  oder  Felder  kein  Problem.  Die  Module  StrConv  und
FuncStrings machen sich diesen Vorteil zunutze, um  bequemer  mit  Strings
umzugehen.

Beispielsweise  liee  sich  ein  Datentyp  COMPLEX  mitsamt  der  blichen
Funktionen fr die Operatoren auf diesen Typ:

TYPE  COMPLEX = RECORD  re, im: REAL  END;
PROCEDURE Add ( a, b: COMPLEX ): COMPLEX;
PROCEDURE Mul ( a, b: COMPLEX ): COMPLEX;

So lt sich dann sehr komfortabel damit rechnen. Z.B. she die Anweisung
  a:= b + c * d
folgendermaen aus:
  a:= Add ( b, Mul ( c, d ));
3.1  Megamax Modula: Sprachumfang                                     3 - 15
________________________________________________________


Lokale Prozeduren als aktuelle Parameter

Megamax-Erweiterung

Standard-Modula  erlaubt  aus  technischen  und  Sicherheitsgrnden  nur  die
Zuweisung globaler Prozeduren an Variablen und Parameter des PROCEDURE-
Typs. Die Sprache Pascal, die keine Prozedur-Variablen kannte, sondern nur
Parameter dieses Typs, erlaubte dafr die bergabe lokaler Prozeduren an die
Parameter.  Nach  einem  persnlichen  Gesprch  von  uns  mit  N.  Wirth
(September '89 auf einem internationalen Treffen von Modula-Entwicklern in
Bled, Jugoslawien) ber diese Einschrnkung bei Modula machte N. Wirth den
Vorschlag, mit einfachen Mechanismen beide Mglichkeiten zu kombinieren und
dies auch in der ISO-Normungsgruppe als Spracherweiterung aufzunehmen. Ob
dies Feature wirklich in den ISO-Standard aufgenommen wird, ist noch nicht
sicher,  wir  haben  dem  jedoch  schon  vorgegriffen  und  es  erfolgreich
implementiert.

Folgende Regeln sind zu beachten: Auf eine Prozedur-Variable drfen weiterhin
nur  globale  Prozeduren,  auf  Prozedur-Parameter  bei   Funktionsaufrufen
beliebige Prozeduren (soweit sie Typ-gleich sind, natrlich) zugewiesen werden.
Der Compiler vermag dafr zu sorgen, da ein formaler Prozedur-Parameter
weiterhin auf eine Prozedur-Variable (gleichen Typs) zugewiesen werden kann,
trotzdem  aber  erkannt  wird,  wenn  es  sich  dabei  nicht  um  eine  globale
Prozedur handelte, um in diesem Fall einen Laufzeitfehler anzuzeigen.

Allerdings ist diese Erweiterung nur anwendbar, wenn beim bersetzen der
Funktion mit dem Prozedur-Parameter  die  Compiler-Direktive  $H+  aktiv  ist
(siehe Kapitel 3.4).

Es mu aber darauf geachtet werden, da sowohl bei FORWARD-Deklarationen
als  auch  in  Definitionsmodulen  die  Direktiven-Einstellungen  mit  der  bei  der
Implementation  bereinstimmen.  Das  gleiche  gilt,  wenn   Prozedur-Typen
deklariert werden: Wenn also ein Versionskonflikt bei einer Zuweisung einer
Prozedur angezeigt wird, sind nicht nur die Parameter auf bereinstimmung,
sondern auch die Einstellung der $H-Direktive zu vergleichen.

Viele Funktionen der Megamax-Bibliothek wurden mit dieser Option bersetzt,
so  da  Sie  bequem  auch  lokale  Prozeduren,  beispielsweise  bei  Call  aus
EasyExceptions, verwenden knnen.
3.1  Megamax Modula: Sprachumfang                                     3 - 16
________________________________________________________


Zuletzt noch ein Anwendungsbeispiel:

  (*$H+*)
  PROCEDURE RufeNmal (prozedurAufruf: PROC; n: CARDINAL);
    VAR c: CARDINAL;
    BEGIN
      FOR c:= 1 TO n DO
        prozedurAufruf ()
      END
    END RufeNmal;

  PROCEDURE schreibeNmal (text: ARRAY OF CHAR; n: CARDINAL);

    PROCEDURE schreibeText;
      BEGIN
        WriteString (text);
        WriteLn
      END schreibeText;

    BEGIN (* schreibeNmal *)
      RufeNmal (schreibeText, n);
    END schreibeNmal;

  BEGIN (* Hauptprogramm *)
    schreibeNmal ('Hallo', 4)
    ...

In  diesem  Beispiel  akzeptiert  die  Routine  RufeNmal  die  lokale  Prozedur
schreibeText von schreibeNmal. Wird sie nun aufgerufen, kann sie wiederum
ganz normal auf die umgebenden Variablen, also auch text, zugreifen, so als
ob sie direkt in schreibeNmal aufgerufen worden wre. Nach dem normalen
Modula-Standard ginge das nicht und man mte den text in einer globalen
Variablen zwischenspeichern, damit schreibeText darauf zugreifen knnte.


Zuweisungen von LONGs auf SHORTs

Nomalerweise  erlaubt  Megamax-Modula  aus  Sicherheitsgrnden  nicht  die
implizite Zuweisung von LONGCARD- oder LONGINT-Werten auf SHORTCARD-
oder SHORTINT-Variablen. Dies kann jedoch ber die Direktive $K+ (siehe Kap.
3.4) ermglicht werden.


Bedingungen fr Laufvariablen von FOR-Schleifen

Der Compiler legt seit Version 4.0 Laufvariablen von FOR-Schleifen mglichst
in  Registern  ab,  anstatt  sie  im  Speicher  zu  halten.  Dies  bringt  teilweise
deutliche Geschwindigkeitsvorteile.
3.1  Megamax Modula: Sprachumfang                                     3 - 17
________________________________________________________


Allerdings sind auch einige Bedingungen daran geknpft, die schon immer bei
Pascal und Modula galten, aber bisher nur selten ernst genommen wurden:

Die  Laufvariable  mu  eine  einfache,  lokale  Variable  sein.  Sie  darf  weder
exportiert/importiert  noch  Feld  eines  Records  sein.  Zuweisungen  darauf
innerhalb der Schleife sind ebenfalls nicht erlaubt, nach dem Schleifenende ist
der Wert wirklich undefiniert (und nicht etwa letzter Schleifenwert plus Eins,
oder sowas).

Der  Compiler  zeigt  bei  Verletzung  dieser  Regeln  entsprechende  Fehler~
meldungen an, so da eine eventuelle Korrektur schnell erledigt ist. Allerdings
kann er das z.Zt. nicht in Assembler-Teilen. Fr solche kritischen Situationen
gibt es deshalb die Direktive $J (s. Kapitel 3.4).

Beispiel:  Eine  globale  Schleifenvariable  darf  keinesfalls  auerhalb  der  FOR-
Schleife im Text abgefragt werden, weil ggf. der Wert in einem Register liegt
und die globale Variable nicht verndert wrde. Beispiel:

    VAR laufvar: CARDINAL;
    PROCEDURE prozedur;
      BEGIN
        IF laufvar = 4 THEN ... END   (* dieser Zugriff ist nicht erlaubt! *)
      END prozedur;
    BEGIN
                  :
      FOR laufvar = 1 TO 10 DO prozedur END


SETs

Seit  der  Revision  von  PIM  knnen  Sets,  die  mit  geschweiften  Klammern
formuliert werden, nicht mehr  nur  Konstanten  sondern  beliebige  Ausdrcke
enthalten. Beispiele:

  VAR set: BITSET; c, d: CARDINAL;
  BEGIN
        :
    set =  c ;
    (* anstatt: *)
        :
    set =   ; INCL (set, c);

    set =  c..d ;

Die letzte Zeile zeigt, da auch ganze Elementbereiche in einem Stck markiert
werden knnen. Ist dabei c grer als d, bleibt die Menge leer - es wird also
nicht etwa ein Laufzeitfehler gemeldet!
3.1  Megamax Modula: Sprachumfang                                     3 - 18
________________________________________________________


Mehrdimensionale offene Felder (Open Array)

ISO-Erweiterung

Damit knnen nun auch mehrdimensionale Felder als offene Felder mitsamt der
Gren aller  Dimensionen  bergeben  werden.  Die  HIGH-Werte  der  tieferen
Dimensionen sollten dabei immer mit dem Zugriff auf das erste Feld mit dem
Index Null ermittelt werden. Beispiel:

    PROCEDURE showMatrix (matrix: ARRAY OF ARRAY OF INTEGER);
      BEGIN
               :
        FOR x = 0 TO HIGH (matrix) DO
                 :
          FOR y = 0 TO HIGH (matrix 0 ) DO
            WriteInt (matrix x,y , 4)
          END;
          WriteLn
        END
      END showMatrix;

    VAR mat1:  ARRAY  1..4  OF  1..2  OF INTEGER;
         mat2: ARRAY  1..3  OF  1..3  OF INTEGER;

    BEGIN
      showMatrix (mat1);
      showMatrix (mat2);
    END


Gre von INTEGER und CARDINAL

Diese Typen knnen wahlweise auf SHORTINT/SHORTCARD (Voreinstellung)
oder auf LONGINT/LONGCARD (Direktive $I+, s. Kap. 3.4) abgebildet werden.


Datengre bei offenen Feldern (Open Array)

Megamax-Erweiterung

Normalerweise knnen an ein Open Array maximal 65536 Elemente bergeben
werden, bei offenen Feldern, deren Elemente nur ein Byte gro sind (BYTE,
CHAR), sind aus Effizienzgrnden sogar nur 32768 Elemente erlaubt! Wenn
Sie beispielsweise ein ARRAY  1..50000  OF BYTE an ein ARRAY OF BYTE-
Parameter bergeben wollen, wird der Compiler eine Fehlermeldung anzeigen.
Zur  Abhilfe  knnen  Sie  das  Open  Array  mit  LONGARRAY  statt  ARRAY
deklarieren. Das teilt dem Compiler mit, einen LONGCARD-Wert statt eines
SHORTCARD  als  HIGH-Wert  zu  verwenden,  so  da  die  Elementanzahl
unbegrenzt gro sein kann.
3.1  Megamax Modula: Sprachumfang                                     3 - 19
________________________________________________________


Beispiel:
   PROCEDURE Clear (VAR data: LONGARRAY OF BYTE);

An diese Funktion kann auch ein Array mit mehr als 32 KB Gre bergeben
werden.


Value Constructors (Aggregate)

ISO-Erweiterung

Damit knnen strukturierte Daten, wie Felder und Records, in einem Stck aus
Ausdrcken geformt werden. Dies ist nicht neu: Bereits SETs konnten schon
immer mit der Form SetTyp  elem1, elem2, ...  erzeugt werden.

Die Syntax fr allgemeine Aggregate lehnt sich an die der SETs an: Zuerst
kommt der Typ der Struktur, danach in geschweiften Klammern die einzelnen
Elemente der Struktur, wie Parameter bei einem Funktionsaufruf.

Bei Feldern (ARRAYs) werden einfach alle Feldelemente aufgezhlt. Statt der
Einzelaufzhlung ist mit dem reservierten  Wort  BY  auch  die  Angabe  eines
Wiederholungsfaktors  (Replikator)  mglich.  Das  Feld  mu  immer  vollstndig
aufgefllt werden. Beispiel:

  TYPE Feld = ARRAY  1..10  OF CARDINAL;
  CONST Leerfeld = Feld   0 BY 10  ;
  VAR f: Feld;
  BEGIN
     :
    f = Leerfeld;
     :
    f = Feld   10, 20, 30, 40 BY 7  ;

Bei Verwendung des Replikators (BY) fr einen Funktionsaufruf wird aber nur
der  Funktionswert  entsprechend  oft  eingesetzt,  nicht  etwa  die  Funktion
mehrfach aufgerufen! Beispielsweise initialisiert
    :
   f = Feld   Random() BY 10  
das Feld nicht etwa mit zehn verschiedenen Random-Werten, sondern zehnmal
mit dem einmalig ermittelten Zufallswert!

Bei RECORDs werden die Elemente in der Reihenfolge angegeben, in der ihre
Felder  deklariert  wurden.  Bei  Record-Varianten  (CASE)  mu  auch  das
Selektionsfeld  immer  passend  mit  angegeben  werden,  damit  der  Compiler
entscheiden kann, fr welchen CASE-Fall die folgenden Elemente angegeben
werden. Beispiel:
3.1  Megamax Modula: Sprachumfang                                     3 - 20
________________________________________________________


  TYPE Rec = RECORD
                  a, b, c: CARDINAL;
                  CASE : BOOLEAN OF
                    TRUE:   ch: CHAR |
                    FALSE:  lc: LONGCARD
                  END
               END;
  VAR r: Rec;
  BEGIN
       :
     r  = Rec  1, 2, 3, TRUE, 'z' ;
     (* dies entspricht: *)
     WITH r DO
          :        :        :         :
        a = 1;  b = 2;  c = 3;  ch = 'z'
     END;


Verkettung von String-Konstanten

ISO-Erweiterung

String-Konstanten  knnen  verkettet  werden.  Damit  ist  es  beispielsweise
mglich,  Sonderzeichen  in  einen  String  einzufgen.  Als  Operator  wird  das
Plus-Zeichen verwendet.

Vorsicht: Dies ist nicht mit der String-Verkettungsmglichkeit bei Pascal zu
verwechseln, wo mit dem Plus-Operatur auch Variablen zusammenfgbar sind
- dazu sind in Modula die Funktionen des Strings-Moduls vorgesehen!

Beispiele:
  CONST Bing = 7C;
           text = "Hallo" + Bing; (* String mit Ctrl-G f. Ton-Ausgabe *)

  WriteString ("Hi!" + Bing);
  (* statt bisher: WriteString ('Hi'); Write (Bing); *)

Generell knnen nur String-Literale verkettet werden, das sind alle Zeichen~
ketten aus einfachen oder doppelten Anfhrungszeichen und Zeichenkonstanten
in  der  Oktaldarstellung  mit  angefgtem  "C".  Die  Funktion  CHR()  liefert
beispielsweise den Typ CHAR und kann deshalb nicht mit verkettet werden.
3.1  Megamax Modula: Sprachumfang                                     3 - 21
________________________________________________________


Funktion LENGTH

ISO-Erweiterung

LENGTH  hat  einen  String  als  Argument  und  liefert  seine  Lnge,  wie  die
Length-Funktion des Strings-Moduls. Ihre Vorteile:
  * Sie kann in CONST-Ausdrcken benutzt werden. Beispiel:
         CONST str = "bla bla";
         VAR    feldFuerStr: ARRAY  0..LENGTH (str)  OF CHAR;
  * Sie ist immer schneller als die Length-Funktion aus Strings.

Sie liefert,  je  nach  Gre  des  Strings,  SHORTCARD  bzw.  LONGCARD  als
Ergebnis.


Funktionen FLOAT und LFLOAT

ISO-Erweiterung

Nach PIM erlaubt FLOAT nur CARDINAL als Argument,  nun  sind  aber  alle
Ganzzahl-  und  Real-Typen  zugelassen.  FLOAT  liefert  ein  REAL-Ergebnis.
Analog dazu liefert LFLOAT LONGREAL-Werte. Die Funktionen haben demnach
den selben Effekt wie VAL (REAL/LONGREAL, argument), jedoch sind sie
nicht auf CHARs und Aufzhlungstypen zugelassen.

Damit eignen sich FLOAT und LFLOAT nicht nur zur Wandlung zw. CARDINAL/
INTEGER und Reals, sondern auch zum Konvertieren von REAL und LONGREAL
in Ausdrcken. Beispiel:

      VAR  sr: REAL;  lr: LONGREAL;
      BEGIN
          :
        lr = lr + LFLOAT (sr);


Funktion INT

ISO-Erweiterung

INT ist eine krzere Form fr VAL (INTEGER, argument); alle Typen sind, wie
bei  VAL,  zugelassen.  INT  und  ORD  lassen  sich  sehr  praktisch  zum
Konvertieren zwischen CARDINAL und INTEGER und  Ausdrcken  verwenden.
Beispiel:

      VAR  int: INTEGER;  card: CARDINAL;
      BEGIN
           :
        int = int * INT (card);
3.1  Megamax Modula: Sprachumfang                                     3 - 22
________________________________________________________


Kompatibilitt bei Open Arrays

Megamax-Erweiterung

Wenn sich Wirth in PIM auch nicht przise darber auslt, hat er jedoch bei
einer Anfrage von ISO klargestellt, da auf ein ARRAY OF Typ nicht einzelne
Ausdrcke des Typs Typ zuweisbar sind, sondern nur echte Felder (ARRAYs)
dieses Typs. Das heit nach ISO, auf ein ARRAY OF CHAR darf nicht eine
einzelne  CHAR-Variable  zugewiesen  werden  (allerdings  schon  eine  String-
Konstante der Lnge Eins, wie z.B. "a").

Megamax Modula-2 erlaubt jedoch auch die Zuweisung einzelner Elemente des
Array-Typs.


Kompatibilitt von Strings

Megamax-Erweiterung

Bei String-Variablen, also ARRAY  0..n  OF CHAR, sind die Regeln  fr  die
Zuweisungskompatibilitt  etwas  gelockert:  Die  Variablen  mssen  nicht  den
selben  Typ  haben,  sondern  lediglich  dieselbe  Gre  aufweisen.  Das  heit,
folgendes Beispiel ist in Megamax-Modula legal:

   VAR a: ARRAY  0..9  OF CHAR;
        b: ARRAY  0..9  OF CHAR;
   BEGIN
       :
     a = b;


Erweiterte Syntax

Durch die Anwendung der Compiler-Direktive $A+ werden die Syntax-Regeln
gelockert:
  * Variable,  die  an  VAR-Parameter  bergeben  werden  sollen,  knnen  mit
    einem Typ-Transfer versehen werden. Beispiele:
        ReadCard ( CARDINAL ( wordVar ) );
        INC ( CAST ( CHAR, byteVar ) );
  * Nach einem Funktionsaufruf (auch Typ-Transfer usw.) knnen die Ergeb~
    nisse weiterhin selektiert, dereferenziert, indiziert bzw. - bei Funktionen -
    aufgerufen werden. Beispiele:
                 :
        cardVar  = ArrayTyp ( pointer^ )  n ;
                 :
        cardVar  = returningRecord().cardElement;
                 :
        cardVar  = CAST (PtrToCard,addressVar)^;
                 :
        cardVar  = FunctionTyp (addressVar) ();  (* Funktionsaufruf *)
3.1  Megamax Modula: Sprachumfang                                     3 - 23
________________________________________________________


REF-Parameter

Megamax-Erweiterung (auch bei einigen anderen Compilern vorhanden)

Eine Schwche von Modula liegt darin, da aktuelle Parameter nur als Wert-
oder  Referenz-Parameter  verwendbar  sind.  Bei  der  bergabe  von  Wert-
Parametern  werden  immer  lokale  Kopien  der  Daten  angelegt,  damit  die
aufgerufene  Funktion  die  Werte  ndern  kann,  ohne  die  Originaldaten  zu
beeinflussen. Sollen nun sehr groe Datenmengen, beispielsweise umfangreiche
ARRAYs, als Parameter bergeben werden, tritt erstens oft die Zeitspanne fr
den  Kopiervorgang  negativ  in  Erscheinung,  zweitens  kann  es  leicht  zu
Stack-berlufen kommen, da die Kopien ja auf dem Stack angelegt werden.

Abhilfe  kann  man  sich  dadurch  schaffen,  da  man  die  Referenz  auf  die
Originaldaten bergibt, indem entweder ein POINTER darauf bergeben oder
der formale Parameter mit VAR versehen wird. Natrlich geht das nur, wenn
auch  sichergestellt  wird,  da  die  aufgerufene  Funktion  die  Daten  nicht
verndert, wenn sie es nicht soll. Dies ist aber leider nicht kontrollierbar. Ein
weiterer Nachteil liegt darin, da an VAR-Parameter keine Konstanten oder
Funktionsergebnisse bergeben werden knnen.

Die Lsung ist nun, REF statt VAR vor den formalen Parameter zu schreiben.
Dann wei  der  Compiler,  da  er  die  Daten  nach  Mglichkeit  als  Referenz
bergeben soll, also keine lokale Kopie anzulegen braucht, und zustzlich kann
er berwachen, da die Daten in der Funktion nicht verndert werden, indem
er Zuweisungen darauf und die bergabe an Prozeduren mit VAR-Parametern
nicht zult. Allerdings erlaubt er den Zugriff auf den Parameter mittels der
CADR-Funktion - da diese aus SYSTEM importiert  werden  mu  und  somit
auffllt, knnen Sie als Programmierer leicht selbst prfen, ob ein  illegaler
Schreibzugriff auf die Daten geschieht.

Beim bertragen eines Programms auf  einen  Compiler,  der  REF-Parameter
nicht kennt, entstehen keine Probleme: Lschen Sie einfach alle Vorkommen
von REF. Dann werden die Daten wieder lokal kopiert, so da bis auf einen
evtl. greren  Stack-Bedarf  keine  weiteren  Programmnderungen  notwendig
werden.

Zu beachten:

Allerdings ist Vorsicht bei der Verwendung von REF-Parametern geboten: Man
kann nicht berall, wo bisher value-Parameter verwendet wurden, nun einfach
REF  einsetzen.  Denn  sonst  das  sogenannte  kann  alias-Problem  auftreten.

Beispiel:

    PROCEDURE proc (in: ARRAY OF CHAR; VAR out: ARRAY OF CHAR);
3.1  Megamax Modula: Sprachumfang                                     3 - 24
________________________________________________________


Wenn hier nun REF bei in eingesetzt wird, knnte es zu Fehlern kommen, wenn
proc mit zwei identischen Variablen aufgerufen wird, also beispielsweise

    proc ( datum, datum );

Greift proc nmlich auf in zu und verndert gleichzeitig out, wrde auch in
indirekt verndert, weil in ja direkt  auf  das  bergebene,  vernderte  datum
zugreift.

Wie kann man diesem Effekt vorbeugen?

* Erste Regel: REF ist kein Ersatz fr value-Parameter, sondern ein  VAR-
  Parameter,  der  auch  Konstant-Zuweisungen  erlaubt.  Nach  dieser  Regel
  erkennt man leicht: Wrde man VAR beim in-Parameter einsetzen, wre das
  alias-Problem leichter erkennbar.

* Zweitens: Nur bei Prozeduren, die zustzliche VAR-Parameter haben, kann
  dieses  Problem  entstehen.  Nur  dann  braucht  berhaupt  die  obige  Regel
  beachtet zu werden.

Beispiel fr eine Anwendung der REF-Parameter:

    MODULE RefBsp;
    FROM InOut IMPORT WriteString, WriteCard, ReadString, Done;
    PROCEDURE spaces (REF str: ARRAY OF CHAR): CARDINAL;
      (* Zhlt die Leerzeichen im String "str" *)
      VAR idx, n: CARDINAL;
      BEGIN
        n:= 0;
        FOR idx:= 0 TO HIGH (str) DO
          IF str  idx  = " " THEN INC (n) END
        END;
        RETURN n
      END spaces;
    VAR s: ARRAY  0..99  OF CHAR;
    BEGIN
      LOOP
        ReadString (s);
        IF NOT Done THEN EXIT END;
        WriteString ("Der eingegebene String enthlt ");
        WriteCard (spaces (s), 0);
        WriteString (" Leerzeichen.");
        WriteLn;
      END
    END RefBsp.
3.2 Megamax Modula: Interne Datenformate                             3 - 25
________________________________________________________


3.2  Interne  Datenformate

Ablage von Strukturen im Speicher, Unterschiede zu anderen Compilern

Hier wird im einzelnen erklrt, wie es  sich  mit  der  Aufteilung  der  unter~
schiedlich  groen  Datenelemente  in  Strukturen  verhlt  und  worauf  bei  der
bertragung (Portierung) von Modula-Programmen anderer Implementierungen
zu achten ist.


Sets und BITSET

Bei Sets werden oft speicheraufteilungsabhngige Annahmen gemacht. Daher
ist es allein aus Grnden der leichteren Handhabung und Portierbarkeit bei den
680x0 CPUs oft wnschenswert, da ein BITSET 16 Elemente fat und diese
genau  den  Bits  eines  Maschinenworts  entsprechen.  Dagegen  spricht  aber,
SETs mit mehr als 32 Elementen, die Megamax Modula-2 auch ermglicht, in
dieser Form abzulegen. Je nach Prozessortyp (68000, wie im Atari ST, oder
68030, wie im Atari TT) bieten sich unterschiedliche Formate  an,  um  den
jeweils  optimalen  Geschwindigkeitsgewinn  zu  erlangen.  Um  nun  dem  oft
ausgesprochenen Wunsch unserer Anwender nachzukommen, bieten wir einen
Kompromi: SETs mit bis zu 32 Elementen werden im Speicher so angelegt,
da  die  Bit-Zhlung  beim  niederwertigsten  Byte  im  untersten  Bit  mit  Null
beginnt. Dies entspricht der blichen Bit-Numerierung von Byte-, Word- und
Long-Daten bei den 680x0-Prozessoren.

Beispiel fr BITSET:
   Byte-Offset im Speicher:            0            |             1
   Bit-Nummern:           7  6  5  4  3  2  1  0  |  7  6  5  4  3  2  1  0
   SET-Elemente:          15 14 13 12 11 10 9  8  |  7  6  5  4  3  2  1  0

Bei  SETs  mit  mehr  als  32  Elementen  ist  die  Aufteilung  ganz  einfach
undefiniert. Wir behalten uns vor, je nach Prozessortyp, fr den der Compiler
Code erzeugen soll, ein anderes Format zu whlen. Sie drfen also keinesfalls
auf die einzelnen Elemente  solcher  SETs  in  Assembler  oder  durch  andere
Tricks zugreifen! Haben Sie groe Bit-Felder, die ein  festes  Format  haben
mssen, z.B. um auf eine Bitmap einer Grafik zuzugreifen, mssen Sie sich
damit behelfen, ARRAYs aus kleinen SETs (bis 32 Elemente) zu bilden.

LONG-Werte

Manche Compiler erlauben es, in Ausdrcken LONG-Werte (z.B. LONGCARD)
mit  WORD-Werten  (z.B.  CARDINAL)  zu  mischen.  Auch  knnen  manchmal
LONG-Werte  auf  SHORT-Variablen  zugewiesen  werden.  Unser  Compiler
erlaubt dies z.Zt. nur bei Konstanten. In anderen Fllen mu explizit durch die
Standardfunktionen LONG und SHORT (bequemer als VAL) oder VAL (portabler)
umgewandelt werden.
3.2 Megamax Modula: Interne Datenformate                             3 - 26
________________________________________________________


Beispiel:
  VAR card: CARDINAL; longcard: LONGCARD;
  BEGIN
         :
    card = SHORT ( longcard * 2 DIV LONG (card) );


Packen von BYTE-Daten

Byte-Daten  sind  alle  diejenigen,  deren  Basistyp  ein  Byte  gro  ist,  also
beispielsweise CHAR und SET OF  0..7 .

Der Prozessor im Atari ST, der 68000, ist daraufhin optimiert, mit Word-
und  Long-Daten  umzugehen.  Zugriffe  auf  Byte-Daten  sind  verhltnismig
ineffektiv. Aus diesem Grund versucht der Compiler, Daten, die grer als ein
Byte sind, mglichst als Word- bzw. Long-Daten anzusprechen, anstatt alles
immer ber byteweisen Zugriff zu erledigen. Dies fhrt aber zu einer neuen
Einschrnkung: Word- (und damit auch Long-) Zugriffe sind nur mglich, wenn
solche Daten auf geraden Adressen liegen. Versucht man, Word-Zugriffe auf
ungeraden Adressen durchzufhren, strubt sich der Prozessor, indem er eine
Exception auslst, was in der Shell zur Fehleranzeige Zugriff auf ungerade
Adresse fhrt.

Werden nun Strukturen, die Byte-Daten enthalten, definiert und verwendet, hlt
der Compiler bestimmte Konventionen ein, um eine solche Fehlermeldung zu
vermeiden:

Enthlt ein RECORD  Byte-Daten,  werden  sie  immer  auf  das  nchste  freie
Byte-Feld im  Record  gelegt.  Andere  Daten  werden  zuerst  immer  synchro~
nisiert, d.h. sie werden immer auf gerade Adressen gelegt - ggf. bleibt davor
ein Byte unbenutzt.

bersetzt der Compiler Zuweisungen von Strukturen, erzeugt er in der Regel
Word-Kopieranweisungen. Lediglich bei reinen Byte-Strukturen, die ber Pointer
dereferenziert oder als REF-/VAR-Parameter bergeben werden, erzeugt er
sicherheitshalber Byte-Kopieranweisungen. Damit besteht also nie die Gefahr,
da ein Adre_Zugriffsfehler auftritt.
3.3 Megamax Modula: SYSTEM-Modul                                    3 - 27
________________________________________________________


3.3   Das  SYSTEM-Modul

Megamax Modula stellt einige Datentypen und Funktionen zur Verfgung, die
besonders die systemnahe Programmierung untersttzen. Naturgem wird die
bertragbarkeit Ihrer Modula-Programme auf andere Rechner gefhrdet, wenn
Sie zu freigiebig von solchen maschinennahen Konstrukten Gebrauch machen.
N. Wirth hat darum  vorgeschlagen,  diese  nicht  als  Standardfunktionen  und
-typen anzubieten, sondern den Import aus einem speziellen Modul SYSTEM zu
verlangen. Damit kann man schon im Kopf eines Moduls erkennen, ob es von
Funktionen Gebrauch macht, die eventuell hardware- oder compiler-spezifisch
sind.

Ein DEFINITION MODULE SYSTEM werden Sie allerdings auf den Megamax-
Disketten nicht vorfinden - das  SYSTEM-Modul  ist  Teil  des  Compilers,  da
seine Funktionen teilweise speziellen Regeln gehorchen und gar nicht in Modula
zu beschreiben wren. Wir versuchen's aber trotzdem,  um  einen  berblick
ber das Modul zu geben - Sie knnen sich die Definition so vorstellen:

DEFINITION MODULE SYSTEM;

CONST   CompilerVersion = 4;      (* 5 bei vollst. ISO-Norm-Compiler *)
CONST   CompilerSubVersion = .. ; (* Revisionsnummer *)

TYPE LOC;  BYTE;  WORD;  LONGWORD;
TYPE ADDRESS = POINTER TO WORD;

PROCEDURE TSIZE (AnyType; ... ): LONGCARD;
PROCEDURE CAST (AnyType; x: AnyType2): AnyType;
PROCEDURE ADR (VAR x: AnyType): ADDRESS;
PROCEDURE CADR (constOrVar: AnyType): ADDRESS;

TYPE BITNUM;
PROCEDURE SHIFT (VAR x: SetOfBitnumType; n: INTEGER);
PROCEDURE ROTATE (VAR x: SetOfBitnumType; n: INTEGER);

PROCEDURE CALLSYS (trap:  0..15 ; parms: AnyType ... ): LONGWORD;
PROCEDURE CALLEXT (addr: ADDRESS; parms: AnyType ... ): LONGWORD;

PROCEDURE CODE (n1: CARDINAL; n2: CARDINAL; ... );
PROCEDURE LOAD (x: LONGWORD; reg:  0..15 );
PROCEDURE STORE (reg:  0..15 ; VAR x: AnyType);
3.3 Megamax Modula: SYSTEM-Modul                                    3 - 28
________________________________________________________


PROCEDURE NEWPROCESS (p: PROC; a: ADDRESS; n: LONGCARD;
                               VAR q: ADDRESS);
PROCEDURE TRANSFER (VAR from, to: ADDRESS);
PROCEDURE IOTRANSFER (VAR from, to: ADDRESS; vector: ADDRESS);
PROCEDURE IOCALL (vector: ADDRESS);
PROCEDURE LISTEN ();

EXPORT ASSEMBLER;

END SYSTEM.

Da die meisten Exporte des SYSTEM-Moduls im  Modula-Standard  eindeutig
charakterisiert sind, sollen hier die folgenden Anmerkungen gengen:


Type ADDRESS

Noch ist ADDRESS als POINTER TO WORD definiert, die ISO-Norm verlangt
hier aber POINTER TO LOC. Achten Sie deshalb darauf,  da  Sie  nie  eine
Address-Variable dereferenzieren (mit "^"), weil damit jetzt noch ein Word,
bald (beim ISO-Compiler) aber ein Byte angesprochen wird!


Typen LONGWORD, WORD, BYTE und LOC

ISO- und Megamax-Erweiterungen

Wird in der Parameterliste einer  Prozedur  ein  Parameter  vom  Typ  WORD
deklariert,  so  lassen  sich  dieser  Prozedur  alle  Datentypen  bergeben,  die
intern  als  16-Bit-Wert  dargestellt  werden  (das  sind  CARDINAL,  INTEGER,
BOOLEAN, Aufzhlungstypen, Unterbereiche dieser Typen, SETs mit 9 bis 16
Elementen).

Analog  knnen  an  einen  LONGWORD-Parameter  beliebige  32-Bit-Typen
bergeben  werden.  Dies  sind  LONGCARD,  LONGINT,  Unterbereiche  davon,
ADDRESS, POINTER, PROC und andere Prozedurtypen, SETs mit 17 bis 32
Elementen.

Ein BYTE-Parameter dient (wie zu erwarten war) dazu, beliebige 8-Bit-Typen
an eine Prozedur zu bergeben; dies knnen CHAR und SETs mit bis zu 8
Elementen sein.

LOC ist in der ISO-Norm der neue Joker-Typ und ersetzt praktisch BYTE. In
Zukunft  sollte  daher  nur  noch  LOC  statt  BYTE,  WORD  und  LONGWORD
verwendet werden, denn LOC ist als kleinster gemeinsamer Datentyp definiert.
brigens: Die Definition nach Wirth hatte dies schon mit WORD beabsichtigt,
3.3 Megamax Modula: SYSTEM-Modul                                    3 - 29
________________________________________________________


nur leider miinterpretierten viele Compiler-Hersteller den Universal-Datentyp
WORD mit der Bezeichnung Word als 2-Byte-Datum bei vielen Mikroprozes~
soren. Daraus folgte dann, da WORD meist zwei Byte belegte und nun nicht
mehr 1-Byte-Typen, wie CHAR, einfach auf einenWORD-Parameter zuweisbar
waren. Deshalb wurde nun von ISO LOC fr diesen Zweck definiert.

Beachten Sie bitte, da diese 'Joker'-Typen nur in Prozedur-Parameterlisten
diese  besondere  Funktion  haben.  Zuweisung  oder  z.  B.  Addition  eines  16
Bit-Typs auf ein WORD sind nicht erlaubt; dazu mssen explizite Typtransfer-
Funktionen aufgerufen werden. An einen ARRAY OF LOC-Parameter  knnen
beliebige Daten bergeben werden.


Funktionen ADR und TSIZE

ADR liefert die Adresse einer Variablen. TSIZE liefert die Gre (in Byte) eines
Typs. Ist der Typ ein Record mit Varianten, knnen nach Modula-Syntax noch
die sog. Tags der Varianten angegeben werden, Megamax Modula-2 ignoriert
sie z.Zt. aber und liefert in jedem Fall die maximale Gesamtgre des Typs.


Konstante CompilerVersion und CompilerSubVersion

Megamax-Erweiterung

Diese Werte eignen sich besonders zur Abfrage beim bedingten Compilieren (s.
Kap. 3.4 ber Direktiven). Beide Werte werden auch vom Compiler beim Start
im Ausgabefenster und im Protokoll angezeigt. Jedes Mal, wenn gravierende
Funktionserweiterungen am Compiler vorgenommen werden,  erhhen  wir  die
CompilerVersion um Eins. Z.Zt. ist sie vier, nach offiziellem Erscheinen der
ISO-Norm werden wir einen vollstndig angepaten Compiler mit der Version
fnf verffentlichen.  Die  CompilerSubVersion  wird  bei  kleineren  nderungen
und Korrekturen erhht, die aber die grundstzliche Funktionsweise von bereits
fr die Version erstellten Programmen nicht beeintrchtigen drfte.


Type BITNUM und Funktionen SHIFT und ROTATE

ISO-Erweiterung

Der  Typ  BITNUM  wird  voraussichtlich  im  ISO-Standard  definiert  und  ist
ausschlielich fr SETs vorgesehen. BITNUM ist in etwa definiert als
  TYPE  BITNUM  =  CARDINAL  0..31 ;
Jedoch sind Variablen vom Typ BITNUM nicht kompatibel mit CARDINAL, eine
Konvertierung, z.B. mit VAL, ist notwendig. Lediglich Konstanten von 0 bis 31
sind kompatibel zum BITNUM-Typ.
3.3 Megamax Modula: SYSTEM-Modul                                    3 - 30
________________________________________________________


Der Zweck ist, mit Sets dieses  Typs  eine  eindeutige  Zuordnung  von  Set-
Elementen  auf  die  Bit-Struktur  des  Speichers  zu  definieren,  um  darauf
portabel, zumindest zwischen verschiedenen Compilern des gleichen Rechners,
zugreifen zu knnen.

Bei Megamax-Modula entspricht des interne Struktur eines BITNUM-Sets genau
dem normaler Sets mit bis zu 32 Elementen.

Die Funktionen SHIFT und ROTATE erlauben das Verschieben und Rotieren der
Elemente  (Bits)  von  BITNUM-Sets.  Der  jeweils  erste  Parameter  ist  eine
Variable vom Typ SET OF BITNUM  a..b  (a und b liegen zw. 0 und 31), der
zweite  Parameter  ist  fr  die  Angabe  der  Schub-/Rotierweite  vorgesehen.
Positive  Werte  schieben/rotieren  zu  den  hherwertigen  Elementpositionen,
negative umgekehrt. Beispiel:

  TYPE Feld = SET OF BITNUM  2..6 ;
  VAR  x: Feld;
  BEGIN
    x:= Feld  2..4 ;       (* Bits in feld:  x00111xx *)
    SHIFT (x, 1);         (* Bits in feld:  x01110xx *)
    ROTATE (x, -2);     (* Bits in feld:  x10011xx *)
    SHIFT (x, 2);         (* Bits in feld:  x01100xx *)


Funktion CAST (AnyType; x: SourceType): AnyType;

ISO-Erweiterung

Die CAST-Funktion erlaubt die Wandlung  eines  Ausdrucks  <x>  in  den  ent~
sprechenden Wert  des  angegebenen  Zieltyps  <AnyType>.  Fr  Ausdruck  und
Zieltyp sind alle Datentypen zulssig, die intern durch 1, 2 oder 4 Byte dar~
gestellt  werden  oder  identische  Gren  besitzen.  Der  Compiler  pat  den
Ausdruck <x> nur der Lnge des Zieltyps an und nimmt keine weiteren Umset~
zungen vor. Es wird keine Bereichsprfung (Rangecheck) durchgefhrt.

Wir  empfehlen,  zur  Typenwandlung  die  CAST-Funktion  grundstzlich  den
Typtransfer-Funktionen  der  Form  AnyType  (x:  SourceType),  z.B.  INTEGER
(TRUE),  vorzuziehen.  Zum  einen  bietet  die  CAST-Funktion  eine  grere
Flexibilitt, da sie automatische Lngenanpassungen durchfhrt. Zum anderen
ist ihre Benutzung durch den Import aus SYSTEM schon im Modulkopf sichtbar.
(Da  die  interne  Darstellung  der  Datentypen  implementationsabhngig  ist,
bedeutet  die  Anwendung  von  Typumwandlungen  immer  ein  Risiko  fr  die
Portabilitt von Programmen!)
3.3 Megamax Modula: SYSTEM-Modul                                    3 - 31
________________________________________________________


Funktion CADR

Megamax-Erweiterung

CADR steht fr constant address. Diese Funktion hat die selbe Funktion wie
ADR, nur erlaubt sie nicht nur Variable als Argument, sondern auch Konstante.
Die Konstante wird dann im Code abgelegt und ihre Adresse zurckgegeben.
Da der Wert im Code liegt, der niemals verndert werden darf, sollte diese
Funktion entsprechend auch nur verwendet werden, wo dies sichergestellt ist.

Die typische Anwendung findet sich bei der bergabe von String-Konstanten
als Argument bei den SYSTEM-Funktionen CALLSYS und CALLEXT (s.u.). Aber
sie erlaubt beispielsweise auch die Adreermittelung bei REF-Parametern (was
ADR nicht erlaubt), um - natrlich nur lesend - mit Zeigern auf den formalen
Parameter zuzugreifen.


Prozeduren CODE, LOAD und STORE

Megamax-Erweiterung

Wollen  Sie  auf  die  Register  der  CPU  zugreifen  oder  kleine  Maschinen~
anweisungen oder Tabellen in den Code einfgen, ohne den Inline-Assembler zu
benutzen,  knnen  Sie  sich  dieser  Funktionen  bedienen.  Sie  sind  auch  in
hnlicher Form bei anderen Modula-Compilern fr den Atari ST vorhanden und
verhelfen dadurch ggf. zu leichterer Portierbarkeit (beispielsweise sind sie beim
Hnisch-Modula in gleicher Weise und Funktion vorhanden, TDI-Modula bietet
REGISTER und  SETREG  statt  STORE  bzw.  LOAD).  Allerdings  ist  trotzdem
Vorsicht geboten - interne  Regeln  des  jeweiligen  Compilers  (nheres  siehe
Kapitel 4 ber den Assembler) knnen dem trotzdem einen Strich durch die
Rechnung machen!

CODE hat einfach beliebig viele, mit Kommata getrennte SHORTCARD (16-Bit)-
Parameter, die alle Konstante sein mssen und direkt in den Code eingefgt
werden, wie beim DC.W-Pseudo-Op des Assemblers.

LOAD ldt den Wert des im ersten Argument angegebenen Ausdrucks in das
danach  angegebene  Register.  Der  Ausdruck  mu  einen  Wert  der  Gre
zwischen einem und vier Byte erzeugen und wird immer auf 4 Byte expandiert.
Die Register-Nummer ist als Konstante anzugeben: 0 bis 7  stehen  fr  die
Datenregister D0 bis D7, 8 bis 15 fr die Adreregister A0 bis A7.

STORE speichert das zuerst angegebene Register (s. LOAD) in die daraufhin
angegebene Variable, die maximal eine Gre von 4 Byte haben darf.
3.3 Megamax Modula: SYSTEM-Modul                                    3 - 32
________________________________________________________


Prozeduren CALLSYS und CALLEXT

Megamax-Erweiterung

Sie dienen zum Aufruf externer Funktionen, also solchen, die nicht in Modulen
des Megamax-Systems implementiert und deshalb importierbar sind. Dies sind
hauptschlich die Funktionen des Betriebssystems TOS (GEMDOS, BIOS usw.).
Wir  haben  natrlich  fr  diese  Betriebssystem-Routinen   Prozeduren   in
Megamax-Modulen   erstellt,   die   dann   die   Routinen   ihren   besonderen
Konventionen entsprechend aufrufen. Sie finden sich in den Modulen GEMDOS,
BIOS, XBIOS, LineA sowie den AES- und VDI-Modulen.

Allerdings kann es immer mal vorkommen, da Sie nicht diese vorbereiteten
Modula-Prozeduren aufrufen wollen, oder  in  einer  kommenden  TOS-Version
neue  Funktionen  enthalten  sind,  fr  die  wir  noch  keine  Modula-Prozedur
vorgesehen haben.

Die  Routinen  gliedern  sich  dabei  in  mehrere  Gruppen  (GEM,  LineA  sowie
GEMDOS  &  BIOS  &  XBIOS),  die  alle  auf  verschiedene  Weise  aufgerufen
werden mssen. Fr die GEMDOS/BIOS/XBIOS-Aufrufe ist  dabei  CALLSYS
vorgesehen:  Der  erste  Parameter  gibt  die  TRAP-Nummer  an,  also  1  fr
GEMDOS,  13  fr  BIOS  und  14  fr  XBIOS  (die  TRAP-Nummer  mu  eine
Konstante zwischen Null und 15 sein). Danach knnen beliebig viele weitere
Parameter folgen (wie in der Sprache C, s.u.). Alle diese Werte werden auf
den  A7-Stack  geladen,  und  danach  wird  die  gewnschte  TRAP-Instruktion
ausgefhrt.

Fr den Fall, da eine Routine aufgerufen werden soll, die nicht ber einen
TRAP erreicht wird, sondern mit einer JSR-Instruktion gerufen wird, und die
auch die Parameter auf dem A7-Stack erwartet, kann CALLEXT verwendet
werden: Statt einer TRAP-Nummer wird hier als erster Parameter die Adresse
der Routine angegeben.

Sie knnen CALLSYS (und CALLEXT) sowohl als Prozedur aufrufen als auch
als Funktion in einem Ausdruck verwenden. Im zweiten Fall wird der Rck~
gabewert der externen Funktion aus dem Register D0 als Funktionsergebnis
verwendet, und zwar als LONGWORD-Typ. Das bedeutet, da Sie den Wert
noch mittels der CAST-Funktion in den bentigten Typ wandeln mssen.

Fr externe Routinen, die auf eine andere Weise ihre Parameter erwarten,
sind  auerdem  noch  Funktionen  im  Modul  Calls  vorhanden,  speziell  fr
individuelle  GEM-Aufrufe  eignen  sich  die  Grundfunktionen  in  den  Modulen
AESBase und VDIBase.
3.3 Megamax Modula: SYSTEM-Modul                                    3 - 33
________________________________________________________


Fr   die   Parameter   bei   CALLSYS   und   CALLEXT   gelten   noch   einige
Besonderheiten:
  * Jedes Argument darf die Gre von vier Byte nicht berschreiten, sonst
    erfolgt eine Fehlermeldung. Bei Strings wird beispielsweise ihre Adresse
    mit  der  SYSTEM-Funktion  ADR  (oder  CADR  bei  String-Konstanten)
    bergeben.
  * Untypisierte  Zahl-Konstanten  werden,  wenn  sie  zwischen  -32768  und
    65535 liegen, als SHORTCARD bzw. SHORTINT auf den Stack geladen,
    grere  Werte  entsprechend  als  LONGCARD  bzw.  LONGINT.  Soll  ein
    kleiner Wert als Long-Wert bergeben werden, ist ihm ein "L" oder "D"
    anzuhngen (Bsp: 0L fr eine Null-Konstante mit 32 Bit) oder man mu sie
    mit VAL oder LONG anpassen.
    Byte-Daten wie CHAR werden auf dem Stack auf der niedrigeren Adresse
    der  beiden  Bytes  eines  Stack-Words  abgelegt.  Die  meisten  Parameter
    erwarten trotz Byte-Parametern aber ein Word auf dem Stack (beispiels~
    weise alle TOS-Funktionen). Dazu wird in der Regel ein Byte-Datum zu
    einem Word-Datum expandiert. Wollen Sie also beispielsweise die GEMDOS-
    Funktion "Conout" aufrufen, mssen Sie das  auszugebende  Zeichen  als
    SHORTCARD-Wert bergeben, z.B. durch "ORD (character)".

Beispiele:

    CALLSYS (1, 2, ORD("A") );                    (*  Conout ("A")        *)
    CALLSYS (1, 9, CADR("text"));                 (*  Conws ("text")      *)
          :                                                     :
    char  = CAST (CHAR, CALLSYS (13, 2, 2);    (*  char  = Bconin (2)  *)


Prozeduren NEWPROCESS, TRANSFER, IOTRANSFER, LISTEN und IOCALL

PROCEDURE NEWPROCESS (p: PROC; a: ADDRESS; n: LONGCARD;
                               VAR q: ADDRESS);
PROCEDURE TRANSFER (VAR from, to: ADDRESS);
PROCEDURE LISTEN ();

Die Prozeduren erlauben die Einrichtung und Ausfhrung von Coroutinen, wie
sie im Modula-Standard definiert sind. Hier nur zwei  Anmerkungen  zu  den
Parametern: Die Deskriptoren fr die Coroutinen <q>, <from>, <to> sind nach
der  revidierten  Sprachdefinition  nicht  mehr  vom  Typ  PROCESS,  sondern
ADDRESS. Die Lnge des Arbeitsbereiches <n> fr NEWPROCESS wird - wie
alle Speichergren - als LONGCARD angegeben.

Die Funktionen und Coroutinen drfen nur im Usermode ausgefhrt werden!
Dies ist der Normalfall und nur zu beachten, wenn Sie teilweise absichtlich im
Supervisor-Modus arbeiten.
3.3 Megamax Modula: SYSTEM-Modul                                    3 - 34
________________________________________________________


Fr sogenannte Monitore kann in bekannter Weise im Modulkopf hinter dem
Modulnamen in eckigen Klammern eine Zahl von eins bis sieben, entsprechend
der Interrupt-Prioritten der 68000-CPU, angegeben werden. Alle Prozeduren
innerhalb dieses Moduls werden dann mit der betreffenden  Interrupt-Maske
ausgefhrt.

LISTEN erlaubt es, in Monitor-Modulen (mit Angabe der Interrupt-Prioritt im
Modulkopf)  kurzfristig  Interrupts  mit  niedrigem  Vorrang  zuzulassen.  Die
Interrupt-Prioritt, die im Modulkopf angegeben wurde, wird dabei kurzzeitig
um Eins verringert.

Ein Anwendungsbeispiel zeigt das Modul HaTschi im DEMO-Ordner.


PROCEDURE IOTRANSFER (VAR from, to: ADDRESS; vector: ADDRESS);

Vorsicht:
IOTRANSFER  erhlt  die  absolute  Adresse  des  Vektors  und  nicht  die
Vektornummer wie bei den meisten anderen Modula-Systemen auf dem ST!

                        >
Ist die Vektoradresse  = 1024, wird automatisch erkannt, da der Einsprung
nicht durch eine Exception, sondern durch  einen  normalen  Unterprogramm~
aufruf erfolgen wird. Somit ist IOTRANSFER auch auf andere Systemvektoren,
z.B. die VBL-Queue, anwendbar.

Sobald nach der IOTRANSFER-Installation der Rcktransfer stattfindet, egal,
ob ber den installierten Vektor oder ber einen expliziten TRANSFER-Aufruf,
wird der alte Vektor wieder hergestellt. blicherweise ist daher vor Beendigung
des Programms  ein  globales  Flag  zu  setzen  und  dann  ein  TRANSFER  zur
Funktion, die den IOTRANSFER auslste, damit diese dann nach Erkennung des
Flags mit TRANSFER zurckkehrt, um den Vektor nicht wieder zu verndern.
Der Vektor mu auf jeden  Fall  bei  Beendigung  des  Programms  restauriert
werden. Dazu sollte CatchProcessTerm (Modul PrgCtrl) benutzt werden, um
auch bei unerwarteten Programmabbrchen den alten Vektor wiederherstellen
zu knnen. (Siehe Hatschi im DEMO-Ordner).

Die Coroutine wird je nachdem, ob sie durch einen expliziten TRANSFER oder
durch einen Aufruf ber den angegebenen Vektor im User- bzw. im Supervisor-
Modus ausgefhrt.
3.3 Megamax Modula: SYSTEM-Modul                                    3 - 35
________________________________________________________


PROCEDURE IOCALL (vector: ADDRESS);

Megamax-Erweiterung

Diese Funktion darf nur nach einer IOTRANSFER-Funktion ausgefhrt werden.
Sie dient dazu, die Routinen aufzurufen, die vor dem IOTRANSFER-Aufruf auf
der anzugebenden Vektoradresse aktiv waren. Wenn man sie z.B. regelmig
(200 Hz) ber den EtvTimer-Vektor (Adr. $400) aufrufen lassen will, kann
man  ihn  mit  der  IOTRANSFER-Funktion  belegen.  Da  sich  aber  auch  noch
weitere, GEMDOS-interne Funktionen dieses Vektors bedienen, mssen auch
sie regelmig ausgefhrt werden. Um dies zu erreichen, braucht nur IOCALL
whrenddessen  aufgerufen  werden.  Die  angegebene  Routine  wird  dann  im
Supervisormodus ausgefhrt.


Benutzung der FPU in Coroutinen

Bei einem Prozewechsel mit TRANSFER/IOTRANSFER werden nur die Register
des  Hauptprozessors  (680x0)  gerettet/restauriert.  Die  Register  und  Ein~
stellungen einer eventuell verwendeten FPU aber nicht! Wird in mehreren, sich
abwechselnden  Coroutinen  die  FPU  benutzt,  mssen  die  FPU-Register  "von
Hand" mittels der Funktionen des Moduls FPUSupport umgeschaltet werden.
Mehr dazu im Definitionstext des Moduls.
3.4 Megamax Modula: Compilerdirektiven                                 3 - 36
________________________________________________________


3.4   Compilerdirektiven  (-optionen)

Sie haben zahlreiche Mglichkeiten, die Arbeitsweise des Modula-Compilers zu
beeinflussen.  Dazu  gibt  es  eine  Reihe  von  "Schaltern",  die  Sie  hin-  und
herschalten knnen. Zum Beispiel knnen Sie entscheiden...

- wie pingelig der Compiler auf korrekte Gro-/Kleinschreibung achten soll;
- wieviel Aufwand er treiben soll, um Laufzeitfehler zu entdecken;
- ob Sie bei der Fehlersuche zustzliche Untersttzung haben mchten.

Vor der bersetzung jedes Moduls werden die Schalter auf ihre Voreinstellung
gebracht (siehe "bersicht aller  Direktiven").  Im  allgemeinen  sind  die  Vor~
einstellungen  so  gewhlt,  da  maximale  Sicherheit  beim  bersetzen  und
anschlieendem  Programmlauf  besteht.  Diese  Voreinstellung  kann  in  der
Compiler-Parameter-Box der Shell verndert werden.

Weiterhin knnen  Compiler-Direktiven  an  beliebiger  Stelle  im  Programmtext
stehen.  Sie  werden  dann  immer  ab  dieser  Stelle  gltig.  Auf  diese  Weise
knnen die Direktiven auch innerhalb eines Programms beliebig oft umgeschaltet
werden, um z.B. nur bei der bersetzung einzelner Prozeduren die Fehler~
prfung auszuschalten.

Die  Direktiven  sind  natrlich  alle  Megamax-spezifisch,  also  nicht  ohne
nderungen auf andere Compiler bertragbar!


Syntax einer Compilerdirektive in der Compiler-Parameter-Box

In der Direktiven-Eingabezeile knnen nur Schalter, jedoch keine Direktiven, die
einen Text als Argument haben (z.B.  Include,  Use),  bestimmt  werden.  Die
Syntax ist recht einfach: Der jeweilige Buchstabe, der auch im Programmtext
(s.u.) fr die Direktive Verwendung findet, wird wahlweise mit einem Plus-
oder Minuszeichen eingeleitet. Werden mehrere Direktiven eingegeben, mssen
sie durch Leerzeichen getrennt werden!

Beispieltext zum Abschalten der Bereichs- und der Stackprfungen:
   -r -s                    (Achtung: Leerzeichen zw. den Direktiven beachten!)

Wird der Compiler als eigenstndiges Programm gestartet, z.B. durch Linken
zusammen mit dem Modul CompInit (s. UTILITY-Ordner), knnen diese Direk~
tiven in gleicher Form in der Argumentzeile bergeben werden.

Die Direktiven in der Compiler-Optionen-Box sind lediglich Voreinstellungen fr
jedes einzelne Modul - sobald  im  Programmtext  eines  Moduls  eine  gegen~
stzliche Direktive erscheint, bestimmt sie die neue Einstellung.
3.4 Megamax Modula: Compilerdirektiven                                 3 - 37
________________________________________________________


Syntax einer Compilerdirektive im Programmtext

Compilerdirektiven sehen aus wie Kommentare, deren erstes Zeichen ein $ ist.
Dann wird die gewnschte Option durch einen Buchstaben gewhlt, gefolgt von
+, - oder = zur Einstellung des Schalters. Ein Schalter wird mit + ein- und mit
- ausgeschaltet; mit = setzen Sie den Schalter auf die Position vor der letzten
Umschaltung  zurck.  (Allerdings  wird  nur  ein  Schalterzustand  gespeichert;
mehrere = in Folge sind also nicht zulssig!)

Sollen weitere Optionen folgen, dann knnen sie jeweils durch Kommata ge~
trennt angegeben werden; ist das nchste Zeichen nach +/- kein Komma, so
wird der Rest des Textes bis zur Klammer *) als Kommentar interpretiert.
Leerzeichen werden berall ignoriert, auer zwischen (* und $. (Wenn dort ein
Leerzeichen steht, ignoriert der Compiler die Option als normalen Kommentar -
eine einfache Mglichkeit also, eine Compileroption  schnell  mal  'ungltig'  zu
machen.)

Alles klar? Sonst helfen bestimmt einige Beispiele beim Umgang mit Compiler~
optionen:

richtig: (*$ R+ *)
        (*$ c-, r-, q+ *)           mehrere Optionen durch Komma trennen
        (*$ R- Rangecheck aus*)   nach der letzten Option Kommentar mglich
falsch: (* $ R+ *)                  Kommentar! (Leerzeichen vor $)
        (*$ R+, Rangecheck an *) hinter Komma mu weitere Option folgen!
        (*$ R+ Q- *)                Q+ ist Kommentar (Komma fehlt)

Nachdem  Sie  nun  wissen,  wie  eine  Compileroption  aussieht,  soll  verraten
werden, was sich damit  machen  lt.  Folgende  Optionen  stehen  Ihnen  zur
Verfgung:


Gro-/Kleinschreibung (Case Sensitivity)

Die Definition von Modula-2 schreibt vor, da zwischen Gro- und Kleinschrei~
bung  streng  unterschieden  wird.  Hallo  und  HALLO  sind  also  verschiedene
Bezeichner; das reservierte Wort REPEAT mu stets grogeschrieben werden;
bei importierten Bezeichnern (z.B. WriteLn) ist ebenfalls genau auf die Schreib~
weise zu achten. Auch der Megamax Modula-Compiler besteht normalerweise
auf diesen Unterscheidungen. Falls Ihnen diese 'Case Sensitivity' aber lstig
wird, knnen Sie sie mit (*$ C- *) abschalten - dann verhlt sich der Compiler
so, wie Sie es vielleicht schon von Pascal-bersetzern gewohnt sind.

Voreinstellung: (*$ C+ *)
3.4 Megamax Modula: Compilerdirektiven                                 3 - 38
________________________________________________________


Bereichsprfungen (Range Checking)

Der Compiler erzeugt bei der  bersetzung  Ihrer  Programme  auch  68000-
Anweisungen, die zur Laufzeit der Programme bestimmte Fehlerquellen berpr~
fen und ggf. eine Fehlermeldung auslsen. Im einzelnen werden berprft:

    * berlufe beim Rechnen mit ordinalen Typen;
    * Zuweisung illegaler Werte auf ordinale Typen;
    * Zugriff auf Feldelemente auerhalb des deklarierten Feldes.
    * korrekte Selektion bei CASE-Anweisungen (fehlt der ELSE-Zweig  und
      wird keine der Marken angesprungen, ist das ein Fehler!)

Diese  Prfungen  erleichtern  bei  der  Erstellung  eines  neuen  Programms
die Fehlersuche sehr; allerdings kosten sie natrlich etwas Zeit und RAM-Platz.
Wenn  Sie  ein  Programm  vollstndig  ausgetestet  haben,  knnen  Sie  mit
(*$ R- *) die Bereichsprfung ausschalten. Im Normalfall gewinnen Sie damit
10..20% Platz und Geschwindigkeit; in einzelnen Fllen kann der Effekt deutlich
grer (oder kleiner) sein.

Beachten Sie bitte, da auch in der Einstellung (*$ R- *) manche Fehler noch
erkannt und gemeldet werden - die Prozeduren des RUNTIME-Moduls, etwa
fr  REAL-Arithmetik,  prfen  weiterhin  auf  berlauf.  Das  Abschalten  der
Bereichsprfung bietet also keine Gewhr dafr, da vom Modula-System keine
Fehlermeldungen mehr erscheinen. Wenn sie fr alle Flle von Laufzeitfehlern
gerstet sein wollen, mssen Sie die Fehler selbst abfangen - lesen Sie dazu
das Kapitel ber Laufzeitfehlerbehandlung (Kapitel 5).

Voreinstellung: (*$ R+ *)


Stack-Platzprfung

Eine Sonderrolle bei den Prfungen, die der Compiler in die erzeugten Pro~
gramme einbaut, nimmt die berwachung des verfgbaren Stack-Bereichs ein.
Whrend des Programmablaufs werden nicht nur Prozedurparameter ber den
Stack bergeben, sondern auch alle lokalen Variablen dort angelegt. Insbeson~
dere bei rekursiven Algorithmen besteht die Gefahr eines Stack-berlaufs.

Zu Beginn jeder aufgerufenen Prozedur wird berprft, ob der  Stack  noch
Platz fr die neuen lokalen Variablen und eine Reserve fr evtl. folgende Parame~
terbergaben bietet. (Der bentigte Reserve-Platz kann natrlich nur abgeschtzt
werden, s.u.) Diese Prfung knnen Sie durch Angabe von (*$ S- *) unter~
drcken. Da ein unerkannter Stackberlauf meist fatale Folgen hat, sollten Sie
dies nur in begrndeten Fllen tun!
3.4 Megamax Modula: Compilerdirektiven                                 3 - 39
________________________________________________________


Wird whrend des Programmlaufs dank der Stack-Prfung eine entsprechende
Fehlermeldung angezeigt,  kann  der  dem  Programm  zur  Verfgung  gestellte
Stack-Bereich in der Shell leicht auf einen greren Wert eingestellt werden
(Umgebungs-Info-Box bzw. Linker-Parameter-Box).

Auer der blichen Schalterfunktion bietet die S-Option aber noch die Mglich~
keit, die geforderte Platzreserve auf dem Stack einzustellen. In aller Regel
kann der voreingestellte Wert unverndert bleiben. Soll jedoch eine Prozedur
(z.B. als Coroutine) mit einem sehr kleinen Stackbereich  auskommen,  kann
diese Abschtzung zu grozgig sein. Zur Umstellung des Wertes geben Sie
hinter dem S eine CARDINAL-Zahl (dezimal) an.

Achtung!  Mit  der  S-Option  kann  nicht  der  zu  verwendende  Stack-Bereich
bestimmt werden, sondern nur die Grenze, wieviel freier Stack verbleiben mu,
bevor ein Fehler gemeldet werden soll! Die Bestimmung des reellen  Stack-
Bereichs erfolgt in der Shell ber die Parameter-Dialoge.

Voreinstellung: (*$ S+, S 512 *)


Testhilfen (Debugging)

Wahrscheinlich  ist  das  Fehlersuchen  in  (fast)  fertigen  Programmen  nicht
gerade  Ihre  Lieblingsbeschftigung.  Testausgaben  ins  Programm  schreiben,
bersetzen, ausprobieren, noch  mehr  Testausgaben,  noch  mal  bersetzen...
Das knnte Ihnen der Rechner eigentlich auch abnehmen!

Kann er auch, und zwar dann, wenn Sie die 'verdchtigen' Programmteile mit
der Optionseinstellung (*$ D+ *) bersetzen! In den Programmcode werden
dann zustzliche Anweisungen eingefgt, die

- den Text jeder bearbeiteten Programmzeile anzeigen;
- darunter die Werte aller berechneten arithmetischen Ausdrcke ausgeben;
- von der Tastatur aus Einzelschrittbetrieb einschalten lassen.

Statt dessen (oder auch zustzlich) kann die Direktive $E+ verwendet werden,
um bei jedem Ein-/Austritt einer Prozedur deren Namen anzeigen zu lassen.

Der  Umgang  mit  der  Debug-Option  wird  im  Kapitel  2.5  beschrieben.  Hier
mchten wir nur noch schnell darauf hinweisen, da Programme im Debug-
Modus deutlich langsamer laufen und mehr Platz fr den Code brauchen - Sie
sollten mit der Debug-Option also sparsam umgehen.

Voreinstellung: (*$ D-, E- *)
3.4 Megamax Modula: Compilerdirektiven                                 3 - 40
________________________________________________________


Lokale Prozeduren als aktuelle Parameter

Die im Kapitel 3.1 beschriebene Spracherweiterung lt sich mit $H+ nutzen.

Voreinstellung: (*$ H- *)


Erweiterte Syntax

Die im Kapitel 3.1 beschriebene Spracherweiterung lt sich mit $A+ nutzen.

Voreinstellung: (*$ A- *)


Zuweisungen von LONGs auf SHORTs

Durch $K+ erlaubt Megamax Modula-2 die Zuweisung von LONGCARD- oder
LONGINT-Werten auf SHORTCARD- oder SHORTINT-Variablen.

Voreinstellung: (*$ K- *)


Automatische Register-Optimierung bei FOR-Schleifen

Wie  schon  in  Kapitel  3.1  beschrieben,  werden  bestimmte  Bedingungen  an
Laufvariablen fr FOR-Schleifen geknpft. Nur wenigen ist dies bisher bewut
gewesen, noch weniger hielten sich daran, hchstens aus Zufall. Durch unsere
neue  automatische  Register-Verwendung  bei  FOR  stieen  wir  nun  auf  den
Grund  dieser  Einschrnkungen:   Nur   so   ist   berhaupt   eine   effiziente
Optimierung der FOR-Schleife mglich, besonders in Hinblick auf die Register-
Verwendung.

Sollten  Sie  in  Zukunft  also  einmal  auf  eine  der  Compiler-Fehlermeldungen
stoen,  die  etwas  an  Ihrer  FOR-Variable  herummkeln,  bereinigen  Sie
entweder das bel oder unterbinden Sie die Register-Belegung durch Verwen~
dung der Direktive $J-.

Sollten Sie einmal unerklrliche Fehler in Ihrem Programm vermuten, sollten
Sie ebenfalls zuerst die $J- Direktive einsetzen (am besten  als  -J  in  der
Direktiven-Zeile der Compiler-Parameter-Box), um zu prfen, ob der Fehler
dann immer noch auftritt. Ist der Fehler dann behoben,  kann  es  entweder
daran liegen, da eine in Assembler erstellte Funktion eines der geschtzten
Register (D3-D7, A4-A6) verndert hat, oder da eine sonstige Verletzung der
FOR-Regeln vorliegt, die der Compiler nicht erkennen konnte (wahrscheinlich
durch Einsatz von Assembler-Routinen).

Voreinstellung: (*$ J+ *)
3.4 Megamax Modula: Compilerdirektiven                                 3 - 41
________________________________________________________


Optimierte Rckgabe von Funktionsergebnissen im Register

Sicher haben Sie schon gelernt, da Register fr  Optimierung,  speziell  fr
hhere Ausfhrungsgeschwindigkeit, stehen. So ist es wnschenswert, so oft
wie mglich die Prozessor-internen Register statt den normalen Speicher fr
die Ablage von Variablen und Zwischenergebnissen zu verwenden.

Eine einfache und wirksame Mglichkeit ist, Funktionsergebnisse nicht auf dem
Stack (im Speicher), sondern in einem Register zu liefern, sofern sie hinein~
passen. Was da intern passiert, wollen wir an dieser Stelle nicht erklren,
wohl aber, warum wir so lange um den heien Brei herumschreiben: Bisher
wurden beim Megamax-System alle Parameter  und  Ergebnisse  im  Speicher
bergeben. Viele von uns erstellte Prozeduren in der Modul-Bibliothek wurden
in Assembler programmiert. Auch einige Anwenderprogramme von Ihnen mgen
in Assembler  unsere  Prozeduren  aufrufen.  Wrde  man  nun  die  bergabe~
konventionen pauschal ndern, gbe  es  viel  Arbeit,  alle  Assembler-Routinen
anzupassen.

Zweitens  mssen  die  Funktion  und  ihr  Aufruf  zueinander  passend  kodiert
werden.  Das  bedeutet,  da  auch  PROCEDURE-Typen  schon  die  Aufruf-/
bergabekonvention festgelegt haben mssen.

Deshalb bleiben wir in der Regel erstmal bei der alten bergabekonvention.
Optional kann ber eine Direktive ($Z+) eine Funktions-Prozedur so deklariert
werden, da sie ihr Ergebnis im Register statt im Speicher zurckgibt. Dann
mu aber darauf geachtet werden, da sowohl bei FORWARD-Deklarationen,
als auch in Definitionsmodulen die Einstellungen mit der bei der Implementation
bereinstimmen  mssen.  Das  gleiche  gilt,  wenn  Prozedur-Typen  deklariert
werden: Wenn also ein Versionskonflikt bei einer Zuweisung einer Funktions-
Prozedur angezeigt wird, sind nicht nur die Parameter auf bereinstimmung,
sondern auch die Einstellung der $Z-Direktive zu vergleichen.

Voreinstellung: (*$ Z- *)


SET-Format

SETs bis 32 Bit werden in einem definierten Format auf die Bits des Prozes~
sors abgebildet (s. Anhang, interne Datenformate). Alte Compiler bis einschlie~
lich Version 3 legten SETs aber in einem anderen Format ab. Um Anpassungen
alter Programme zu erleichtern, kann mit der Direktive $U- das alte Format
eingestellt werden. Die aktuelle Einstellung ist nur relevant fr die Typdeklara~
tion von SETs; BITSET liegt nur im neuen Format vor! Ersatzweise ist nach
$U- ein neuer Typ als SET OF  0..15  zu deklarieren, und die betroffenen
BITSET-Verwendungen sind dann durch diesen neuen Typ zu ersetzen.

Voreinstellung: (*$ U+ *)
3.4 Megamax Modula: Compilerdirektiven                                 3 - 42
________________________________________________________


Register-Variable

Durch das einfache Ein-Pass Konzept des Compilers kann  er  leider  (noch)
nicht selbstttig entscheiden, wann  es  gnstig  ist,  Variablen  ber  mehrere
Anweisungen hinweg in den nur begrenzt zur Verfgung stehenden Registern
der CPU zu halten. Statt dessen legt er sie immer im Speicher ab, was mehr
Zeit und Programmlnge bentigt.

Dafr ist Ihnen aber mglich, dem Compiler von vornherein mitzuteilen, da er
bestimmte Variablen in Registern halten soll. Dies wird erreicht, indem vor die
betreffende  Variable  bei  ihrer  Deklaration  die  Direktive  (*$ Reg *)  gesetzt
wird. Dann wird die Variable in der gesamten Prozedur im Register gehalten.

Allerdings gibt es dabei einige Restriktionen, die vom Compiler auch geprft
werden, und bei denen er dann ggf. eine Fehlermeldung anzeigt:

  * Nur lokale Variablen knnen in Registern gehalten werden.
  * Die lokalen Variablen drfen jeweils nicht mehr als 4 Byte belegen.
  * Es darf weder die Adresse solch einer Variable mit ADR ermittelt, noch
    darf sie an einen VAR-Parameter bergeben werden.
  * Auf  eine  Register-Variable  darf  nicht  in  einer  dazu  lokalen  Prozedur
    zugegriffen werden.
  * Kommt in der Prozedur eine WITH-Anweisung vor, mu dazu mindestens
    ein  nicht-temporres  Adre-Register  noch  frei  sein.  Da  z.Zt.  nur  ein
    solches Adre-Register zur Verfgung steht, heit das: Bei Verwendung
    von WITH darf keine  POINTER-Variable  als  Register-Variable  deklariert
    werden.

Die nicht-temporren Register, die  sich  damit  als  Register-Variable  eignen,
sind zur Zeit: D3 bis D7 und A4. Die Daten-Register (D3-D7) werden fr
skalare  Register-Variablen  verwendet,  Adre-Register  (A4)  fr  POINTER.
Werden  mehr  Register-Variablen  deklariert,  als  Register  dafr  vorgesehen
bzw. frei sind, kommt keine Fehlermeldung, sondern es werden nur die zuerst
deklarierten Variablen auf die entsprechenden Register aufgeteilt, die restlichen
bleiben im Speicher, wie sonst auch.

Es gibt Datentypen, die sich theoretisch als Register-Variablen eignen, aber
z.Zt. nicht vom Compiler untersttzt werden. Ihre Deklaration als Register-
Variable erzeugt keine Fehlermeldung. So knnen Sie schon jetzt Variablen fr
Register  vorsehen,  die  erst  in  spteren  Compiler-Versionen  entsprechend
benutzt werden - eine vorsorgliche Optimierung.

Bei  zeitintensiven  Prozeduren  lohnt  es  sich  oft,  mit  ein  paar  Blicken
abzuschtzen,  welche  Variablen  in  jeder  einzelnen  Prozedur  am  hufigsten
benutzt werden (z.B. in Schleifen), um diese dann als Register-Variablen zu
deklarieren.
3.4 Megamax Modula: Compilerdirektiven                                 3 - 43
________________________________________________________


Beispiel:

  (* folgende Funktion liefert TRUE, wenn das bergebene Feld
   * nur Nullwerte enthlt:
   *)
  PROCEDURE nullFeld (VAR feld: ARRAY OF CARDINAL): BOOLEAN;
    VAR (*$Reg*) c: CARDINAL;
         (*$Reg*) ptr: POINTER TO CARDINAL;
    BEGIN
      ptr:= ADR (feld);     (* Startadresse vom Feld ermitteln *)
      (* nun alle Werte einzeln prfen *)
      FOR c:= 0 TO HIGH (feld) DO
        IF ptr^ # 0 THEN
          RETURN FALSE
        END;
        INC (ptr, SIZE (ptr^))
      END;
      RETURN TRUE
    END nullFeld;

Im  obigen  Beispiel  bruchte  'c'  nicht  als  Register-Variable  deklariert  zu
werden, weil die Laufvariable schon automatisch von der FOR-Anweisung im
Register gehalten wird.


Mathe-Koprozessor (FPU)

Ist im Atari ST oder Atari TT ein Mathe-Koprozessor vorhanden (z.B. SFP004
von Atari f. den ST bzw. 68882 im TT) kann er automatisch genutzt werden.
Dazu mu der Compiler allerdings anderen Code erzeugen als ohne eine solche
FPU (Floating Point Unit). Das bedeutet:  Um  die  FPU  zu  nutzen,  mu  ein
Programm speziell dafr bersetzt werden, umgekehrt kann ein fr die FPU
bersetztes Programm nicht in einem Rechner ohne diese Zusatz-Hardware
ablaufen.

Das hrt sich erst einmal nachteilig an. Wir sind beim Megamax-System dazu
gezwungen, weil wir bei Verwendung der FPU mit ihrem internem Darstellungs-
Format (nach IEEE-Norm) arbeiten mssen, whrend wir ohne die FPU mit
unserem  eigenen  Format  rechnen,  das  in  der  reinen  Software-Auswertung
gegenber dem IEEE-Format schneller ist. Beide Formate sind demnach nicht
kompatibel und erfordern deshalb unterschiedliche Behandlungen und Bibliotheks~
module (so sind in den Ordnern ST FPU und TT FPU gesonderte Module fr
                                     _             _
das IEEE-Format enthalten).

Aber wir haben daraus einen Vorteil gezogen: Da der Compiler nun ber die
Existenz der FPU informiert wird,  kann  er  sich  darauf  einstellen  und  ihre
besonderen Fhigkeiten besser nutzen, als dies durch einen reinen Austausch
3.4 Megamax Modula: Compilerdirektiven                                 3 - 44
________________________________________________________


der  normalen  Real-Laufzeitfunktionen  mglich  wre.  Ein  Beispiel:  Die  FPU
besitzt 8 Register, in denen sie Real-Werte speichert. Greift sie auf diese
internen Register zu, geht das viel schneller als der Zugriff auf die Variablen
im  Speicher,  wo  Variablen  normalerweise  abgelegt  werden.  Whrend  die
Zwischenergebnisse  bei  der  Software-Lsung  ohne  FPU  immer  wieder  im
Speicher abgelegt werden mssen, kann der Compiler bei der FPU diese Werte
in den Registern ablegen. So wird der Geschwindigkeitsvorteil umso grer, je
komplexer ein Ausdruck wird. Auerdem sollen beim Megamax-System auch
Register-Variable fr Reals mglich werden (beachten Sie die Hinweise in der
Datei LIESMICH.TXT), was nochmals einen deutlichen Vorteil bringt.

Die Wahl des Real-Formats bzw. der FPU kann auf zwei Arten geschehen:
Wird keine besondere Direktive verwendet ($F), wird das Format verwendet,
das in der Shell in der Umgebungs-Info-Box unter Real-Format angezeigt wird.
Diese Shell-Einstellung ist fest beim Linken der Shell bestimmt worden (durch
Wahl der Module ausschlielich aus dem IMP-Ordner bzw. durch Verwendung
derer aus dem Ordner FPU) und kann nicht verndert  werden.  Das  IEEE-
Format steht dabei fr die FPU-Verwendung, das Megamax-Format  fr  die
Software-Lsung.

Wer eine FPU besitzt, linke sich also (siehe Linken der Shell, Kap. 2) eine
Shell mit den FPU-Modulen und starte dann diese Shell zum bersetzen neuer
Module, die die FPU nutzen sollen.

Wer keine FPU besitzt, kann die FPU-Shell nicht benutzen, weil sie nur mit
einer FPU lauffhig ist. Die Direktive $F ist hier die Lsung: $F- erzeugt Code
fr die Software-Lsung, $F+ fr die FPU-Verwendung. Die Direktive mu vor
der ersten Benutzung von Reals stehen und darf nicht mehrmals im Modul mit
verschiedenen  Einstellungen  vorkommen,  sonst  meldet  der  Compiler  einen
Fehler. Nur wenn die Direktive nicht im Text oder in der Direktiven-Zeile der
Shell vorkommt, wird das Format verwendet, das in der Shell bestimmt ist.

Voreinstellung: Format der Shell verwenden


Ausgaben des Compilers (Quiet Compilation)

Whrend  der  bersetzung  protokolliert  der  Compiler  auf  dem  Bildschirm,
welches Modul er gerade bearbeitet und welche Prozedur jeweils  bersetzt
wird. Diese Ausgaben knnen Sie durch Setzen von (*$ Q+ *) abschalten; in
dieser Einstellung wird Ihnen der Compiler nur noch anzeigen, wenn  er  zu
einem neuen Quell-Textfile wechselt (s. Include-Option). Bei der bersetzung
groer Programme knnen Sie so den berblick behalten, wie weit der Compiler
gekommen ist, ohne da die Ausgabe durch die Auflistung der einzelnen Proze~
duren gestrt wird. (Ein bichen schneller geht's ohne die Ausgaben auch!)
3.4 Megamax Modula: Compilerdirektiven                                 3 - 45
________________________________________________________


Die Voreinstellung dieser Option wird brigens in der Shell in der Compiler-
Parameter-Box mit dem Schalter Ausgabe der Kurzmeldungen gewhlt.

Voreinstellung: (*$ Q- *)


Zugriff auf lokale Variable (Linking)

Diese Option ist nur fr Benutzer des integrierten 68000-Assemblers interes~
sant! Daher geht auch diese Beschreibung hier schon etwas 'ans Eingemachte';
Nur-Modula-Programmierer drfen sie gerne berspringen:

Zu Beginn jedes Prozedurrumpfes erzeugt der Compiler Maschinencode, der
die lokalen Variablen der Prozedur anlegt und - falls vorhanden - die Prozedur~
parameter in die entsprechenden Variablen bernimmt. Wenn Sie eine komplette
Prozedur in Assembler implementieren wollen, kann es effizienter sein, statt
lokaler Variablen CPU-Register zu verwenden und auch alle Prozedurparameter
direkt in CPU-Register zu bernehmen. Dazu kann mit (*$ L- *) der Code zur
Parameter-bernahme unterdrckt werden. Wie Sie mit Assembler-Anweisungen
an die Parameter herankommen, wird in Kapitel 4.3 verraten.

Beachten Sie aber unbedingt, da Prozeduren, in denen mit Modula-Befehlen
auf lokale Variable zugegriffen wird, in aller Regel unter (*$ L+ *) bersetzt
werden  mssen!   Also   bitte   nicht   vergessen,   die   Link-Option   wieder
zurckzusetzen! Es ist, schon zur besseren Abtrennung maschinenspezifischer
Programmteile, empfehlenswert, Assembler- und Modula-Prozeduren in einem
Programm nicht bunt zu mischen, sondern in Blcken zu gruppieren. Oft ist es
sinnvoll,  alle  Assembler-Prozeduren  in  einem  separaten  Modul  zusammen~
zufassen.

Voreinstellung: (*$ L+ *)


Wahl der Namens-Endung (Extension)

Der Compiler speichert bersetzte Module stets  unter  dem  auf  8  Zeichen
gekrzten Modulnamen als Dateinamen ab. Die Extension (Endung des Namens
nach dem '.') wird dabei normalerweise automatisch bestimmt:

MOD fr einfache Programm-Module,
IMP fr Implementations-Module,
DEF fr Definitionsmodule.

Soll Ihr Programm unter einer anderen Extension gespeichert werden, knnen
Sie irgendwo im Programm  (am  besten  direkt  hinter  dem  Modulkopf)  eine
$Extension-Option setzen. Beispiel: (*$ E MTP *) bewirkt, da der Dateiname
auf '.MTP' endet.
3.4 Megamax Modula: Compilerdirektiven                                 3 - 46
________________________________________________________


Dauerhaft ndern knnen Sie die Endungen auch durch Anpassung der Shell-
Source, indem Sie dort nach den bisher verwendeten Endungen suchen und sie
ersetzen. Auerdem mssen Sie dann noch die betreffenden Variablen in den
Modulen MOSConfig und ShellMsg, am besten durch Zuweisungen im Shell-
Initialisierungs-Code,  entsprechend  setzen  (beachten  Sie  dazu  die  Doku~
mentation in den Definitions-Texten).


Einschieben externer Textfiles (Include File)

Die Include-Option bettigt keinen 'Schalter' im Compiler und hat daher eine
etwas andere Syntax als ihre Verwandten. Durch Angabe von (*$ I FileName *)
weisen Sie den Compiler an, an der aktuellen Textposition zunchst die Datei
FileName  einzuschieben.  Nach  der  Bearbeitung  dieses  Textes  (hoffentlich
bezeichnet   FileName   eine   Textdatei!)   kehrt   der   Compiler   dann   zur
ursprnglichen Datei zurck.

Der  FileName  ist  immer  komplett  mit  Laufwerks-  und  evtl.  Ordnernamen
anzugeben. Wie blich drfen in der Options-Klammer weitere Optionen folgen
(durch Komma getrennt, z. B. so: (*$ I A:Teil2.Doc, Q+ *)). Diese Optionen
werden dann ausgewertet, bevor das eingeschobene Textfile bearbeitet wird;
sie beeinflussen also bereits die Verarbeitung des Einschubs.

Include-Anweisungen drfen geschachtelt werden, d. h. der eingeschobene Text
darf ebenfalls einen Einschub benutzen, in dem ein Einschub benutzt werden
darf, in dem... Das geht allerdings nicht ewig so weiter: Maximal 15 Include-
Schachtelungen sind erlaubt.

Wofr  braucht  man  nun  eigentlich  Include-Anweisungen?  Hufig  benutzte
Prozeduren oder Typdeklarationen sollten Sie lieber  in  ein  separates  Modul
schreiben, statt sie in einem Include-File bei jeder Benutzung neu zu bersetzen
(... und bei jeder Verbesserung Ihrer Standard-Prozeduren noch einmal alle
Benutzerprogramme zu compilieren!). Eine der ntzlichsten Anwendungen, die
wir selbst fr Include-Anweisungen haben, beruht darauf, da der Compiler
auch mehrere Module in einer Textdatei akzeptiert: Um nach greren nderun~
gen ein ganzes System von Modulen (z.B. das MOS) neu zu bersetzen, gengt
eine Datei, die nur aus Include-Optionen fr alle Module besteht.

Beispiel fr das Compilieren mehrerer Module auf einmal:

  (*$ I QUEUES.D *)
  (*$ I QUEUES.I  *)
  (*$ I TESTQ.M *)

Wird eine Datei, die nur die obigen drei Zeilen enthlt, compiliert, bearbeitet
der Compiler nacheinander alle drei Module.
3.4 Megamax Modula: Compilerdirektiven                                 3 - 47
________________________________________________________


Bibliotheksvorgabe (Use Library)

Die importierten Definitionsmodule sucht der Compiler im Normalfall auf allen
Pfaden, die in der Shell-Info-Datei (Kapitel 2.2) angegeben sind. Mchten Sie
einzelne  Definitionsmodule  auf  anderen  Pfaden  erreichen,  oder  haben  Sie
verschiedene Versionen einer Definition in Ihren Bibliotheksordnern, dann ist die
gezielte Angabe des Suchpfades ntzlich. Durch Angabe von (*$ U pathname
*) veranlassen Sie den Compiler, die im Folgenden bentigten Definitionsmodule
zunchst auf dem Pfad pathname zu suchen. Falls diese Suche keinen Erfolg
hat, wird wieder die bliche Pfadliste durchsucht.


Protokoll mit Statistik

Wird  eine  Protokolldatei  beim  Compilieren  erzeugt,  knnen  durch  (*$V+*)
Informationen ber Compilierrate, -zeit usw. am Ende des Protokolls abgelegt
werden. Ist nur die Statistik erwnscht, kann das Listing zu Beginn mit $P-
unterdrckt werden; ganz am Ende mu es aber  mit  $P+  wieder  aktiviert
werden!


Bedingte Compilierung

Erstellt man grere Programme fr verschiedene Konfigurationen, ist es oft
notwendig, verschiedene Code-Teile dafr zu verwenden. Anstatt fr jeden Fall
ein separates Modul erstellen zu mssen, knnen die verschiedenen Code-Se~
quenzen in einem Quelltext stehen und dann beim Compilieren durch "Schalter"
ein- oder ausgeklammert werden. Dazu wird erstmal der Programmteil wie ein
Kommentar eingeklammert, dann wird am Kommentarbeginn die Compileroption
$? eingetragen, gefolgt von einer Boolean expression (logischer Ausdruck) und
einem Doppelpunkt. Ist der Ausdruck beim Compilieren falsch (FALSE), bleibt
der Kommentar bestehen - der Programmteil wird nicht bersetzt. Ist  der
Ausdruck  wahr  (TRUE),  ignoriert  der  Compiler  die  Kommentarklammerung.
Beispiel fr bedingte Compilierung:

  CONST  MehrAls512KB =TRUE;
  TYPE
    (*$?      MehrAls512KB: Feld = ARRAY OF  1..40000  OF Daten; *)
    (*$? NOT MehrAls512KB: Feld = ARRAY OF  1..10000  OF Daten; *)

In diesem Beispiel wird z.B. ein Datenfeld definiert, das normalerweise 40000
Elemente enthalten soll. Im  Falle,  da  das  Programm  auf  einem  Atari  mit
nur 512KB eingesetzt wird, wrde das Feld zu viel Speicher belegen - dort soll
nur ein Feld mit 10000  Elementen  verwendet  werden.  Dies  ist  im  Beispiel
dadurch zu erreichen, da beim Compilieren je nach Zielrechner die Konstante
MehrAls512KB entsprechend definiert wird.
3.4 Megamax Modula: Compilerdirektiven                                 3 - 48
________________________________________________________


System-Module mit "shared data"

Diese  Option  ist  fr  Sie  nur  interessant,  wenn  Sie  System-Module
programmieren  oder  in  Ihren  Programmen  Gebrauch  vom  Loadtime-Linking
machen  wollen:  Normalerweise  wird  jedes  Modul,  das  von  einer  Haupt~
anwendung  importiert  wird,  beim  Start  der  Anwendung  initialisiert,  indem
dessen Modulkrper ausgefhrt wird. Wenn sie nun aber in der Anwendung ein
weiteres Modul als Anwendung starten (mit Hilfe der Funktion CallModule aus
dem Modul Loader), wrden alle von ihm importierten Module neu initialisiert,
auch wenn sie schon in der aufrufenden Anwendung vorhanden und initialisiert
waren. Das heit aber auch, da dann beispielsweise keine Datenbergaben
ber gemeinsam benutzte Module mglich sind, weil bei der Initialisierung auch
alle globalen Variablen neu angelegt (und gelscht) werden.

Damit  nun  verschachtelte  Module-Anwendungen  auf  die  gleichen  Daten
zugreifen knnen, mssen solche Module, die nur einmal anfangs initialisiert
werden sollen, mit der Direktive $Y+ bersetzt werden. Natrlich funktioniert
dies nur, wenn die Module mit CallModule gestartet werden und nicht schon zu
einem fertigen Programm gelinkt sind.

Ein Beispiel ist das Modul ShellMsg: Es wird sowohl von der Shell als auch von
Linker, Compiler, Make, usw, benutzt. Diese Programme tauschen  ber  die
dortigen Variablen ihre Parameter und Ergebnisse aus. Die Programme werden
ber CallModule in der Shell gestartet und ShellMsg wurde mit der Option $Y+
bersetzt, damit dabei die Variablen nicht jedesmal neu initialisiert werden.

Ebenso  knnen  Sie  selbst  eine  Anwendung  A  schreiben,  die  die  Funktion
CallModule des  Loaders  verwendet,  um  eine  weitere  Sub-Anwendung  B  zu
starten (diese mu dann aber ein ungelinktes Modul/Programm sein!). Dann
stehen die vom aufrufenden Programm A importierten Module auch dem neuen
Programm B zur Verfgung. Alle beiderseits importierten Module, die mit $Y+
bersetzt wurden, werden dabei beim Start von B nicht  erneut  initialisiert.
Damit knnen Sie erreichen, da die Hauptanwendung A und die von ihr als
eine  Art  Unterprogramm  gestartete  neue  Anwendung  B  ber  gemeinsame
Module Daten austauschen. So knnten beide das selbe (mit $Y+ bersetzte)
Modul importieren, aus dem globale Variablen exportiert werden: Das Haupt~
programm A schreibt Werte in diese Variablen, das dann davon gestartete
neue Programm B importiert ebenfalls das Modul, und dadurch, da der Loader
das fr die Hauptanwendung bereits geladene Modul auch dem neuen Modul B
zur Verfgung stellt, ohne es neu zu initialisieren, kann es  auf  die  Werte
zugreifen, die die Hauptanwendung A hineingeschrieben hat.

Voreinstellung: (*$ Y- *)
3.4 Megamax Modula: Compilerdirektiven                                 3 - 49
________________________________________________________


Entfernung nicht bentigter Module beim optimierten Linken

Bindet der Linker ein Programm mit vollstndiger Optimierung, entfernt er alle
Module, die keine bentigten Prozeduren oder Variablen exportieren. Das ist
beim  Linken  daran  zu  erkennen,  da  solche  Modulnamen  wieder  aus  dem
Fenster gelscht werden. Mit der Entfernung verschwindet auch sein Initiali~
sierungscode (Modulkrper), weil der in der Regel nur interne Initialisierungen
vornehmen  soll  und  daher  nicht  mehr  bentigt  wrde.  Nun  gibt  es  aber
Anwendungen,  bei  denen  ein  Modul  nichts  anderes  tun  soll,  als  externe
Variablen zu initialisieren. Solche Module nennen wir in der Regel Treiber oder
Konfigurationsmodule. Da diese  Treiber  nicht  beim  Optimieren  verschwinden
drfen, mssen dafr besondere Vorkehrungen getroffen werden.

Eine Mglichkeit - die "sauberere" - ist, solche Module in den Linker-Optionen
als Treibermodule einzutragen. Dann werden sie nicht entfernt.

Die andere Mglichkeit besteht darin, das betroffene Modul im Quelltext mit
der Option $B+ zu versehen. Wird das Modul dann vom Hauptmodul importiert,
wird  es  keinesfalls  vom  Linker  entfernt  (wie  dies  auch  beim  niemals
optimierenden Loader beim Starten mit Load-Time-Linking geschieht).


Compiler-Warnungen

Bisher gibt es nur eine  Warnung  seitens  des  Compilers,  und  die  tritt  bei
falscher  Verwendung  von  REF-Parametern  auf  (siehe  Abschnitt  ber  REF-
Parameter weiter oben). Und sie ist nicht mal als Warnung ausgewiesen - sie
bricht die bersetzung in jedem Fall ab. Naja. Auf jeden Fall ist die Fehler~
meldung  teilweise  sehr  lstig,  beispielsweise,  wenn  ein  REF-Parameter  als
VAR-Parameter an eine weitere Funktion bergeben wird, von der man aber
genau wei, da sie das Datum nicht verndern wird. Dies kommt beispiels~
weise bei den FastStrings-Funktionen vor, die immer noch VAR- statt REF-
Parameter haben, weil die REF-bergabe noch nicht optimal implementiert ist.
Um in einem solchen Fall die Fehlermeldung zu unterbinden, kann die Option
$W- vor dem - sonst - illegalen Zugriff verwendet werden. Dahinter sollte
dann  aber  wieder  mit  $W+  (Standard-Einstellung)  oder  $W=  der  normale
Zustand fr Warnungen hergestellt werden.
3.4 Megamax Modula: Compilerdirektiven                                 3 - 50
________________________________________________________


bersicht: Compilerdirektiven

Syntax-Beispiel:  (*$ R-, S-  Kommentar: alle Prfungen aus *)


Schalter

     Vor-
Name      Bedeutung               Erluterungen
    einst
 A -  Erweiterte Syntax   A+ lockert einige Syntax-Regeln.
 B  -  Body Requirement    B+  verhindert  das  Entfernen  des  Modulkrpers
                                beim optimierten Linken
 C +  Case Sensitivity      C-  hebt Unterscheidung von Gro-/Kleinschrift auf
 D -  Debugging            D+  erzeugt Zusatzcode zur Fehlersuche
 E  -  Procedure Trace     E+ erzeugt Code zur Anzeige von Prozeduraufrufen
 F  -  Float-Format         F+ dient zur Verwendung einer FPU
 H -  Local Procedures    H+ erlaubt lokale Prozeduren als Parameter
 I  -  Integer-Size         I+ ordnet CARDINAL/INTEGER den LONG-Typen zu
 J  +  Optimized Code      J- verhindert evtl. kritische Optimierungen
 K  -  Long-Short-Assign  K+ erlaubt Zuweisung von Long- auf Short-Variable
 L  +  Parameter Linking   L-  erlaubt Parameterbernahme von Assembler
 M +  Prozedurnamen      M- spart Platz, aber Prozedurnamen knnen dann
                                nicht mehr bei Fehlern angezeigt werden. Beim
                                vollst. optimierten Linken werden alle Prozedur~
                                namen automatisch entfernt.
 N -  No Runtime          N+ verhindert den autom. Runtime-Import
 P  +  Protokoll             P-  nimmt Programmteile aus dem Protokoll aus
 Q -  Quiet Compilation    Q+ schaltet Ausgaben beim bersetzen ab
 R  +  Range Checking      R-  spart Code fr Bereichsprfungen
 S +  Stack Checking      S- spart Code fr Stackplatz-Prfungen;
                              S 512 setzt geforderte Stackplatz-Reserve
 T  +  Record Ordering     T- reiht Felder mit Kommataaufzhlung rckwrts
 U +  Set Format          U- whlt altes SET-Format (Compiler Version 3)
 V -  Verbose Protocol    V+ erzeugt Statistik am Ende der Protokolldatei
 W +  Warnings            W- verhindert Fehlermeldung bei REF-Parametern
 X -  Extended Asm       X+ erlaubt 68020 & 68881 Mnemonics (nur  bei
                                erweitertem Compiler / Assembler)
 Y -  System-Module      Y+ erlaubt "shared data"
 Z -  Value Return Mode  Z+ lt Funktionsergebnisse im Register liefern.


Sonstige Direktiven

 E      Extension           E xyz  setzt Endung der Codedatei auf '.xyz'
 I       Include              I filename  fgt Datei filename ein
 U      Uses Library        U path  lt Definitionsmodule auf path suchen
 ?       Conditional Comp.  ?constExpr:  bersetzt Folgendes nur bedingt
 Reg    Register Var.       deklariert Variable, die im Register zu halten sind
