\section{Systemspezifische Besonderheiten}

\label{refErweiter}
Dieser etwas gr"ossere Abschnitt beschreibt die besonderen Eigenschaften
von \mtwoamiga. Ebenfalls werden Unterschiede zu den "ublichen
Implementationen und Differenzen zu g"angigen Lehrb"uchern aufgezeigt.
Diese entstanden aus ersten kleinen Anpassungen an den zuk"unftigen
\mtwo-Standard.\footnote{Auch wenn es niemand glaubt: wir
{\em warten\/} tats"achlich immer noch}. Einige Elemente wurden auch 
neueren Modula-Varianten entlehnt.
Wo das nicht gen"ugte, musste speziell f"ur 
das Betriebssystem angepasst werden.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Abschlussprozeduren (CLOSE)}
\label{refClose}
Der Modulrumpf eines \mtwo-Programmes hat die Aufgabe, einen
definierten Zustand zu schaffen. Oft werden dabei Betriebsmittel
reserviert, beispielsweise wird Speicher alloziert, Dateien oder
Fenster ge"offnet.
Bei Programmende besteht f"ur das Programm keine M"oglichkeit,
die Betriebsmittel wieder freizugeben. Da das Betriebssystem des
Amigas die Betriebsmitel zwar vergibt, aber nicht kontrolliert,
bleiben diese auch nach Programmende reserviert\footnote{Die Kontrolle
der Betriebsmittel wird auch "'Resource Tracking"' genannt}
Daher musste ein Mechanismus
gefunden werden, der die Freigabe nach dem Programmende erm"oglicht.
Dies gilt besonders f"ur fehlerhafte Programme, bei denen der
Programmabbruch an einer beliebigen Stelle m"oglich ist.

\mtwoamiga{} bietet daf"ur das Konzept des {\bf Abschluss\-codes}.
Jedes Imple\-men\-ta\-tions- oder Progra"mmodul {\em kann\/} einen
Codeteil enthalten, der bei Programmende oder bei einem "`Absturz"'
aufgerufen wird. Daf"ur gibt es in diesem Compiler eine syntaktische
Erweiterung: das reservierte Wort {\bf CLOSE}. Es darf
nur innerhalb des Modulblockes eines Implementations- oder
Progra"mmoduls angegeben werden. Dieses Wort beendet syntaktisch den
Initialisierungsteil des Moduls und leitet den Teil ein, der
beim Programmende 
ausgef"uhrt wird. Im weiteren Verlauf wird dieser
Teil auch {\bf Close-Phase} genannt.

\begin{note}
 Genau wie f"ur die Initialisierungsphase, w"ahrend der die Modulr"umpfe
 aller importierten Moduln automatisch aufgerufen werden, wird auch
 f"ur die  Close-Phase vom Compiler
 ein Aufruf an alle {\tt CLOSE}-Teile der
 importierten Moduln generiert. Durch die Art der Aufrufe mit Hilfe
 einer (versteckten) Z"ahler-Variablen ist garantiert, dass tieferliegende
 Moduln nicht vor dem Hauptmodul geschlossen werden. Dadurch bleiben
 importierte Prozeduren auch w"ahrend der  Close-Phase benutzbar.
\end{note}

\begin{warning}
Alle {\tt CLOSE}-Teile sollten sehr robust und mehrfach aufrufbar programmiert
sein! Es kann vorkommen, dass nach einem Programm-Absturz w"ahrend
der  Close-Phase ein weiterer Laufzeitfehler auftritt. In diesem Fall
wird die Close-Phase erneut durchlaufen, was bei unsauberer Programmierung
zur unvollst"andigen Betriebsmittel-Freigabe oder gar zu
einer endlosen Schleife f"uhren kann!
\end{warning}

\begin{example}
Beispiel:
\begin{verbatim}
IMPLEMENTATION MODULE Terminal;
IMPORT Arts,DosD,DosL;

CONST window="CON:0/0/640/100/out";

VAR out: DosD.FileHandlePtr;

BEGIN (* Hauptmodul *)
  out:=DosL.Open(ADR(window),DosD.newFile);
  Arts.Assert(out#NIL,ADR("Fehler: Dos.Open"));
CLOSE
  IF out <> NIL THEN
    DosL.Close(out);
    out:=NIL;
  END;
END Terminal.
\end{verbatim}
Bei der Initialisierung des Moduls {\tt Terminal} wird ein Fenster ge"offnet,
auf das "uber {\tt out} zugegriffen werden kann. Bei Programmende schliesst
der Close-Teil dieses Fenster wieder. Die Abfrage \verb|out<>NIL| verhindert,
dass es {\em mehrfach\/} geschlossen werden kann, was zu einem Systemabsturz
f"uhren w"urde. Das Modul {\tt DosL} ist noch benutzbar,
weil es erst geschlossen
wird, wenn kein anderes Modul es mehr ben"otigt.
\end{example}

Auf "ahnliche Weise schliessen die Moduln {\tt FileSystem} und {\tt SeqIO}
alle offenen Dateien, wie auch {\tt Heap} und {\tt Storage} alle zuvor
allozierten Speicherbereiche wieder freigeben. Insbesondere das Modul
{\tt DosSupport}, das bei Benutzung alle Directory-Locks und offenen
Dateien verwaltet, sei in diesem Zusammenhang empfohlen. Fehlerhafte Programme
verhindern somit das Entstehen von "`unsauberen"' Situationen und ersparen
einen Neustart des gesamten Systems.

\subsection{Import-Alias}

Da insbesondere bei Aufz"ahlungstypen --- erst recht mit der in
\ref{newEnum} beschriebenen "Anderung --- 
die Anzahl der "`versteckten"' Importe immer weiter
steigt, ist es vermehrt angebracht, Objekte nur noch qualifiziert zu
importieren.  Dies ist aber mit einer enormen Tipparbeit verbunden
--- man bedenke, warum ein Modul "`{\tt R}"' genannt wurde.
Darum kann nun beim Import von Modulen 
ein {\bf Alias} angegeben werden.

Die neue Syntax einer {\tt IMPORT}-Anweisung:
\begin{quote}
\verb|"IMPORT" [alias ":"] ModName.|
\end{quote}

Damit kann nun statt dem vollen Modulnamen der
vern"unftigerweise k"urzere Alias verwendet werden.

\begin{alltt}
  IMPORT d:DosL, e:ExecL;
  {\rm \ldots}
  d.Delay(5)  (* {\rm Abk"urzung f"ur} DosL.Delay(5) *)
  {\rm \ldots}
\end{alltt}

Dies geht aber nur im Hauptmodul, nicht in lokalen.
Ebenfalls ist nach der obigen
Deklaration die folgende Anweisungsfolge nicht erlaubt:
\begin{alltt}
  FROM d IMPORT \ldots ;
\end{alltt}
Vielmehr muss auch hier
\begin{alltt}
  FROM DosL IMPORT \ldots
\end{alltt}
geschrieben werden!

\subsection{Bezeichner}

Um die Portierung von C-Quelltexten zu vereinfachen,
wurde der Unterstrich als g"ultiges Zeichen in allen Bezeichnern
ausser Modulnamen erlaubt. Bei Ausnutzung dieser M"oglichkeit sind
die Quelltexte allerdings nicht mehr auf andere Systeme portierbar.

\subsection{Restriktionen des Einpass-Compilers}

Da der Compiler in einem Durchlauf den Code erzeugt,
m"ussen alle referenzierten Objekte bereits bekannt sein.
Eine Ausnahme bilden Zeigerdeklarationen, die auch vor der
referenzierten Struktur deklariert werden k"onnen.
M"ochten Sie eine Prozedur aufrufen, die erst
sp"ater deklariert wird, muss diese Prozedur {\bf vorw"artsdeklariert}
werden. Dazu wird der Prozedurkopf geschrieben, und anstelle
des Prozedurrumpfs steht das reservierte Wort {\bf FORWARD}.
Die Prozedurimplementation geht dann unver"andert vor sich.

\begin{example}
\begin{alltt}
PROCEDURE ForwProc(i: INTEGER); FORWARD;
 {\rm\ldots}
  (* Aufruf von ForwProc innerhalb einer Prozedur *)
 {\rm\ldots}
PROCEDURE ForwProc(i: INTEGER);
BEGIN
  (* {\cmsltt Anweisungen} *)
END ForwProc;
\end{alltt}
\end{example}

\subsection{Typentransfer und Typenkonversion}

Die systemnahe Programmierung macht es zeitweilen n"otig,
einer Variablen innerhalb eines Ausdrucks einen neuen Typ zu geben.
Dabei wird die Bitkombination der Speicherzelle, die f"ur eine
Variable des Ursprungtyps reserviert ist, unver"andert in einen
neuen Zieltyp "ubernommen. Dabei m"ussen jedoch die Gr"ossen
des Ursprungtyps sowie des Zieltyps gleich gross sein.

Programme, die diesen Mechanismus verwenden, sind allerdings
schlecht portierbar, da der Speicherbedarf der einzelnen
Typen nicht auf allen Rechnern gleich ist. Wird ein solcher
{\bf Typentransfer} ben"otigt, muss daf"ur in \mtwoamiga{} die
Prozedur {\tt CAST} aus dem Modul {\tt SYSTEM} importiert
werden. Dadurch ist die Systemabh"angigkeit bereits in der
Importliste angezeigt.

Der vielleicht bekannte Mechanismus, dass ein Ausdruck
geklammert und von einem Typnamen angef"uhrt wird, ist
ebenfalls noch enthalten. Allerdings wird dann kein Typentransfer,
sondern eine sichere {\bf Typenkonversion} ausgef"uhrt. Dies macht
eigentlich die Prozeduren {\tt ORD}, {\tt CHR}, {\tt FLOAT} und
{\tt VAL} unn"otig, sie bleiben jedoch aus Gr"unden der
Kompatibilit"at in der Sprache enthalten, sollten aber nicht mehr verwendet
werden. Die Typenkonversion funktioniert nur mit den unstruktierten
Typen, also auch mit Unterbereichen und Aufz"ahlungstypen.

\smallskip\begin{tabular}{lll}
{\tt LONGINT("B")} & entspricht & {\tt ORD("B")} \\
{\tt CHAR(66)} & entspricht & {\tt CHR(66)} \\
{\tt REAL(100)} & entspricht & {\tt FLOAT(100)} \\
& \multicolumn{1}{c}{\ldots} & \\
{\tt BITSET(3)} & \multicolumn{2}{l}{\bf Geht nicht, da nicht unstrukturiert}
\end{tabular}\smallskip

Die Verwendung von Typkonversionen bietet den Vorteil, dass
der Compiler angewiesen werden kann, einen ganz bestimmten Typ zu
erzeugen. Die Funktion {\tt ORD()} konvertiert immer zu einem
{\tt LONGINT}. Soll aber das Resultat einer Konversion beispielsweise
einer Variablen vom Typ {\tt INTEGER} zugewiesen werden,
muss anschliessend wieder zu {\tt INTEGER} konvertiert und dazu
zus"atzlicher Code erzeugt werden. Dies kann mit
Typkonversionen vermieden werden.

Viele Betriebssystemroutinen geben einen zu wenig spezifischen
Zeigertyp oder gar {\tt ADDRESS} zur"uck. F"ur die Weiterverarbeitung
muss der Typ des Resultats konvertiert werden. 
Dies geschieht mit einer {\tt CAST}-Anweisung, die den Resultatstyp
in den f"ur die weitere Bearbeitung n"otigen Typ umwandelt.
In gewissen F"allen wird durch dieses Vorgehen eine Hilfsvariable
ben"otigt, die unter Umst"anden danach nie mehr verwendet wird.

\begin{example}
Beispiel:
\begin{verbatim}
VAR
 p:ProcessPtr;
BEGIN
 p:=CAST(ProcessPtr,FindTask(NIL));
 Assert(p^.stackSize>4000,ADR("Zuwenig Stack"));
\end{verbatim}
Neu ist erlaubt:
\begin{verbatim}
 Assert( CAST(ProcessPtr,FindTask(NIL))^.stackSize>4000,
   ADR("Zuwenig Stack"));
\end{verbatim}
\end{example}

Damit dies m"oglich ist, musste die Syntax erweitert werden:
\begin{ebnf}{Designator}
\item[Factor]
  {\tt NOT Factor \verb'|' number \verb'|' string \verb'|' set
  \verb'|' \dq(\dq\ Expression \dq)\dq\ \verb'|' Designator.}
\item[Designator]
  {\tt qualident \{\dq.\dq ident \verb'|' \dq[\dq\ ExpList \dq]\dq\
  \verb'|' \dq\verb'^'\dq\ \verb'|' ActualParameter\}.}
\end{ebnf}

\subsection{Charakteristik verschiedener Typen}

\subsubsection{Ganze Zahlen}

Da die Prozessoren der M68000-Familie eine Registerbreite
von 32 Bit haben, werden auch Rechengr"ossen dieser Gr"osse
angeboten. Die entsprechenden Typen heissen {\tt LONGINT}
bzw.\ {\tt LONGCARD}. Der {\tt LONGINT}-Bereich umfasst alle
Zahlen im von -2\,147\,483\,648 ($-2^{31}$) bis 2\,147\,483\,647
($2^{31}-1$), der {\tt LONGCARD}-Bereich geht von 0 bis
4\,294\,967\,295 ($2^{32}-1$).

Zudem werden auch die Typen {\tt SHORTINT} und {\tt SHORTCARD}
angeboten, die jeweils den Wertebereich von -128 bis 127
bzw.\ 0 bis 255 umfassen. Variablen dieses Typs belegen
folglich ein Byte im Speicher, beachten Sie allerdings auch
den Unterabschnitt \ref{refAlign}, Anordnung von Typen und Variablen.

Zahlen-Konstanten, wie zum Beispiel 0 oder -4009, haben
an sich keinen bestimmten Typ. Der Compiler weiss lediglich,
dass es sich um skalare Zahlen handelt. Erst wenn sie in Rechnungen
gebraucht oder einer Variablen zugewiesen werden, erhalten
sie einen Typ. Bei Zuweisungen wird nat"urlich kontrolliert,
ob diese Konstante "uberhaupt in dieser Variablen Platz hat.
In verschiedenen anderen Systemen wird eine "`lange Zahl"' mit
einem {\tt D} hinter der Zahl gekennzeichnet, z.B. {\tt 12D}
w"are die {\tt LONGCARD}-Konstante 12. Dies ist in \mtwoamiga{}
{\em nicht\/} zul"assig, aber auch nicht n"otig.

In diesem Zusammenhang sei eine vor allem f"ur Numeriker
wichtige Anmerkung zu den Operatoren {\tt DIV} und {\tt MOD}
erw"ahnt. Die mathematische Definition des Rests und der
ganzzahligen Division lautet:

%\begin{quote}
\[ x \mbox{~DIV~} y = q \quad:\quad q \le x / y \] \\
\[ x \mbox{~MOD~} y = r \quad:\quad 0 \le r < y \mbox{~f"ur~} y > 0\mbox{~;~}
  y < r \le 0 \mbox{~f"ur~} y < 0 \]
Dabei muss immer gelten: \[ q \ast y + r = x \]
%\end{quote}

Diese Bedingungen sind bei den meisten Implementationen {\em nicht\/}
erf"ullt. So ist bei negativen Divisoren das Resultat der
ganzzahligen Division gr"osser als der Quotient (n"aher bei Null)
und der Rest hat das Vorzeichen des Dividends statt des Divisors.
Die Operatoren {\tt DIV} und {\tt MOD} f"uhren im \mtwoamiga\ die
numerisch sauberen Operationen durch. Wird jedoch einmal die alte
Definition ben"otigt, k"onnen die Operatoren "'{\tt /}"' und {\tt REM}
verwendet werden. Der "'{\tt /}-Operator hat bei Zahlen des Typs
{\tt REAL}, {\tt LONGREAL} oder {\tt FFP} die gewohnte Bedeutung
der Division.
Um die Unterschiede deutlich vor Augen zu f"uhren, sollen die Tabellen
\ref{operandDiv} und \ref{operandSlash} dienen.
Dabei f"allt vor allem die Symmetrie bei der alten Definition auf.
Die korrekte L"osung hat keine Symmetrie,
ist aber kontinuierlich.
 
\begin{table}[p]
\begin{center}
\begin{tabular}{c|rrrr}
i: & i {\tt DIV 3} & i {\tt MOD 3} & i {\tt DIV -3} & i {\tt MOD -3} \\ \hline
4: & 1 & 1 & -2 & -2 \\
3: & 1 & 0 & -1 & 0 \\
2: & 0 & 2 & -1 & -1 \\
1: & 0 & 1 & -1 & -2 \\
0: & 0 & 0 & 0 & 0 \\
-1: & -1 & 2 & 0 & -1 \\
-2: & -1 & 1 & 0 & -2 \\
-3: & -1 & 0 & 1 & 0 \\
-4: & -2 & 2 & 1 & -1 \\
\end{tabular}
\end{center}
\caption{\label{operandDiv} Operatoren {\tt DIV} und {\tt MOD}}
\end{table}

\begin{table}[p]
\begin{center}
\begin{tabular}{c|rrrr}
i: & i {\tt / 3} & i {\tt REM 3} & i {\tt / -3} & i {\tt REM -3} \\ \hline
4: & 1 & 1 & -1 & 1 \\
3: & 1 & 0 & -1 & 0 \\
2: & 0 & 2 & 0 & 2 \\
1: & 0 & 1 & 0 & 1 \\
0: & 0 & 0 & 0 & 0 \\
-1: & 0 & -1 & 0 & -1 \\
-2: & 0 & -2 & 0 & -2 \\
-3: & -1 & 0 & 1 & 0 \\
-4: & -1 & -1 & 1 & -1 \\
\end{tabular}
\end{center}
\caption{\label{operandSlash} Operatoren {\tt /} und {\tt REM}}
\end{table}


\subsubsection{Gleitkommazahlen}

Zum  Rechnen mit Gleikommazahlen seien folgende Anmerkungen
erlaubt:
der {\tt REAL}-Bereich umfasst Zahlen von $-1.0*10^{38}$ bis
$1.0*10^{38}$. Da dieser Bereich nicht immer gen"ugt, gibt
es in \mtwoamiga{} auch noch den Typ {\tt LONGREAL}, der von
$-1.0*10^{308}$ bis $1.0*10^{308}$ reicht. Intern werden diese
Zahlen nach dem Standard von IEEE\footnote{Institute
of Electrical and Electronics Engineers} abgelegt. Motorola
entwickelte eine dritte, spezielle Darstellung der Gleitkomma-Zahlen,
das {\bf FFP (Fast Floating Point) Format}. Auch dieses Format
wird vom Amiga \mtwo{}  Compiler unterst"utzt; n"ahere Details
sind im Abschnitt \ref{SysMod} zum Pseudo-Modul {\tt SYSTEM}
beschrieben. Das FFP-Format umfasst zwar einen
kleineren Bereich als die {\tt REAL}-Darstellung --- es sind
lediglich Zahlen von $-1.0*10^{19}$ bis $1.0*10^{19}$
darstellbar ---, daf"ur sind die Operationen etwas schneller.

Die Verwendung von Variablen des Typs {\tt REAL} hat zur Folge,
dass zus"atzliche Moduln geladen werden. Der Programmierer 
muss dazu keine besonderen Vorkehrungen treffen, da der Compiler
diese Eintragungen vornimmt. Werden Variablen vom Typ {\tt LONGREAL}
benutzt, wird ebenfalls ein zus"atzliches Modul geladen. 
Spielt die Genauigkeit und der Bereich keine Rolle,
k"onnen auch Variablen des Typs {\tt FFP} aus dem Modul {\tt SYSTEM}
benutzt werden. Diese Operationen der Zahlen in {\tt FFP}-Darstellung
sind im Betriebssytem-Kern enthalten, und vergr"ossern darum die Codegr"osse
{\em nicht}.

Bei den Konstanten einer Gleitkommazahl gelten im Wesentlichen
dieselben
Regeln wie im skalaren Fall: von vornherein haben die Zahlen keinen
bestimmten Typ. Er wird erst bei Rechnungen oder Zuweisungen ermittelt
und gepr"uft. Es gibt also auch hier keine Unterscheidung mittels
eines {\tt D} in der Schreibweise, wie dies in einigen Publikationen
zu finden ist; die Konstantendefinition {\tt 1.234D201} ist nicht
erlaubt. Stattdessen schreibt man einfach {\tt 1.234E201}.

\subsubsection{Zeichenketten}
Zeichenketten erfahren in allen Programmiersprachen eine gewisse
Sonderbehandlung, da sie f"ur den Benutzer von gr"osster Wichtigkeit
sind, vom Computer aber nur sehr aufwendig verwaltet werden
k"onnen.
\paragraph{Das Abschlusszeichen {\tt 0C}:}
Zeichenketten werden in \mtwo{} in Variablen des Typs
 \verb|ARRAY[0..n] OF CHAR| abgelegt. Die darin abgelegte Zeichenkette
 darf $0$ bis $n+1$ Zeichen umfassen. Ist sie k"urzer als $n+1$, dann
 wird sie mit einem {\tt 0C} Zeichen abgeschlossen. Ist die Zeichenkette
 jedoch genau $n+1$ Zeichen lang, so ist sie {\em nicht\/} mit einem
 {\tt 0C} Zeichen abgeschlossen. Die Amiga-Prozeduren erwarten jedoch,
dass jede Zeichenkette mit einem Nullbyte endet. Der Programmierer ist
also daf"ur verantwortlich, die Zeichenketten lang genug zu deklarieren!

Zeichenketten werden meist als Offene Feldparameter ("'Open Arrays"')
an Prozeduren "ubergeben. Diese
besitzen eine
Besonderheit: Offene Feldparameter mit der Komponentengr"osse 1 
--- dies ist bei Zeichenketten der Fall --- enden nun
{\em garantiert\/} immer mit einem Nullbyte, wenn sie von der Prozedur
auf den Stack kopiert werden. Sie werden genau dann auf den
Stack kopiert, wenn sie Werte-Parameter sind und nicht die
Option \verb|(*$ CopyDyn:=FALSE *)| angegeben wurde.

Der Nutzen liegt darin, dass derartige Parameter direkt an
das Betriebssystem "ubergeben werden k"onnen.

\begin{example}
Ein Beispiel:
\begin{alltt}
PROCEDURE WriteS(s: ARRAY OF CHAR);
BEGIN
  DosL.Write(file, ADR(s), Length(s))
END WriteS;
\end{alltt}
\end{example}

Im \mtwoamiga-System kann es nur nach einer Zuweisung an eine Variable
oder beim direkten Manipulieren einzelner Feldelemente des {\tt ARRAY}s
vorkommen, dass eine Zeichenkette nicht mit {\tt 0C} abgeschlossen ist.

Alle konstanten Zeichenketten werden vom Compiler automatisch mit einem
Nullbyte abgeschlossen und auf einer geraden Adresse im Konstantenbereich
abgelegt.

Bei der "Ubergabe konstanter Zeichenketten an einen offenen Feldparameter
wird das abschliessende Nullbyte mitkopiert, sodass auch diese Zeichenketten
"`sicher"' sind. Der Wert von {\tt HIGH} ist also gleich {\tt SIZE} oder
{\tt String.Length}, jedoch mindestens 1. Hier heisst es aufzupassen:
dies ist eine
Neuerung gegen"uber der Compiler-Version 3.3!.

Ebenso schliessen alle Prozeduren des Moduls {\tt String} --- mit Ausnahme
der Prozeduren, welche die L"ange nicht ver"andern ---
und {\tt Terminal.ReadLn}
nach der Verarbeitung die Zeichenkette mit einem Nullbyte ab.

\paragraph{Speicherung der Zeichenketten:}
Es werden nur die Zeichenketten im Konstantenbereich
abgelegt, die tats"achlich benutzt werden. Sind in einem
Definitionsmodul Zeichenkettenkonstanten deklariert,
werden sie in der Objektdatei auf jeden Fall abgelegt, da
hierbei nat"urlich nicht festgestellt werden kann, ob die
Zeichenketten jemals benutzt werden.

Die Ablage der Konstanten im Datenbereich erfolgt optimiert.
Endet eine neu abzulegende Zeichenkette gleich wie eine bereits
bestehende und ist eine {\em gerade\/} Anzahl Zeichen von deren
Anfang entfernt, wird nur eine Referenz auf die bestehende 
Teilzeichenkette generiert. So wird kein weiterer Speicher
ben"otigt.

\begin{example}
Beispiel: Existiert bereits die konstante Zeichenkette "`{\tt verschoben}"'
im Konstantenbereich, wird eine neu zu vermerkende Zeichenkette
"`{\tt oben}"' {\em nicht\/} neu abgelegt, sondern nur ein Verweis
auf den f"ur beide gemeinsamen Teil "`{\tt oben}"'
erzeugt. F"ur die Zeichenketten "`{\tt D"ubel}"' und
"`{\tt "ubel} m"ussen zwei Bereiche verwendet werden, da das Wort
"`{\tt D"ubel}"' auf einer geraden Adresse liegt, und die so zu
bildende Teilzeichenkette "`{\tt "ubel}"' auf einer ungeraden Adresse zu
liegen k"ame.
\end{example}

Ausser in Definitionsmoduln ist f"ur die Optimierung nicht die
Reihenfolge der Deklaration, sondern die der {\em Benutzung\/}
entscheidend.

\paragraph{Zeichenkettenverkettung:}

Zeichenkettenkonstanten k"onnen nun bis zu 32\,kByte lang sein.
Dies wird durch eine neue Syntax erreicht. "Uberall,
wo konstante Zeichenketten verlangt sind, k"onnen nun
beliebig viele {\bf einfache} Zeichenketten durch 
Plus-Zeichen ("`{\tt +}"') getrennt {\bf verkettet}
werden.

Im Beispiel sieht das folgendermassen aus:

\begin{alltt}
CONST
  date="5.3.91";
  version="4.1";
  title=\dq M2-Beispiel \dq+version+\dq \dq+date+\dq\ \verb|\|n\dq;
...
  WriteString(\dq Heute ist\dq+date);
\end{alltt}


\paragraph{Sonderzeichen in konstanten Zeichenketten:}
\label{refCStrings}
\mtwoamiga{} bietet "ahnlich zu ANSI-C
die M"oglichkeit, innerhalb von konstanten
Zeichenketten Sonderzeichen und Steuercodes anzugeben. Hierdurch
ist es m"oglich, {\em jedes\/} Zeichen von {\tt CHAR(0)} bis
{\tt CHAR(255)} zu erreichen.

Einleitendes Zeichen ist immer der Backslash "`\verb|\|"'. Direkt
daran anschliessend folgen bestimmte Zeichen oder Kombinationen,
die den Wert des Zeichens bestimmen (Tabelle \ref{ctable}). Der
Backslash selbst wird als "`\verb|\\|"' angegeben.
Alle in der Tabelle nicht vermerkten Zeichen nach "`\verb|\|"'
ergeben eine Fehlermeldung.

\begin{table}[hbt]
\begin{center}
\begin{tabular}{|l|l|r|r|r|} \hline
Kombination & Zeichen & Dezimal & Hex & Oktal\\ \hline \hline
\verb|\o| & ASCII.nul & 0  & 00H & 000B\\ \hline
\verb|\b| & ASCII.bs  & 8  & 08H & 010B\\ \hline
\verb|\e| & ASCII.esc & 27 & 1BH & 033B\\ \hline
\verb|\f| & ASCII.ff  & 12 & 0CH & 014B\\ \hline
\verb|\n| & ASCII.eol & 10 & 0AH & 012B\\ \hline
\verb|\r| & ASCII.cr  & 13 & 0DH & 015B\\ \hline
\verb|\t| & ASCII.tab & 9  & 09H & 011B\\ \hline
\verb|\[| & ASCII.csi & 155& 9BH & 233B\\ \hline
\verb|\"| & \verb|'"'|& 34  & 22H& 042B\\ \hline
\verb|\'| & \verb|"'"|& 39  & 27H& 047B\\ \hline
\verb|\\| & \verb|"\"|& 92  & 5CH& 134B\\ \hline
\verb|\|x12 & CHAR(12H)&\multicolumn{3}{l|}{12 = Zweistellige Hexzahl} \\
            &          &\multicolumn{3}{l|}{(gross oder klein)} \\ \hline
%\raisebox{-1.5ex}[1.5ex]{\verb|\|x12} &
%  \raisebox{-1.5ex}[1.5ex]{CHAR(12H)}&
%  \multicolumn{3}{l|}{12 = Zweistellige Hexzahl} \\
%            &          &\multicolumn{3}{l|}{(gross oder klein)} \\ \hline
\verb|\|123 & 123C&\multicolumn{3}{l|}{123 = Dreistellige Oktalzahl} \\ \hline
\end{tabular}
\end{center}
\caption{\label{ctable} Sonderzeichen in Zeichenketten-Konstanten.}
\end{table}

\begin{note}
Da diese Art der Codierung zu Inkompatibilit"aten f"uhren kann, besteht die
M"oglichkeit, durch die Compiler-Anweisung
$$\verb|(*$ CStrings:=FALSE *)|$$
die Interpretation des Backslash als einleitendes Sonderzeichen auszuschalten.
Danach werden alle Zeichenketten also wieder ganz normal behandelt.
\end{note}

\begin{example}
 Diese M"oglichkeit kann unter Umst"anden
eine Menge Code sparen. Zum Beispiel kann die Anweisungsfolge
\begin{verbatim}
    WriteString("Zeile 1");
    WriteLn;
    WriteString("Zeile 2");
    WriteLn; WriteLn;
\end{verbatim}
\noindent
durch die einzelne Anweisung
\begin{verbatim}
    WriteString("Zeile 1\nZeile 2\n\n");
\end{verbatim}
\noindent
ersetzt werden.
\end{example}

\noindent\medskip
Zu den Sonderzeichen noch einige Anmerkungen und Tips:
\begin{itemize}
\item
  Die Angabe der Sonderzeichen ist teilweise redundant. Ein Zeilenvorschub
  ({\tt CHAR(10)})
  l"asst sich z.B. durch "`\verb|\n|"', "`\verb|\x0a|"',
  "`\verb|\x0A|"' oder als
   "`\verb|\012|"' angeben.
\item
  "`\verb|\o|"' liefert {\tt ASCII.nul}. Dieses Zeichen dient aber auch
  gleichzeitig als Ende-Kennung eines Strings. Der Compiler selbst
  k"ummert sich beim Einlesen von Konstanten nicht darum, da er die L"ange
  der Konstanten intern vermerkt. Alle Standard- und Bibliotheks-Prozeduren
  hingegen kennen die L"ange nicht und sehen dieses Zeichen als Ende an.
  Die Anweisung
  $$\verb|WriteString("Eis\oWasser");|$$
  wird also {\em nur\/} "`{\tt Eis}"' ausgeben, da die Zeichenkette
  scheinbar mit dem Nullzeichen endet.
\item
  Das Zeichen "`\verb|\|"' muss bei (standardm"assig) eingeschalteter
  Option \optK{} nun beispielsweise in einer {\tt CASE}-Anweisung als
  "`\verb|\\|"' geschrieben werden, sonst wird das abschliessende Hochkomma
  als Sonderzeichen behandelt und die Zeichenkette endet erst am Zeilenende
  (mit einer Fehlermeldung).
  \begin{verbatim}
    CASE char OF
    "\o": WriteInt(0,3); |
    "\\": WriteInt(92,3); |
    "x" : WriteInt(120,3);
  \end{verbatim}
\item
  BString-Strukturen\footnote{Zeichenketten,
  die im ersten Zeichen ihre L"ange
  angeben}, die Sie vielleicht von PASCAL her kennen,
  lassen sich leicht erstellen:
\begin{verbatim}
  "\x03DF0"
  "\002AB"
\end{verbatim}
\item
 Sogar komplett initialisierte, konstante {\tt RECORD}s kann man erstellen.
 Die Daten d"urfen aber w"ahrend des Programmlaufs nicht ver"andert werden,
 da Zeichenketten-Konstanten im Code-Bereich liegen:
  \begin{verbatim}
  VAR
    ldb:POINTER TO RECORD
          len:LONGINT;
          name:ARRAY[0..1000] OF CHAR
        END;
  ldb:=ADR("\o\o\o\011_LinkerDB\o\o\o");
  \end{verbatim}
\item Zeichenketten, die beide Arten von Anf"uhrungszeichen enthalten:
\begin{verbatim}
  WriteString("\"'Hallo', sagte er\", sagte sie.");
\end{verbatim}
ergibt die Ausgabe
\begin{verbatim}
  "'Hallo', sagte er", sagte sie.
\end{verbatim}
\item Eine komplette Alert-Message:
\begin{verbatim}
  "\o\xa0\x11Guru Medi\o\001\o\xAc\x1Ctation\o\o"
  -->  Guru Medi
        tation
\end{verbatim}
\end{itemize}

\subsubsection{Wahrheitswerte (BOOLEAN)}

Variablen vom Typ {\tt BOOLEAN} werden intern {\em nicht\/} als
{\tt [FALSE,TRUE]} dargestellt, sondern als 0 und -1. Dies f"uhrt
zu deutlich dichterem MC68000-Code in Boole'schen Ausdr"ucken und
erspart Umrechnungen nach einem Betriebssystem-Aufruf. Werden
Boole'sche Werte als Argumente an Standardfunktionen "ubergeben
--- beispielsweise {\tt ORD} --- wird vom Compiler automatisch eine
Umrechnung vorgenommen. Der internen Repr"asentation ist nur in der
systemnahen Programmierung Rechnung zu tragen.

\subsubsection{Aufz\protect"ahlungstypen}

\label{newEnum}
F"ur die TagItems (siehe \ref{tags}) musste ein Weg gefunden werden, die
Tag-Konstanten zu deklarieren.

In der Programmiersprache C sieht das so aus:
\begin{verbatim}
enum{WA_Dummy=TAG_USER+99,
     WA_Left,
     WA_Top,
     ...
     };
\end{verbatim}

Der erste Versuch f"ur \mtwo\ sieht so aus:
\begin{verbatim}
CONST
  waLeft=tagUser+100;
  waTop=tagUser+101;
  ...
\end{verbatim}

Dies ist nicht nur sehr aufwendig, sondern auch sehr fehleranf"allig.
Zudem werden dadurch die {\tt IMPORT}-Listen extrem lang.

Die in \mtwoamiga\ verwendete L"osung definiert
eine neue Syntax f"ur Auf"-z"ah\-lungs\-typen:

\begin{alltt}
  Enum= "(" ident [ ":=" {\cmsltt ConstExpr\/} ] \{"," ident\}")".
\end{alltt}
Die {\cmsltt ConstExpr\/} muss vom Typ UniversalInteger sein!

Hierbei wird die Ordinalzahl des ersten Elements
durch {\cmsltt ConstExpr\/}
festgelegt und bei den folgenden entsprechend weitergez"ahlt.

Somit lautet die Deklaration nun:

\begin{alltt}
TYPE
  WaTags=(waDummy:=tagUser+99,waLeft,waTop,...);
\end{alltt}

Dabei d"urfen nur positive Werte verwendet werden.
Sets sind weiterhin nur mit
normalen Aufz"ahlungstypen, deren Untergrenze 0 ist, erlaubt.

\subsubsection{SET-Typen}

Der Typ {\tt BITSET} soll nach Definition die Wortgr"osse des
verwendeten Prozessors repr"asentieren. Wegen dieser Abh"angigkeit
ist der Typ vom Modul {\tt SYSTEM} zu importieren. Zus"atzlich stehen die
Typen {\tt SHORTSET} und {\tt LONGSET} zur Verf"ugung, die 1 Byte
beziehungsweise 1 Langwort gross sind. Normale {\tt SET}s, deren
Gr"osse durch die Deklaration bestimmt sind, k"onnen wie gewohnt
benutzt werden. Die maximale {\tt SET}-Gr"osse ist 32 Elemente.

\subsubsection{BPOINTER und BPTR}
\label{refBPTR}
AmigaDOS verwendet neben normalen Zeigern sogenannte {\bf BCPL-Zeiger}.
Dies sind Zeiger, deren Wert 4 mal kleiner ist als die Adresse, auf
die sie zeigen. \mtwoamiga{} erlaubt die Deklaration derartiger
Zeiger. Dies geschieht. indem man einen Zeiger als
{\tt BPOINTER TO \rm\ldots} deklariert.

Beispielsweise enth"alt das Modul {\tt DosD} die Deklaration
\begin{quote}\tt
FileHandlePtr = BPOINTER TO FileHandle;
\end{quote}

Variablen dieses Typs kann man wie normale Variablen verwenden, der
Compiler erzeugt n"otigenfalls automatisch die Multiplikation mit 4,
um auf die Elemente des {\tt FileHandles} zuzugreifen.

Wird eine Typenkonversion eines {\tt BPOINTER}s nach {\tt POINTER} oder
umgekehrt durchgef"uhrt, dann wird ebenfalls der Wert des Zeigers
entsprechend konvertiert.

\begin{warning}
Wird statt einer Typenkonversion ein Typentransfer mit {\tt CAST}
durchgef"uhrt, wird der Wert {\em nicht\/} angepasst!
\end{warning}

Soll eine Variable zu allen {\tt BPOINTER}-Typen kompatibel sein,
muss diese vom Typ {\tt SYSTEM.BPTR} sein. Dieser hat f"ur die
{\tt BPOINTER}-Typen die gleiche Funktion wie {\tt ADDRESS} f"ur
die {\tt POINTER}-Typen.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%sep%%

\subsection{Typisierte Konstanten}

\label{typedCons}

Die einzigen bisher erlaubten
typisierten Konstanten waren Zeichenketten,
die implizit vom Typ
{\tt ARRAY [0..{\cmsltt n\/}] OF CHAR} sind und {\tt SET}s.

In \mtwoamiga\ kann 
{\em jeder beliebige Typ\/} als Konstante deklariert werden.
Dazu wird der Name des Typs wie bei {\tt SET}s von geschweiften Klammern
gefolgt, in denen ein konstanter Ausdruck dieses Typs beschrieben
wird.

Syntax:
\begin{quote}
\begin{verbatim}
CONST
  Const = TypIdent "'{"' constexpression "'}"'.
\end{verbatim}
\end{quote}

Diese Konstanten werden --- wie die Zeichenketten ---
im {\tt CODE}-Bereich des Programms
abgelegt, falls sie im Programm ben"otigt werden. Sie k"on"-nen in
Definitionsmoduln deklariert werden, wenn sie keine Referenzen
erzeugen, also {\tt ADR} nicht beutzt wird (siehe unten).

\subsubsection{Unstrukturierte Typen}

Bei unstrukturierten Typen wird der Wert innerhalb der geschweiften
Klammern in den angegebenen Typ konvertiert, falls dies
m"oglich und n"otig ist.

\begin{example}
Beispiele:
\begin{verbatim}
CONST
  li = LONGINT{-50};
  r  = REAL{1.5};
  c  = Farbe{gruen};
\end{verbatim}
\end{example}

Einen Sonderfall stellt hier die Standardprozedur {\tt ADR} dar.
Das Ergebnis
ist als {\tt ADDRESS} nat"urlich zuweisungskompatibel
zu allen Zeigern, jedoch
muss auch das Objekt, dessen Adresse bestimmt werden soll, konstant sein.

Dazu z"ahlen:
\begin{itemize}
  \item Zeichenketten
  \item Einzelzeichen
  \item globale Variablen (das Programm ist dann aber
    nicht mehr reentrant)
  \item typisierte Konstanten
\end{itemize}

Dazu z"ahlen {\em nicht}:
\begin{itemize}
  \item numerische Literale
  \item lokale Variablen
  \item Registervariablen
  \item Moduln
\end{itemize}

Objekte, die via {\tt ADR} referenziert werden,
werden auf jeden Fall im
Konstantenbereich abgelegt, auch wenn die eigentliche Konstante
im Programm nicht benutzt wird. So wird die
Versionszeichenkette {\tt a1} des untenstehenden
Beispiels nicht wegoptimiert.
In Definitionsmoduln darf {\tt ADR} nicht benutzt werden.

\begin{example}
Beispiele:

\begin{alltt}
CONST
  \verb|a1 = ADDRESS{ADR("$VER: prog 1.0 32-Aug-1805\n")};|
  a2 = {\cmsltt Typ}Ptr {ADR(GlobVar)}; (* Programm NICHT reentrant! *)
\end{alltt}
\end{example}


\begin{warning}
Durch dieses Feature werden leicht Referenzen erzeugt, die
ein Programm nicht mehr reentrant werden lassen. Jede Referenz von
Nicht-MERGED auf MERGED verhindert reentrant! MERGED sind alle
globalen Variablen, wenn die Option {\tt LargeVars} nicht
gesetzt ist (Kommandozeilenoption {\tt -y}).
Sobald Konstanten mit Referenzen (aus {\tt ADR}) im Konstantenpuffer
abgelegt wurden wird die optimierende Ablage der
Zeichenketten abgeschaltet.
\end{warning}


\subsubsection{Arrays}

Bei Arrays werden innerhalb der geschweiften Klammern alle Elemente,
durch Kommata getrennt, aufgez"ahlt. Falls nicht alle Elemente angegeben
werden sollen, m"ussen am Schluss zwei Punkte gesetzt werden. Dies
bedeutet, dass das Array mit dem
{\em letztem angegebenen\/} Element bis zum
Ende aufgef"ullt wird.

Eine Ausnahme bildet hierbei {\tt ARRAY OF CHAR}. In diesem Fall wird
einfach eine Zeichenkette angegeben,
die aber k"urzer als das {\tt ARRAY} sein
muss, damit noch das abschliessende Nullzeichen Platz hat.
Einzelzeichen werden
bei Bedarf zu Zeichenketten der L"ange 1 konvertiert.

Syntax:
\begin{quote}
\begin{verbatim}
ArrayConst:
  TypIdent "{" Const {"," Const} [".."] "}".
\end{verbatim}
\end{quote}

\begin{example}
Beispiele:
\begin{verbatim}
TYPE
  Color  = (red, green, blue, white);
  BigArr = ARRAY [5..100] OF INTEGER;
  ColArr = ARRAY Color    OF Color;
  Str80  = ARRAY [0..79]  OF CHAR;
CONST
  Big = BigArr {-1, -10, 5, 100, ..};
  Col = ColArr {blue, green, red, red};
  str = Str80  {"Text"};
\end{verbatim}
\end{example}


\subsubsection{Records}

Bei Records werden innerhalb der geschweiften Klammern die Feldelemente
in beliebiger Reihenfolge angegeben. F"ur jedes Element wird der Feldname,
gefolgt von einem Doppelpunkt und dem zugeh"origen Wert, geschrieben.

Es m"ussen nur die gew"unschten Elemente angegeben werden, bei varianten
Records nur die zugeh"origen Felder. Alle nicht angegebenen Felder
sind automatisch mit Nullbytes belegt.

Syntax:
\begin{quote}
\begin{verbatim}
RecordConst:
  TypIdent "{" { fieldname ":" val
    { "," fieldname ":" val } } "}".
\end{verbatim}
\end{quote}


\begin{example}
Beispiele:
\begin{verbatim}
TYPE
  Rec1 = RECORD
    a, b: INTEGER;
    c: Color;
  END;
  Rec2 = RECORD
    hoehe: LONGCARD;
    CASE type: Color OF
    | red:   length: INTEGER;
    | green: next:   Color;
    | blue:  drink:  Alcoholics;
    | white: depth:  REAL;
    END;
  END;
CONST
  r1a = Rec1 {}; (* unsinnig, aber moeglich *)
  r1b = Rec1 {c: green,  a: 3, b: 5+6};
  r1c = Rec1 {c: white};
  r2a = Rec2 {hoehe: 4, type: white, depth: 7.8E8};
  r2b = Rec2 {type: green, next: red};
\end{verbatim}
\end{example}


\subsubsection{Allgemeines}

Diese Strukturen k"onnen nat"urlich beliebig tief geschachtelt werden,
also {\tt ARRAY}s in {\tt RECORD}s,
{\tt RECORD}s in {\tt ARRAY}s, und so fort.
Sie k"onnen nat"urlich nicht nur als Konstanten deklariert werden, sondern
auch in Ausdr"ucken oder Funktionsaufrufen auftreten.

Auf typisierte Konstanten darf im Programm lesend zugegriffen werden,
auch Elementweise.

\begin{example}
Beispiele:
\begin{verbatim}
  TYPE
    Str16 = ARRAY[0..16] OF CHAR;
    Rec = RECORD x:INTEGER; y:CHAR; str:Str16; END;
  CONST
    rec1 = Rec{y:"A", x:3, str:"Hallo"};
    rec2 = Rec{str:Str16{"H","A","L","L","O","\o",..}, x: 4};
    HexArray = Str16{"0123456789ABCDEF"};
  BEGIN
    char1 := rec1.y;
    char2 := HexArray[nr MOD 16];
    Proc(3, Rec{x:5, y:"Z", str: "Welcome"});
\end{verbatim}
\end{example}


\subsection{Initialisierte Variablen}
\label{initVar}

Durch {\bf initialisierte Variablen} besteht die M"oglichkeit,
lange und un"ubersichtliche
Variablen-Initialisierungen w"ahrend des Programmstarts zu vermeiden.
Den Variablen werden ihre Werte unmittelbar bei der
Deklaration zugewiesen.

Syntax:
\begin{quote}
\begin{verbatim}
VAR
  Variable ":=" TypisierteKonstante ";"
\end{verbatim}
\end{quote}

Der Typ der Variablen ergibt sich aus dem
eindeutigen Typ der typisierten Konstanten.

Initialisierte Variablen d"urfen nicht in Definitionsmoduln deklariert
werden und m"ussen global sein, also nicht Register, lokal oder absolut.

Der Modus der initialisierten Variablen ist im allgemeinen der gleiche
wie der der normalen Variablen,
also \near\ oder \far\ je nach Stand der Option {\tt LargeVars}.
Wird jedoch eine der Option
{\tt ChipDATA} oder {\tt ChipBSS} auf gesetzt, werden
die beiden unabh"angig voneinander \far.

Die Menge aller initialisierten Variablen
pro Modul darf 22\,kByte nicht
"uberschreiten. Die Menge aller initialisierten und normalen Variablen
zusammen ist weiterhin auf 32\,kByte pro Modul begrenzt, wenn sie
\near-Variablen sind.

Initialisierte Variablen werden immer auf geraden Adressen abgelegt.
Sind sie gr"osser als 4 Byte und
ist die Option {\tt LongAlign} eingeschaltet,
liegen sie auf Langwortgrenzen.

\begin{example}
Beispiele:
\begin{verbatim}
VAR
  x, y: INTEGER; (* Normale Variablen, mit 0 vorbelegt. *)
  y   := LONGINT{-4};
  v   := rec1; (* siehe Beispiel oben *)
  w   := Rec{x:4, str: "abc"};
\end{verbatim}
Weitere Beispiele sind im Demo-Programm Talker zu finden.
\end{example}

%%sep%%

\subsection{Tagitems}

\label{tags}
Die Version 2.0 des Betriebssystems macht intensiven Gebrauch
von sogenannten "`{\bf TagItems}"'.

Deren Deklaration gestaltet sich etwa folgendermassen:

\begin{alltt}
TYPE
  TagItem = RECORD
    tag:LONGCARD; (* Kennung, was data bedeuten soll *)
    data:ADDRESS  (* beliebiges Langwort *)
  END;
  TagItemPtr = POINTER TO ARRAY [0..{\cmsltt ??\/}] OF TagItem;
\end{alltt}

Die Prozeduren erwarten also als Parameter einen Zeiger auf
ein offenes Feld aus Langworten.

In Intuition gibt es z.B. neu die Prozedur:

\begin{alltt}
PROCEDURE OpenWindowTagList(
                nw\{R.A0\}:NewWindowPtr;
                tags\{R.A1\}: TagItemPtr;
                ):WindowPtr;
\end{alltt}

Mit Hilfe der Tags k"onnen mehr Parameter angegeben werden,
als es in der {\tt NewWindow}-Struktur m"oglich w"are. Hier kann sogar
der Zeiger auf {\tt NewWindow} {\tt NIL} sein, womit dann
{\em alle\/} Einstellungen
"uber die Tags vorgenommen werden. Jede Eigenschaft --- Breite,
H"ohe, Flags, und so fort --- des neuen Fensters wir durch {\em ein\/} TagItem
festgelegt. Nicht angegebene Eigenschaften bekommen einen Vorgabewert
zugewiesen.

In \mtwo\ gestaltet sich ein derartiger Aufruf im Gegensatz zur
Sprache C sehr aufwendig, was an einem Beispiel demonstriert werden
soll:

\begin{example}
\begin{alltt}
VAR
  buffer: ARRAY [0..8] OF TagItem;
...
  buffer[0].tag:=waLeft; (* Konstante *)
  buffer[0].data:=20;
  ...
  buffer[5].tag:=waPubScreenFallBack;
  buffer[5].data:=ADDRESS(TRUE);
  buffer[6].tag:=waTitle;
  buffer[6].data:=ADR("MyWindow");
  buffer[7].tag:=waIDCMP;
  buffer[7].data:=CAST(LONGINT,IDCMPFlagSet{...});
  buffer[8].tag:=tagEnd;
    (* Kennung: Feld ist zu Ende, data egal *)
...
  win:=OpenWindowTagList(NIL,ADR(buffer));
\end{alltt}
\end{example}

Um diesen Aufwand zu reduzieren, wurde eine neue Standard Prozedur
implementiert:

\begin{quote}\tt
SYSTEM.TAG(VAR x:AnyType;\\
  val \{,val\}:ADDRESS):ADDRESS;
\end{quote}

Der erste Parameter ist eine Variable beliebigen Typs, die als
Speicherbereich zur Aufnahme der nachfolgenden Langworte dient.
Sie muss gross genug sein, um alle Langworte aufnehmen zu k"onnen.
Sie darf {\em kein\/} offener Feldparameter sein.
Falls eine der Bedingungen nicht zutrifft, erfolgt eine Fehlermeldung.

Die nachfolgenden Parameter d"urfen beliebigen skalaren Typs oder
Mengen sein.
Sie werden implizit in den Typ {\tt ADDRESS} konvertiert, also je
nach Typ vorzeichenlos oder vorzeichenbehaftet auf Langworte
erweitert; Mengen sind in diesem Sinne vorzeichenlos. 
Der Typ {\tt BOOLEAN} wird wie "ublich gehandhabt, d.h.\ {\tt FALSE} ergibt
{\tt ADDRESS(0)}, {\tt TRUE} ergibt {\tt ADDRESS(1)},
wie es das Betriebssystem
auch erwartet. Im allgemeinen wird sowieso nur auf 0 getestet.

Der genaue Algorithmus ist:
\begin{verbatim}
  (*$ RangeChk:=FALSE OverflowChk:=FALSE *)
  IF valtyp=set THEN valtyp:=SHORTCARD|CARDINAL|LONGCARD END;
  buffer[i]:=ADDRESS(val);
  (*$ POP RangeChk POP OverflowChk *)
\end{verbatim}

Der R"uckgabewert der Prozedur {\tt TAG} ist die Adresse der "ubergebenen
Variablen.

Der Aufruf nach obigem Beispiel sieht hiermit nun so aus:

\begin{verbatim}
VAR
  bufferForAllTags: ARRAY [0..50] OF LONGINT;
...
  win:=OpenWindowTagList(NIL,SYSTEM.TAG(bufferForAllTags,
        waLeft,              20,
        ...,                 ...,
        waPubScreenFallBack, TRUE,
        waTitle,             ADR("MyWindow"),
        waIDCMP,             IDCMPFlagSet{...},
        tagEnd)); (* niemals vergessen! *)
\end{verbatim}

Obwohl diese Prozedur nur f"ur die TagItems entwickelt wurde, kann
sie nat"urlich auch anderweitig verwendet werden, z.B. um Arrays zu
initialisieren oder auch f"ur die Prozedur {\tt Terminal.Format}. Hierbei
muss aber bedacht werden, dass sie nur Langworte verarbeitet!
Bei der Format-Prozedur muss also immer (bis auf {\tt \%s}) das
"`{\tt l}"' mit angegeben werden!

\begin{example}
Beispiel:
\begin{verbatim}
  Format("Name: %s, Geschlecht: %lc, Alter: %03ld\n",
     TAG(buffer,ADR("Klaus Klaps"),sex,age));
\end{verbatim}
ergibt die Ausgabe
\begin{verbatim}
   "Name: Klaus Klaps, Geschlecht: m, Alter: 021\n"
\end{verbatim}
\end{example}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Bedingte Compilation}
\label{refCondComp}
F"ur das gute Verst"andnis dieses Abschnitts ist die Kenntnis der
Com\-piler-Op\-tio\-nen, beschrieben in \ref{refOptions},
unbedingte Voraussetzung!

\mtwoamiga{} stellt mit der bedingten Compilation ein weiteres
m"achtiges Werkzeug zur Programmentwicklung zur Verf"ugung.
Den Mechanismus der bedingten Compilation kann man etwa ausnutzen,
um Quelltexte f"ur verschiedene Sprachen\footnote{Deutsch oder Englisch,
{\em nicht\/} BASIC oder COBOL}, mit oder ohne Fehlersuchhilfen,
oder f"ur die Ausnutzung der unterschiedlichen Prozessoren in
{\tt ASSEMBLE}-Teilen
zu erstellen. Durch ein einfaches Setzen von benutzerdefinierten Optionen
kann dann ein v"ollig anderes Programm erzeugt werden.

Bestimmte Abschnitte des Quelltextes werden abh"anging von "ausseren
Bedingungen entweder normal kompiliert oder wie ein Kommentar
"ubersprungen. Die Steuerung erfolgt durch die
benutzerdefinierten Compiler-Optionen.

\subsubsection{Die Syntax}
Die Syntax ist "ahnlich der von \mtwo{}
("`{\tt ENDIF}"' statt "`{\tt END}"'), nur
dass die Pseudo-Befehle --- wie die Optionen --- in der Schreibweise
von Compiler-Anweisungen angegeben werden:
\begin{alltt}
  (*$ IF {\cmsltt BoolescherOptionsAusdruck1} *)
  {\rm\ldots (wird kompiliert, wenn Ausdruck1=TRUE)}
  (*$ ELSIF {\cmsltt BoolescherOptionsAusdruck2} *)
  {\rm\ldots (wird kompiliert, wenn Ausdruck2=TRUE}
  {\rm\ldots und Ausdruck1=FALSE)}
  (*$ ELSE *)
  {\rm\ldots (wird kompiliert, wenn beide FALSE)}
  (*$ ENDIF *)
\end{alltt}
Hierbei bezeichnet "`{\cmsltt BoolescherOptionsAusdruck}"' einen Ausdruck,
welcher durch {\bf NOT}, {\bf AND}, {\bf OR}, oder Klammerung
mit Options-Bezeichnern oder den Konstanten {\bf TRUE} und {\bf FALSE}
gebildet wird. Die Rangfolge der Operatoren
ist {\tt NOT}, {\tt AND}, {\tt OR}, kann aber --- wie in \mtwo{}
-- durch Klammerung
aufgehoben werden. Eine Schachtelung der {\tt IF}-Ausdr"ucke ist erlaubt.

Alle Schl"usselworte m"ussen {\em gross\/} geschrieben werden. Die Namen der
vom Benutzer und vom Compiler definierten Optionen k"onnen beliebig
gross oder klein geschrieben werden.

\subsubsection{Vorgehensweise}
\begin{example}
Zu Beginn gleich ein Beispiel, an dem die exakte Vorgehensweise
des Compilers erl"autert werden soll:
\begin{verbatim}
CONST
  (*$ DEFINE Demo:=TRUE *)
  (*$ IF Demo *)
    str = "Demo Version";
    (*$ DEFINE Help:=TRUE *)
  (*$ ELSE *)
    str = "Normale Version";
    Dies Zeile liefert keinen Syntaxfehler!
    (*$ DEFINE Help:=FALSE *)
  (*$ ENDIF *)
\end{verbatim}
Falls von der Kommandozeile nichts Gegenteiliges bestimmt wurde (durch
"`\verb|-oDemo|"'), ist nach der ersten {\tt DEFINE}-Anweisung die Option
 "`{\tt Demo}"' wahr.
Folglich f"allt der Test "`{\tt IF Demo}"' positiv aus, die Konstante
{\tt str} erh"alt den Wert "`Demo Version"' und eine neue Benutzer-Option
"`{\tt Help}"' wird definiert und mit dem Wert {\tt TRUE} initialisiert. Danach
trifft der Compiler auf die {\tt ELSE}-Anweisung und
unterbindet die Compilation.
Er "uberliest folglich die zweite Deklaration von {\tt str} und den Text
"`Diese Zeile liefert\ldots"' --- der bei durchgef"uhrter Compilation einige
Fehlermeldungen erzeugen w"urde \mbox{---,} und trifft auf eine weitere
Compiler-Anweisung, die ausgewertet werden muss; dies k"onnte ja das zugeh"orige
"`{\tt ENDIF}"' sein. Diese Anweisung wird nur syntaktisch "uberpr"uft,
aber {\em nicht ausgef"uhrt}. Andernfalls k"ame die Fehlermeldung
"`\ldots doppelt definiert"')! Zum Schluss trifft er auf die Compiler-Anweisung
"`{\tt ENDIF}"' und schaltet die Compilation wieder ein.
\end{example}

Compiler-Anweisungen werden auch in "`"ubersprungenen"' Abschnitten
{\em immer\/} ausgewertet, k"onnen somit auch Fehlermeldungen erzeugen,
werden aber {nicht ausgef"uhrt\/}!
Dies zu wissen ist besonders wichtig bei "`kritischen"'
Compiler-Optionen.
\begin{example}
\begin{verbatim}
(*$ IF FALSE *)
  (*$ EntryExitCode:=FALSE *)
  PROCEDURE DemoDaten;
  ...
  END DemoDaten;
(*$ ENDIF *)

PROCEDURE Normal;
...
\end{verbatim}
St"unde die Compiler-Anweisung "`EntryExit\ldots"' {\em vor\/}
der {\tt IF-}Anweisung,
w"urde die n"achste kompilierte Prozedur ("`{\tt Normal}"') ohne Eingangs-
und Ausgangscode erzeugt, was wahrscheinlich zu einem Programm-Absturz
f"uhrte! Wenn es so wie oben angegeben geschrieben
wird, kann jedoch nichts passieren, da die Option {\tt EntryExitCode} nicht
ver"andert wird, bzw. nur dann, wenn auch die Prozedur "`{\tt DemoDaten}"'
kompiliert und danach die Option wieder automatisch auf {\tt TRUE} gesetzt wird.
\end{example}

\subsubsection{Die Prozessor-Optionen}
\label{prozComp}
Wie man der bei den Optionen enthaltenen Tabelle \ref{compproc} auf Seite
\pageref{compproc} entnehmen kann, werden die Optionen {\tt m68010} bis
{\tt m68881} immer gleichzeitig ver"andert. Sie sind derart voneinander
abh"angig, dass eine {\tt IF}-Abfrage eher einem
Vergleich "`gr"osser oder gleich"' 
entspricht. Diese Tatsache kann man ausnutzen, um den optimalen
Code f"ur den Zielprozessor auch in Assembler zu erzeugen.

Wenn man beispielsweise wissen will, ob man im Assembler den {\tt RTD}-Befehl
benutzen darf, muss man nicht auf {\tt m68010 OR m68020 OR m68030 OR
m68040} abfragen, ein einfaches {\tt IF m68010} gen"ugt!
Da die MC68040 intern eine eingeschr"ankte MC68881 besitzt, ist hier etwas
mehr Denkarbeit erforderlich, auch bei einigen Sonderbefehlen wie
etwa der MC68030-CPU. F"ur die Grundrechenarten gen"ugt die Abfrage
 {\tt IF m68881}, f"ur die transzendenten Funktionen sollte man hingegen
{\tt IF m68881 AND NOT m68040} schreiben!

\subsubsection{Beispiele}
\begin{example}
Anhand einiger Beispiele soll dieser
Mechanismus nun etwas verst"andlicher gemacht und verschiedene
M"oglichkeiten aufgezeigt werden:
\begin{verbatim}
(*$ DEFINE German:=TRUE DEFINE English:=FALSE *)
(*$ DEFINE Debug:=FALSE *)
CONST
  (*$ IF german *) (* Benutzer-Option *)
    msg = "deutsche Version"
  (*$ ELSIF english *) (* Benutzer-Option *)
    msg = "english version"
  (*$ ELSE *)
    msg = "Cfsoe Qsfvtjoh"
  (*$ ENDIF *) ;
BEGIN
  ...
  (*$ IF Debug *)  (* Benutzer-Option *)
    FormatNr("Debug: Variable x ist: %ld\n",x);
  (*$ ENDIF *)
  ...
  (*$ IF LargeVars *) (* Compiler-Option *)
  MOVE.W myInteger,D0
  (*$ ELSE *)
  MOVE.W myInteger(A4),D0
  (*$ ENDIF *)
  ...
  (*$ IF NOT StackChk *) (* Compiler-Option *)
  Arts.StkChk(-25000);
  (*$ ENDIF *)
  ...
  (*$ DEFINE NonSens:= LongAlign AND NOT Debug *)
  (*$ IF nonsens *)
    (*$ IF NilChk AND m68020 *)
    TRAPEQ
    (*$ ELSIF NilChk *)
    BNE.S ok
    TRAP #13
   ok:
  (*$ ENDIF ENDIF *)
  (*$ IF NOT NoNSeNs *)
  WriteString("Zu einfach!\n"); Terminate;
  (*$ ENDIF *)
\end{verbatim}
\end{example}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Codegenerierung f\protect"ur h\protect"ohere Prozessoren}
\label{refProzessoren}
Wie im Abschitt \ref{refOptions} beschrieben, kann man den
Zielprozessor des kompilierten Codes auf der Kommandozeile
angeben. Dies wird genutzt, um bestimmte Operationen
so effektiv wie m"oglich zu kodieren. Da der so erzeugte
Code nicht mehr auf jedem Amiga lauf"|f"a\-hig ist, wird
\begin{enumerate}
\item f"ur jede Art von CPU/FPU an den Namen des Objekt-Files eine andere
 Endung angeh"angt, die der Linker nutzt, um den bestm"oglichen
 Code f"ur ein Programm zusammenzustellen.
 \begin{note} Der Compiler selbst macht
 zwischen dem 68020 und 68030 {\em keinen}
 Unterschied. Wenn Sie im Assembler keine speziellen Befehle dieser
 Prozessoren benutzen, sind die erzeugten Objektdateien identisch.
 \end{note}
\item am Beginn des Modul-Codes eine "`{\bf Fang-Instruktion}"' eingef"ugt,
die keine Wirkung hat, wenn der Code auf dem daf"ur bestimmten Prozessor
gestartet wurde, aber auf einem
"`niedrigeren"' zu einem Guru, bzw.\ zum Requester
"`{\tt Ung"ultige Instruktion}"' f"uhrt.
Dadurch soll verhindert werden, dass ein
derartiges Programm Amok l"auft und eventuell sogar Speicherinhalte
zerst"ort.
\end{enumerate}

\noindent
Nachfolgend in Tabelle \ref{zusInstr} eine Liste der Instruktionen,
die der Compiler f"ur
die einzelnen Prozessoren zus"atzlich nutzt, sowie die zugeh"origen
"`Fang-Instruktionen"' und Endungen der Objekt-Dateien.
 Ein "`h"oherer"' Prozessor nutzt selbstverst"andlich auch die Instruktionen
 der "`niedrigeren"'!

\begin{table}[hbt]
\begin{center}
\begin{tabular}{|c|l|l|c|} \hline
CPU & Instruktionen & Fang-Instr. & Endung \\ \hline \hline
68000 & --- & --- & {\tt .obj} \\ \hline
68010 & RTD \#dist & MOVE CCR,D0 & {\tt .ob1} \\ \hline
68020 & CHK.L \#imm32 & TRAPF & {\tt .ob2} \\
u.\ 68030 & TRAPcc u.\ EXTB.L Dn & & {\tt .ob3} \\
      & MULx.L u.\ DIVx.L ea,Dn & &\\ \hline
68040 & Grundrechenarten & FNOP & {\tt .ob4} \\
u.\ 68881 & und Konvertierungen & & {\tt .ob8} \\ \hline
\end{tabular}
\end{center}
\caption{\label{zusInstr}genutzte Instruktionen h"oherer Prozessoren}
\end{table}

\subsubsection{FPU 68881, FPU 68882 und CPU 68040}
F"ur die mathematischen Coprozessoren generiert der Compiler nur Code,
wenn Berechnungen mit dem Typ {\tt LONGREAL} durchgef"uhrt werden.
Die Typen {\tt REAL} und {\tt FFP} bleiben hiervon ausgenommen!

Da der Befehlsumfang von 68881 und 68882 identisch ist (die 68882 ist
lediglich schneller und kann zwei Befehle gleichzeitig bearbeiten),
reden wir in diesem Handbuch immer nur von der FPU~68881.

Die FPUs sind vom Betriebssystem so initialisiert, dass sie bei Fehlern
("Uberlauf, Division durch 0, Argumente ausserhalb des Bereichs, etc.)
{\em keinen\/} Laufzeitfehler generieren, was dann unbemerkt zu falschen
Resultaten f"uhrt. Da die {\tt mathieeedoubbas.library} -- die vom Compiler
verwendet wird, wenn {\em nicht} f"ur eine FPU kompiliert wird --- keine
Laufzeitfehler erzeugt, haben wir auch f"ur den FPU-Code keine
Ausnahme-Behandlungen vorgesehen.

\begin{warning}
  Wenn Sie bei {\tt LONGREAL}-Berechnungen eine "`saubere"' Verarbeitung,
  d.h.\ im Fehlerfall einen Programm-Abbruch w"unschen, m"ussen Sie
  das Modul {\tt FPUExc} (Seite \pageref{FPUExc}) importieren.
  Der einfache Import gen"ugt,
  das Modul stellt jedoch noch weitergehende Prozeduren zur Steuerung
  der FPUs bereit.
\end{warning}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Variablen}
\mtwoamiga{} kennt mehr Variablen-Typen als das Standard-\mtwo{}.
Um das Laufzeitverhalten zu verbessern, die Codegr"osse zu verringern,
Residentf"ahigkeit zu erreichen und \mtwo-fremde Objekte einbinden
zu k"onnen, wurden einige neue Variablen-Typen implementiert, bzw.\ die
bekannten Typen verfeinert.

Der Unterschied zwischen {\em lokal\/} und {\em global\/} ist in diesem
Zusammenhang von untergeordneter Bedeutung und f"uhrt bei einigen
Typen lediglich zu Einschr"ankungen. Der Unterschied zwischen
{\em Parametern} und {\em Variablen} ist g"anzlich ohne Belang, da Parameter
immer auch lokale Variablen sind. Den Unterschied zwischen \near{} und
\far{} wird ebenfalls noch im Abschnitt \ref{refNearFar} angeschnitten,
er wird im Anschluss zun"achst eingef"uhrt.

Wir unterscheiden somit aufgrund der unterschiedlichen Deklarations-Syntax
zwischen f"unf Typen:
\begin{itemize}
\item "`Normal"' k"onnen lokale Variablen, Parameter,
globale \near-Va\-ria\-blen
oder globale \far-Va\-ria\-blen sein. Sie liegen immer entweder auf dem Stack
oder im Va\-ria\-blen-Bereich des Moduls.
\begin{example}
\begin{verbatim}
  VAR val : INTEGER;
\end{verbatim}
\end{example}

\item "`Register"' k"onnen lokale Variablen oder Parameter sein. Sie
werden permanent in dem angegebenen Register gehalten.
\begin{example}
\begin{verbatim}
  VAR reg0 {R.D0} : INTEGER;
\end{verbatim}
\end{example}

\item "`Absolut"' k"onnen lokal oder global deklarierte Variablen sein.
Sie liegen an einer festen Adresse im Speicher.
\begin{example}
\begin{verbatim}
  VAR vhposr [0DFF006H]: INTEGER;
\end{verbatim}
\end{example}

\item "`Extern, \near"' k"onnen lokal oder global deklariert werden. Sie
sind ausserhalb des \mtwo-Raums definiert und werden gleich wie \near-Variablen
adressiert.
\begin{example}
\begin{verbatim}
  VAR myMenu [ < "Ext_Menu"]: Menu;
\end{verbatim}
\end{example}

\item "`Extern, \far"' k"onnen ebefalls
lokal oder global deklariert werden. Sie
sind ausserhalb des \mtwo-Raums definiert und werden wie \far-Variablen
adressiert.
\begin{example}
\begin{verbatim}
  VAR imageData ["Ext_ChipData"]: ARRAY ... ;
\end{verbatim}
\end{example}
\end{itemize}


\subsubsection{Register-Variablen und -Parameter}
Genau wie Register-Parameter k"onnen auch Register-Variablen
deklariert werden. Diese d"urfen allerdings nicht global, sondern
nur lokal zu einer Prozedur sein. Hierzu sollte unbedingt der
Abschnitt \ref{refRegPars}, Seite \pageref{refRegPars} "uber die
Register-Parameter gelesen werden!
\begin{example}
Das folgende Beispiel zeigt auf extreme Weise
den Nutzen von Register-Variablen.
Die Prozedur ist bei eingeschalteter Optimierung ("`{\tt -d}"') genau 8 Byte
lang. Ohne Register-Variablen belegt sie 44 Byte
und ist sehr viel langsamer.
\begin{verbatim}
IMPORT R;
PROCEDURE Swap(VAR a{R.A0},b{R.A1}:LONGINT);
VAR temp{R.D0}:LONGINT;
BEGIN
  temp:=a; a:=b; b:=temp
END Swap;
(* erzeugter Code:  MOVE.L  (A0),D0
                    MOVE.L  (A1),(A0)
                    MOVE.L  D0,(A1)
                    RTS
*)
\end{verbatim}
\end{example}

\subsubsection{Globale Variablen}
\label{refNear}
\label{refFar}
Bei den globalen Variablen wird zwischen zwei verschiedenen Arten
unterschieden: {\bf \near}- und {\bf \far}-Variablen.
Wird die daf"ur verantwortliche Option "`{\tt LargeVars}"'
nicht explizit auf {\tt FALSE} gesetzt,
werden standardm"assig alle global deklarierten,
"`normalen"' (siehe obige Aufstellung) Variablen als \far-Variablen angelegt,
andernfalls als \near-Variablen.

Wer auf die Residentf"ahigkeit seiner Programme nicht verzichten,
Teile in Assembler programmieren oder "`fremde"' (C, Assembler) Teile
zum Programm hinzulinken m"ochte, sollte folgende Ausf"uhrungen beachten:

\begin{description}
\item[\far-Variablen] werden absolut lang adressiert. Sie unterliegen
keinerlei Einschr"ankungen, erzeugen jedoch l"angeren und langsameren
Code. Sobald aber auch nur ein einziges Modul eines Programmes
\far-Variablen benutzt, ist dieses Programm nicht mehr resident\-f"a\-hig!

\item[\near-Variablen] sind "`schneller"' und "`k"urzer"', sparen also
Laufzeit und Code, weil sie immer mit einem 16Bit-Offset relativ zum
Basisregister A4 adressiert werden.
Hierdurch ergeben sich zwei Einschr"ankungen:
\begin{enumerate}
\item Ein Modul darf maximal 32KByte mit \near-Variablen belegen.
"Uberschreitungen meldet der Compiler als Fehler.
\item Ein Programm darf maximal 64KByte \near-Variablen besitzen.
Die Einhaltung kann erst der Linker "uberpr"ufen und als Fehler melden.
\end{enumerate}
\end{description}

Der Typ der globalen Variablen ist jeweils pro Compilationseinheit
(Modul) festgelegt. Dies bestimmt die Compiler-Option \optY{}.
Hierbei ist unbedingt darauf zu achten, dass Definitions- und
Implementationsmodule mit derselben Option "ubersetzt werden, sofern
in den Definitionsmodulen "`normale"' (also keine absoluten oder externe)
Variablen deklariert werden. Andernfalls erfolgt eine Fehlermeldung.

Standardm"assig werden \far-Variablen erzeugt, um die Anzahl globaler
Variablen (bzw.\ die Gr"osse des von ihnen belegten Speichers) nicht
von vornherein einzuschr"anken. Man sollte jedoch m"oglichst immer die
Option "`\verb|LargeVars:=FALSE|"' bzw.\ "`{\tt -y}"' einsetzen, um kompakten
und schnellen Code zu erzeugen. Alle zum \mtwoamiga-System geh"origen
Standard-Moduln --- Profiler-Modul ausgenommen --- enthalten m"oglichst
wenige globale Variablen und sind im \near-Modell kompiliert.

\subsubsection{Absolute Variablen}
Die {\bf absoluten} Variablen sind im \mtwo-Standard definiert.
Der Voll"-st"an\-dig\-keit halber seien sie hier noch einmal erw"ahnt.
Sie werden deklariert, indem hinter dem Namen der Variablen in eckigen
Klammern eine Zahlenkonstante angegeben wird, die ihre absolute Adresse
im Speicher des Rechners festlegt. Sie werden ebenso absolut lang
(oder auch absolut kurz) adressiert wie die \far-Variablen.
Auf dem Amiga ist die Auswahl
absoluter Adressen allerdings nicht sehr gross, allenfalls 4 als
Zeiger auf die {\tt exec}-library sowie die Adressen der
Customchips sind hier m"oglich.
\begin{example}
Beispiel:
\begin{quote}\tt
  VAR absExecBase[4]:ExecBasePtr;
\end{quote}
\end{example}

\subsubsection{Externe Variablen}
\label{refExtVars}
Variablen oder initialisierte Daten, die nicht aus der
M2Amiga-Umgebung stammen und z.B. mit einem fremden Assembler
oder in "`C"' deklariert wurden, k"onnen in M2Amiga mit Hilfe
einer speziellen Deklaration eingebunden werden. Hierzu wird
--- "ahnlich wie bei absoluten Variablen --- in eckigen Klammern
der Name des Symbols als String, der aus beliebigen Zeichen
bestehen darf, angegeben. In diesem Fall wird die Variable wie
eine \far-Variable behandelt. Da wir auch hier nicht auf das
\near-Modell verzichten wollen, besagt ein "`\verb|<|"'-Zeichen
vor dem Namen (steht symbolisch f"ur small, near), dass diese
Variable \near{} ist. Dies entspricht im Grunde einem IMPORT
aus dem Unbekannten! Es ist sp"ater die Aufgabe des Linkers
(bzw.\ der Person, die das Programm linkt), das Symbol in
irgendeiner Datei zu finden. Die Deklaration
\begin{quote}
\verb|VAR pImage["__Image1"]:WORD; myGad[<"Gad2"]:Gadget;|
\end{quote}
definiert zwei Variablen, wobei {\tt pImage} eine (vorzugsweise
gleich im CHIP-Speicher liegende) \far- und {\tt myGad}
eine (bei Programmstart bereits initialisierte!) \near-Variable ist.

\subsection{Externe Prozeduren, Libraries}
\subsubsection{Externe Prozeduren}
\label{refExtProc}

Externe Prozeduren sind --- "ahnlich den externen Variablen ---
nicht in \mtwo, sondern in einer anderen Sprache deklariert.
Somit wird die volle Verantwortung f"ur
den korrekten Aufruf auf den Programmierer
abgew"alzt.

Wie externe Variablen sind externe Prozeduren
in Definitionsmoduln auch erlaubt.

Externe Prozeduren werden deklariert als
\begin{quote}\tt
PROCEDURE {\cmsltt name\/}({\rm\ldots}):{\rm\ldots};
 CODE "{\cmsltt LinkerName\/}";
\end{quote}

Der Programmierer ist selbst fuer die korrekte Angabe von
Parametern und Resultat verantwortlich.

Die eigentliche Prozedur kann in einer beliebigen Sprache
geschrieben sein. Hierbei sind jedoch die Namenskonventionen
der Sprache zu beachten. Die Sprache C stellt beispielsweise
"ublicherweise einen Underscore-Zeichen
an den Anfang des Namens.

Externe Prozeduren d"urfen in Definitionsmodulen deklariert werden
und nat"urlich auch lokal innerhalb anderer Prozeduren.

Dadurch ist es nun m"oglich, ein Prozedur-Alias zu erzeugen.
Als {\cmsltt LinkerName\/} wird dann das Modul, gefolgt von einem
Underscore und dem Prozedurnamen angegeben. Das erleichtert
das Schreiben von Erweiterungsmodulen ungemein.

\begin{example}\begin{alltt}
DEFINITION MODULE MyInOut;

PROCEDURE WriteLn; CODE "Terminal_WriteLn";
PROCEDURE WriteBin(nr:LONGINT);

{\rm \ldots}

END MyInOut.
\end{alltt}\end{example}

Hierdurch erpart man sich das Schreiben einer Dummy-Prozedur,
die doch nur die Parameter weiterreicht und nichts Eigenes
tut.
Dann {\em muss\/} allerdings das
Implementations-Modul (hier {\tt MyInOut}) auf jeden
Fall das andere Modul (hier {\tt Terminal}) importieren,
weil es ja sonst nie initialisiert w"urde!

\subsubsection{Libraries}
\label{refCODE}
Eine besondere Syntax in Definitionsmoduln erlaubt es, f"ur die
{\bf Amiga-Bibliotheken} (z.B. {\tt icon.library}) {\bf Schnittstellen-Moduln}
zu schreiben, die dem Compiler erm"oglichen, direkt den Aufrufcode f"ur
die Prozeduren zu generieren. Die Bibliothek wird vom Programm dann
auch automatisch ge"offnet und bei Programmende wieder geschlossen.
Um ein Schnittstellen-Modul zu definieren, m"ussen nach dem Modulnamen
sowohl der Name der Bibliothek sowie die verlangte
Versionsnummer in geschweiften
Klammern angegeben werden.

\begin{example}
\begin{quote}\tt
  DEFINITION MODULE IconL{\dq icon.library\dq,33};
\end{quote}
\end{example}

Zu einem Schnittstellen-Modul muss kein Implementationsmodul geschrieben
werden, die Objekt-Datei wird vom Compiler automatisch beim "Ubersetzen
des Definitionsmoduls erzeugt.

Da die Bibliotheken automatisch ge"offnet werden, ist es im Gegensatz
zu C-Programmen nicht n"otig, f"ur die Bibliotheksadresse eine Variable
zu deklarieren. Manchmal ben"otigt man aber doch die Adresse der
Bibliothek, beispielsweise, um auf die {\tt IntuitionBase} zugreifen
zu k"onnen. Dies kann mit der Funktion {\tt SYSTEM.ADR} geschehen.
Dazu importiert man das Modul unqualifiziert und verwendet als
Parameter von {\tt ADR} den Modulnamen.

\begin{example}
\begin{verbatim}
  ...
  IMPORT IntuitionL;
  VAR
    intuiBase: IntuitionBasePtr;
  BEGIN
    intuiBase:=ADR(IntuitionL);
\end{verbatim}
\end{example}

In Library-Moduln k"onnen keine oder genau folgende
Variablen deklariert werden:
\begin{quote}
{\cmsltt library\/\tt Version:\ INTEGER} \\
{\cmsltt library\/\tt Base:\ POINTER TO \cmsltt??} \\
\end{quote}
Diese werden vom automatisch erzeugten Code gesetzt und k"onnen
jederzeit abgefragt werden. Somit ist ein Aufruf von
{\tt ADR(\cmsltt library\/\tt)} eigentlich unn"otig.

\subsubsection{CODE}
Alle in der Definition eines Schnittstellen-Moduls enthaltenen Prozeduren
m"ussen jedoch eine
{\tt CODE}-Anweisung enthalten, die ihren Offset in der Li\-bra\-ry-Ta\-belle
angibt. Der Compiler sorgt im Falle eines Prozeduraufrufs selb"-st"an\-dig
daf"ur, dass das Register A6 mit der Adresse der Library geladen wird. Die
nachfolgende Anweisung ist dann {\tt JSR \cmsltt d\/\tt(A6)},
wobei f"ur {\cmsltt d} der angegebene Offset verwendet wird.

\begin{example}
\begin{verbatim}
  PROCEDURE GetDiskObject(name{8}:ADDRESS):DiskObjectPtr;
    CODE -78;
\end{verbatim}
\end{example}

Es ist auch m"oglich, {\tt CODE}-Prozeduren in normalen Moduln zu definieren,
als Beispiel diene das Modul {\tt Timer}.
In diesem Fall muss jedoch das Register
A6 explizit als Parameter der Prozedur auftreten. Bei einem Prozeduraufruf
wird das Register nicht geladen, weil es durch den Parameter bereits
gesetzt wurde. Es wird nur die Anweisung \verb|JSR d(A6)| ausgef"uhrt.
Der Programmierer ist daf"ur verantwortlich, dass der A6-Parameter einen
g"ultigen Wert erh"alt, z.B. den Zeiger auf das {\em ge"offnete\/} Device!
\begin{example}
\begin{verbatim}
  PROCEDURE AddTime(timer{14}:ADDRESS;
              dest{8},source{9}:TimeValPtr); CODE -42;
\end{verbatim}
\end{example}

\subsubsection{Optionale Libraries ohne Implementation}

\label{optLibWithout}
Ist die angegebene Versionsnummer negativ, so wird lediglich
{\em versucht}, die Library mit dem Absolutwert der Version zu
"offnen. Der Programmierer {\em muss\/} zur Laufzeit
"uberpr"ufen, ob das "Offnen erfolgreich war. Getestet wird
mit
\begin{quote}
{\tt ADR(\cmsltt library\/\tt) \# NIL}
\end{quote}
oder
\begin{quote}
{\cmsltt library\/\tt Base \# NIL}
\end{quote}

\subsubsection{Optionale Libraries mit Implementation}

Optionale Libraries werden {\em nicht} automatisch ge"offnet.
Vor der Benutzung irgendwelcher Prozeduren einer solchen Library muss
unbedingt getestet werden, dass die Library-Basis ungleich {\tt NIL}
ist!

Dabei sind folgende Punkte zu beachten:
\begin{itemize}
\item
  Das Modul darf nur \near-Variablen beinhalten.
\item
  Die Library-Basis muss auf der Langwortadresse mit dem Offset 4
  liegen. Auf Offset 0 liegt der versteckte Ini\-tia\-li\-sie\-rungs\-z"ahler
  --- eine {\tt INTEGER}-Variable --- des Moduls.
\end{itemize}

Das Ger"ust eines solchen Moduls sieht folgendermassen aus:

\begin{verbatim}
DEFINITON MODULE OptLib;
 ...
(*$LargeVars:=FALSE *)
(*$LongAlign:=FALSE *)
VAR
  optLibVersion: INTEGER;   (* Offset = 2 *)
  optLibBase: ...           (* Offset = 4 *)

PROCEDURE ...
  CODE ...
(* beliebige Mischung von CODE und normalen Prozeduren *)

END OptLib.

IMPLEMENTATION MODULE OptLib;
(*$LargeVars:=FALSE *)
 ...

BEGIN
  optLibBase:=OpenLibrary( ... );
  IF optLibBase<>NIL THEN
    optLibVersion:=optLibBase^.Lib.version
  END
CLOSE
  IF optLibBase<>NIL THEN
    CloseLibrary( ... );
    optLibBase:=NIL
  END
END OptLib.
\end{verbatim}

