\documentstyle[titlepage,german,dina4]{article}

\long\def\throwaway#1\thrend{}
\def\lra{\rightarrow}
\def\LRA{\Rightarrow}
\def\caret{\hbox{\tt\char94}}
\def\refname{}
\def\to{\mathrel{.\,.}}
\def\becomes{\mathrel{:=}}

\newcommand{\oberon}{\hbox{\sc Oberon}}
\newcommand{\pascal}{\hbox{\rm PASCAL}}
\newcommand{\modula}{\hbox{\rm MODULA-2}}
\newcommand{\ceres}{\hbox{CERES-II}}
\newcommand{\OP}{\hbox{\sc OP2}}

\title{Studienarbeit\\
       Eine 68000-Implementation des OP2-Oberon-Compilers}
\author{Martin Momberg\\(cand.-inform.)}
\date{25. Februar 1992}
\begin{document}
\maketitle

\section{Einleitung}

\throwaway
Im vergangenen Jahrzehnt begann ein radikaler Wandel in der Topologie
von Rechnenanlagen.
Bis vor wenigen Jahren bestanden leistungsf"ahige Rechensysteme
vorwiegend aus einem zentralen Gro"srechner, an den eine gro"se Anzahl
von Datensichtger"aten angeschlossen war.
Dislozierung von Rechenleistung wurde meistens durch die Verwendung von
Standleitungen zwischen Datensichtger"aten und Rechner erreicht.
Die Entwicklung neuer Verfahren zur Herstellung h"ochstintegrierter
Schaltungen (VLSI) und der darauffolgende Preisverfall insbesondere bei dynamischen
Schreib-Lese-Speichern lie"sen einen neuen Rechnertyp entstehen:
den Arbeitsplatzrechner (engl. {\it workstation}).
Mit einem solchen Rechner, der heute durchaus die Leistungsf"ahigkeit von kleinen
Gro"srechnern erreichen und "ubertreffen kann, lassen sich auch ohne einen
zentralen Gro"srechner und der damit verbundenen bedingten Verf"ugbarkeit
einer solchen Anlage mittelgro"se Rechnungen und administrative Aufgaben
erledigen.

Gleichzeitig wurde die Verbindung und der Datenaustausch zwischen verschiedenen
Rechnern durch die Verwendung neuer physikalischer Medien wie Breitband-
und sp"ater dann Glasfaserkabel und darauf aufbauend von leistungsf"ahigen
"Ubertragungsprotokollen soweit verbessert, da"s Hochgeschwindigkeits-Rechnernetze
sowohl im Nahbereich (engl. {\it local area networks, LAN}) als auch
zwischen geographisch weit entfernten Orten (engl. {\it wide area networks, WAN})
realisiert werden konnten.

Die Software-Entwickler versuchten, mit den rasanten Fortschritten im Hardware-Sektor
schrittzuhalten, und erarbeiteten, gest"utzt auf und best"atigt durch Ergebnissen
der Software-Ergonomie, einen neuen Typ von Benutzungsschnittstellen, die
{\em graphischen Benutzungsoberfl"achen}.
Auf den bei Arbeitplatzrechnern meist im Lieferumfang enthaltenen
graphischen Ein- und Ausgabeger"aten wie Maus und Bitmap-Schirm aufbauend konnte die
Zweidimensionalit"at des Bildschirms nun voll ausgenutzt und ein weiterer
Abstraktionsgrad durch die Repr"asentation von Daten und Operationen auf ihnen
durch Bilder (sog. {\it icons}) hizugef"ugt werden.
Erste Beispiele hierf"ur sind die Benutzungsoberfl"achen von \hbox{SMALLTALK-80}
\cite{smalltalk80} und der MacIntosh-Rechnerserie von Apple Computers.

Auch bei den Programmiersprachen zeigten sich Ver"anderungen, die sich im
industriellen Bereich vor allem an dort gebr"auchlichen Begriffen wie
Modularit"at, Robustheit, kurze Herstellungszeit, Wartungsfreundlichkeit
und leichte Austauschbarkeit und Wiederverwendbarkeit von Komponenten orientieren.
Dort haben sich, basierend auf der prozeduralen und imperativen Beschreibung
von Algorithmen, die blockstrukturierten Programmiersprachen besonders gut
entwickelt.
\footnote{Da"s in bestimmten Gebieten der industriellen
Fertigung wie der Qualit"atssicherung oder in der Forschung andere
Anforderungsprofile existieren und somit die Evolution der Programmiersprachen
dort einen anderen Weg geht, ist erw"ahnenswert, aber im Rahmen der vorliegenden
Arbeit von untergeordnetem Interesse.}
Aufbauend auf dem "`Urvater"' der blockstrukturierten Sprachen, \hbox{ALGOL-60}
\cite{algol60}, und seinem bekannterem Nachfolger \hbox{PASCAL} \cite{pascal}
entstanden Sprachen, die besonders das {\it Programmieren im Gro"sen\/}%
\footnote{NOCH ZU ERG"ANZEN: ZITAT ZUR DEFINITION}
unterst"utzen und zu deren wichtigsten Vertretern \modula\ \cite{modula-2} und \hbox{ADA}
\cite{ada} geh"oren.

Gemeinsame Eigenschaften dieser Sprachen sind

\begin{itemize}
\item das Modulkonzept, das es erlaubt, "uber die Definition von
  Schnittstellen zu anderen Komponenten (Modulen) des Programmsystems die
  Sichtbarkeit modulinterner Objekte zu kontrollieren und Dienstleistungen
  in einer, bei diesen Sprachen nur syntaktisch abpr"ufbar,
  wohldefinierten Art und Weise anzubieten, und
\item die strenge Typisierung und Typ-"Uberpr"ufung, die eine feste Bindung
  eines Objekts zu seinem Namen und seiner Struktur und einen sicheren
  Umgang mit diesen Objekten gew"ahrleistet.
\end{itemize}

In den letzten Jahren gewann eine anderen Art der Abbildung realer Kontexte
in rechnerorientierte Darstellungen erheblichen Einflu"s auch auf die Entwicklung
der blockorientierten Sprachen: das sich immer weiter verbreitende holistische
Verst"andni"s von Dingen und Zusammenh"angen, gerade im Umweltbereich, legt es nahe,
Dinge zusammen mit ihren Eigenschaften zu betrachten und Wechselwirkungen zwischen
ihnen nicht {\it per se\/} zu behandeln, sondern immer auch die beteiligten
Objekte als Ganzes miteinzubeziehen.
Das dr"uckt sich bei der Abstraktion von Objekten zum Zweck ihrer Beschreibung
in einer Programmiersprache darin aus, da"s zusammen mit der Repr"asentation
des Objekts an sich (als Datenstruktur) auch seine Eigenschaften und Wechselwirkungen
mit anderen Objekten (als Algorithmus) "ortlich und logisch zusammenh"angend
dargestellt werden.

Das Auftreten von objekt-orientierten Konzepten bei einer Programmiersprache
war zuerst bei \hbox{SIMULA-67} \cite{simula-67}, einer Obermenge von
\hbox{ALGOL-60}, zu beobachten und wurde fast unmittelbar daraus hervorgehend
mit \hbox{SMALLTALK-80} zur Hochbl"ute gef"uhrt, einer Sprache, bei der selbst
elementare Operationen auf ein objekt-orientiertes Modell zur"uckgef"uhrt werden.

Da durch blockstrukturierte Sprachen wie \modula\ einige Forderungen
an Software-Produkte wie leichte Austauschbarkeit und Wiederverwendbarkeit
von Komponenten nur schlecht abgedeckt waren, sie sich aber mit
objekt-orientierten Konzepten als gut beherrschbar erwiesen, wurden Sprachen
entwickelt, die Objekt- und Block-Orientiertheit in sich vereinigen.
Ein herausragendes Beispiel ist hier \hbox{EIFFEL} \cite{eiffel}, bei der
zus"atzlich Elemente aus der Programmverifikation integriert wurden, die z.B.
eine Schnittstellen-Definition von der syntaktischen auf die semantische
Ebene erweitern und somit die Schnittstelle zus"atzlich absichern.
\thrend

1986 begann N.~Wirth, der "`Vater"' von \hbox{PASCAL} und \modula,
zusammen mit seinem Kollegen J.~Gutknecht mit dem
Projekt, in einem kleinen Team sowohl das Betriebssystem als auch
wichtige Teile der Anwendungssoftware f"ur einen Ein-Benutzer-Arbeitsplatzrechner
innerhalb eines begrenzten Zeitrahmens zu entwickeln.
Die Hardware-Plattform stellte die Workstation \ceres\ dar,
die zwischen 1984 und 1986 von H.~Eberle entworfen und gebaut wurde und
die aus
\begin{itemize}
\item dem Mikroprozessor NS32032 von National~Semiconductor,
\item 2 MB Hauptspeicher,
\item einem Bitmap-Schirm mit Tastatur und Maus,
\item einer Festplatte,
\item einem 3.5''-Diskettenlaufwerk und
\item einem Netzwerkinterface
\end{itemize}
bestand.

Das Betriebssystem sollte streng hierarchisch und modular aufgebaut sein
und aus Gr"unden der Robustheit, mit Ausnahme extremer "`Low-Level-Routinen"',
ausschlie"slich in einer Programmiersprache geschrieben sein, die auch sp"ater
f"ur die Anwendungsprogramme verwendet werden sollte, denn
"`{\it\ldots an operating system should be no more than a set of basic modules, and
the design of an application must be considered as a goal-oriented extension
of that basic set\ldots}"'\cite{modulaToOberon2}
\modula\ bietet eine modulare Systementwicklung mit getrennt voneinander
"ubersetzbaren Einheiten und wurde deshalb von dem Entwicklungsteam
in die n"ahere Wahl gezogen.
Die Komplexit"at der Sprache und des resultierenden Compilers wurde aber
als unn"otig (und behindernd) hoch eingestuft, und es wurde entschieden,
die Sprache auf ein Minimum an Konstrukten zu verengen.

Die zur Zeit aktuelle Diskussion zur objekt-orientierten Programmierung
und die Problematik der Erweiterung von Systemkomponenten f"uhrte zu
einer weiteren Design-Entscheidung, die den nun eingeschr"ankten Sprachumfang
wieder erweiterte:
"`{\it whereas modern languages, such as \/\modula, support the notion of
extensibility in the procedural realm, the notion is less well established
in the domain of data types.
In particular, \modula\ does not allow the definition of new data types as
extensions of other, programmer-defined types in an adequate manner.
An additional feature was called for, thereby giving rise to an\/ {\em extension}
of \modula}"'%
\cite{modulaToOberon2}

F"ur die so vorgegebene Sprache, die den Namen \oberon\ erhielt und in
Abschnitt~\ref{Die Sprache Oberon} noch n"aher beschrieben wird,
wurde auf der Lilith-Workstation, einer
fr"uheren Eigenentwicklung Wirths als Plattform f"ur \modula, ein
\oberon-Cross-Compiler f"ur die \ceres\ in \modula\ gebaut, mit dem
das neue Betriebssystem in mehreren Phasen "`hochgezogen"' wurde.
Basis auf der \ceres\ war ein im ROM abgelegter Bootstrap-Lader,
der "uber eine V24-Schnittstelle die "ubersetzten Module in die
Workstation "ubertrug und startete.
Geladen und getestet wurde zun"achst der sog. {\it inner core}, der
aus maschinennahen Routinen, der Speicherverwaltung, Prozeduren f"ur
den Dateizugriff und dem Modul-Lader, der im laufenden System neue
Module zuladen kann, besteht.\cite{design}

Der {\it outer core}, der auf dem inner core aufsetzt und nach ihm erarbeitet
wurde, beinhaltet Module zur Ansteuerung der Ein- und Ausgabeger"ate auf
einer niedrigen Ebene.
Das zentrale Modul {\tt Oberon\/} besitzt unter anderem die sogenannte "`event loop"', in
der sich der Prozessor befindet, wenn keine vom Benutzer initiierte Aktion
ausgef"uhrt wird.
Dort werden die Eingabeger"ate abgefragt und auftretende Ereignisse an
bestimmte Routinen, sogenannte {\it event handler}, weitergeleitet.
Die {\it handler\/} wurden beim Initialisieren von Anwendungs-Modulen dem
Modul~{\tt Oberon\/} bekanntgemacht.

Das \oberon-System ist insbesondere ein Single-Tasking-System in dem Sinne, da"s
der Prozessor einer anderen Task nur zugeteilt wird, wenn die vorherige Task
terminiert hat.
Die Zuteilung geschieht ausschlie"slich in der {\it event loop\/} durch Benutzeraktionen
an die oben erw"ahnten {\it handler}.%
\footnote{Eine Ausnahme bieten nur Hardware-Unterbrechungen zur Befriedigung
von Peripherieger"ate-Anforderungen.}
Da ein expliziter Kontextwechsel zwischen den {\it handlers\/} nicht stattfindet,
ist der Zustand eines Anwendungs-Moduls nach der Beendigung eines seiner
{\it handlers\/} in dessen modulglobalen Datenstrukturen "`eingefroren"'.

Im \oberon-System werden Anwendungs-Module f"ur
\begin{itemize}
\item Systemfunktionen ({\tt System}),
\item Disketten-Operationen ({\tt Diskette}),
\item Netzwerkdienste wie e-mail und file-services ({\tt Server}),
\item das Editieren von Texten ({\tt Edit}),
\item das Herstellen von Zeichnungen ({\tt Draw}) und
\item das Herstellen von Bildern ({\tt Paint})
\end{itemize}
angeboten (Modulnamen in Klammern).
Ferner existieren ein \oberon-Compiler und ein Assembler f"ur NS32xxx.
Diese Dienstleistungen sollen nur einen Grundstock darstellen und k"onnen
beliebig erweitert werden.

Zwischen den Anwendungen und dem Ger"atetreiber zur Interaktion mit dem
Bitmap-Schirm vermittelt eine Hierachie von Dienstleistungsmodulen, die
nach der Art der darzustellenden Informationen in Text-, Graphik- und
Bild-orientierte Module eingeteilt ist.

Eine gesamte "Ubersicht "uber das \oberon-System ist in \cite{oberonSystem}
und \cite{oberonGuide} zu finden.

\medskip
Die Aufgabe der vorliegenden Arbeit ist es, einen Grundstein in Form eines Compilers
zu legen, um das \oberon-System auf die Rechner der Atari-ST-Serie
(Mikroprozessor Motorola MC68000) zu portieren.
Ein Mitarbeiter Wirths, R.~Crelier, erstellte auf der Grundlage und unter Benutzung
von Teilen des Original-\oberon-Compilers einen "ubersichlichen und
gutstrukturierten "Ubersetzer, der sich f"ur die Portierung auf andere Systeme
besser eignet.
Der \oberon-Compiler, im folgenden \OP\ genannt, wird gegen eine Schutzgeb"uhr
von Herrn~Crelier abgegeben.
Im Lieferumfang sind eine \oberon- und eine \modula-Version (zum Bootstrap)
enthalten, wobei die Routinen f"ur die Code-Generierung bis auf wenige
Ausnahmen keinen K"orper enthalten.
Das Referenz-Handbuch zum Compiler kann von Herrn~Crelier bezogen werden.\cite{op2doc}

Diese schriftliche Ausarbeitung spiegelt in etwa das Vorgehen des Autors
strukturell wider:
\begin{itemize}
\item Empfang des Roh-Compilers bei Herrn~Crelier in Z"urich,
\item Einarbeitung in die Sprache \oberon, den Compiler und das
  \oberon-System,
\item Anpassen des Roh-Compilers an den Sprachumfang des Megamax-\modula-Compilers
  von der Firma {\sl Application Systems}, der auf der Ziel-Maschine
  {\it Atari-ST\/} arbeitet,
\item "Andern der systemabh"angigen Stellen, insbesondere Ein- und Ausgabe
  auf Terminal und Datei, auf vorhandene Bibliotheken,
\item Festlegen der modulglobalen Speicheraufteilung,
\item Erstellen der Routinen zur Code-Generierung und des Objektdatei-Formats,
\item Entwicklung eines Linkers, der Objektdateien zu einem unter dem
  Betriebssystem des STs, TOS, lauff"ahigen Programm zusammenbindet, und
\item Ausarbeitung des Laufzeitsystems einschlie"slich des Garbage Collectors.
\end{itemize}

Das Ergebnis ist ein Programm-System, das es gestattet, sowohl
\oberon-Programme auf dem Atari zu entwickeln und zu betreiben als auch
als Basis f"ur eine Implementation der \oberon-Umgebung zu dienen.
Dabei k"onnte der {\it inner core\/} als ausf"uhrbare Datei gehalten werden,
die bei Ausf"uhrung den {\it outer core\/} l"adt und startet.

Auf eine Implementation der \oberon-Version des \OP\ "uber die lauff"ahige
\modula-Version und der Behandlung der sich dabei ergebenden, f"ur den
"Ubersetzer-Bau interessanten Fragen des Bootstrapping und der Selbstverifikation
wurde im Rahmen dieser Arbeit verzichtet, da die f"ur die \oberon-Version n"otigen
Support-Module, die der \oberon-Umgebung entnommen sind, nicht zur Verf"ugung
standen und eine Eigenimplementation der Module neben der Zeitfrage auch wegen
der unzureichenden Dokumentation mit gro"ser Wahrscheinlichkeit Inkompatibilit"aten
geschaffen h"atte.

Voraussichtlich noch in diesem Jahr (1991) wird ein zweib"andiges Werk des Entwicklungsteams
erscheinen, in dem insbesondere die Umgebung in Quell-Form vorgestellt wird
und damit in die Public Domain einflie"st.

Der Autor dankt Herrn Prof. Dr.-Ing. H.-J.~Hoffmann, der durch seine vielf"altige
Unterst"utzung die Arbeit erst erm"oglicht hat, Herrn R.~Crelier f"ur die
Bereitstellung des Roh-"Ubersetzers und die interessanten Diskussionen via
E-Mail, Herrn F.~Grabenhorst f"ur die anregenden Gespr"ache zur
Code-Optimierung und den Eigenarten der ST-Serie und Herrn M.~Grebe fur
seine schnelle Redigierung des Textes.

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

\section{Die Programmiersprache \oberon}
\label{Die Sprache Oberon}

Wirths weitverbreitete Sprache \modula\ stand Pate bei der Entwicklung
von \oberon.
In der Tat k"onnen \oberon-Programm fast unmittelbar in "aquivalente
\modula-Programme umgesetzt werden.
\oberon\ stellt im wesentlichen eine Untermenge von \modula\ dar,
Inkompatibilit"aten gibt es nur bei der {\it Programmierung im Gro"sen\/}
und dem Verbund-Datentyp.
Deshalb werden in den nachfolgenden Ausf"uhrungen vorwiegend Unterschiede
zu \modula\ behandelt, wobei als Grundlage \cite{oberon2} dient.

%*** Entwicklungsgeschichte der Sprache

\subsection{Die Deklarationen und Definitionen}

Die Definition von Typen und Prozeduren und die Deklaration von Konstanten und
Variablen wurden unver"andert von \modula\ "ubernommen.

\subsubsection{Die Konstanten}

Unter den numerischen Konstanten unterscheiden sich nur die langen reellwertigen
Konstanten durch die Ersetzung des den Exponenten einleitenden "`{\tt E}"' durch
ein "`{\tt D}"' von den in \modula\ eingef"uhrten Schreibweisen.
Sowohl Zeichenkonstanten als auch Zeichenketten d"urfen nur noch durch
"`{\tt\char34}"' begrenzt werden.
Die oktale Schreibweise von Zeichenkonstanten wird durch eine hexadezimale
Schreibweise abgel"ost, bei der das "`{\tt X}"' als Abschlu"s dient.

Wie in \modula\ sind auch hier die booleschen Konstanten {\bf TRUE} und {\bf FALSE},
die Zeigerkonstante {\bf NIL}, Mengenkonstanten ohne Mengentyp als Pr"afix und
Prozedurkonstanten vorhanden.

\subsubsection{Die Datentypen}
\label{Datentypen}

Es stehen die Basis-Typen {\bf BOOLEAN}, {\bf CHAR}, {\bf SET}, {\bf SHORTINT},
{\bf INTEGER}, {\bf LONGINT}, {\bf REAL} und {\bf LONGREAL} zur
Verf"ugung.
In den fr"uhen Versionen von \oberon\ geh"orte zus"atzlich der Datentyp
{\bf BYTE} zu den Basis-Typen, er wird nun aber aus dem Modul {\tt SYSTEM}
exportiert.
Die kurzen und langen Varianten von {\bf INTEGER} und {\bf REAL} zeichnen sich
durch einen kleineren bzw. gr"o"seren Speicherplatzbedarf und einer
Wertebereichseinschr"ankung bzw. -erweiterung aus.
Der Typ {\bf SET} entspricht dem {\bf BITSET} in \modula.

\medskip
Als strukturierte Datentypen sind Felder ({\it arrays}), Verbunde ({\it records}),
Zeiger ({\it pointer}) und Prozedurtypen zugelassen.

Da in \oberon\ Felder nur nat"urliche Zahlen mit 0 als Indizes haben d"urfen,
er"ubrigt sich die Angabe der unteren Indexgrenze.
Die Definition eines zweidimensionalen Feldes mit f"unf Zeilen, sechs Spalten
und ganzzahligen Elementen hat die Form
{\bf ARRAY} 5, 6 {\bf OF INTEGER}.

\medskip
Die Verbunde haben in \oberon\ die gleiche Struktur wie in \modula.
Varianten sind nicht mehr erlaubt.
Stattdessen und in Erweiterung zu \modula\ wird der Begriff des
erweiterbaren Verbundes eingef"uhrt.

Zwischen Verbund-Typen kann eine Relation $T_1\lra T_2$ (gesprochen: $T_1$ ist
eine direkte Erweiterung von $T_2$) existieren, wobei $T_1$ und $T_2$ die Typ-Bezeichner
sind.
Die reflexiv-transitive H"ulle der direkten Erweiterung, im folgenden nur Erweiterung
genannt, wird durch $\LRA$ bezeichnet, es
gilt also: wenn $T_{i+1}\lra T_i$ f"ur beliebige $i\in{\cal N}_0$ gilt, dann
folgt f"ur alle $j\in{\cal N}_0$, also insbesondere f"ur $j=0$,
$T_{i+j}\LRA T_i$.
Der Index $i$ wird {\em Erweiterungstiefe\/} genannt.
Ein Verbund-Typ ohne Basistyp hat die Erweiterungstiefe~0 und
jede direkte Erweiterung eine um eins gr"o"sere Erweiterungstiefe als
ihr Basistyp.
Die maximal erlaubte Erweiterungstiefe ist eine implementationsabh"angige
Gr"o"se und bei der Atari-Implementation wie auch auf der \ceres\ auf 7
begrenzt.

In \oberon\ wird zum Beispiel die Relation $t \lra t0$ durch eine Typ-Definition
der Form $t =\hbox{\bf RECORD} (t0) \ldots \hbox{\bf END}$ abgebildet.
Dabei werden $t$ "`direkte Erweiterung von $t0$"' und $t0$ "`direkter Basistyp von
$t$"' genannt.
Durch eine solche Definition sind nicht nur die dort vereinbarten Komponenten
sondern auch die Komponenten des Basistyps erreichbar.
Eine direkte Erweiterung kann nur einen Basistyp haben, ein Basistyp aber beliebig viele
direkte Erweiterungen.
Besonders interessant wird diese Eigenschaft, wenn der Basistyp aus einem anderen
Modul importiert wird.
Weiter unten werden Operationen vorgestellt, die das Vorhandensein einer
Relation $\LRA$ sicherstellen ({\it type guard}) oder testen k"onnen ({\it type test}).
Eine ausf"uhrliche Behandlung von Erweiterungen zusammen mit einem
Implementationsvorschlag ist in Abschnitt~\ref{erweiterbare Verbunde} und in
\cite{typeExtensions} zu finden.

\medskip
Zeiger d"urfen in \oberon\ nur auf Felder und Verbunde zeigen.
Die Zuweisung von Speicherplatz geschieht hier auch durch die
Standardprozedur {\bf NEW}, allerdings steht kein {\bf DISPOSE} (wie in \modula)
zur R"uckgabe nicht mehr ben"otigten Speicherplatzes zur Verf"ugung, sondern
freier Speicherplatz wird durch einen {\it garbage collector\/}
(Abschnitt~\ref{Supportstrukturen}) aufgesp"urt und eingesammelt.

Die Relation $\lra$ und ihre reflexiv-transitive H"ulle $\LRA$ ist auch auf
Zeiger auf Verbunde anwendbar.
Sind $P$ und $Q$ als Zeiger auf Verbunde des Typs $R$ bzw. $S$ definiert,
so gilt $P\LRA Q$ genau dann, wenn $R\LRA S$ gilt.

\medskip
Bei der Definition von Prozedurtypen gilt die gleiche Syntax wie sie f"ur
Prozedurk"opfe "ublich ist, d.h. die Bezeichner f"ur die Parameter m"ussen
angegeben werden, es reicht nicht mehr, nur die verwendeten Typen zu
erw"ahnen.

\subsubsection{Die Deklararation von Variablen}

Die Variablen-Deklaration wurde von \modula\ unver"andert "ubernommen.

\subsubsection{Die Definition von Prozeduren}
\label{Definition von Prozeduren}

Alle von \modula\ her bekannten Eigenschaften und Schreibweisen bis auf eine
Ausnahme wurden in \oberon\ "ubernommen.
{\it Forward\/}-Deklarationen werden nicht mehr durch die Verwendung des
Schl"usselwortes {\bf FORWARD} als Ersatz f"ur {\bf PROCEDURE} oder den
Prozedurk"orper (je nach \modula-Version verschieden) sondern durch
Einf"ugen eines {\em caret} ({\caret}) zwischen
{\bf PROCEDURE} und dem Prozedurbezeichner in der Kopie des Prozedurkopfes
formuliert.

\medskip
Mehrere Neuerungen hielten bei der Parameter"ubergabe Einzug:
\begin{enumerate}
\item f"ur die {\it call-by-value}-"Ubergabe gelten die gleichen Regeln wie bei
  der Wertzuweisung (Abschnitt~\ref{Wertzuweisung}), also insbesondere die
  erweiterte Zuweisungsf"ahigkeit von Verbunden und von Zeigern auf Verbunde;
\item die erweitere Zuweisungsf"ahigkeit von Verbunden gilt auch f"ur
  die {\it call-by-reference}-"Ubergabe, die sonst eine Typ-Identit"at
  zwischen aktuellem und formalem Parameter voraussetzt (eine weitere
  Ausnahme f"ur die Identit"at wird im n"achsten Punkt besprochen);
  mit type tests kann der Typ des aktuellen Parameters identifiziert werden;
  bei Zuweisungen ganzer Verbunde zu einem formalen Parameter
  wird durch einen {\it implicit type guard\/} (Abschnitt~\ref{Wertzuweisung})
  sichergestellt, da"s der aktuelle Parameter vom {\em gleichen\/} Typ wie in der
  Parameter-Deklaration ist;
\item die in \modula\ meist mit {\bf CHAR} als Elementtyp gebr"auchlichen
  eindimensionalen dynamischen Felder als formale Parameter sind nun auch
  mehrdimensional verf"ugbar und werden {\em offene Felder\/} ({\it open arrays})
  genannt;
  die Deklaration einen dreidimensionalen {\bf SHORTINT}-Feldes hat z.B.
  die Form {\bf ARRAY OF ARRAY OF ARRAY OF SHORTINT};
  bei der Parameter-"Ubergabe m"ussen die Anzahl der Dimensionen und der
  Elementtyp "ubereinstimmen;
  die Anzahl der Elemente in einer Dimension kann man (auch bei statischen
  Feldern) erfahren durch die Funktion {\bf LEN} mit dem Feldbezeichner
  als ersten und der Nummer der Dimension als zweiten Parameter, wobei
  die dem in einem Designator am weitesten links stehenden Index zugeordnete
  Dimension die Nummer~0 erh"alt;
  wird der zweite Parameter weggelassen, dann ist automatisch die Dimension
  Nr.~0 gemeint;
  der R"uckgabewert von {\bf LEN} hat den Typ {\bf LONGINT}.
  Offene Felder als Wert-Parameter werden beim Aufruf der Prozedur kopiert;
  nur die Kopie findet dann in der Prozedur Verwendung.

  Eine besondere Art des offenen Feldes geh"orte bei den "alteren Versionen
  von \oberon\ zum Sprachumfang und wurde dann zusammen mit dem Datentyp {\bf BYTE}
  in das Modul {\tt SYSTEM} verlegt.
  Hat ein Referenz-Parameter den Typ {\bf ARRAY OF SYSTEM.BYTE}, so kann eine
  Struktur jeden Typs als aktueller Parameter "ubergeben werden.
\end{enumerate}

\subsection{Die Ausdr"ucke}

\subsubsection{Die Designatoren}
\label{Designatoren}

Die aus \modula\ bekannten Designatoren, bestehend aus einem Bezeichner und
nachfolgenden Kombinationen aus Dereferenzierern (\caret) und Selektoren ({\tt.})
f"ur Verbunde und Felder, finden auch in \oberon\ Verwendung.

Bei den Designatoren, die den genauen Ort eines Speicherplatzes f"ur einen
Basistyp beschreiben, vereinfacht sich das Dereferenzieren von Zeigern: die
Dereferenzierung geschieht automatisch (implizit) beim Selektieren einer Verbundkomponente
oder eines Feldelements.
{\tt x\caret.f} bzw. {\tt y\caret[0]} kann dann zu {\tt x.f} bzw. {\tt y[0]} abgek"urzt
werden.
Da Felder von Feldern zu mehrdimensionalen Feldern transformiert werden und
Elemente dort mit einem einzigen aus mehreren durch Kommata
getrennten und von eckigen Klammern umgebenen Indizes festgelegten Selektor
ausgew"ahlt werden k"onnen, wird die vereinfachte Dereferenzierung auch auf
Felder aus Zeigern auf Felder erweitert.
Z.B. kann der Designator {\tt z\caret[2]\caret[3,4]\caret[5]} einfacher in der Form
{\tt z[2,3,4,5]} geschrieben werden.

Eine Neuerung, die durch die Einf"uhrung der erweiterbaren Verbunde
motiviert ist, stellen die {\it type guards\/} dar, die allerdings
nur sinnvoll sind, wenn die in Abschnitt~\ref{Wertzuweisung} besprochene
erweiterte Zuweisungsf"ahigkeit von Verbunden und Zeigern auf Verbunde
genutzt wird.
Syntaktisch besteht eine type guard aus einem von runden Klammern umgebenen
Typ-Bezeichner, der zusammen mit einem Designator als Pr"afix wieder
einen Designator ergibt.
Erlaubt sind type guards aber nur hinter Designatoren, die (innerhalb einer
Prozedur) einen Referenz-Parameter~$r$ vom Verbund-Typ oder einen Zeiger~$p$
auf einen Verbund beschreiben, also z.B. $r(R0)$ oder $p(P0)$, wobei
$R0 = \hbox{\bf RECORD} \ldots\hbox{\bf END}$ und
$P0 = \hbox{\bf POINTER TO } R0$ sind.%
\footnote{Die Abh"angigkeit zwischen $R0$ und $P0$ ist nicht notwendig und
dient hier nur zur Vereinfachung der Notation.}
Habe im ersten Fall $r$ den Typ $R = \hbox{\bf RECORD} \ldots\hbox{\bf END}$
und im zweiten Fall $p$ den Typ $P = \hbox{\bf POINTER TO } R$, so mu"s
als Voraussetzung f"ur den type guard zum einen
$R0 \LRA R$ und zum anderen $P0\LRA P$ gelten (siehe Abschnitt~\ref{Datentypen}).
Diese Bedingungen werden f"ur jeden type guard statisch durch den Compiler abgepr"uft.
Sei desweiteren der dem formalen Parameter~$r$ zugeordnete aktuelle Parameter
vom Typ~$R1$, so gilt schon wegen der oben erw"ahnte erweiterte Zuweisungsf"ahigkeit
f"ur die Parameter-"Ubergabe die Relation $R1\LRA R$.
Durch den type guard $r(R0)$ wird sichergestellt, da"s nach seiner Bearbeitung
zus"atzlich $R1\LRA R0$ gilt und der Designator erh"alt den neuen Typ $R0$.
Zeige der Zeiger $p$ nach einer entsprechenden Wertzuweisung auf einen Verbund
vom Typ~$R1$ und sei $P1$ als {\bf POINTER TO} $R1$ definiert, so gilt wieder
wegen der erweiterten Zuweisungsf"ahigkeit bei Zeigern auf Verbunde
$P1\LRA P$.
Der type guard $p(P0)$ stellt dann sicher, da"s $P1\LRA P0$ gilt, und "andert
den Typ des resultierenden Designators zu $P0$.
%***
Nur mit den g"ultigen Relationen w"are eine Zuweisung des Designator-Wertes
vor dem type guard an den (vom Typ her ge"anderten) Designator nach dem type guard
erlaubt.
Wenn diese Typanpassungen durchgef"uhrt wurden, kann mit einem dem type guard
nachfolgenden Verbund-Selektor, bei Zeigern eingeleitet durch eine explizite
oder implizite Dereferenzierung (s.o.), neben den Komponenten von $R$ bzw.
$P$ auch auf die Komponenten von $R0$ bzw. $P0$ zugegriffen werden.

Nun ist es nicht so, da"s der type guard die Sicherstellung der G"ultigkeit
der neuen Relationen durch irgendwelche aufwendigen, dem Programmierer
verdeckten Transformationen von Datenstrukturen bewerkstelligt.
Vielmehr f"uhrt er einen (weiter unten beschriebenen) type test durch, der eben
diese G"ultigkeit berechnet; f"allt der Test negativ aus, unterbricht der
type guard den Programm\-ablauf mit einem Laufzeitfehler, die auf den type guard
folgenden Operationen, die sich vielleicht auf die G"ultigkeit der Relation
st"utzen, werden also "uberhaupt nicht erreicht.
Um so wichtiger ist es f"ur Programmierer, wie bei der Dereferenzierung von
Zeigern durch einen Vergleich mit {\bf NIL}, vor type guards deren Erfolg mit
einem type test abzusichern.

Die auf den normalen type guards aufbauenden {\it regional\/} und {\it implicit type guards\/}
werden in den Abschnitten \ref{Wertzuweisung} und \ref{WITH-Anweisung}
beschrieben.

\subsubsection{Die Operatoren}
\label{Operatoren}

Alle Operatoren aus \modula\ wurden zusammen mit ihren Priorit"aten und
Assoziativit"aten "ubernommen, Synonyme f"ur Operatoren aber entfernt.
Betroffen sind die Invertierung (statt {\bf NOT} nur noch "`$\widetilde{\ }\,$"'), das
logische Und ({\bf AND} f"allt weg, es darf nur noch "`\&"' hei"sen) und die
Antivalenz (fr"uher auch "`$<>$"', jetzt ausschlie"slich "`\#"').

Gegen"uber den fr"uheren \oberon-Versionen m"ussen die zweiten Operanden von
{\bf DIV} und {\bf MOD} positiv sein (fr"uher beliebige ganzzahlige Werte ohne Null).

Hinzugekommen ist der {\it type test\/} {\bf IS}, eine dyadische Operation mit einem
Designator als linken, einem Typ-Bezeichner als rechten Operand und
einem booleschen Resultat.
Betrachtet man einen type guard als dyadische Operation, deren Ergebnis
"`kein Laufzeitfehler und Typ-"Anderung"' oder "`Laufzeitfehler"' ist, so
unterscheidet sich der type test vom type guard nur durch die Syntax und die
Art des Ergebnisses.
Dabei ist {\bf TRUE} der ersten und {\bf FALSE} der zweiten Ergebnisauspr"agung
zugeordnet.

Die Operationen, die zur Berechnung des Ergebnisses notwendig sind, m"ussen
dem Programmierer nicht transparent sein.
Es gibt mehrere Implementationsm"oglichkeiten f"ur type tests: ein zur Erweiterungstiefe
proportionaler Algorithmus ist in \cite{typeExtensions} beschrieben, ein
anderer mit konstantem Aufwand, aber einer Einschr"ankung in der maximalen
Erweiterungstiefe wird in \cite{op2doc} vorgeschlagen und auch
bei der vorliegenden Implementation verwendet.
Beide Algorithmen werden in Abschn.~\ref{erweiterbare Verbunde} n"aher vorgestellt.

\subsection{Die Anweisungen}

Die folgende Untermenge von Anweisungen wurde von \modula\ "ubernommen:
Wertzuweisung, Prozeduraufruf, {\bf IF}-, {\bf CASE}-, {\bf WHILE}-,
{\bf REPEAT}-, {\bf LOOP}-, {\bf RETURN}-, {\bf EXIT}- und {\bf WITH}-Anweisung.
Au"ser bei der Wertzuweisung und der {\bf WITH}-Anweisung ist die Semantik
der Anweisungen erhalten geblieben.

\subsubsection{Die Wertzuweisung}
\label{Wertzuweisung}

Die "Anderungen betreffen nur die Regeln "uber die Zuweisungskompatibilit"at
zwischen rechtem und linkem Operanden der Wertzuweisung.
Grunds"atzlich m"ussen der Typ des Ausdrucks auf der rechten Seite und
der Typ des Designators auf der linken Seite identisch sein.

Bei numerischen Typen auf beiden Seiten ist eine Zuweisung erlaubt, wenn der
Typ der rechten Seite Untermenge des Typs der linken Seite ist, wobei die
folgenden Beziehungen zwischen diesen Typen bestehen:
\[
  \hbox{\bf SHORTINT}\subseteq\hbox{\bf INTEGER}\subseteq
  \hbox{\bf LONGINT}\subseteq\hbox{\bf REAL}\subseteq
  \hbox{\bf LONGREAL}
\]
Diese Untermengen-Beziehung ist auch Grundlage einer automatischen Typanpassung
bei dyadischen Operationen in Ausdr"ucken.

Zeichenketten d"urfen an beliebige (auch offene) eindimensionale Zeichenfelder
zugewiesen werden, wobei eine Konsistenzpr"ufung der L"angen von Zeichenkette und
-feld vorgenommen wird.

Der vom normalen Sprachumfang in das Modul~{\tt SYSTEM} abgewanderte
Datentyp~{\bf BYTE} hat die Eigenschaft, da"s Variablen von diesem Typ
{\bf CHAR}- oder {\bf SHORTINT}-Werte aufnehmen d"urfen.
Umgekehr kann ein {\bf BYTE}-Wert mit der Standardfunktion~{\bf ORD} in ein
Zeichen oder einen ganzzahligen Wert umgewandelt werden.

Die Zuweisungkompatibilit"at von Verbundtypen wurde erweitert.
Die Typen der beiden Operanden m"ussen nicht l"anger gleich sein,
stattdessen hat f"ur sie die Relation $\LRA$ in folgender Art zu gelten:
sind der Designator~$r$ vom Verbundtyp~$R$ und der Ausdruck~$e$ vom
Verbundtyp~$R0$, so ist die Zuweisung $r:=e$ genau dann erlaubt, wenn die
Relation $R0\LRA R$ gilt, andernfalls meldet der Compiler einen Fehler.
Es werden nur die Komponenten von $e$ nach $r$ umkopiert, die auch in $r$
erreichbar sind.
Somit erf"ahrt $r$ (sinnvollerweise) eine vollst"andige "Anderung, f"ur die aber nur Teile von
$e$ verwendet werden.

Die Erweiterung der Zuweisungskompatibilit"at wird auch auf Zeiger auf Verbunde
angewendet, sch"utzt aber dort nur davor, da"s nach der Zuweisung Komponenten
zugreifbar sind, die der Typ des Ausdrucks auf der rechten Seite nicht besa"s.

Zu unterstreichen ist, da"s die Anzahl der Komponenten, die bei einer
Verbund-Zuweisung kopiert werden, vom Typ des Designators auf der linken Seite
abh"angt; Mehrdeutigkeiten treten bei Referenz-Parametern
vom Verbundtyp und dereferenzierten Zeigern auf Verbunde auf, denn bei ihnen
steht erst zur Laufzeit fest, welche Verbunde an sie gebunden sind.
Der Typ des zugeh"origen aktuellen Parameters oder des Verbundes, auf den der
Zeiger zeigt, kann ja eine Erweiterung des Typs des formalen Parameters oder
des Basistyps des Zeigers sein.
Setzt man voraus, da"s das Ziel der Zuweisung eine vollst"andige Ver"anderung
desjenigen Verbundes ist, den der Designator auf der linken Seite beschreibt,
so mu"s entweder die Gr"o"se des Verbundes zur Laufzeit bestimmt werden oder
der Typ des Verbundes mu"s mit dem des Designators "ubereinstimmen;
im zweiten Fall kann dann die Gr"o"se des Verbundes zur "Ubersetzungszeit
berechnet werden.
In \oberon\ wird der zweiten Weg beschritten, indem an den Designator ein
sog. {\it implicit type guard\/} angeh"angt wird, der nicht wie ein normaler
type guard die Relation~$\LRA$ sondern die (sch"arfere) Gleichheit zwischen
den beteiligten Typen sicherstellt.
Ein Vorteil dieser L"osung ist die M"oglichkeit, durch alleiniges Betrachten
der Zuweisung auf ihre Auswirkungen auf den linken Operanden
zu schlie"sen und damit die Validierbarkeit des Programmes zu erh"ohen.
Nachteilig ist, da"s vor der Zuweisung f"ur jeden Typ, den ein aktueller Parameter
bzw. ein an den Zeiger gebundener Verbund haben kann, eine Fallunterscheidung
durchzuf"uhren ist, die f"ur einen Referenz-Parameter die Form
\begin{quotation}
\obeylines
{\bf IF} $r$ {\bf IS} $R0$ {\bf THEN}
\ \ $r(R0):=\cdots$
{\bf ELSIF} $r$ {\bf IS} $R1$ {\bf THEN}
\ \ $r(R1):=\cdots$
\ \ \ $\vdots$
{\bf END}
\end{quotation}
und f"ur einen dereferenzierten Zeiger die Form
\begin{quotation}
\obeylines
{\bf IF} $p$ {\bf IS} $P0$ {\bf THEN}
\ \ $p(P0)\caret:=\cdots$
{\bf ELSIF} $p$ {\bf IS} $P1$ {\bf THEN}
\ \ $p(P1)\caret:=\cdots$
\ \ \ $\vdots$
{\bf END}
\end{quotation}
hat.
Der explizite type guard in den Zuweisungen wird vom Compiler durch
den impliziten ersetzt, der Typ des Designators bleibt erhalten.
Ein impliziter type guard wird aber auch dann eingesetzt, wenn kein
expliziter type guard verwendet wird.
In diesem Fall entspricht der Designatortyp dem Typ des formalen Parameters
oder des Zeigers in seiner Definition oder Deklaration.
W"urde man also schlicht $r:=\cdots$ oder $p\caret:=\cdots$ schreiben und keine
Fallunterscheidung machen, so d"urfte der aktuelle Parameter zu $r$ oder
der an $p$ gebundene Verbund nur den gleichen Typ wie $r$ bzw. wie $p\/$'s
Basistyp haben.

Die Existenz des impliziten type guards wurde erst in \cite{op2doc} beschrieben.
Seine Notwendigkeit hat das Team um Wirth vermutlich erst sp"at erkannt, was
sich auch daraus schlie"sen l"a"st, da"s die Optimierung mehrerer aufeinanderfolgender
type guards zu einem, die sonst im vorliegenden Compiler "uberall vorgesehen
wurde, beim Anh"angen des impliziten type guards f"ur die dereferenzierten Zeiger
fehlt.%
\footnote{Der Autor wies das Team auf diese Tatsache hin und nahm die notwendigen
  "Anderungen im Frontend selbst vor; in den Folgeversionen des Roh-Compilers
  wird die Optimierung eingebaut sein.}

\subsubsection{Die {\bf WITH}-Anweisung}
\label{WITH-Anweisung}

Die {\bf WITH}-Anweisung wurde in ihrer Semantik und z.T. Syntax ge"andert.
Zwischen {\bf WITH} und {\bf DO} befinden sich jetzt die Symbole
$v: T$, wobei $v$ ein Variablen- und $T$ ein Typ-Bezeichner sind, f"ur die die
gleichen  Einschr"ankungen wie f"ur die Bezeichner bei type guards gelten.
In der Tat nennt sich die {\bf WITH}-Anweisung jetzt {\it regional type guard},
was bedeutet, da"s die mit der type guard im "`Kopf"' der {\bf WITH}-Anweisung
erreichte Typ-"Anderung des Bezeichners sich auf mehrere Anweisungen erstreckt:
gerade die Anweisungen zwischen {\bf DO} und {\bf END}.
Hervorzuheben ist, da"s $v$ nicht etwa ein Designator sondern ein echter
Variablenbezeichner sein mu"s, was den Aufwand im Compiler erheblich
reduziert (siehe auch Abschnitt~\ref{OPP}).

\subsection{Die Standardprozeduren und -funktionen}

Die folgenden Funktionen wurden von \modula\ "ubernommen und werden deshalb nicht
n"aher erl"autert:
{\bf ABS}, {\bf ODD}, {\bf CAP}, {\bf ASH}, {\bf MAX} und {\bf MIN}.

Die Funktion {\bf SIZE}, in \modula\ {\bf TSIZE} genannt, befand sich in den ersten
Versionen von \oberon\ im Modul~{\tt SYSTEM} und wanderte in der aktuellen
Version (\cite{oberon2}) in den normalen Sprachumfang.

Die Funktion {\bf LEN} zur Feststellung des Indexbereichs einer bestimmten
Dimension eines Feldes wurde schon in Abschnitt~\ref{Definition von Prozeduren}
erl"autert.

\medskip
An Prozeduren wurden {\bf INC}, {\bf DEC}, {\bf INCL}, {\bf EXCL},
{\bf NEW} und {\bf HALT} "ubernommen.
Neu ist die Prozedur~{\bf COPY}, die eine Wertzuweisung zwischen
zwei verschieden eindimensionalen Zeichenfeldern durchf"uhrt.

Zur Typenkonversion existieren die gewohnten Funktionen {\bf ORD} und
{\bf CHR}, die, nach Wissen des Autors, neuen Funktionen {\bf ENTIER}
zur Umwandlung von {\bf REAL} oder {\bf LONGREAL} zu {\bf LONGINT},
{\bf SHORT} zur Verengung des Wertebereich auf den n"achstkleineren Typ
({\bf LONGREAL} $\lra$ {\bf REAL}, {\bf LONGINT} $\lra$ {\bf INTEGER} und
{\bf INTEGER} $\lra$ {\bf SHORTINT}) und {\bf LONG} zur Erweiterung auf
den n"achstgr"o"seren Typ.
Ty"penanpassungen von kleineren zu gr"o"seren Typen werden in \oberon\
automatisch vorgenommen.
Deshalb hat {\bf LONG} in erster Linie die Aufgabe, Konstanten, denen
durch ihren Wert ein kleinerer Typ zugeordnet w"urde, mit einem
gr"o"seren Typ zu verbinden.

\subsection{Die Module}

Die Ver"anderungen im Modulkonzept, die die wichtigsten Unterschiede
zwischen der ersten und den nachfolgenden Versionen von \oberon\ ausmachen,
zeigen, da"s eine Programmiersprache "ahnlich einer nat"urlichen Sprache
gerade in der Endphase der Entwicklung eine Evolution durchl"auft.
Die von \modula\ stammende Trennung eines Moduls in zwei Teile, dem
Definitionsmodul, das die Schnittstellenbeschreibung enth"alt, und dem
Implementationsmodul, in dem die Schnittstellen-Routinen zusammen mit
Hilfsprozeduren als Programmtext formuliert werden, war Grundlage der
ersten Version von \oberon \cite{oberon0}.
Diese Aufteilung hatte sich in vielen Projekten bew"ahrt, erlaubt
aber das gegenseitige Importieren von Modulen, das dem Dogma,
eine Modulhierarchie solle durch einen {\em azklischen\/} Graphen darstellbar
sein, widerspricht.

Den wesentlichen Grund zur Abschaffung der Zweiteilung lieferte allerdings
eine Eigenschaft von exportierten Verbundtypen, die sog. {\it public projection\/}.
Sie besagt, da"s in der Beschreibung eines Verbundtyps im Definitionsmodul
nicht alle Komponenten, die in der Definition im Implementationsmodul genannt
sind, auftauchen m"ussen.%
\footnote{Das ist auch der einzige Fall, bei dem ein Typ sowohl im
Definitions- als auch im Implementationsmodul aufgef"uhrt werden mu"s.
Opaque Datentypen existieren in \oberon\ nicht mehr.}
Nur die im Definitionsmodul aufgef"uhrten Komponenten sind von anderen
Modulen aus zug"anglich.
Alle anderen Komponenten existieren zwar, wenn eine Variable dieses Typs
in einem externen (den Typ importierenden) Modul deklariert wird, k"onnen
aber nur vom exportierenden Modul angesprochen werden.

Das Problem besteht nun darin, da"s f"ur eine Erweiterung des Typs im
externen Modul seine wahre Gr"o"se, also nicht die der public projection,
bekannt sein mu"s.
Importiert ein Modul ein anderes, so wird vom Compiler nur eine Datei,
die sog. Symboldatei, eingelesen, die aus dem Definitionsmodul hergestellt wurde.
Da die wahre Gr"o"se des Typs aber erst mit der Bearbeitung des
Implementationsmoduls feststeht, sollte, so der Vorschlag Wirths, dem
Compiler im Definitionsmodul ein Hinweis ({\it hint\/}) gegeben werden,
welche Gr"o"se der Verbundtyp im Implementationsmodul maximal annehmen kann.

Die Unzufriedenheit mit dieser Verlegenheitsl"osung lie"s eine Revision
des Modulkonzepts folgen, in der Definitions- und Implementationsmodul
in einem Modul vereinigt sind \cite{oberon1,oberon2}.
W"ahrend des "Ubersetzens erstellt der Compiler neben der Objektdatei,
die den Code enth"alt, auch eine Symboldatei.
Nach der Fertigstellung vergleicht er diese Datei mit einer eventuell
vorhandenen;
stellen sich Unterschiede heraus, meldet der Compiler einen Fehler;
wurde aber eine bestimmte Compileroption ({\tt /S}) gesetzt, dann "uberschreibt
der Compiler die alte Symboldatei mit der neuen Version.
Diese Sicherheitsma"snahme ist erforderlich, da m"oglicherweise viele
Module von der Schnittstelle des eben "ubersetzten Moduls abh"angen,
deren ungewollte "Anderung zu unn"otigen Inkompatibilit"aten mit diesen Modulen
f"uhren w"urde.

\subsubsection{Die Importe}

\leavevmode\oberon\ erlaubt nur noch unqualifiziertes Importieren von Modulen in der
Form {\bf IMPORT} $M1$, $M2$, d. h. Bezeichner aus anderen Modulen m"ussen
in jedem Fall den Modulnamen, gefolgt von einem Punkt, als Pr"afix tragen.
Damit ist jeder Bezeichner sofort als modullokal oder importiert erkennbar.

Neu eingef"uhrt wurde eine Umbenennungsm"oglichkeit von importierten Modulen,
die Module mit gleichen Schnittstellen, aber unterschiedlichem Verhalten mit
einer einzigen Programm"anderung verf"ugbar macht.
Sollen z.B. alle Aufrufe von Routinen des Moduls~{\tt texts} durch die des
Moduls~{\tt texts1}, das vielleicht die Ein- und Ausgabe auf andere Ger"ate
unterst"utzt, ersetzt werden, so schreibt man {\bf IMPORT} {\tt texts }$:=$ {\tt texts1}.
Oft sind Modulnamen recht lang, soda"s eine Umbenennung in einen k"urzeren
Bezeichner und dessen Benutzung im Modul handlicher ist.

\subsubsection{Die Exporte}

Zu exportierende Objekte (Konstanten, Typen, Variablen oder Prozeduren) werden
bei der Definition oder Deklaration durch einen Asterisk hinter dem Bezeichner
gekennzeichnet.
Werden Verbundtypen exportiert, so m"ussen alle Komponenten, die nach au"sen
hin sichtbar sein sollen, ebenfalls mit einem Asterisk versehen werden.

Parameterlose exportierte Prozeduren werden {\it commands\/} genannt, da sie im \oberon-System
durch Anklicken ihres Namens mit der Maus aktiviert werden k"onnen.
Durch commands werden die wesentlichen Dienstleistungen des Moduls dem
Endbenutzer zur Verf"ugung gestellt, w"ahrend andere exportierte Prozeduren
nur durch Importieren innerhalb von anderen Modulen genutzt werden k"onnen.

\subsubsection{Die Modul-Initialisierung}

Nachdem ein Modul durch Aufruf eines commands oder Import durch ein anderes Modul
in den Speicher geladen wurde, wird es in einen definierten Ausgangszustand
gebracht, indem die Anweisungsfolge, die in \modula\ den Modulrumpf ausmachte,
ausgef"uhrt wird.
Der Terminus~"`Modulrumpf"' wurde deshalb ersetzt durch den Begriff der
Modul-Initialisierung ({\it module initialization\/}).

\subsection{Das Modul {\tt SYSTEM}}

Mit dem Modul~{\tt SYSTEM} wurde in \modula\ viel Unfug getrieben, insbesondere
fanden seine angebotenen Routinen und Typen nicht nur in Low-Level-Modulen sondern
oft auch "uber die gesamte Modulhierarchie verstreut Anwendung.
Um diesem "Ubel in \oberon\ zu begegnen, hatte Wirth ein solches Modul anf"anglich
nicht definiert.
Das Ziel des Projekts, ein Betriebssystem mit (fast) ausschlie"slich einer einzigen
Sprache zu formulieren, zeigte aber den Bedarf nach M"oglichkeiten auf,
Speicherzellen und Register manipulieren zu k"onnen, und so tauchte in
\cite{oberon1} das Modul~{\tt SYSTEM} wieder auf.

Wirth erlaubt ausdr"ucklich, das Modul an die Gegebenheiten des Prozessors
anzupassen, die Notwendigkeit zur Erweiterung oder Streichung von Objekten
f"ur die vorliegende 68000-Implementation ergab sich aber nicht, soda"s
die in \cite{op2doc} beschriebene Schnittstelle f"ur {\tt SYSTEM} voll
g"ultig ist.
Im Unterschied zur \oberon-Sprachbeschreibung sind dort zus"atzlich die
Prozeduren {\bf GETREG} und {\bf PUTREG} aufgef"uhrt, die Werte aus
den Prozessorregistern holen oder in diese hineinschreiben.

F"ur die aktuelle \oberon-Version wurden der Datentyp {\bf BYTE} aus dem
normalen Sprachumfang herausgenommen und in das Modul~{\tt SYSTEM} transferiert.

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

\section{Implementationsvorschl"age f"ur die Spracherweiterungen}
\label{Implementationsvorschlaege}

W"ahrend die "ublichen Code-Schablonen und Verwaltungsstrukturen
f"ur die \modula-Konstrukte schon l"anger bekannt sind, warten die
neuen Sprachelemente von \oberon\ dort mit Neuland --- zumindest f"ur den Bereich
der blockstrukturierten Sprachen --- auf.
Gerade die Einf"uhrung der erweiterbaren Verbunde und die Verwendung eines
Garbage Collectors zur dynamischen Speicherverwaltung lassen einen
erh"ohten Speicher- als auch Rechenzeit-Overhead vermuten.

Die L"osungsvorschl"age der Arbeitsgruppe um Wirth und des Autors
zur Implementation der erweiterbaren Verbunde, der Hilfsstrukturen f"ur die
Garbage Collection und der offenen Felder
werden in den folgenden Abschnitten vorgestellt.

\subsection{Die erweiterbaren Verbunde und type tests/guards}
\label{erweiterbare Verbunde}

Eine Realisierung der erweiterbaren Verbunde mu"s die Relationen $\lra$ und
$\LRA$ zwischen dem erweiterten Verbundtyp und seinen Basistypen einbeziehen
und die Nachpr"ufung ihrer Existenz mit type guards und type tests zulassen.

Ein erster Vorschlag wurde von N.~Wirth in dem Artikel "`Type Extensions"'
\cite{typeExtensions} vorgestellt.
In ihm wird jedem definierten Verbundtyp ein sog. {\em Typdeskriptor\/}
zugeordnet, ein dem Programmierer verdeckter Verbund, der (zun"achst nur)
aus einer Komponente besteht: einem Zeiger auf den Typdeskriptor des
direkten Basistyps, {\it base tag\/} genannt.
Besitzt ein Verbundtyp keinen Basistyp, so hat der Zeiger im Typdeskriptor
den Wert~{\bf NIL}.
Die Deskriptoren werden durch den Modul-Lader oder automatisch eingef"ugten
Code vor der Modul-Initialisierung aufgebaut.
Vom Compiler wird im Konstantenbereich Speicherplatz f"ur jeweils einen Zeiger
auf jeden Typdeskriptor angelegt, die zur selben Zeit wie die base tags der Typdeskriptoren
mit deren Adresse vorbelegt werden.
Die Zeiger, sog. {\it constant type tags\/}, erm"oglichen dem Compiler, bei type guards und type tests auf den
in diesen Konstrukten verwendeten Typ Bezug zu nehmen.

Die Typdeskriptoren werden eingesetzt in den F"allen, wo der Typ des an einen
Bezeichner gebundenen Verbundes zur "Ubersetzungszeit noch nicht feststeht:
\begin{itemize}
\item neben der Adresse des Verbundes "ubergibt die aufrufende Prozedur
  im Fall eines Referenz-Parameters zus"atzlich
  einen Zeiger auf den Deskriptor des zugeh"origen Verbundtyps, der dann in
  der aufgerufenen Prozedur f"ur type guards und type tests verwendet wird (s.u.);
\item die Standardprozedur~{\bf NEW} setzt den {\it by reference\/} "ubergebenen
  Zeiger auf den Anfang eines Speicherbereichs, der der Gr"o"se des Zeigerbasistyps
  entspricht; direkt vor diesem Bereich und damit unerreichbar f"ur den Programmierer
  richtet {\bf NEW} einen Zeiger auf den Typdeskriptor des Zeigerbasistyps ein, das
  sog. {\it type tag}.
\end{itemize}

"`The type test $x$~{\bf IS}~$T$ is implemented by a simple search algorithm
which typically consists of six to eight machine instructions compiled
as in-line code:
\begin{quotation}
\obeylines
$t := x.\hbox{\it typetag\/};$
{\bf LOOP}
\ \ {\bf IF} $t=\hbox{constTypeTag\/}(T)$ {\bf THEN}  $\hbox{\it result} := \hbox{\bf TRUE};$ {\bf EXIT END};
\ \ $t := t.\hbox{\it basetag\/};$
\ \ {\bf IF} $t = \hbox{NIL}$ {\bf THEN} $\hbox{\it result} := \hbox{\bf FALSE};$ {\bf EXIT END};
{\bf END}
\end{quotation}
In the case of a type guard $x(T)$, "`$\hbox{\it result} := \hbox{\bf FALSE};$ {\bf EXIT}"'
is replaced by {\bf HALT}."'\cite[S.~872]{oberonSystem}
Die Hilfsvariable $t$ kann in einem Register gehalten werden.

F"ur einen impliziten type guard vereinfacht sich der zu erzeugende Code auf
einen Vergleich zwischen dem type tag des Verbundes und dem zum abzusichernden
Typ geh"orenden constant type tag.

Die lineare Komplexit"at des Algorithmus' in Abh"angigkeit von der
Erweiterungstiefe des zu testenden Verbundes (besser: seines Typs) bewegte
das Entwicklungsteam dazu, einer anderen L"osung mit konstanter Komplexit"at
den Vorrang f"ur die Verwendung im \OP\ zu geben.
Der Typdeskriptor besteht jetzt nicht mehr nur aus dem base tag des direkten
Basistyps sondern einer Auflistung der base tags aller Basistypen.
Dazu ist im Deskriptor ein Feld mit $n$ Elementen f"ur die base tags angelegt
worden, wobei der Index durch die Erweiterungstiefe minus 1 des Basistyps bestimmt
wird.
Ist im type guard $x(T')$ $T'$ keine Eweiterung eines anderen Typs,
so mu"s wegen der notwendigen G"ultigkeit der in Abschnitt~\ref{Designatoren}
genannten Relation $T'\LRA\hbox{Typ}(x)$ der Typ von $x$ identisch mit $T'$ sein.
Somit ist ein type guard "uberfl"ussig (es wird kein Code erzeugt) und das
base tag f"ur $T'$ kann aus den Typdeskriptoren seiner Erweiterungen herausgelassen
werden;
ein type test $x$~{\bf IS}~$T'$ wird automatisch zu {\bf TRUE} vereinfacht.
Die direkte Erweitung eines solchen Basistyps, der selbst keinen Basistyp
besitzt, erscheint dann als erstes Element und der direkte Basistyp des
betroffenen Verbundtyps als letztes Element im Feld.

Der type test $x$~{\bf IS}~$T$ kann dann als logischer Ausdruck geschrieben werden:
\[ \hbox{\it result} := x.\hbox{\tt typetag\/}\caret.\hbox{\tt basetag}[\hbox{\it extensionLevel}(T)-1] = \hbox{constTypeTag\/}(T);\]
F"ur einen type guard $x(T)$ wird ein Laufzeitfehler erzeugt, wenn Ungleichheit
existiert.

Der Nachteil, der mit dieser L"osung erkauft wurde, besteht in der Beschr"ankung
der maximal erlaubten Erweiterungstiefe~$n$ durch die Gr"o"se des Zeigerfeldes auf
die Basistypen, die f"ur alle im laufenden System vorhandenen Deskriptoren
konstant sein mu"s.
Die f"ur die NS32000-Implementation gew"ahlte maximale Erweiterungstiefe~$n=7$
hat sich in den meisten F"allen als ausreichend erwiesen und wurde auch
in der vorliegenden Arbeit benutzt.%
\footnote{Ein "Anderung der maximalen Erweitungstiefe kann durch Anpassung
der Konstanten {\tt OPL.MaxExts} erreicht werden.
Der Linker arbeitet ausschlie"slich auf den in der Objektdatei vorgegebenen
Daten und ben"otigt deshalb keine "Anderung.
Nach einer "Anderung m"ussen {\em alle\/} vorhanden Module inklusive der des
Compilers neu "ubersetzt werden.}

\subsection{Die Supportstrukturen f"ur die Garbage Collection}
\label{Supportstrukturen}

Nach \pascal\ und \modula\ wird in \oberon\ erstmalig ein Garbage Collector
anstelle einer expliziten R"uckgabe nicht mehr ben"otigten Speicherplatzes
(z.B. wie in \modula\ durch eine Standardprozedur {\bf DISPOSE}) verwendet.
Die Entscheidung fiel auf einen Garbage Collector des Mark-Scan-Typs:
in einer ersten, der {\em Mark-}Phase werden all die dynamischen Strukturen (in \oberon\
sind Verbunde und Felder m"oglich) markiert, die von globalen Zeigervariablen
aus erreichbar sind; w"ahrend der {\em Scan-}Phase durchl"auft der Collector
den Speicherbereich f"ur dynamische Strukturen, den sog. {\it heap}, sequentiell
und kettet alle nicht markierten Bereiche in eine von mehreren Freilisten ein;
die Markierungen werden dabei gel"oscht.

Die Standardfunktion {\bf NEW} und der Garbage Collector teilen den
Speicherplatzbedarf von Strukturen in f"unf Klassen mit
maximal 16, 32, 64, 128 oder Vielfache von 128 Bytes ein.
Die f"ur eine Klasse maximale Strukturgr"o"se wird {\em Blockgr"o"se\/}
genannt.
Eine Struktur wird der Klasse mit der kleinsten Blockgr"o"se zugeordnet,
die gerade gr"o"ser oder gleich der Strukturgr"o"se einschlie"slich des
type tags und, bei Feldern, des Hilfszeigers ist.\cite[S. 871]{oberonSystem}

Die Beschr"ankung auf globale Zeigervariablen als Ausgangspunkte f"ur die Markierung
wurde zur Vereinfachung des Collectors gew"ahlt, impliziert aber, da"s
bei seinem Aufruf der Stack, der die lokalen (Zeiger-) Variablen enth"alt,
leer ist.

Da dynamische Strukturen "ublicherweise aufeinander verweisen und die wenigsten
Strukturen unmittelbar "uber globale Zeiger erreichbar sind, m"ussen
zus"atzliche Informationen zur Verf"ugung gestellt werden, die
die Orte von Zeigern in den Strukturen beschreiben.
Diese Orte sind f"ur Strukturen des gleichen Typs invariant und es liegt daher
nahe, die Informationen in den Typdeskriptoren abzulegen, die f"ur die
Verbundtypen sowieso schon existieren und bei Feldern zus"atzlich eingef"uhrt
werden m"ussen.

Um die Notwendigkeit von Komponenten der Supportstrukturen zu begr"unden,
ist eine detailierte Kenntnis der Vorg"ange beim Markieren und Scannen
unumg"anglich.

\subsubsection{Das Markieren der Strukturen}
\label{Markieren}

Angenommen, der Garbage Collector (im folgenden GC genannt) habe gerade
in einer dynamischen Struktur einen Zeiger auf eine weiter Struktur
ausfindig gemacht.
Die Adresse dieses Zeigers merkt er sich in einem Arbeitsregister, dessen
Name~$r_b$ sei.
Die Adresse der neuen Struktur befinde sich im Register~$r_a$.
Nun mu"s der GC feststellen, ob die neue Struktur schon markiert ist, denn
ist dies der Fall, so kann er mit der vorherigen Struktur fortfahren.
Die Markierung befindet sich im h"ochstwertigen Bit des type tags.
Fehlt die Markierung, so beginnt der GC mit der Untersuchung der neuen
Struktur:
er stellt zun"achst fest, ob die Struktur ein Verbund oder ein Feld ist.
Dazu fragt er das zweith"ochstwertige Bit des type tags ab; ist es gesetzt,
so handelt es sich um ein Feld, sonst um einen Verbund.
Diese beiden Bits k"onnen bei dieser Implementation ohne Probleme benutzt
werden, da der Mikroprozessor~68000 nur 24-Bit-Adressen besitzt.

\paragraph{Ein Verbund als dynamische Struktur}

Sei die dynamische Struktur ein Verbund.
Indem der GC die beiden h"ochstwertigen Bits aus dem type tag ausmaskiert,
erh"alt er die Adresse des Typdeskriptors, in dem er den Hinweis auf
den ersten Zeiger in der Struktur aufsucht, der immer im neunten Langwort
eines Verbunddeskriptors steht (siehe n"achsten Abschnitt).
Diese Hinweise sind die relativen Adressen der Zeigerkomponenten im Verbund,
im folgenden {\it offsets\/} genannt.
Das Ende der Offset-Tabelle ist durch einen negativen (Zweierkomplement) Wert
gekennzeichnet, der, aufaddiert auf seine Adresse, die Anfangsadresse des
Typdeskriptors ergibt.

Da ein Verbund nicht unbedingt Zeiger enthalten mu"s, kann die Tabelle auch
leer sein.
Deshalb testet der GC, ob der Offset schon negativ ist: bei positivem Ausgang
wird der GC die Struktur markieren und mit der vorherigen Struktur fortfahren,
deren Adresse er sich ja im Register {\it rb\/} gemerkt hat.
Meist haben die Offsets aber positive Werte, die auf einen Zeiger im Verbund
hindeuten.
Der GC sieht sich den Inhalt des Zeigers, dessen Adresse er durch die Addition des
Offsets auf die Adresse der Struktur in Register~$r_a$ erh"alt, an.
Ist der Inhalt Null, was dem Wert~{\bf NIL} entspricht, so kann der GC sich
dem n"achsten Offset im Deskriptor zuwenden.
Enth"alt der Zeiger aber eine g"ultige Adresse, steht der GC vor der Aufgabe,
die hinter dieser Adresse stehende Struktur zu erkunden.
Dazu mu"s er aber seinen momentanen Zustand sichern, denn die einzige
Information, die er von der vorherigen Struktur hat, ist auch nur ihre
Anfangsadresse.
Sein momentaner Zustand setzt sich aus den folgenden Informationen zusammen:
\begin{itemize}
\item die in Register $r_b$ gehaltene Adresse der vorherigen Struktur,
\item die Adresse der aktuellen Struktur in $r_a$ und
\item die Adresse des momentan bearbeiteten Offsets.
\end{itemize}

Das zuletzt erw"ahnte Datum sichert der GC, indem er das type tag der
Struktur auf die Adresse des Offsets setzt.
Die Adresse des Typdeskriptors ist nicht verloren, da sie am Ende der
Offset-Tabelle, wie oben beschrieben, wieder errechnet werden kann.
Schwieriger ist es mit der Adresse der vorherigen Struktur.
Um die Benutzung eines Stacks zu vermeiden, fanden im Jahre 1965
P.~Deutsch und H.~Schorr mit W.M.~Waite unabh"angig voneinander eine
M"oglichkeit, die Adresse der vorherigen Struktur in der aktuellen
Struktur zu speichern \cite{garbColl}.
Sie benutzen dazu den Speicherplatz des Zeigers, der die Adresse der neuen
Struktur enth"alt.
Die aktuelle Struktur wird markiert, bevor ihre Adresse in Register~$r_b$,
und die Adresse der neuen Struktur in Register~$r_a$ kopiert wird.
Der GC kann nun mit dem Besuch der neuen Struktur beginnen.

\medskip
Nachdem der GC die neue Struktur vollst"andig bearbeitet hat, kann er zu
der nun wieder aktuellen Struktur zur"uckkehren.
Dazu sucht er "uber ihre gemerkte Adresse das type tag und mit ihm den Offset
des zuletzt bearbeiteten Zeigers auf, berechnet seine absolute Adresse und
speichert die dort enth"altene Adresse auf die vorherige Struktur wieder in
Register~$r_b$.
Die Adresse auf die ehemals neue Struktur, die sich noch in Register~$r_a$
befindet, wird an ihren alten Aufenthaltsort, den Zeiger, zur"uckkopiert.
Register~$r_a$ nimmt die Adresse der aktuellen Struktur auf.
Somit ist der alte Zustand wieder erreicht und die durch den n"achsten Offset
beschriebene Zeigerkomponente der Struktur kann bearbeitet werden.
Am Ende der Offset-Tabelle angelangt, legt der GC die Deskriptoradresse
wieder im type tag ab und sucht die vorherige Struktur auf, deren Adresse
sich in Register~$r_b$ befindet.


\paragraph{Ein Feld als dynamische Struktur}

Hat die dynamische Struktur den Typ {\bf ARRAY}, geht der erste Blick
des GC in den Typdeskriptor.
Im Gegensatz zu Verbunddeskriptoren steht in Felddeskriptoren der erste
Hinweis auf den ersten Zeiger im Elementtyp des Feldes im vierten Langwort.
Als Hinweis wurden hier keine Offsets zur absoluten Adresse des Elementtyps
sondern die Differenzen zwischen den einzelnen Offsets verwendet.
Eine Begr"undung f"ur diese Entscheidung wird weiter unten gegeben.
Eine negative Differenz zeigt an, da"s das Ende der Tabelle erreicht ist.
Da, wie bei Verbunden, der Datentyp keine Zeiger enthalten mu"s, pr"uft
der GC, ob eine solche negative Differenz vorliegt, infolge derer er
nach dem Markieren der Struktur zur vorherigen Struktur zur"uckkehrt.
Vor dem ersten Zeiger im Elementtyp kann kein Zeiger existieren, zu dessen
Adresse die Differenz gebildet werden kann.
Deshalb bezieht sich die erste Differenz auf den Anfang des Elements.
Sie wird auf die Adresse der Struktur addiert, der so spezifizierte Zeiger
wird auf {\bf NIL} "uberpr"uft, was bei Gleichheit eine sofortige Bearbeitung
der n"achsten Differenz zur Folge hat.
Ist der Zeiger von {\bf NIL} verschieden, mu"s zum bevorstehenden Besuch der
neuen Struktur der aktuelle Zustand des GC abgespeichert werden.
Die Zusammensetzung des Zustands unterscheidet sich von dem eines Verbundes:
\begin{itemize}
\item die Adresse der vorherigen Struktur in Register~$r_b$,
\item die Adresse der aktuellen Struktur in Register~$r_a$,
\item die Adresse der zum Zeiger geh"orenden Differenz im Typdeskriptor und
\item die absolute Adresse des Zeigers in der Struktur.
\end{itemize}
Der letzte Punkt fehlt in der Zustandsbeschreibung f"ur den Fall des Verbundes,
da auf die absolute Adresse des zuletzt bearbeiteten Zeigers dort aus den
restlichen Daten geschlossen werden kann.
Gegen"uber den Verbunddeskriptoren beschreiben die Felddeskriptoren nicht
die Zeiger in der gesamten Struktur sondern nur in einem Element des Feldes.
Deshalb geh"ort zum Zustand eine Information, welches Element gerade bearbeitet
wird.
Der Verfasser entschied sich, anstelle der absoluten Adresse des aktuellen
Elements die absolute Adresse des aktuellen Zeigers im Element zu verwenden.
Ob dadurch eine Platz- oder Zeitersparnis eintrat, wurde nicht gepr"uft.

Der Zustand wird gesichert, indem das type tag auf die Adresse der Differenz
gesetzt, die Adresse der vorherigen Struktur im Zeiger f"ur die neue
Struktur abgelegt und die absolute Adresse des Zeigers im letzten
Langwort des f"ur die Struktur allozierten Blocks gespeichert wird.
Der GC markiert die aktuelle Struktur, speichert deren Adresse in
Register~$r_b$, die Adresse der neuen Struktur in $r_a$ und beginnt mit
dem Besuch letzerer.

\medskip
Kehrt der GC zur vormals aktuellen Struktur zur"uck, mu"s er den alten
Zustand wiederherstellen.
Er ist zun"achst nur im Besitz der Adresse der Struktur.
"Uber das type tag erh"alt er Zugang zu der Differenz des zuletzt
bearbeiteten Zeigers zum vorherigen Zeiger.
Mittels einer Schleife sucht der GC das Ende der Differenzen-Tabelle.
Im Langwort hinter dem Tabellenende befindet sich die Gr"o"se des
allozierten Blocks, die, addiert auf die Strukturadresse, die Adresse
hinter dem Langwort ergibt, in dem die absolute Adresse des
zuletzt bearbeiteten Zeigers hinterlegt wurde.
Der Inhalt der Zeigers --- die Adresse auf die vorherige Struktur --- findet Platz
in Register~$r_b$, w"ahrend die Adresse der ehemals neuen Struktur wieder
im Zeiger abgespeichert wird.
Mit dem Verbringen der aktuellen Strukturadresse in Register~$r_a$ ist der
alte Zustand wiederhergestellt.
Ist das Ende der Differenzen-Tabelle noch nicht erreicht, so addiert der GC
die neue Differenz auf die absolute Adresse des letzten Zeigers auf und erh"alt
die Adresse des neuen Zeigers, mit deren "Uberpr"ufung auf {\bf NIL} der
Zyklus erneut beginnt.
Das Erreichen des Tabellen-Endes bedeutet, wie oben schon erw"ahnt, nicht
unbedingt das Erreichen des Strukturendes sondern nur des n"achsten Elements.
Um die Adresse des aktuellen Zeigers auf den Anfang des n"achsten Elements
zu setzen, erh"oht der GC sie um den Inhalt des zweiten Langworts im Deskriptor,
das zu diesem Zweck vom Compiler mit dem korrekten Wert vorbelegt wurde.
Die Entscheidung, ob das Ende des Feldes erreicht ist, trifft der GC, indem
er die Differenz zwischen Elementadresse und der Anfangsadresse der Struktur
bildet und das Ergebnis mit dem dritten Langwort im Deskriptor vergleicht, das
die echte Feldgr"o"se enth"alt.
Ist das Ergebnis gr"o"ser oder gleich der Feldgr"o"se, dann kann der GC die
Bearbeitung der Struktur abschlie"sen:
er speichert die Adresse des Typdeskriptors im typ tag ab und befa"st sich
weiter mit der vorherigen Struktur, deren Adresse sich in Register~$r_b$
befindet.
Sollte der GC aber nur ein weiteres Element des Feldes erreicht haben, so
kann er bei dem Punkt weitermachen, als er das erste Element des Feldes
zu bearbeiten begann.

\subsubsection{Das Scannen des dynamischen Speichers}
\label{Scannen}

Der Haufenspeicher ({\it heap}) ist ein zusammenh"angender Teil des
dem \oberon-System zugeteilten Hauptspeicherbereichs mit der F"ahigkeit,
in Richtung h"oherer Adressen zu wachsen, und wird vom Laufzeitsystem im
Modul~{\tt Runtime} verwaltet.

Der Scan-Proze"s des GC besucht nun jeden Block im Heap, ob er schon als frei
bekannt ist oder nicht.
Den Anfang eines Blocks macht immer das type tag, das auch hier
verwendet wird, um die Gr"o"se des Blocks festzustellen.
F"ur den Fall, da"s der Block vom ersten Teil des GC markiert wurde,
also noch ansprechbar ist, entfernt der GC die Markierung und sieht
im ersten Wort des Typdeskriptors nach, wie gro"s der Block ist.
Die Gr"o"se wird auf die Adresse des Blocks aufaddiert, was den GC zum
n"achsten Block oder zum Ende des Heaps f"uhrt.

Tr"agt der Block keine Markierung, so kann er eingesammelt und als frei
deklariert werden, indem er in eine von f"unf Freilisten eingekettet wird.
Da der Block sich schon vor diesem Scannen in einer Freiliste befunden
haben kann, schl"agt die Feststellung seiner Gr"o"se "uber einen
Typdeskriptor fehl, da ihm kein solcher mehr zugeordnet ist.
Stattdessen ist das type tag auf bin"ar Null gesetzt und die Blockgr"o"se
befindet sich im dritten Langwort des Blocks (das zweiten Langwort dient
als Verbindungszeiger zum n"achsten Block in der Freiliste).
Die Umverwendung eines Teils des Blockes als Tr"ager von Verwaltungsinformation
kann deshalb gefahrlos stattfinden, weil die kleinste Blockgr"o"se vier
Langworte betr"agt.

Die Vergabe von Bl"ocken aus den Freilisten durch die Standardprozedur~{\bf NEW}
und das Aufstellen der Freilisten durch den GC sind in Abschnitt~\ref{Freilisten}
beschrieben.

\subsubsection{Die Verbund-Typdeskriptoren}

Der Aufbau eines Verbund-Deskriptors entspricht der Beschreibung in \cite[S.~33]{op2doc}.

Der Deskriptor eines Verbundtyps besteht aus drei Teilen:
\begin{itemize}
\item (1 Langwort) der Blockgr"o"se der der Struktur zugeordneten Klasse in Bytes;
  sie wird w"ahrend der Scan-Phase ben"otigt;
\item (7 Langworte) dem base-tag-Feld f"ur type guards und type tests;
\item (1 Langwort/Eintrag) einem Feld aus den Adressen der
  Zeiger-Komponenten relativ zur ersten Komponente des Verbundes, der
  sog. {\it offsets}, abgeschlossen durch eine negative Zahl, die,
  aufaddiert auf die Adresse ihres Speicherplatzes, gerade die Adresse
  des Typdeskriptors ergibt.
\end{itemize}

\subsubsection{Die Feld-Typdeskriptoren}
\label{Feld-Typdeskriptoren}

Der Garbage Collector der NS32000-Implementation konnte keine dynamischen
Felder durchsuchen.
Feld-Typdeskriptoren wurden deshalb nicht erzeugt, der Sprachumfang
erfuhr sogar die Einschr"ankung, da"s keine Zeiger auf Felder definiert
werden durften, deren Elemente Zeiger enthielten.

Die Sprach-Einschr"ankung wurde richtigerweise im \OP-Roh-Compiler wieder
aufgehoben.
Das machte im Rahmen der vorliegenden Arbeit die Entwicklung eines
Konzepts zur Behandlung von dynamisch erzeugten Feldern notwendig,
das im oben beschriebenen Markieren von dynamisch allozierten Feldern
innerhalb des Garbage Collectors und in den Felddeskriptoren seinen Ausdruck
findet.

Aus den Bed"urfnissen des Collectors ergibt sich die Struktur der
Typdeskriptoren f"ur Felder:
\begin{itemize}
\item (1 Langwort) die Blockgr"o"se der Klasse, der die Struktur zugeordnet
  ist, in Bytes; wie im Verbunddeskriptor wird sie in der Scan-Phase verwendet;
\item (1 Langwort) die Anzahl der Bytes vom letzten Zeiger im Elementyp
  zum Ende des Typs, erh"oht um 1;
  damit kann der GC den Hilfszeiger, der am Bearbeitungsende eines Elements
  auf den letzten dort enthaltenen Zeiger verweist, auf den Anfang des n"achsten
  Elements setzen;
\item (1 Langwort) die echte Feldgr"o"se in Bytes; sie findet Verwendung
  bei der Entscheidung, ob das Ende eines Feldes erreicht wurde oder ein
  weiteres Element zu behandeln ist;
\item (1 Langwort/Eintrag) die Tabelle der Differenzen zwischen der Adresse
  eines Zeigers und der seines Vorg"angers; die erste Differenz in der
  Tabelle bezieht sich auf den Anfang des Elements;
  abgeschlossen wird die Tabelle durch eine negative Zahl, deren Summe mit
  der Adresse ihres Speicherplatzes die Adresse des Typdeskriptors ergibt;
\item (1 Langwort) einer Kopie der Blockgr"o"se aus dem ersten Langwort;
  sie wird ben"otigt, um die Adresse des Hilfszeigers im letzten Langwort
  des f"ur die Struktur allozierten Blocks zu berechnen.
\end{itemize}


\subsection{Die offenen Felder}
\label{offene Felder}

Zwei Aspekte der offenen Felder sollen betrachtet werden: ihre Repr"asentation
auf dem Stack und das Selektieren von Teilfeldern oder Elementen aus
offenen Feldern.

\medskip
Durch die Deklaration des formalen Parameters sind die Anzahl der Dimensionen
und der Elementtyp des Feldes bekannt.
Die Indexbereiche der einzelnen Dimensionen werden erst beim Aufruf der
zugeh"origen Prozedur zusammen mit der Adresse des aktuellen Parameters festgelegt.
Zur "Ubersetzungszeit m"ussen also neben der Adresse Platzhalter f"ur die
Zahl der Indizes in jeder Dimension reserviert werden.
Die entsprechende Struktur ist also (in der Reihenfolge aufsteigender Adressen):
\begin{itemize}
\item (1 Langwort) die Adresse des aktuellen Parameters,
\item (1 Langwort/Dimension) der Indexbereich jeder Dimension, wie er in
  der Deklaration des aktuellen Parameters angegeben wurde, also
  maximaler Index plus eins;
  die Reihenfolge der Dimensionen entspricht der Deklarationsreihenfolge.
\end{itemize}

Zu dieser Repr"asentation sind zwei Verfahren zur Selektion von Teilfeldern
und Elementen bekannt.
Als Grundlage f"ur das folgende Beispiel diene ein formaler Parameter~$f$
vom Typ {\bf ARRAY OF ARRAY OF ARRAY OF INTEGER.}
Der Designator $f[i, j, k]$ soll ausgewertet werden, d.h. die Adresse
des ausgew"ahlten Elementes soll bestimmt werden.
Die Adresse des ersten Elementes von $f$ sei $\hbox{ADR}(f)=\hbox{ADR}(f[0,0,0])$,
die Zahl der Indizes in den drei Dimensionen sei $d_1, d_2, d_3$, was einer
Deklaration einer Variablen als aktueller Parameter von
$\hbox{\bf ARRAY } d_1, d_2, d_3 \hbox{\bf\ OF INTEGER}$ entspricht.
Die Gr"o"se des Elementtyps werde \hbox{\it elsize\/} genannt, f"ur diese
Implementation und dieses Beispiel w"are $\hbox{\it elsize\/} = 2$.

Nach dem ersten Verfahren w"urde die Adresse des Designator mit
\[   \hbox{ADR}(f[i, j, k]) :=
    \hbox{ADR}(f) + i\cdot d_2\cdot d_3\cdot \hbox{\it elsize\/} + j\cdot d_3\cdot \hbox{\it elsize\/} +
     k\cdot \hbox{\it elsize\/}
\]
bestimmt, also durch Ausmultiplizieren des Indizes mit der Gr"o"se des
selektierten Teilfeldes.

Das zweite Verfahren arbeitet nach dem Horner-Schema, klammert somit
gleiche Operanden in den Multiplikationen aus:
\[  \hbox{ADR}(f[i, j, k]) := \hbox{ADR}(f) + ((i\cdot d_2 + j)\cdot d_3 + k)\cdot
      \hbox{\it elsize\/}
\]

Man sieht sofort, da"s das erste Verfahren allgemein bei $n$~Dimensionen
$\sum_{i=1}^n i=(n(n+1))/2$ Multiplikationen ben"otigt, w"ahrend beim
zweiten Verfahren nur $n$-mal multipliziert werden mu"s.
Ist also eine Multiplikation auf der Zielmaschine sehr teuer, wie es auf
dem Atari wegen des Fehlens eines passenden Befehls%
\footnote{Der 68020 besitzt einen solchen Befehl.}
oder eines mathematischen Coprozessors der Fall ist, dann sollte das
zweite dem ersten Verfahren vorgezogen werden.

Der Nachteil des zweiten Verfahrens soll aber nicht verschwiegen werden.
Denn soll nur ein Teilfeld selektiert werden, wie z.B. mit $f[i]$, so mu"s
an jeder Stelle, an der nach der Syntax ein Designator benutzt werden darf,
sichergestellt werden, da"s die Multiplikationen mit $d_2$, $d_3$ und
\hbox{\it elsize\/} durchgef"uhrt wurden, da bei der Bearbeitung des
Selektor von links nach rechts nicht bekannt ist, ob nach dem gerade
ausgewerteten Index noch weitere folgen.
Diese Absicherung w"are in der Implementation des Autors kein Problem gewesen,
da dort vor jeder Benutzung eines Designators f"ur ein offenes Feld die Adresse
des Feldes dereferenziert werden mu"s (f"ur die Auswertung des Designators wird
nur die Adresse der Parameterstruktur auf dem Stack benutzt), von der Existenz
des zweiten Verfahrens erhielt der Autor aber erst nach der Implementation der
offenen Felder durch einen Briefwechsel mit Herrn~Crelier Kenntnis.
Deshalb fand in dieser Implementation das erste Verfahren Eingang.

Eine Variante des ersten Verfahrens, bei dem der Aufwand f"ur die Auswertung des
Selektors nur linear ist, wurde erst k"urzlich in \cite{macOberonImp} vorgestellt.
Die Gr"o"sen der Teilfelder, im Beispiel $d_2\cdot d_3\cdot \hbox{\it elsize\/}$,
$d_3\cdot \hbox{\it elsize\/}$ und \hbox{\it elsize\/}, die f"ur jeden aktuellen
Parameter konstant sind, werden bei jedem Prozeduraufruf vom Compiler berechnet
und auf dem Stack mit"ubergeben.
Die Repr"asentation eines offenen Feldes erweitert sich somit um einen Platzhalter
pro Dimension.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newpage
\section{Der Aufbau des Compilers}

Der \oberon-Compiler \OP\ von R.~Crelier und N.~Wirth arbeitet in zwei
Phasen:
\begin{enumerate}
\item zun"achst wird im sog. {\em frontend\/} der Programmtext in
  Symbole zerlegt, die mit einem LL(1)-Parser auf syntaktische Korrektheit
  "uberpr"uft und nach einer semantischen Analyse in die Knoten eines
  Syntaxbaumes "uberf"uhrt werden; an bestimmte Knoten des Syntaxbaumes sind
  Symboltabellen angef"ugt, in denen die auf dieser Ebene deklarierten
  Bezeicher aufgelistet sind;
  die Symboldatei, in der alle notwendigen Informationen "uber die exportierten
  Objekte des Modul w"ahrend des Aufbaus des Syntaxbaums festgehalten wurden,
  wird mit einer eventuell schon vorhandenen Symboldatei verglichen und bei
  Auftreten von Unterschieden wird, abh"angig von einer Compiler-Option,
  entweder eine Fehlermeldung ausgegeben oder die neue Symboldatei an die Stelle der
  alten gesetzt;
\item im sog. {\em backend\/} werden der Speicherplatzbedarf der Datentypen,
  die relativen Adressen von Verbundtypen und die Adressen der globalen und
  lokalen Variablen berechnet; eine Prozedur traversiert unter Aufruf von
  code-generierenden Routinen den Syntaxbaum; der generierte und im Speicher
  gehaltene Code wird zusammen mit anderen Verwaltungsinformationen in der
  Objektdatei abgelegt.
\end{enumerate}

Der gesamte Compiler, der in \oberon\ geschrieben und f"ur den Bootstrap-Proze"s
in \modula\ umgesetzt wurde, besteht aus neun Modulen,
von denen im wesentlichen drei Module ({\tt OPP}, {\tt OPB} und {\tt OPS})
zum Frontend und drei ({\tt OPV}, {\tt OPC} und {\tt OPL}) zum Backend
geh"oren.
Die restlichen drei Module sind entweder als Low-Level-Module ({\tt OPT} und
{\tt OPM}) konzipiert oder steuern den Compiler ({\tt OP2}).

Motiviert durch die gro"se Anzahl von code-generierenden Routinen teilten
die Entwickler f"ur die NS32000-Implementation das Modul~{\tt OPC} in zwei
Teile, {\tt OPC} und {\tt OPCa}, auf.
Desweiteren war im Lieferumfang ein {\tt Debug}-Modul enthalten, das den
Syntaxbaum und die Teile der Symboltabelle nach deren Aufbau auf Anfrage
ausgibt.
Die 68000-Implementation beh"alt diese nicht im Diagramm aufgef"uhrten Erweiterungen
bei.

In der \modula-Version des Compilers, die dieser Arbeit zugrunde liegt,
ist jedes Modul --- au"ser {\tt OP2} als Wurzel der Hierarchie ---
zus"atzlich aufgeteilt in ein Definitions- und ein Implementationmodul.

Die nachfolgenden Abschnitten stellen in kurzer Form dar, welche Strukturen
sich hinter den Modulnamen verstecken.

\subsection{Das Modul {\tt OP2}}

Das Modul~{\tt OP2} bietet im wesentlichen zwei Prozeduren zum Aufruf des
Compilers an:
\begin{itemize}
\item {\tt CompilationUnit} kann von anderen Modulen importiert werden
  und "ubersetzt ein Modul, dessen Name und Aufenthaltsort im Dateisystem zusammen
  mit den Compiler-Optionen "ubergeben wird;
  nach den Initialisierungen der einzelnen Module wird mit {\tt OPP.CompilationUnit}
  der Quelltext eingelesen, geparst und der Syntaxbaum aufgebaut, dessen Wurzel
  sich in der lokalen Variable~{\tt prog} befindet;
  sind w"ahrend dieser ersten Phase keine Fehler aufgetreten, folgt die
  Berechnung der Variablen-Adressen und der Typgr"o"sen in der
  Prozedur~{\tt OPV.AdrAndSize};
  {\tt OPT.Export} vergleicht die alte Symboldatei mit der neuen und schreibt
  letztere ggf. ins Dateisystem;
  nach einer m"oglichen Ausgabe des Syntaxbaumes "uber {\tt OPdump.stat} und
  der Initialisierung der Backend-Module wird mit {\tt OPV.CompilationUnit}
  die Code-Generierung angesto"sen und nachfolgend die Objektdatei durch {\tt OPL.OutCode}
  erstellt;
\item {\tt Compile} ist als {\it command\/} die Schnittstelle zum End-Benutzer, der
  durch Anklicken oder Eingabe des vollst"andigen Namens {\tt OP2.Compile}
  mit eventuell nachfolgenden Parametern den Compiler anwenden will;
  in der \modula-Version wird {\tt Compile} durch den Modulrumpf repr"asentiert, der
  beim Starten des Compilers aufgerufen wird;
  n"ahere Hinweise zur Arbeit mit der \modula-Version werden in
  Anhang~\ref{Compileranleitung} gegeben.
\end{itemize}

\subsection{Das Modul {\tt OPM}}

Die Verbindung des Compilers zur "`Au"senwelt"' wird mit dem Modul~{\tt OPM}
durch Routinen zum Einlesen des Quelltextes, zur Ausgabe von Fehlermeldungen und
zum Lesen und Schreiben der Symboldatei hergestellt.
Wichtige Konstanten wie die Gr"o"se der Basistypen, deren Wertebereiche und
einige Angaben zur Unterst"utzung der semantischen Analyse werden hier
definiert.

In der \modula-Version wurden noch einige Prozeduren zur dynamischen Speicherverwaltung
und Verarbeitung von Zeichenketten angef"ugt.

\subsection{Das Modul {\tt OPS}}

Das Modul {\tt OPS} besteht im wesentlichen aus dem der lexikalischen Analyse dienenden
Scanner, repr"asentiert durch die Prozedur~{\tt Get}.
Sie entscheidet durch Fallunterscheidung anhand des n"achsten Zeichens, wieviele
der nachfolgenden Zeichen gelesen, im Fall von Zahlen interpretiert und zu einem Symbol
zusammengefa"st werden.
Sie wird durch die Prozeduren {\tt Identifier} und {\tt Number} unterst"utzt,
von denen die erste eine Zeichenkette in ein Zeichenfeld ablegt, w"ahrend die andere eine
aus einzelnen Zeichen bestehende Zahl in eine interne Darstellung umwandelt und,
abh"angig vom Typ der Zahl, in exportierten Hilfsvariablen speichert.

Kommentare werden von {\tt Get} uninterpretiert "ubersprungen, Zeichenketten
im Quelltext durch {\tt Str} eingelesen.

Da in {\tt OPS} die Datentypen {\tt Name} und {\tt String} definiert werden,
steht das Modul in der Hierarchie unterhalb des Dienstleistungsmoduls~{\tt OPT},
das die Typen zum Aufbau komplexerer Strukturen verwendet.

\subsection{Das Modul {\tt OPP}}
\label{OPP}

Um Vorw"arts-Referenzen m"oglichst zu vermeiden, beginnt das Modul~{\tt OPP},
zust"andig f"ur die Syntax-Analyse und den Aufruf der in {\tt OPB}
befindlichen Routinen zur semantischen Analyse und dem Aufbau des Syntaxbaumes,
mit der Definition der Parse-Prozeduren f"ur die kleinsten syntaktischen
Einheiten {\tt qualident} und {\tt CheckMark} (f"ur Exportmarkierungen).

Das {\em Sysflag}, das in {\tt CheckSysFlag} auf korrekte Benutzung
gepr"uft wird, geh"ort nicht zum normalen Sprachumfang von \oberon.
Es bietet f"ur den Systemprogrammierer eine M"oglichkeit der Attributierung
von strukturierten Datentypen einschlie"slich der offenen Felder und wird
als konstanter ganzzahliger Ausdruck, umgeben von eckigen Klammern, nach den Schl"usselworten
{\bf RECORD}, {\bf ARRAY} oder {\bf POINTER} eingef"ugt.
Fehlt das Sysflag, so wird der Typ mit dem Vorgabewert~0 initialisiert oder
bei erweiterten Verbundtypen vom Basistyp ererbt.
Die Interpretation des Sysflags ist dem Backend "uberlassen und sollte f"ur
verschiedene Ausrichtungen der Komponenten oder Elemente der Typen oder
"ahnliche Systemabh"angigkeiten verwendet werden.
Die vorliegende Implementation unterst"utzt keine spezifischen Werte von Sysflags,
ihre Angabe oder ihr Fehlen wirkt sich nicht auf die Code-Generierung aus.

Nach den Routinen zum Parsen der Deklarationen der verschiedenen strukturierten
Datentypen und formalen Parameter in Prozedurk"opfen folgt die Verarbeitung
von Ausdr"ucken, wobei Operator-Priorit"aten in der gewohnten Wirth'schen
Weise (\cite{compilerBau}) durch separate Prozeduren dargestellt werden.

Die Syntax der Prozeduredeklarationen zeigt Erweiterungen in der Verwendung
der Sonderzeichen $+$ (Interpretation der Routine als Interrupt-Handler),
$-$ (die Routine besteht nur aus Maschinenbefehlen), $\caret$ (der Prozedurkopf stellt
eine Vorw"artsdeklaration dar) und $\ast$ (die Routine kann
an eine Prozedurvariable zugewiesen werden), die hinter dem Schl"usselwort
{\bf PROCEDURE} und, im Fall von $\ast$ auch hinter dem Prozedurnamen erscheinen
k"onnen (die Prozedur wird exportiert). Dabei schlie"sen sich die ersten drei
Zeichen gegenseitig aus.
Sowohl die Deklaration von Interrupt-Handlern als auch von Maschinensprach-Prozeduren
wurde erst in \cite[S.~38]{op2doc} definiert und k"onnen somit nicht zum
offiziellen Sprachumfang von \oberon\ gez"ahlt werden.
Da sie aber im Frontend des \OP\ implementiert sind, werden sie auch in der
68000-Version ber"ucksichtigt.

Die Routine zum Parsen der {\it statement sequence\/}, {\tt StatSeq}, spiegelt
gut die Konstruktion des Syntaxbaums mit {\tt OPB.Construct} wider.
Im {\tt ELSIF}-Ast f"ur den {\bf WITH}-Befehl ist zu erkennen, da"s nach dem
Generieren des Baumknotens f"ur den type guard, {\tt OPB.TypTest}, nur der
Typ der abzusichernden Variablen in der Symboltabelle ver"andert wird.
Diese einfache Methode w"are nicht anwendbar, wenn auch Designatoren wie im
type test oder den anderen type guards zugelassen w"aren.

Bemerkenswert an der Prozedur {\tt Block} ist zum einen die lokal deklarierte
Prozedur {\tt CheckUDP}, die nach dem Parsen einer Verbund- oder Felddeklaration
aufgerufen wird und eventuell vorangegangene Vorw"artsdeklarationen von
Zeigern auf den eben deklarierten Typ aufl"ost, und zum anderen die letzte
{\bf IF}-Anweisung am Ende der Prozedur, die die in der Prozedur {\tt TypeDecl}
beim Parsen von Verbund- und Felddeklarationen generierten Syntaxbaumknoten der
Klasse {\it Ninittd} vor die Knoten der statement sequence setzt. Diese Knotenklasse
hat die Aufgabe, die Generierung von Code zur Initialisierung der Typdeskriptoren
anzusto"sen; sie wird in Abschnitt~\ref{OPC} n"aher behandelt.

Die letzte Prozedur des Moduls {\tt OPP}, {\tt CompilationUnit}, besch"aftigt
sich mit der Grobstruktur eines Moduls, aufgeteilt in Modulkopf, Importliste und
Modulblock und schlie"st somit die Syntax\-analyse von \oberon\ ab.

\subsection{Das Modul {\tt OPB}}

Die Hauptaufgabe des Moduls {\tt OPB} ist es, dem Parser {\tt OPP} Werkzeuge
an die Hand zu geben, mit denen er die korrekte semantische Benutzung der
Sprache "uberpr"ufen und den Syntaxbaum erstellen kann.

Die Aufgaben verteilen sich auf die Routinen wie folgt:
\begin{itemize}
\item Generierung von Syntaxbaumbl"attern ({\tt NewLeaf}, {\tt NewBoolConst},
  {\tt Nil}, {\tt EmptySet}, {\tt NewIntConst}, {\tt NewRealConst},
  {\tt NewString}),
\item Generierung von inneren Knoten ({\tt BindNodes}, {\tt Construct},
  {\tt Link}),
\item implizite Typkonversionen ({\tt Convert}, {\tt SetIntType},
  {\tt CheckRealType}),
\item semantische "Uberpr"ufung von einzelnen Konstrukten ({\tt DeRef},
  {\tt Index}, {\tt Field}, {\tt TypTest}, {\tt In}, {\tt SetRange},
  {\tt PrepCall}, {\tt Call}, {\tt Enter}, {\tt Return}, {\tt Assign},
  {\tt InitTD}),
\item semantische "Uberpr"ufung von monadischen und dyadischen Operationen
  ({\tt MOp}, {\tt ConstOp}, {\tt Op}),
\item semantische "Uberpr"ufung von Standardprozeduren und -funktionen
  ({\tt StPar0}, {\tt StPar1}, {\tt StPar2}, {\tt StParN}, {\tt StFct}),
\item semantische "Uberpr"ufung der Wertzuweisung ({\tt Assign},
  {\tt CheckAssign}, {\tt CheckProc}, {\tt CheckPtr}), {\tt CheckParameters},
\item semantische "Uberpr"ufung von Parameter"ubergaben ({\tt Param},
  {\tt CheckAssign}, {\tt DynArrParCheck}).
\end{itemize}

\medskip
Meist folgen auf die semantische "Uberpr"ufung in denselben Routinen auch
die Generierung des f"ur die Operation spezifischen inneren Knoten.

Die in Abschnitt~\ref{Designatoren} beschriebene Voraussetzung f"ur die Anwendung
von type tests und guards und die Abpr"ufung der erweiterten Zuweisungsf"ahigkeit von
Verbunden und Zeigern auf Verbunde (Abschnitt~\ref{Wertzuweisung}) wurde in den
Routinen {\tt TypTest}, {\tt CheckAssign} und {\tt Param} mittels des in
Abschnitt~\ref{erweiterbare Verbunde} von Wirth vorgeschlagenen Algorithmus'
mit linearer Komplexit"at realisiert.
In {\tt Assign} wird f"ur den Fall, da"s der Designator auf der linken Seite
der Wertzuweisung ein dereferenzierter Zeiger auf einen Verbund oder ein
call-by-reference "Ubergabeparameter ist, hinter den Designator ein Knoten
der Klasse {\it Neguard\/} angeh"angt, der die Generierung eines impliziten
type guard anst"o"st (Abschnitt~\ref{Wertzuweisung}).

\medskip
Die Struktur des Syntaxbaums beschreibt Crelier in \cite{op2doc} ab Seite~42 ausf"uhrlich.

\subsection{Das Modul {\tt OPT}}
\label{OPT}

Verwaltungsroutinen f"ur den Syntaxbaum und die Symboltabellen sowie die
Realisation von Importen und Exporten sind das Aufgabengebiet des Moduls~{\tt OPT}.

Konstuktoren f"ur verschiedene komplexe Datentypen sind {\tt NewConst} (f"ur Konstanten),
{\tt NewObj} (f"ur Symboltabellenknoten), {\tt NewStr} (f"ur die Beschreibung einer
Stufe eines Datentyps), {\tt NewNode} (f"ur Syntaxbaumknoten) und
{\tt NewExt} (f"ur Zeichenketten).
Zum Einf"ugen in eine Symboltabelle und Suchen in ihr existieren die Prozeduren
{\tt Insert}, {\tt InsertImport}, {\tt Find}, {\tt FindField} und {\tt FindImport}.
Lokale Objekte werden in eine eigener Symboltabelle untergebracht, indem am
Anfang der zu diesen Objekten geh"orenden Prozedur {\tt OpenScope} und
am Ende {\tt CloseScope} aufgerufen wird.
Um vordefinierte Konstanten, Datentypen und Prozeduren in die globale Symboltabelle
einlesen zu k"onnen, stehen die Prozeduren {\tt EnterBoolConst}, {\tt EnterTyp},
{\tt InitStruct} und {\tt EnterProc} zur Verf"ugung, die im Modulrumpf von {\tt OPT}
f"ur diesen Zweck benutzt werden.

\medskip
In einer gro"sen Fallunterscheidung liest die Routine {\tt Import} die
einzelnen Elemente einer zu einem zu importierenden Modul geh"orenden
Symboldatei ein und wandelt sie in dynamischen Datenstrukturen um,
die in die globale Symboltabelle unter dem Eintrag des Modulnamens
eingef"ugt werden.

Interessant sind die Klassen 18 und 19, die als Komponenten
vom Typ eines Zeigers oder einer Prozedur in Verbunden auftreten.
Diese Komponenten wurden von importierten Modul nicht exportiert, sind
also eigentlich nicht sichtbar.
Sie wurden trotzdem in die Symboldatei aufgenommen, um schon zur
"Ubersetzungszeit Vorbereitungen f"ur den garbage collector treffen zu k"onnen
und Zusatzinformationen zum sicheren Entfernen des Moduls aus dem
laufenden \oberon-System bereitzustellen.

Das Modul {\tt SYSTEM} erf"ahrt beim Import eine Sonderbehandlung, bei der
nach dem Einf"ugen des f"ur das Modul geltenden Namens in die globale
Symboltabelle f"ur die lokale Symboltabelle des Moduls die schon vorhandene,
mit der Zeigervariablen {\tt syslink} erreichbare Symboltabelle der in
{\tt SYSTEM} definierten Objekte gesetzt wird.

\medskip

Das Erstellen der Symboldatei des "ubersetzten Moduls im Speicher, der
Vergleich mit einer eventuell vorhandenen Datei und das Abspeichern der
neuen Datei nimmt unter Zuhilfenahme von Routinen aus dem Modul {\tt OPM}
die Prozedur {\tt Export} vor.
Die Generierung der beiden o.g. Klassen f"ur verdeckte Verbundkomponenten
h"angt von dem Zustand der booleschen Konstanten {\tt OPM.ExpHdPtrFld} und
{\tt OPM.ExpHdProcFld} ab.

\subsection{Das Modul {\tt OPV}}
\label{OPV}

Das f"ur die Steuerung der Codeerzeugung zust"andige Modul {\tt OPV} gliedert
sich in zwei Teile auf: die Zuweisung der absoluten und relativen Adressen
f"ur deklarierte Objekte und formale Parameter einschlie"slich der
Gr"o"senberechnung der strukturierten Typen und die Traversierung des Syntaxbaums
zur Codegenerierung.

Die den ersten Teil ansto"sende Routine {\tt AdrAndSize} traversiert zun"achst
die globale Symboltabelle, um die Adressen und Datentypgr"o"sen der exportierten
Objekte festzustellen.
Die nachfolgende Zuweisung der Adressen f"ur die globalen Variablen wird
abgeschlossen durch die Berechnung der Adressen und Datentypgr"o"sen der
verbleibenden Objekte.

Eine Schl"usselrolle spielt hier die Prozedur {\tt TypeSize}, die rekursiv
die Gr"o"se eines Datentyps berechnet.
Bei Verbunden werden auch die relativen Adressen der Komponenten zusammen
mit einer von der Zielmaschine abh"angenden Wort- oder Langwort-Ausrichtung
({\it Alignment\/}) festgelegt.
Die Routine {\tt OPM.AllocTypDesc} reserviert im Konstantenbereich Platz f"ur
das f"ur jeden Verbund- und Feldtyp notwendige constant type tag
(Abschnitt~\ref{erweiterbare Verbunde}).
F"ur Prozedurtypen bestimmt {\tt ParamAdr} die relativen Adressen der formalen
Parameter auf dem Stack.
Die der in Abschnitt~\ref{offene Felder} beschriebenen Repr"asentation der dynamischen
Felder auf dem Stack entsprechenden relativen Adressen werden mit Hilfe
der Routine {\tt AllocDynArrDim} berechnet.

Die Adressen der formalen Parameter und der lokalen Variablen einer Prozedur
stellt {\tt ProcSize} fest.
Sie reserviert auch die Stackbereiche f"ur die R"ucksprungadresse und die
Zeiger f"ur den statischen und den dynamischen Aktivierungsrahmen, %***
abh"angig vom Typ der Prozedur.

Die Routinen mit den Pr"afixen {\tt Alloc\ldots} und {\tt Align\ldots} werden
in Abschnitt~\ref{Speicheraufteilung} n"aher besprochen, da sie am st"arksten
von der Zielmaschine abh"angen.

\medskip
Der zweite Teil des Moduls {\tt OPV} besch"aftigt sich mit der Traversierung
des Syntaxbaums, der mit entsprechenden Routinen auf die syntaktischen Einheiten
"Ubersetzungseinheit ({\tt CompilationUnit}), Anweisung ({\tt stat}),
Ausdruck ({\tt expr}) und Designator ({\tt design}) zur"uckgef"uhrt wird.

Basierend auf den "`primitiven"' codegenerierenden Routinen aus den Modulen {\tt OPC}
und {\tt OPCa} baut {\tt stat} die Codeschablonen f"ur die komplexen
Ablaufkonstrukte {\bf CASE}, {\bf IF}, {\bf WHILE}, {\bf REPEAT} und {\bf LOOP}
auf und gibt die Auftr"age f"ur die einfachen Konstrukte direkt an
Prozeduren der untergeordneten Module weiter.
Die Adressen f"ur Vorw"artsspr"unge werden mit den Routinen {\tt OPL.Fixup} und
{\tt OPL.FixLink} eingesetzt.
%, die eingehender in Abschnitt~\ref{Backend} besprochen werden.
In der Fallunterscheidung der Knotenklasse {\it Nenter\/} legt {\tt stat} "uber
die Aufrufe von {\tt OPL.OutRefPoint}, {\tt OPL.OutRefName} und {\tt OPL.OutRefs}
Zusatzinformationen ab, die sp"ater in die Objektdatei geschrieben werden und
zur Analyse von Laufzeitfehlern durch einen Debugger dienen k"onnen.

\medskip
Die Operatoren monadischer und dyadischer Operationen werden in {\tt expr} und
auch {\tt design} zu den Operanden in Postorder gebracht.
Die Weitergabe der Information, wo sich die einzelnen Operanden befinden
(in welchen Registern bzw. durch welche Adressierungsart erreichbar), erfolgt
durch eine Datenstruktur vom Typ {\tt OPL.Item}, einem Verbund mit einem
stark von der Zielmaschine beeinflu"sten Inhalt (Abschnitt~\ref{OPL}).
W"ahrend die codegenerierenden Prozeduren f"ur die Operatoren den Inhalt der
"ubergebenen {\it items\/} ver"andern, um dadurch den Ort des Ergebnisses
zu beschreiben, erstellt {\tt OPCa.CompleteItem} aus den in einem Syntaxbaumblatt
enthaltenen Informationen wie Adresse und Datentyp ein neues item.

\subsection{Die Module {\tt OPC} und {\tt OPCa}}
\label{OPC} \label{OPCa}

Die K"orper der Prozeduren der Module {\tt OPC} und {\tt OPCa} sind
bis auf wenige Ausnahmen vollst"andig leer.
Sie sollen vom Autor des jeweiligen Backends ausgef"ullt werden.
Das Entwicklungsteam um Wirth nahm eine Aufteilung des Moduls {\tt OPC}
in die zwei vorliegenden Module vor, da {\tt OPC} gew"ohnlich das
umfangreichste Modul des Compilers ist und \oberon-Module nur eine
sehr begrenzte Code-Gr"o"se haben d"urfen.

Die einzigen Informationen, die die Routinen von {\tt OPC} und {\tt OPCa}
erhalten, befinden sich in den "Ubergabeparametern, meist vom Typ {\tt OPL.Item}.%
\footnote{Ausnahmen bilden nur die von den Compileroptionen beeinflu"sten
  booleschen Variablen f"ur Index-, "Uberlauf-, Wertebereichs- und
  Typ"uberpr"ufungen.}
Allgemein generieren die Prozeduren unter ausschlie"slicher Benutzung der
Unterprogramme des Moduls {\tt OPL} von den in den "Ubergabeparametern
beschriebenen Operanden abh"angige Codesequenzen, deren Ergebnisse wieder
in einem Parameter an die aufrufende Routine zur"uckgegeben werden.
Wie die Module {\tt OPC} bzw. {\tt OPCa} mit {\tt OPL} zusammenarbeiten
ist weitestgehend dem Backend-Entwickler "uberlassen, meist werden die beiden
"ubergeordneten Module aber auf einer Assembler-artigen Ebene arbeiten,
w"ahrend {\tt OPL} die Umwandlung in Maschinensprache vornimmt.

Detailierte Beschreibungen "uber die Verwendung der Prozeduren in der
vorliegenden Implementation enth"alt der Abschnitt~\ref{Backend}.

\subsection{Das Modul {\tt OPL}}
\label{OPL}

Wie die vorangegangenen Module ist auch das low level Modul f"ur
die Codegenerierung, {\tt OPL}, spartanisch mit Code ausgestattet.
Au"ser den K"opfen der in {\tt OPV} verwendeten Prozeduren befindet
sich hier die die Objektdatei formatierende Routine {\tt OutCode}.
Alle f"ur diese Routine ben"otigten Daten werden in modulglobalen
Datenstrukturen gehalten, was die Beschr"anktheit der Resourcen
f"ur Code und Konstanten erkl"art.

\subsection{Das Modul {\tt OPdump}}

Die Dienste des Moduls {\tt OPdump} d"urften vorwiegend in der
Entwicklungsphase eines Backends benutzt werden: die Prozedur
{\tt OPdump.stat} gibt auf der Standardausgabe den Syntaxbaum
in linearisierter Form aus.
Das Ausgabeformat ist recht eing"angig und soll hier nicht weiter
besprochen werden.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newpage
\section{Die Anpassung an die Atari-ST-Umgebung}

\subsection{Die Entwicklungsplattform}

Die Mikrocomputer der Atari-ST-Serie zeichnen sich durch die folgenden
Gemeinsamkeiten aus:
\begin{itemize}
\item 16-Bit-Mikroprozessor 68000 mit intern 32 Bit Daten- und Adressbusbreite,
   8 Daten- und 8 Adressregister, 8 MHz Taktfrequenz,
\item mindestens 512KB Hauptspeicher,
\item 192KB Betriebssystem TOS mit graphischer Benutzeroberfl"ache,
\item eine Centronics-, eine RS-232-, eine Midi-, eine "`DMA"'- und
   eine Floppy-Disk-Schnittstelle,
\item S/W-Bildschirm mit $640\times400$ Pixel oder Farbbildschirm
   mit $640\times200$ Pixel und 4 Farben oder $320\times200$ Pixel
   und 16 Farben Aufl"osung
\end{itemize}

Die vom Verfasser benutze Konfiguration hatte noch folgende Eigenschaften:
\begin{itemize}
\item ATARI-260-ST mit 2.5MB Hauptspeicher,
\item zwei Floppylaufwerke \'a 720KB,
\item 20MB Festplatte
\end{itemize}

Der fertige \oberon-"Ubersetzer und der Linker sind aber auf jedem System
der Atari-ST-Serie lauff"ahig.

\medskip
Zur Implementation des \oberon-Compilers auf dem Atari-ST stand dem
Verfasser das Entwicklungssystem {\it Megamax \modula\ V~1.00\/}
von Application~Systems, Heidelberg, zur Verf"ugung.
Es besteht aus einer Shell
dem "Ubersetzer f"ur \modula\ und einem in der Shell integrierten
{\it load time linker}, der ein Modul mit seinen Importen im Hauptspeicher
bindet und startet.
Weiter existieren ein gew"ohnlicher Linker, der auf dem Atari-ST
ausf"uhrbare Dateien erzeugt, und ein separater Editor, der in die
Shell einkonfiguriert wurde.

\subsection{Die Unterschiede im \modula-Sprachumfang}

Der von Megamax~\modula\ akzeptierte Sprachumfang entspricht der ersten
revidierten Fassung von \modula, die in \cite{modula2} beschrieben wird.

Die Unterschiede zwischen MacMETH-\modula, in der die \modula-Version des
\oberon-Compilers geschrieben ist, und Megamax \modula\ beschr"anken sich
innerhalb des "Ubersetzer-Quelltextes auf die folgenden Punkte:
\begin{itemize}
\item Megamax \modula\ verlangt hinter Langwort-Konstanten ein {\tt L}
   zur Typisierung;
\item in Megamax \modula\ existiert der Datentyp {\bf LONGREAL} nicht,
   er wurde auf {\bf REAL} korrigiert, was aber zu keiner
   Wertebereichverengung f"uhrt, da sich die beiden Datentypen der
   \modula-Versionen im Speicherplatzbedarf entsprechen;
\item f"ur den optionalen zweiten Parameter von {\bf INC} und {\bf DEC}, der
   in der \modula-Version oft benutzt wird, erlaubt Megamax \modula\
   nur Konstantenausdr"ucke;
   die Summen mu"sten also ausgeschrieben werden.
\end{itemize}

\subsection{Die importierten Module}

Die Module {\tt OP2}, {\tt OPdump} und {\tt OPM} importieren neben
den restlichen Modulen des \oberon-"Ubersetzers auch betriebssystemabh"angige
Module.
Die Modulk"opfe mit den Importlisten sehen wie folgt aus:

\begin{verbatim}
  MODULE OP2;

  IMPORT FileUtil, Terminal,  FileSystem, ...


  MODULE OPdump;

  IMPORT ..., InOut, ...


  MODULE OPM;

  IMPORT InOut, FileSystem, FileUtil, System, ...
\end{verbatim}

Da die importierten Module mit Ausnahme von {\tt Terminal} und {\tt InOut} nicht
auf dem Atari-ST zur Verf"ugung standen, mu"sten die drei Module vollst"andig
"uberarbeitet werden.
Anstelle der Importe {\tt FileSystem}, {\tt FileUtil} und {\tt System}
verwendete der Verfasser das Modul {\tt TOS}, eine privat hergestellte
\modula-Schnittstelle zum Betriebssystem~TOS, die sich an der offiziellen
C-Schnittstelle orientiert.

\medskip
Die von {\tt FileSystem} angebotenen Routinen zur Ein- und Ausgabe auf eine
Datei wurden mit gleicher Signatur an den Anfang von {\tt OPM} gesetzt
und benutzen Teile von {\tt TOS}.
Neu sind auch drei Unterprogramme zur Handhabung von TOS-Dateinamen:
{\tt Append} zum Anh"angen einer Zeichenkette an eine andere,
{\tt ReplaceSuffix} zur Ersetzung des Dateinamens in einer vollst"andigen
Pfadangabe, z.B. von {\tt C:$\backslash$ OP2$\backslash$ Test.Mod} in
{\tt C:$\backslash$ OP2$\backslash$ Hallo.Mod}, und
{\tt ReplaceExt} zum "Andern der Dateiendung von z.B. {\tt .Mod} auf
{\tt .Obj}.

Prozeduren wie {\tt FileSystem.Lookup}, die der Dateiverwaltung dienen,
fanden teilweise ad"aquaten Ersatz in {\tt TOS}-Aufrufen, teilweise
wurden sie, wie {\tt FileUtil.ExtLookup} in {\tt OPM.OldSym}, gegen neue
Programmst"ucke ausgetauscht.

Eine betr"achtliche Laufzeitverringerung des "Ubersetzers erzielte der
Verfasser, indem er die f"ur den Scanner ma"sgebliche Routine {\tt OPM.Get}
zum Lesen eines Zeichens aus der Quelldatei mit einem 4KB gro"sen Puffer
versah.
Ob die Puffergro"se optimal ist, wurde nicht gepr"uft.

Der durch {\tt OPM.NewKey} erzeugte Versionschl"ussel f"ur {\tt .Sym}- und
{\tt .Obj}-Dateien ergibt sich hier, "ahnlich der MacMETH-Version, aus dem
Produkt der TOS-internen Darstellungen des aktuellen Datums und der Uhrzeit.

Die mit {\tt OPM.ErrorBlock} protokollierte Fehlermeldung besteht nun
ausschlie"slich aus lesbaren Zeichen, die Position des Fehlers wird aber
noch immer in Zeichen ab Quelltextanfang angegeben.%
\footnote{Das Program {\tt OP2CONV.TTP}, das diese Fehlerdatei in ein mit dem Texteditor
{\bf TEMPUS} nutzbares Format konvertiert, ist Bestandteil dieser
Implementation und wird im Anhang~\ref{Fehlerdatei-Konverter} beschrieben.}

{\tt OPM.OldSym} sucht die alte Symboldatei im aktuellen Pfad auf dem
aktuellen Laufwerk --- beides Werte, die durch das Betriebssystem festgelegt
werden --- und, wenn sie dort nicht gefunden wird, auf dem Laufwerk und Pfad,
auf dem sich auch die Quelldatei befindet.
Die Verwendung einer passenden Environment-Variablen wird nicht unterst"utzt.

Die neue Symboldatei, die zun"achst die Endung {\tt .Tmp} tr"agt und im
aktuellen Pfad des aktuellen Laufwerks steht, wird in {\tt OPM.RegisterSym}
umbenannt, nachdem die gegebenenfalls dort existierende alte Symboldatei
gel"oscht wurde.

Die Eigenverwaltung des im \oberon-"Ubersetzers benutzten dynamischen
Speichers wurde ein\-schlie"s\-lich des Algorithmus' zur Berechnung des
verf"ugbaren Speichers beibehalten.

\medskip
F"ur das Modul {\tt OPdump} konnte die Megamax-\modula-Version von {\tt InOut}
verwendet werden.
Obwohl die Prozeduren {\tt WriteLongInt} und {\tt WriteLongReal} hier fehlen,
f"uhrte die Verwendung der entsprechenden Routinen {\tt WriteInt} und
{\tt WriteReal} zu keiner Wertebereichseinschr"ankung, da an {\tt WriteInt}
ohnehin ein Wert vom Typ {\bf LONGINT} "ubergeben wird und, wie oben schon
beschrieben, die Datentypen {\bf LONGREAL} in MacMETH und {\bf REAL} in
Megamax \modula\ "aquivalent sind.

\medskip
Unter Verwendung des mit Megamax \modula\ mitgelieferten Moduls {\tt ArgCVIO},
das einen C-"ahnlichen Zugriff auf die Kommandozeile erlaubt,
wich der Verfasser von der direkten Eingabe des Namens der zu "ubersetzenden
Quelldatei ab.
Der Modulrumpf von {\tt OP2} geht nun die einzelnen in der Kommandozeile
"ubergebenen Parameter durch und unterscheidet zwischen Compileroptionen,
die mit einem Schr"agstrich beginnen, und den Quelldateinamen.
Es k"onnen mehrere Namen, mit oder ohne Suffix  {\tt .Mod}, angegeben werden,
die der "Ubersetzer nacheinander bearbeitet.
Alternativ zum angegebenen Pfad wird eine Quelldatei, wenn sie dort nicht
zu finden ist, auch auf dem aktuellen Pfad des aktuellen Laufwerks gesucht.
Die Dateizugriffe bestreiten ausschlie"slich Routinen aus dem Modul {\tt TOS}.

Im Laufe der Backend-Implementation stellte es sich als n"utzlich heraus,
drei neue Compileroptionen einzuf"uhren:
\begin{itemize}
\item angelehnt an den Megamax-\modula-Compiler erm"oglicht es die Option
  {\tt /A}, anhand einer bekannten Stelle im generierten Code die
  entsprechende Stelle im Quelltext herauszufinden.
  Die Implementation dieser Eigenschaft stellte kein gro"ses Problem dar und
  wird im Abschnitt~\ref{Suchen} weitergehend behandelt.
\item Wegen der M"achtigkeit der Adressierungsarten des Mikroprozessors~68000
  und der g"unstigen Wahl der Komponenten des Datentyps {\tt OPL.Item}
  konnte teilweise die Codegenerierung aus den Operanden einer Operation in
  den Operator verlagert werden.
  Der resultierende Code ist sehr kompakt und von handgeschriebenem oft nicht
  zu unterscheiden.
  Wie im Abschnitt~\ref{Optimierung} ausgef"uhrt, kann es mit diese Art der Generierung
  aber zu einer Vertauschung der Evaluierung der Operanden kommen, was gerade
  bei Funktionsaufrufen in einem Ausdruck zu anders erwarteten Seiteneffekten
  f"uhren kann.
  Deshalb werden Ausdr"ucke nur unter Angabe der Option {\tt /O} optimiert.
\item W"ahrend des Entwicklungsprozesses war es oft vorteilhaft, mit Hilfe
  des Moduls {\tt OPdump} den Syntaxbaum ausgeben zu lassen.
  Die Ausgabe wurde aber im MacMETH-Original nicht "uber eine Compileroption
  sondern "uber die boolesche Variable  {\tt ShowTree} ausgew"ahlt.
  Die Folge war eine Neu"ubersetzung von {\tt OP2} bei jeder "Anderung von
  {\tt ShowTree}.
  Zur Bequemlichkeit und Zeitersparnis kann nun die Option {\tt /B} benutzt
  werden, die genau diese Variable entsprechend setzt.
\end{itemize}

\section{Die Speicheraufteilung}
\label{Speicheraufteilung}

\subsection{Die Repr"asentation der Datentypen}

Die Definitionen des Speicherplatzbedarfs verteilen sich auf das
Modul {\tt OPM} f"ur die einfachen Datentypen und auf das Modul
{\tt OPV} f"ur die strukturierten Typen.

\subsubsection{Die einfachen Datentypen}

Die Gr"o"sen der einfachen Typen wurden so gew"ahlt, da"s die
Eigenschaften des Mikroprozessors m"oglichst gut genutzt werden.
Der Prozessor~NS32000, f"ur den das erste Backend erstellt wurde,
"ahnelt dem 68000 sehr in seiner internen Struktur.
Daher sind die gew"ahlten Typgr"o"sen f"ur beide Prozessoren identisch
und in der folgenden Tabelle aufgef"uhrt.

\medskip
\noindent
\begin{tabular}{l|c|l|l}
Datentyp	& Gr"o"se & Wertebereich & Repr"asentation\\\hline
{\bf BYTE}	& 1	  & ($0 \to 255$) & Positive Bin"arzahl\\
{\bf CHAR}	& 1	  & 0X $\to$ 0FFX & Positive Bin"arzahl\\
{\bf BOOLEAN}	& 1	  & {\bf TRUE, FALSE} & 0 $\widehat{=}$ {\bf FALSE},\\
		&	  &		      &  andere {\bf TRUE}\\
{\bf SET}	& 4	  & \{\} $\to$ \{0 $\to$ 31\} & \{0\}$\widehat{=} 2^0$, \{31\}$\widehat{=} 2^{31}$\\
{\bf SHORTINT}	& 1	  & $-128 \to 127$ & Zweierkomplement\\
{\bf INTEGER}	& 2	  & $-32768 \to 32767$ & Zweierkomplement\\
{\bf LONGINT}	& 4	  & $-2147483648 \to 2147483647$ & Zweierkomplement\\
{\bf REAL}	& 4	  & $1.2\times10^{-38} \to 3.4\times10^{38}$ & IEEE einfache Genauigkeit\\
{\bf LONGREAL}	& 8	  & $2.2\times10^{-308} \to 1.8\times10^{307}$ & IEEE doppelte Genauigkeit\\
{\bf PROCEDURE} & 4	  & {\bf NIL} oder Prozedur & Adresse des Prozeduranfangs\\
{\bf POINTER}	& 4	  & {\bf NIL} oder Zeiger   & Adresse des dynamischen\\
		&	  &			    & Speicherbereichs \\
\end{tabular}

\medskip
Die Gr"o"sen sind in Byte angegeben.
Die Konstante {\bf NIL} besitzt sowohl f"ur Zeiger als auch f"ur Prozedurvariablen
den bin"aren Wert~0.

\medskip
Die Repr"asentationen von Konstanten des jeweiligen Typs innerhalb der
Megamax-\modula-Version des \oberon-"Ubersetzers und des von ihm generierten
Codes stimmen in den folgenden F"allen nicht "uberein:
\begin{itemize}
\item Konstanten vom Typ {\bf SET} werden intern durch den Typ~{\bf BITSET}
  dargestellt.
  Der Megamax-\modula-Compiler bietet nur 2 Byte gro"se {\bf BITSET}s,
  die zudem in umgekehrter Reihenfolge (\{0\} $\widehat{=} 2^{15}$)
  auf die Mengenelemente zugreifen.
  Die \oberon-Version des \oberon-Compilers nutzt {\bf SET} intern nur
  bis Element~15, soda"s eine "Ubersetzung dieser Version mit dem in
  \modula\ geschriebenen Compiler kein Problem darstellt.
  Die 68000-Implementation zielt allerdings auf eine 4-Byte-Repr"asentation
  von {\bf SET} ab.
\item Das Megamax-\modula\ stellt den \modula-Typ {\bf REAL}, der f"ur die
  Repr"asentation sowohl von {\bf REAL} als auch f"ur {\bf LONGREAL}
  verwendet wurde, durch 8 Byte dar.
  Eine Einschr"ankung der Wertebereiche tritt also nicht auf.
\end{itemize}

\subsubsection{Die strukturierten Datentypen}
\label{strukturierte Datentypen}

Die Repr"asentation der strukturierten Datentypen, die haupts"achlich
von der Routine {\tt OPV.TypeSize} festgelegt wird, konnte von der
NS32000-Implementation nahezu unver"andert "ubernommen werden.
Einzig die Ausrichtung verschiedener Strukturen mu"ste nicht so
streng, d.h. auf Langworte%
\footnote{2 Byte $\widehat{=}$ 1 Wort, 4 $\widehat{=}$ 1 Langwort.}
ausgerichtet, gehandhabt werden.

Im einzelnen gelten f"ur die strukturierten Typen die folgenden
Festlegungen:
\begin{description}
\item[statischer Verbund] Nach den Komponenten des Basistyps werden die eigenen Komponenten
  in der Reihenfolge der Deklaration alloziert, wobei Komponenten mit Gr"o"sen
  von mehr als ein Byte wortweise ausgerichtet werden ({\tt OPV.AlignFld}).
  Eine Ausnahme bildet eine Komponente vom Typ {\bf ARRAY}, wo, auch bei
  mehrdimensionalen Feldern, die Gr"o"se des Elementtyps f"ur die Ausrichtung
  ma"sgeblich ist.
  Die Gr"o"se des gesamten Verbundes wird am Ende auf eine gerade Byteanzahl
  aufgerundet ({\tt OPV.AlignRec}).
\item[Verbund auf dem Heap] Zus"atzlich zur Gr"o"se des statischen Verbundes werden
  bei der Platzzuweisung durch {\bf NEW} ein Langwort f"ur das type tag reserviert,
  das, entsprechend der Beschreibung in Abschnitt~\ref{erweiterbare Verbunde},
  unsichtbar f"ur den Programmierer vor den Verbund gesetzt wird.
\item[Verbund als {\bf VAR}-Parameter] Reserviert werden, unabh"angig von
  der Gr"o"se des Verbundes zwei Langworte auf dem Stack ({\tt OPV.ParamAdr},
  {\tt OPV.RecVarParSize}),
  das erste zur Aufnahme der Adresse des Verbundes, das zweite als type tag
  f"ur den aktuellen Typ des Verbundes (siehe Abschnitt~\ref{erweiterbare Verbunde}).
\item[statisches Feld] Nachdem die Gr"o"se des Elementtyps, wenn sie mehr als
  ein Byte betr"agt, auf eine gerade Byteanzahl aufgerundet worden ist
  ({\tt AlignArrElem})%
  \footnote{In der Frage des Aufrundens hatte der Verfasser einen ausf"uhrlichen
   Briefwechsel mit Herrn~Crelier, der das % in Abschnitt~\ref{Backend} eingehender beschriebene
   Problem der Parameter"ubergabe eines Zeichenfeldes mit ungerader L"ange,
   das Element eines weiteren Feldes ist, betraf.
   Die L"osung des Verfassers verschenkt zwar ein Byte, ist aber bei Parameter"ubergaben
   einfacher zu bearbeiten.}%
   , ergibt das Produkt dieser Zahl mit der Anzahl der Feldelemente
  die Gr"o"se des Feldes.
\item[Feld auf dem Heap] Aufbauend auf der Beschreibung in Abschnitt~\ref{Feld-Typdeskriptoren}
  veranschlagt {\bf NEW} zu\-s"atz\-lich zu der Feldgr"o"se zwei Langworte: das
  erste ist wieder das unsichtbare type tag direkt vor dem Feld, das zweite
  steht im letzten Langwort des allozierten Blocks und dient als Hilfszeiger
  f"ur den Garbage Collector.
\item[dynamisches Feld als {\bf VAR-Parameter}] Auf dem Stack folgen nach
  einem Langwort f"ur die Adresse des aktuellen Parameters f"ur jede
  Dimension ein Langwort zur Aufnahme des maxi\-mal in dieser Dimension erlaubten
  Index' plus eins ({\tt AllocDynArrDim}, siehe Abschnitt~\ref{offene Felder}).
\item[dynamisches Feld als {\bf value-Parameter}] Es gilt das gleiche wie
  im vorangegangenen Punkt.
  Zudem kopiert, hinter dem Eintritt in die Prozedur, eincompilierter Code
  das Feld auf den Stack und "andert die im formalen Parameter
  befindliche Adresse des Feldes in den neuen Wert um ({\tt OPCa.CopyDynArray}).
\end{description}


\subsection{Die modulglobale Speicheraufteilung}

Die Module {\tt OPV} und {\tt OPL} realisieren die Adresszuteilung f"ur die folgenden
Resourcen des Hauptspeichers:
\begin{description}
\item[Codebereich] Die Variable {\tt OPL.pc} beinhaltet die Adresse, in die
  der n"achste generierte Befehl geschrieben wird.
  Die Belegung des Codebereichs, der im Compiler als Zeichenfeld~{\tt OPL.code}
  implementiert ist, erfolgt monoton steigend ab der relativen Adresse~0 und
  ausschlie"slich durch Routinen des Moduls~{\tt OPL}.
  Lediglich die Ziele von Vorw"artsspr"ungen werden, wenn sie bekannt sind,
  nachtr"aglich von den Routinen {\tt OPL.Fixup} und {\tt OPL.FixLink}
  eingetragen.
  Eine Besonderheit bilden die internen Sprungtabellen f"ur die {\bf CASE}-Anweisung,
  die wegen der zu relozierenden Adressen nicht im Konstanten- sondern im
  Codebereich abgelegt werden ({\tt OPL.AllocCaseTab}).
\item[Konstantenbereich] Repr"asentiert durch das Zeichenfeld~{\tt OPL.constant}
  finden im Konstantenbereich Zeichenketten und constant type tags Platz,
  die von den Routinen {\tt AllocString} und {\tt OPL.AllocTypDesc}, beginnend
  mit der relativen Adresse~0, aufsteigend und auf eine Wortgrenze ausgerichtet
  eingeschrieben werden.
\item[Variablenbereich] Die Adressvergabe f"ur die globalen Variablen nimmt
  die Routine~{\tt VarAdr} schon im Modul {\tt OPV} vor.
  In der Reihenfolge der Deklaration weist sie den Variablen gegebenenfalls
  auf eine Wortgrenze ausgerichtete, aufsteigende relative Adressen zu, wobei
  die erste Variable die Adresse~0 erh"alt.
  Die Ausrichtung ist notwendig, wenn eine Variable mehr als ein Byte belegt.
  {\tt OPV.AlignBlock} bringt dann den vollst"andigen Variablenbereich auf eine
  gerade Byteanzahl.
\item[Stack] Der Stack des 68000 w"achst von h"oheren zu niedrigeren Adressen
  hin.
  Er wird zur Speicherung der Aktivierungssegmente von aufgerufenen
  Prozeduren verwendet.
  Ein Aktivierungssegment beinhaltet (in der Reihenfolge, in der die Bestandteile
  auf den Stack geschoben werden)
  \begin{itemize}
  \item die "Ubergabeparameter,
  \item ggf. einen Zeiger auf das Aktivierungssegment der Prozedur, in der die
    zum aktuellen Aktivierungssegment geh"orende Prozedur deklariert ist, zum
    Zugriff auf die dort deklarierten lokalen Variablen ({\it static link\/})
  \item ggf. der Inhalt des Prozessorstatusregisters,
  \item die R"ucksprungadresse,
  \item einen Zeiger auf das vorherige Aktivierungssegment ({\it dynamic link\/}) und
  \item die in der Prozedur deklarierten lokalen Variablen.
  \end{itemize}
  W"ahrend der Verarbeitung einer Prozedur h"alt der Prozessor neben dem
  Stackzeiger in Adress\-register~{\tt A7} einen Zeiger auf das aktuelle
  Aktivierungssegment, genauer auf den dort enthaltenen Zeiger auf das
  vorige Aktivierungssegment, in Register~{\tt A6}.
  Auf ihn beziehen sich die relativen Adressen der "Ubergabeparameter und der
  lokalen Variablen, die von der Prozedur~{\tt OPV.ProcSize} berechnet werden.
  Da die "Ubergabeparameter mit dem ersten beginnend auf den Stack geschoben
  werden, befindet sich der letzte Parameter am n"achsten zum Zeiger in {\tt A6}.
  Zuerst deklarierte Parameter besitzen also h"ohere relative Adressen.
  Die relative Adresse des zuletzt deklarierten Parameters, und damit auch aller
  anderen, h"angt von der Art der Prozedur ab und ist in entsprechenden
  Konstanten im Modul~{\tt OPV} festgehalten:
  \begin{itemize}
  \item f"ur Prozeduren, die nicht lokal zu anderen deklariert wurden ({\tt L0ProcOff}),
    sowie f"ur exportierte Prozeduren ({\tt ExtProcOff}) besitzt der zuletzt
    deklarierte Parameter wegen der R"ucksprungadresse, die zwischen dem
    Zeiger auf das vorherige Aktivierungssegment und dem letzten Parameter
    steht, die Adresse~8.
  \item Prozeduren, die lokal zu anderen deklariert wurden ({\tt LProcOff}),
    ben"otigen zus"atzlich den Zeiger auf das Aktivierungssegment der
    umgebenden Prozedur, der letzte Parameter erh"alt also die relative
    Adresse~12.
  \item Prozeduren, die als Interrupt-Handler deklariert sind ({\tt IProcOff}),
    bekommen neben der R"ucksprungadresse den Inhalt des 16 Bit breiten
    Prozessorstatusregisters~SR auf dem Stack geliefert, den sie zum
    Wiederherstellen des Kontextes nach Beendigung des Handlers benutzen.
    Folglich ist die relative Adresse des letzten Parameters~{\tt 10}.
  \end{itemize}

  Da die lokalen Variablen sp"ater als der Zeiger auf das vorherige
  Aktivierungssegment entstehen, besitzen sie negative relative Adressen.
  Die Allozierung der Adressen geschieht wieder in der Routine~{\tt OPV.ProcSize}
  mit der gleichen Prozedur {\tt OPV.VarAdr}, die auch f"ur die Adresszuweisung
  der globalen Variablen zust"andig war, in der Reihenfolge der Deklaration.
  Die erste deklarierte Variable hat eine h"ohere Adresse als die restlichen
  Variablen.
  Ihre Adresse ergibt sich aus ihrer Gr"o"se, versehen mit negativem Vorzeichen
  und eventuell, zur Ausrichtung auf eine Wortgrenze, um eins reduziert.
\item[Heap] Der dynamische Speicherbereich wird systemglobal von der Prozedur
  {\bf NEW} des Laufzeitsystems und dem Garbage Collector verwaltet.
  Die Strukturen der auf dem Heap befindlichen Verbunde und Felder sind
  in Abschnitt~\ref{strukturierte Datentypen} beschrieben.
\end{description}

Um dem Linker eine Relozierung der absoluten Adressen von globalen Variablen,
absoluten Spr"ungen, Zeichenketten und constant type tags
zu erm"oglichen, erzeugt der Compiler drei Listen mit den relativen Adressen
der Speicherstellen, deren Inhalt zu relozieren ist:
\begin{description}
\item[{\tt OPL.plink}] zur Relozierung von absoluten Adressen, die sich im
  Codebereich befinden,
\item[{\tt OPL.dlink}], deren absolute Adressen aus dem Bereich der globalen
  Variablen kommen und
\item[{\tt OPL.clink}], die f"ur Konstantenbereiche zust"andig ist.
\end{description}

Neben der relativen Adresse im jeweiligen Bereich enth"alt
jedes Langwort der Listen in den oberen 8 Bit die laufende Nummer des
Moduls, aus dem der Bereich stammt.
Die Modulnummern werden von der Routine~{\tt OPT.Import} vergeben.
Vordefiniert ist die Modulnummer~255 des Laufzeitmoduls.


\section{Das Backend}
\label{Backend}

Aufgrund des Umfangs der Backend-Routinen kann nur exemplarisch auf
einige Besonderheiten der Codegenerierung eingegangen werden.
Nach einer kurzen Beschreibung der 68000-Architektur wird die
Registerverwaltung und die Abbildung der Maschinenbefehls-Struktur
auf Prozeduren des Moduls~{\tt OPL} erl"autert.
Einer Behandlung des Datentyps~{\tt OPL.Item} folgt die Detailierung
einiger ausgew"ahlter Themen, die sich w"ahrend der Implementation
des Backends als problematisch oder interessant erwiesen haben.

\subsection{Die Architektur des Mikroprozessors 68000}

Der Mikroprozessor~68000, entwickelt von Motorola, besitzt einen
16-Bit-Daten- und einen 24-Bit-Adressbus, bei dem das niederwertigste
Bit immer Null ist.
Die internen Register der Breite 32~Bit sind in zwei Gruppen, Daten-
und Adressregister, aufgeteilt.
Mathematische und logische Operationen k"onnen nur mit den Datenregistern
vorgenommen werden, w"ahrend die Adressregister ma"sgeblich bei der
Berechnung von effektiven Adressen beteiligt sind.
Es existieren acht Datenregister {\tt D0}--{\tt D7}, neun
Adressregister {\tt A0}--{\tt A7} und {\tt A7'}, der 32-Bit-Programmz"ahler {\tt PC}
und das 16-Bit-Statusregister {\tt SR}.
Die Adressregister~{\tt A7} und {\tt A7'} haben entgegen den anderen
Adress- und Datenregistern, die frei verwendbar sind, eine vorbestimmte Aufgabe:
sie sind der Anwender- und der Supervisor-Stackzeiger.

Der Prozessor besitzt im wesentlichen zwei Arbeitszust"ande, den Anwender-Zustand,
in dem die normalen Anwendungsprogramme ablaufen, und den Supervisor-Zustand,
der Betriebssystemroutinen vorbehalten ist.
Im Anwender-Zustand k"onnen einige privilegierte Befehle nicht ausgef"uhrt werden,
der obere Teil des Statusregisters, der u.a. die Interruptmaske beinhaltet,
und das Adressregister~{\tt A7'} sind nicht zugreifbar.
Der Eintritt in den Supervisor-Zustand geschieht durch bestimmte Befehle, die
sog. Software-Interrupts ausl"osen, oder durch Hardware-Interrupts.
Der Supervisor-Zustand besitzt einen eigenen Stack, der mit dem
Adressregister~{\tt A7'} verwaltet wird.
Der Anwender-Stackzeiger hei"st im Supervisor-Zustand {\tt USP}, da der
Supervisor-Stackzeiger mit der Mnemonic~{\tt A7} ansprechbar ist, die sonst
dem Anwender-Stackzeiger vorbehalten ist.

"`{\it Die Bytes\/ {\rm (des Hauptspeichers)} sind einzeln adressierbar, und
zwar ist dem Byte in der oberen Worth"alfte eine geradzahlige Adresse zugeordnet,
die mit der Adresse des gesamten Wortes identisch ist \ldots\ . Die Adresse
der unteren Worth"alfte ist ungeradzahlig, und zwar um 1 h"oher als die Adresse der
oberen Worth"alfte oder des gesamten Wortes.

Befehle und Daten mit mehreren Bytes werden nur auf Wortbasis adressiert, d.h.
sie d"urfen nur geradzahlige Adressen haben.
Beginnt ein Langwort mit dem 1.~Wort auf der Adresse~$n$ ($n$ geradzahlig), so
hat das zugeh"orige 2.~Wort die Adresse~$n+2$.\/}"' \cite[S.~17]{SC68000}

Die Bestimmung, ob ein Befehl ein Byte, ein Wort oder ein Langwort manipuliert,
geschieht durch den Befehlsmnemonic-Suffix {\tt .B}, {\tt .W} oder {\tt .L}.
Verschiedene Befehle k"onnen allerdings nicht alle Suffixe verarbeiten.

Um den Ort zu beschreiben, an dem sich ein Operand eines Befehls befindet,
stehen dem Programmierer 14~Adressierungarten zur Verf"ugung, von denen jedoch
nur eine Untermenge auf einen bestimmten Befehl angewendet werden kann.
Zur ausf"uhrlichen Behandlung der Adressierungsarten sei auf \cite{SC68000} verwiesen.
Im Rahmen der Beschreibung des Datentyps~{\tt OPL.Item} in Abschnitt~\ref{Item}
wird auf die Adressierungsarten nocheinmal eingegangen.

Von den 57~Befehlen des Prozessors benutzt das Backend~45.
Die zw"olf nicht verwendeten Befehle sind {\tt ABCD}, {\tt DIVU}, {\tt EXG},
{\tt ILLEGAL}, {\tt MOVEP}, {\tt NBCD}, {\tt NOP}, {\tt RESET}, {\tt RTR},
{\tt SBCD}, {\tt STOP} und {\tt TAS}.

\subsection{Die Registerverwaltung}

Das Modul~{\tt OPL} "ubernimmt mit seinen Routinen {\tt GetAReg}, {\tt GetDReg},
{\tt ReserveReg}, {\tt ReleaseReg}, {\tt Release} und {\tt TestAndRelease}
die Verwaltung der Arbeitsregister des Prozessors.
In der {\bf BITSET}-Variablen~{\tt regset} ist festgehalten, welche Register
im Moment benutzt werden.
Die Vergabe von Registern geschieht, getrennt nach Registertyp, mit den
Routinen {\tt GetAReg} und {\tt GetDReg}, beginnend mit {\tt A0} bzw. {\tt D0}.
Ausgenommen sind die Register {\tt A6} und {\tt A7}, die f"ur den
Aktivierungssegment-Zeiger und den Stackzeiger reserviert sind.
Die R"uckgabe eines Registers wird mit {\tt ReleaseReg} oder, f"ur alle
in einem Item benutzten Register, mit {\tt Release} durchgef"uhrt.
Sp"atestens am Ende einer \oberon-Anweisung darf kein Register mehr reserviert
sein; die am Beginn der Generierung einer Anweisung aufgerufene Routine~{\tt OPL.BegStat}
stellt mit der Benutzung der Prozedur~{\tt TestAndRelease} sicher, da"s alle
Register frei verf"ugbar sind.

\subsection{Die Emission von Befehlen in {\tt OPL}}

Ein Maschinenbefehl des 68000 ist ein Wort lang und kann, je nach Befehl
und verwendeten Adressierungarten, mehrere Folgeworte haben.
Das Befehlswort besteht aus festen Bitkombinationen, die f"ur den Befehl
charakteristisch sind, und bis zu f"unf Feldern, die von diversen
Zusatzinformationen und den Beschreibungen der Adressierungsart der
Operanden gef"ullt werden.
Diese Struktur wird durch die Routinen des Moduls~{\tt OPL} unterst"utzt.
Zur Emission der Befehlsworte existieren die Prozeduren {\tt PutCom0} bis
{\tt PutCom5}, die sich in der Anzahl der im Wort enthaltenen Felder
unterscheiden.
Die Felder zur Beschreibung der effektiven Operandenadressen werden von
{\tt ComputeEA} anhand eines Items berechnet.
Eventuell entstehende Folgeworte werden in der globalen Variable~{\tt appendix}
gepuffert und mit der Routine~{\tt PutAppendix} an das Befehlswort angeh"angt.

Die oft ben"otigte Operation, den Wert eines Operanden in ein Datenregister
zu laden, "ubernimmt die Routine~{\tt MoveDReg}, die je nach Lage auch
andere Befehle als {\tt MOVE} erzeugt.
"Ahnliches leistet {\tt LoadAReg}, die die effektive Adresse eines Operanden
in ein Adressregister l"adt.
Andere Routinen werden an geeigneter Stelle beschrieben.


\subsection{Der Datentyp {\tt OPL.Item}}
\label{Item}

"`{\it The procedure\/ {\tt CompilationUnit}, another exported procedure of\/ {\tt OPV},
recursively traverses the syntax tree and calls procedures of underlying
modules, that take and/or return `items' as parameters, and that produce
code as side effect.
An item is a record representing an operand of an operation.
It indicates where the operand can be found.
Items make it possible to delay emmision of code, so that processor addressing
modes can be optimally used.}"' \cite[S.~35]{op2doc}

Als einzige Datenstruktur des in \oberon\ geschriebenen Compilers nutzt
{\tt Item} die Eigenschaft der erweiterbaren Verbunde, indem sie den
Typ~{\tt ItemBase} als Basistyp verwendet.
Die in {\tt Item} zus"atzlich spezifizierten Komponenten enthalten die
zu einer Operandenbeschreibung auf der Zielmaschine notwendigen Informationen.

Die Zusammensetzung der Komponenten in der 68000-Version von {\tt Item}
kristallisierte sich erst im Laufe der Backend-Entwicklung heraus.
Jedem durch ein Item beschriebenen Operanden ist seine Art~{\tt mode},
z.B. {\it Variable}, {\it Konstante} oder {\it Prozedur}, sein Datentyp~{\tt typ},
insbesondere zur Gr"o"senbestimmung, und Ort der Deklaration~{\tt mnolev}
in Form der (negativen) Nummer des Moduls, aus dem der Operand importiert
wurde, oder der (positiven) Deklarations-Ebene, die angibt, in welcher
Prozedurschachtelungstiefe der Operand vereinbart wurde.
Ist der Operand z.B. eine Variable, die lokal in einer Prozedur deklariert wurde,
welche wiederum lokal zu einer Prozedur ist, so erh"alt {\tt mnolev} den
Wert~2.

Die restlichen Komponenten von {\tt Item} werden je nach Ort der Benutzung
und den Werten der drei o.g. Komponenten unterschiedlich benutzt.

Die Komponente~{\tt mode} kann neben den vorgegebenen noch die
68000-spezifischen Werte {\tt RegA}, {\tt RegD}, {\tt RegAOffs}, {\tt RegAInc},
{\tt RegAIndOffs} und {\tt Coc} annehmen, die, bis auf den letzteren, die
entsprechende Adressierungsart beschreiben, mit der auf den Operanden
zugegriffen werden kann.
Der letzte Wert~{\tt Coc} sagt aus, da"s sich der Operand im Statusregister
des Prozessors befindet.
Das ist insbesondere nach Operationen mit booleschem Ergebnis der Fall.

\subsection{Die Prozedur {\tt OPCa.CompleteItem}}

Die Items entstehen in der Routine~{\tt CompleteItem} des Moduls~{\tt OPCa}
aus den Bl"attern des Syntaxbaums.
Umgewandelt werden Variablen, "Ubergabeparameter, Konstanten und
Prozedurbezeichner (zur Zuweisung an Prozedurvariablen).

Im Falle der Variablen oder "Ubergabeparameter mu"s hier schon Code
erzeugt werden:
der Zugriff auf eine Variable oder einen Parameter einer Prozedur,
zur der die die aktuelle Anweisung enthaltene Prozedur lokal ist,
kann nicht durch die Emission eines einzelnen Befehls aufgel"ost werden.
Vielmehr mu"s die Kette der {\it static links\/} entlanggegangen werden,
bis man an dem Aktivierungssegment angekommen ist, das die gew"unschte Variable
enth"alt.
Die Anzahl der Kettenglieder, die abzuschreiten sind, erh"alt man aus der
Differenz der Deklarations-Ebenen~{\tt mnolev} der aktuellen Prozedur und der
Variablen.
Betr"agt die Differenz z.B.~2, so wird die folgende Code-Sequenz erzeugt:
\begin{verbatim}
        MOVE.L  8(A6),An
        MOVE.L  8(An),An
\end{verbatim}
wobei {\tt An} ein durch {\tt GetAReg} angefordertes Adressregister ist.
Das entstehende Item hat dann den {\tt mode} {\tt RegAOffs} f"ur
die Adressierungart {\it Adressregister indirekt mit Offset}.
Das Adressregister ist das reservierte Register~{\tt An}, das in der
Komponente~{\tt adr} Platz findet und den Offset stellt die relative
Adresse der Variablen aus der dem Syntaxbaumblatt dar, die in {\tt offset}
gespeichert wird.
Da die Offsets in dieser Adressierungsart auf den Bereich $-32768\to32767$
beschr"ankt sind, mu"s in {\tt OPL.TestOffsetRange} eventuell
Code erzeugt werden, der den Offset in den erlaubten Bereich bringt.
Dies geschieht, indem der Offset mit dem Befehl {\tt MOVE.L\ \ \#offset,Dn}
in ein zuvor zu reservierendes Datenregister geschrieben und der
{\tt mode} des Items auf {\tt RegAIndOffs} gesetzt wird, was
der Adressierungsart {\it Adressregister indirekt mit Index und Offset\/}
entspricht.
Eine "ahnliche Einschr"ankung f"ur den Offset gilt auch f"ur diese Adressierungart,
die in {\tt TestOffsetRange} mit dem Befehl {\tt ADDI.L\ \ \#offset,Dn}
behandelt wird, wobei {\tt Dn} das schon vorher benutzte Indexregister darstellt.

Konstanten werden solange wie m"oglich in Form eines Items gehalten,
um eine kompakte Codeerzeugung zu erhalten.
So w"urde eine Zuweisung {\tt A $\becomes$ 1} an die {\bf INTEGER}-Variable~{\tt A}
"ubersetzt mit
\newpage
\begin{verbatim}
  MOVE.W  #1,D0
  MOVE.W  D0,adr(A)
\end{verbatim}
wenn die Konstante schon in {\tt CompleteItem} in ein Datenregister geladen
w"urde.
Stattdessen wird mit der im Item enthaltenen Information "uber
die Konstante in {\tt OPCa.Assign} der Befehl~{\tt MOVE.W\ \ \#1,adr(A)}
erzeugt.

\subsection{Die Routine~{\tt OPC.TypTest}}

Die drei type guards, normaler guard, regional guard und impliziter guard,
und der Typ-Test werden in der Routine~{\tt OPC.TypTest} in Code
umgesetzt.
Da der implizite type guard sich wesentlich von den anderen unterscheidet,
wird er in einem gesonderten Fall betrachtet.
Abh"angig davon, ob der Operand ein Referenz-Parameter oder ein
Zeiger ist, mu"s das type tag auf verschiedene Art adressiert werden.
Im ersten Fall wird auf die effektive Adresse ein Offset von 4
aufaddiert, im zweiten ist der Offset~-4 zu w"ahlen.
Das Item des Operanden, das nach einem guard ja noch weiterverwendet
wird, darf durch die Offsets nicht ver"andert werden.
Die Manipulationen finden daher in einer Kopie des Items, {\tt xt},
statt.
Der Zugriff auf den Deskriptor des Typs, der abgesichert werden soll,
geschieht "uber das constant type tag im Konstantenbereich.
Der generierte Code hat die folgende Form, wenn der Operand ein
Referenzparameter mit der relativen Adresse~8 ist:
\begin{verbatim}
  MOVE.L  12(A6),D0
  CMP.L   tagadr,D0
  BEQ.S   *+4
  MOVEQ.L #EqGuardTest,D0
  TRAP    #OberonTrap
\end{verbatim}
Der Software-Interrupt~{\tt OberonTrap} wird also aufgerufen, wenn das
auf dem Stack mitgelieferte type tag nicht mit dem constant type tag
"ubereinstimmt.

Erschwerend kommt bei den restlichen guards und dem Typ-Test hinzu,
da"s in den Typdeskriptor geschaut werden mu"s.
Dazu wird die Adresse des Deskriptors zun"achst in ein reserviertes
Adressregister kopiert.
Von dort aus wird "uber den Extensionlevel des abzusichernden Typs
das type tag im Deskriptor ausgew"ahlt, das auf den Deskriptor
dieses Typs zeigen sollte, wenn der guard erlaubt oder der Test
positiv ist, was durch den Vergleich mit dem constant type tag des
Typs gew"ahrleistet ist.
Hat {\tt TypTest} einen guard zu "ubersetzen, folgt eine "ahnliche
Sequenz f"ur einen Software-Interrupt wie beim impliziten guard,
andernfalls wird der {\tt mode} des Items~{\tt x}, das den Ort des
Ergebnisses angibt, auf {\tt Coc} und die Komponente~{\tt adr} auf {\tt eq}
gesetzt, um zu kennzeichnen, da"s durch einen Test auf Gleichheit
der Typ-Test als positiv entschieden werden kann.

F"ur den type guard {\tt p(P00)}, wobei {\tt p} ein Zeiger auf einen Verbund und
und {\tt P00} ein Zeigertyp auf einen Verbundtyp mit Extensionlevel~2 sei,
wird die folgende Code-Sequenz generiert:
\begin{verbatim}
  MOVE.L  adr(p),A0
  MOVE.L  -4(A0),A1
  MOVE.L  8(A1),D0
  CMP.L   tag,D0
  BEQ.S   *+4
  MOVEQ.L #GuardTest,D0
  TRAP    #OberonTrap
\end{verbatim}

Eine Zuweisung {\tt b $\becomes$ p {\bf IS} P00} mit {\tt b} als boolescher
Variable wird in {\tt OPCa.Assign} bearbeitet, deren Aufruf durch die
Postorder-Umordnung der Operatoren in {\tt OPV.stat} und {\tt OPV.expr}
ein Aufruf von {\tt TypTest} vorausgeht.
Der erzeugte Code hat dann die Form:
\begin{verbatim}
  MOVE.L  adr(p),A0
  MOVE.L  -4(A0),A0
  MOVE.L  8(A0),D0
  CMP.L   tag,D0
  SEQ     adr(b)
\end{verbatim}

Die regional type guards werden behandelt wie gew"ohnliche guards.
Die Unterscheidung ergibt sich erst in der Routine~{\tt OPCa.With}.
Da im Item~{\tt x}, das nach dem type guard noch immer den Ort des
Operanden beschreibt, noch Register in Benutzung sein k"onnen,
mu"s {\tt With} sie freigeben, bevor die erste Anweisung in der
Anweisungsfolge des {\bf WITH}-Statements ausgef"uhrt wird.

Ein Beispiel sei der Designator {\tt p(P00)}, wobei {\tt p} hier
eine lokale Variable mit der relativen Adresse~-12 sei, die in der die
aktuelle Prozedur umgebenden Prozedur deklariert wurde:
\begin{verbatim}
  MOVE.L  8(A6),A0    ;In CompleteItem generiert.
  MOVE.L  -12(A0),A1
  MOVE.L  -4(A1),A1
  MOVE.L  8(A1),D0
  CMP.L   tag,D0
  BEQ.S   *+4
  MOVEQ.L #GuardTest,D0
  TRAP    #OberonTrap
\end{verbatim}
An dieser Stelle steht der Inhalt von {\tt A0} zur Verf"ugung, um
z.B. den Zugriff auf eine Komponente des Verbundes zu erm"oglichen,
auf den {\tt p} zeigt.
Der beim regional type guard {\bf WITH} {\tt p : P00} {\bf DO} \ldots {\bf END}
identisch generierten Code-Sequenz folgt aber keine weitere Verwendung
von {\tt A0} mehr, soda"s das Register explizit mit {\tt OPL.Release}
zur"uckgegeben werden mu"s.

%\subsection{Die Parameter"ubergabe}



\subsection{Die optimierte Codeerzeugung von arithmetischen Ausdr"ucken}
\label{Optimierung}

Die Emission von Code f"ur Operanden kann durch die Verwendung der
Items oft bis zur "Ubersetzung des verbindenden Operators verz"ogert
werden.
So ist es z.B. bei der Zuweisung {\tt a $\becomes$ b}, wobei {\tt a} und {\tt b}
lokale {\bf INTEGER}-Variablen mit den relativen Adressen -4 und -6 sind.
Die "Ubersetzung lautet: {\tt MOVE.W\ \ -6(A6),-4(A6)}.

Probleme treten erst bei arithmetischen Operationen auf, die kommutativ sind.
Z.B. erzeugen die Terme {\tt a + (b - 1)} und {\tt (b - 1) + a}
bei Angabe der Compileroption~{\tt /O} richtigerweise die vollst"andig
identische Code-Sequenz:
\begin{verbatim}
  MOVE.W  -6(A6),D0
  SUBQ.W  #1,D0
  ADD.W   -4(A6),D0
\end{verbatim}
Ersetzt man den Summand~{\tt b - 1} durch den Funktionsaufruf {\tt f()},
der einen {\bf INTEGER}-Wert zur"uckgibt, so wird wieder f"ur die
Terme {\tt a + f()} und {\tt f() + a} die gleiche Code-Sequenz
erzeugt:
\begin{verbatim}
  JSR	  adr(f)            ;der Funktionswert wird in D0 zurueckgegeben
  ADD.W   -4(A6),d0
\end{verbatim}

Die Funktion erh"ohe nun intern den Wert von {\tt a} um 1 und gebe die
Konstante~2 zur"uck.
Weiterhin habe {\tt a} vor der Auswertung des Terms den Wert~0.
Intuitiv w"urde man jetzt aus der Reihenfolge der Summanden auf die
Ergebnisse schlie"sen, die da $0+2=2$ und $2+1=3$ w"aren.
Da die f"ur beide F"alle gleiche Code-Sequenz, die zuerst den Funktionsaufruf durchf"uhrt,
generiert wird, ergibt sich aber auch im ersten Term der Wert~3.
Auf Kosten der effizienten Codegenerierung kann nun durch Weglassen der
Option~{\tt /O} die Evaluierung der Operanden von links nach rechts
erzwungen werden:
\begin{verbatim}
  MOVE.W  -4(A6),D0
  MOVE.W  D0,-(A7)
  JSR     adr(f)
  MOVE.W  D0,D1
  MOVE.W  (A7)+,D0
  ADD.W   D1,D0
\end{verbatim}

\subsection{Das Suchen der Quelltextposition mit der Option~{\tt /A}}
\label{Suchen}

Das Frontend versieht u.a. jeden Syntaxbaumknoten~{\tt n}, der eine Anweisung
repr"asentiert, mit der Quelltextposition der Anweisung.
Die Position kann durch den Designator~{\tt n\caret.conval\caret.intval}
wiedergewonnen werden.
Bei Auftreten eines Fehlers im Backend wird durch den Aufruf von {\tt OPM.err}
eine Beschreibung des Fehlers mit Ortsangabe protokolliert.
Die Implementation der Compileroption~{\tt /A}, die von der Vorgabe einer
Codeadresse auf die Quelltextposition der an dieser Stelle generierten
Anweisung schlie"st, beschr"ankte sich damit auf die Ausgabe einer Fehlermeldung,
wenn die Codeerzeugung die gegebene Adresse erreicht hat.
Die einzigen Routinen, die direkt in das den Code enthaltende Datenfeld~{\tt OPL.code}
schreiben, sind {\tt OPL.PutByte} und {\tt OPL.PutWord}.
Daher reichte es aus, diese Routinen mit einer entsprechenden Abfrage zu
versehen.

%\subsection{Das Patchen von Vorw"artsspr"ungen}

\subsection{Die Routinen {\tt OPC.SYSput} und {\tt OPC.SYSputr}}

Zahlenkonstanten erhalten in \oberon\ den Typ zugeordnet, in dessen
Wertebereich sie gerade noch hineinpassen.
Sie werden auch automatisch auf andere Typen mit gr"o"serem Wertebereich
angepa"st, wenn es n"otig ist.
Z.B. wird die Konstante~1 in der Zuweisung {\tt a $\becomes$ 1} in den
Typ {\bf LONGINT} der Variablen {\tt a} konvertiert und der generierte
Befehl lautet {\tt MOVE.L\ \ \#1,adr(a)}.
Den Routinen~{\tt PUT} und {\tt PUTREG} des Moduls~{\tt SYSTEM}
k"onnen als zweiter Parameter, der den zu schreibenden Wert bezeichnet,
auch Konstanten "ubergeben werden.
Die Generierung ist stark abh"angig von der Gr"o"se des Datentyps des
zweiten Parameters.
Das Problem ergibt sich, wenn man z.B. in ein Langwort den Wert~1 schreiben
will.
Der Aufruf~{\tt SYSTEM.PUT(1000, 1)} w"urde nur in das Byte mit
der Adresse~1000 eine 1 einschreiben.
Um ein Langwort zu schreiben, mu"s der Typ von 1 k"unstlich erweitert werden.
Das geschieht durch die Verwendung der Standardfunktion {\bf LONG}.
Wenn man {\tt SYSTEM.PUT(1000, LONG(LONG(1)))} aufruft, wird in der Tat
in das Langwort an der Adresse~1000 eine 1 abgelegt.


\section{Der Linker}

Ein auf dem Atari-ST implementiertes \oberon-System mu"s mehrere
Anforderungen erf"ullen, die an das System auf der \ceres\ nicht
gestellt wurden:
\begin{itemize}
\item der Atari-ST soll ein Rechner bleiben, auf dem beliebige Programme
  zu beliebigen Zeitpunkten ausgef"uhrt werden k"onnen.
  Die \ceres\ wurde als alleinige \oberon-Maschine konzipiert, was beim
  Atari ja nicht zutrifft.
  Deshalb darf das \oberon-System oder Teile davon nicht fest in EPROMs,
  die man gegen die TOS-ROMs austauscht, gespeichert werden.
\item Ein Teil des \oberon-Systems, vorzugsweise der {\it inner core},
  sollte in einer ausf"uhrbaren Datei als Programm vorliegen, das nach dem
  Starten das System komplett "`hochzieht."'
  Der verbleibende Speicher kann als Arbeitsspeicher vom \oberon-System
  verwendet werden.
\item Um die Schnittstelle zwischen inner core und dem Rest des \oberon-Systems
  nicht unn"otig zu komplizieren, sollte auch der inner core in \oberon\
  geschrieben sein.
  Es mu"s also ein Linker existieren, der den inner core zusammenbindet.
\item Wie Prof.~Wirth dem Verfasser gegen"uber versicherte, kann die
  Sprache~\oberon\ auch vollkommen unabh"angig von dem System~\oberon\
  gesehen werden.
  Daher erschien es dem Verfasser w"unschenswert, \oberon-Programme auch
  au"serhalb der Programmierumgebung erstellen und benutzen zu k"onnen.
  Der Linker sollte deshalb aus jedem \oberon-Modul und seinen Importen
  ein auf dem Atari-ST lauff"ahiges Programm herstellen k"onnen.
\end{itemize}

Ein solcher Linker liegt nun, sozusagen als Nebenprodukt der Backend-Entwicklung,
vor und soll in den folgenden Abschnitten beschrieben werden.
Grundlegend f"ur die Arbeitsweise des Linkers sind die Informationen, die
er aus den Objektdateien erh"alt, und die in ein Format zu transformieren sind,
das der Atari-ST verarbeiten kann.
Deshalb befassen sich die n"achsten beiden Abschnitte mit den Formaten der
Objekt- und der ausf"uhrbaren TOS-Datei.


\subsection{Die Informationen in der Objektdatei}
\label{Objektdatei}

Eine Objektdatei teilt sich in zwei Teile auf: den Dateikopf und den
-rumpf.

\subsubsection{Der Dateikopf}

Im Kopf der Objektdatei legt der Compiler Informationen ab, die
f"ur den Linker/Lader notwendig sind, um den Rest der Datei einlesen
zu k"onnen.
Im einzelnen sind das
\begin{itemize}
\item (1 Wort) die Konstante {\tt 0F836H},
  die zur "Uberpr"ufung dient, ob die Datei eine Objektdatei ist;
\item (1 Langwort) ein Zeiger auf den Anfang der f"ur einen Stackdump
  notwendigen Referenzdaten;
\item (1 Wort) die Anzahl der Eintr"age im entry block;
\item (1 Wort) die Gr"o"se des command blocks in Bytes;
\item (1 Wort) die Anzahl der Zeiger in den globalen Variablen und damit im
  pointer block;
\item (1 Wort) die Anzahl der importierten Module;
\item (1 Wort) die Anzahl der Typdeskriptoren;
\item (1 Wort) die Anzahl der Eintr"age der Relozierungsliste f"ur den
  Variablenbereich;
\item (1 Wort) die Anzahl der Eintr"age der Relozierungsliste f"ur den
  Codebereich;
\item (1 Wort) die Anzahl der Eintr"age der Relozierungsliste f"ur den
  Konstantenbereich;
\item (1 Langwort) die Gr"o"se des Bereichs der globalen Variablen in Bytes;
\item (1 Wort) die Gr"o"se des Konstantenbereichs in Bytes;
\item (1 Langwort) die Gr"o"se des Codebereichs in Bytes;
\item (1 Langwort) der Modulschl"ussel (module key);
\item (20 Byte) der Modulname, abgeschlossen durch ein oder mehrere {\tt 0X}.
\end{itemize}

\subsubsection{Der Dateirumpf}

Der Rumpf einer Objektdatei ist in mehrere Bl"ocke aufgeteilt,
die jeweils mit einer dem Block zugeordneten Zeichen-Konstanten beginnen:
\begin{itemize}
\item {}[{\tt 82X}] (1 Langwort/Eintrag) der {\it entry block\/} ordnet der in
  der Symboldatei mit jeder exportierten Prozedur verbundenen Nummer die
  relative Adresse des Prozeduranfangs zu;
\item {}[{\tt 83X}] ((Namenl"ange + 1 Langwort)/Eintrag) der Name jedes {\it commands},
  d.h. jeder parameterlosen exportierten Prozedur wird, gefolgt von der
  relativen Adresse seines Prozeduranfangs, im {\it command block} abgelegt;
  der Block endet mit {\tt 0X} anstelle eines Namens;
\item {}[{\tt 84X}] (1 Langwort/Eintrag) der {\it pointer block\/} besteht aus
  den relativen Adressen der Zeiger im globalen Variablenbereich;
\item {}[{\tt 85X}] ((1 Langwort + 20 Byte)/Eintrag) der Schl"ussel eines importierten
  Moduls und sein durch ein oder mehrere {\tt 0X} terminierter Name sind die
  Bestandteile eines Eintrags im {\it import block};
\item {}[{\tt 86X}] (1 Langwort/Eintrag) aus den drei Relozierungslisten
  {\tt dlink}, {\tt plink} und {\tt clink} setzt sich der {\tt link block\/}
  zusammen;
\item {}[{\tt 87X}] der {\it constant block\/} besteht alleinig aus dem
  Konstantenbereich;
\item {}[{\tt 88X}] im {\it code block\/} ist der Codebereich abgelegt;
\item {}[{\tt 89X}] die Typdeskriptoren finden im {\it type block\/} Platz;
  die abgespeicherten Daten h"angen vom Datentyp des Deskriptors ab:
  \begin{itemize}
  \item die Typdeskriptoren von Verbunde bestehen aus:
    \begin{itemize}
      \item (1 Wort) der Konstanten~{\tt 4} zur Kennzeichnung eines Verbunddeskriptors;
      \item (1 Langwort) der L"ange des Deskriptors in Bytes;
      \item (1 Langwort) der relativen Adresse des constant type tags im
        Konstantenbereich;
      \item (1 Langwort) der Blockgr"o"se eines Verbundes in Bytes (zur Definition des
        Begriffs {\it Blockgr"o"se\/} siehe Abschnitt~\ref{Supportstrukturen});
      \item (1 Langwort) der relativen Adresse des constant type tags des
        Basistyps im Konstantenbereich des Moduls mit der Modulnummer in
        den oberen 8 Bit des Langwortes;
        ist der Typ nicht erweitert, hat das Langwort den
        Zweikomplement-Wert~ {\tt -1};
      \item (7 Langworte) dem Platzhalter f"ur die Tabelle der Zeiger auf
        die Deskriptoren der Basistypen der jeweiligen Erweiterungtiefe;
      \item (1 Langwort/Eintrag) die Tabelle der relativen Komponentenadressen
        der Zeiger im Verbund;
      \item (1 Langwort) dem negativen Offset, der, auf seine Adresse aufaddiert,
        die Adresse des Typdeskriptors ergibt; dadurch mu"s sich der
        Garbage Collector nicht die Adresse des Deskriptors merken.
    \end{itemize}
  \item die Typdeskriptoren von Feldern setzen sich zusammen aus:
    \begin{itemize}
      \item (1 Wort) der Konstanten~{\tt 2} zur Kennzeichnung eines Felddeskriptors;
      \item (1 Langwort) der Gr"o"se des Deskriptors in Bytes;
      \item (1 Langwort) der relativen Adresse des constant type tags (nur aus
        Konformit"ats\-gr"un\-den);
      \item (1 Langwort) der Blockgr"o"se (s.o.);
      \item (1 Langwort) der Differenz zwischen den relativen Adressen des
        n"achsten Feldelements und des letzen Zeigers im aktuellen Feldelement
        in Bytes;
      \item (1 Langwort) der echten Gr"o"se des Feldes in Bytes;
      \item (1 Langwort/Eintrag) der Tabelle der Differenzen der relativen
        Adressen jeder Zeigers zum vorherigen Zeiger im Elementtyp;
      \item (1 Langwort) dem negativen Offset, der, auf seine Adresse
        aufaddiert, die Adresse des Typdeskriptors ergibt;
      \item (1 Langwort) der Blockgr"o"se des Feldes in Bytes;
        sie dient dem Garbage Collector der Berechnung der Adresse des
        Hilfszeigers im letzten Langwort des allozierten Blocks.
    \end{itemize}
  \end{itemize}
\item {}[{\tt 8AX}] in den {\it ref block\/} wird der Inhalt der Tempor"ardatei
  {\tt OP2Ref.Tmp} kopiert;
  im wesentlichen besteht sie aus je einem Eintrag pro deklarierter Prozedur:
  \begin{itemize}
  \item der relativen Adresse der Prozedur im Codebereich, angef"uhrt durch
    die Konstante~{\tt 0F8X};
  \item dem durch {\tt 0X} terminierten Namen der Prozedur;
  \item f"ur jeden formalen Parameter und jede lokale Variable einfachen
    Typs oder vom Typ eines Zeichenfeldes mit weniger als 33 Zeichen (sie
    sind in alphabetischer Reihenfolge aufgef"uhrt):
    \begin{itemize}
    \item die Zeichen-Konstante~{\tt 1X} f"ur eine Variable oder einen
      Wert-Parameter oder die Zeichen-Konstante~{\tt 3X} f"ur einen
      Referenz-Parameter;
    \item die Zeichen-Konstante~{\tt 15X} f"ur ein Zeichenfeld oder die
      dem Typ entsprechende {\it structure form\/} (siehe die Konstantendefinition
      z.B. im Modul~{\tt OPC};
    \item die relative Adresse der Variable oder des Parameters als Langwort;
    \item der durch {\tt 0X} terminierte Name der Variable oder des Parameters.
    \end{itemize}
  \end{itemize}
\end{itemize}

\subsection{Der Aufbau einer ausf"uhrbaren TOS-Datei}

Die ausf"uhrbaren Datei haben auf dem Atari-ST die Endungen {\tt .PRG},
{\tt .TOS} und {\tt .TTP}.
Ihre inneren Strukturen stimmen vollst"andig "uberein, die Unterschiede
bestehen im Verhalten des Programm-Laders:
\begin{itemize}
\item eine {\tt .PRG}-Datei wird als GEM-Anwendung gestartet, der Mauszeiger
  bleibt aktiv und beim Laden wird der Default-GEM-Schirm mit dem Dateinamen
  in der Men"uzeile dargestellt;
\item f"ur eine {\tt TOS}-Datei wird der Bildschirm gel"oscht, er erscheint
wei"s, der Mauszeiger ist deaktiviert;
\item vor dem Laden einer {\tt .TTP}-Datei "offnet sich eine Dialogbox,
  in die die Kommandozeile eingegeben werden kann ({\it TOS takes parameters\/});
  nach dem Dr"ucken von {\tt RETURN} oder dem Anklicken der OK-Taste geschieht
  das gleiche wie im Punkt {\tt .TOS}-Datei beschrieben.
\end{itemize}

Eine solche Datei spaltet sich in vier Teile:
den Kopf, den Programmteil, den Datenteil und die Relozierungstabelle.

\subsubsection{Der Dateikopf}

Der Dateikopf kann durch den folgenden Verbund beschrieben werden:
\begin{verbatim}
  RECORD
    branch  : CARDINAL;
    txtlen  : LONGCARD;
    datalen : LONGCARD;
    bsslen  : LONGCARD;
    comlen  : LONGCARD;
    unused1 : LONGCARD;
    unused2 : LONGCARD;
    unused3 : CARDINAL
  END
\end{verbatim}

Dabei hat {\tt branch} immer den Wert~{\tt 601AH}, was dem Maschinenbefehl
{\tt BRA.S\ \ \ *+\$1A} entspricht.
Mit diesem Befehl kann der restliche Dateikopf "ubersprungen werden.
{\tt txtlen} ist die L"ange des des Programmteils, {\tt datalen} die
L"ange des Datenteils und {\tt bsslen} die L"ange des BSS-Segments, jeweils
in Bytes gerechnet.
Die restlichen Komponenten werden meist nicht verwendet und sind dann 0.
Das BSS-Segment ist ein zweiter Datenteil, der nach dem Laden, aber vor
dem Starten des Programms alloziert wird.

\subsubsection{Der Programm- und der Datenteil}

Die Tr"ager der Nutzinformation sind der Programm- und der Datenteil.
Der Befehl in den ersten Speicherstellen des Programmteils ist auch der
erste Befehl, der ausgef"uhrt wird.

\subsubsection{Die Relozierungstabelle}

Da bei der Herstellung der ausf"uhrbaren Datei noch nicht feststeht, an
welche Adressen des Hauptspeichers der Programm- und Datenteil geladen wird,
m"ussen Zusatzinformationen in die Datei aufgenommen werden, die eine
Korrektur der im Programm enthaltenen absoluten Adressen erm"oglichen.
Diesen Zweck erf"ullt die Relozierungstabelle ({\it relocation table\/}).
Jede "`absolute"' Adresse ist zun"achst auf den Anfang des Programmteils bezogen
und kann durch Addition der absoluten Adresse des Programmteilanfangs zu
einer absoluten Adresse reloziert werden.

Der erste Eintrag in der Tabelle besteht aus einem Langwort, das die
zum Anfang des Programmteils relative Adresse des ersten Langwortes%
\footnote{Absolute Adressen sind immer nur in Langworten gespeichert
und auf eine Wortgrenze ausgerichtet.}
enth"alt, in dem eine absolute Adresse gespeichert ist.
Der verbleibende Teil der Tabelle ist in Bytes eingeteilt.
Allgemein erh"alt man die n"achste Adresse, in der eine absolute Adresse abgelegt
ist, indem man den Wert des n"achsten Bytes in der Relozierungtabelle auf die
aktuelle Adresse aufaddiert.
Die folgenden Byte-Werte haben dabei eine besondere Bedeutung:
\begin{description}
\item[{\tt 00H}] das Ende der Relozierungstabelle ist erreicht;
\item[{\tt 01H}] addiere {\tt 0FEH} auf die aktuelle Adresse, reloziere
  den Inhalt dieser Adresse aber nicht.
\end{description}


\subsection{Die systemglobale Speicheraufteilung}

Obwohl das Speicherkonzept von Wirth und Gutknecht aus \cite[S.~867]{oberonSystem}
"ubernommen wurde, ergeben sich doch einige "Anderungen.
Der Programmteil der gelinkten TOS-Datei besteht aus der Aneinanderreihung
der von {\tt GetMod} geladenen Module, beginnend mit dem Laufzeitsystem {\tt Runtime}
"uber das zu linkende Modul bis zu seinen Importen.
Der Datenteil setzt sich nur aus den globalen Variablen von {\tt Runtime}
zusammen, die vom Linker initialisiert wurden.
Die globalen Variablen der anderen Module sind in das BSS-Segment verlagert,
das erst nach dem Laden der Programmdatei vom Betriebssystem alloziert wird und
somit keinen Platz in der Datei einnimmt.

Nach dem Laden der Programmdatei und dem Allozieren des BSS-Segments durch das
Betriebssystem wird der Modulrumpf von {\tt Runtime} ausgef"uhrt, der
den verf"ugbaren Arbeitsspeicher reserviert und Initialisierungen
der restlichen Module vornimmt.

Der Arbeitsspeicher teilt sich in den Heap, den Stack und den Modulbereich auf.
Der Heap w"achst vom Beginn des reservierten Speicherbereichs in Richtung
aufsteigender Adressen, w"ahrend sich der Stack zu den fallenden Adressen hin
vergr"o"sert.
Der Stack setzt unterhalb des Modulbereichs an, der gleichfalls nach unten
w"achst.
Der Modulbereich wird durch den dynamischen Lader verwaltet, der zum \oberon-System
geh"ort.
Da das \oberon-System nicht implementiert wurde, ist der Modulbereich leer und
der Stack beginnt an der h"ochsten Adresse des reservierten Bereichs.%
\footnote{Strenggenommen sitzt der Stackzeiger anfangs auf der ersten Adresse,
die nicht mehr reserviert ist, da er {\em vor\/} der Abspeicherung von Daten dekrementiert
wird.}

\medskip
Im Programmteil der TOS-Datei setzt sich ein Modul aus dem Moduldeskriptor
und dem Modulblock zusammen, der direkt hinter dem Deskriptor liegt.
Die Moduldeskriptoren sind Verbunde, die in der Initialisierungsreihenfolge
der Module miteinander zu einer einfach verketteten Liste verbunden sind.
Der Listenkopf befindet sich in der Variablen~{\tt Runtime.modroot.}
Die Komponenten {\tt entries}, {\tt commands}, {\tt pointerRefs},
{\tt imports}, {\tt constants}, {\tt code} und {\tt variables}
verweisen auf die zugeh"origen Teile des Modulblocks, w"ahrend die
restlichen Komponenten Zusatzinformationen, wie Name der Objektdatei {\tt filename},
Modulname {\tt modname}, Gr"o"se des Variablenbereichs {\tt dsize},
Gr"o"se des Modulblocks {\tt blocksize} und Modulschl"ussel {\tt key},
oder "`tempor"are"' Variablen zum Informationstransport zum zweiten Teil
des Linkers darstellen (siehe Datentyp~{\tt Runtime.ModuleDesc}).

Ein Modulblock besteht aus dem {\it entry\/}-, dem {\it command\/}-,
dem {\it pointer\/}-, dem {\it import\/}-, dem {\it constant\/}- und dem
{\it code block}, gefolgt von dem Datei- und Modulnamen.
Die Bedeutung und Struktur der Bl"ocke kann aus Abschnitt~\ref{Objektdatei}
entnommen werden.
Ihre Aufgaben sind in \cite{oberonSystem} auf S.~866ff beschrieben.

Die Modulbl"ocke, die sp"ater von {\tt Modules.GetMod} in den Modulbereich geladen
werden, beinhalten zus"atzlich den {\it variable block}, der f"ur die
Module des Programmteils im BSS-Segment angelegt wurde.

Neben dem code block enthalten der entry, command, pointer und constant block
absolute Adressen, die vom Linker auf den Anfang des Programmteils reloziert
und in die Relozierungstabelle der TOS-Datei eingetragen werden m"ussen, was
u.a. im n"achsten Abschnitt beschrieben wird.


\subsection{Die Arbeitsweise des Linkers}

Der Linker transformiert die Objektdateien in zwei Phasen in die TOS-Datei.
Mit der Prozedur {\tt GetMod} l"adt der Linker zun"achst das Laufzeitsystem
und das zu linkende Modul mit seinen Importen in den Hauptspeicher.
Die Allozierung der globalen Variablen im BSS-Segment und das Zusammensetzen
der TOS-Datei nimmt die Prozedur~{\tt SavePrg} vor.

\subsubsection{Der Modullader {\tt OP2Link.GetMod}}
\label{GetMod}

Angelehnt an die Beschreibung der \oberon-Systemroutine {\tt Modules.GetMod}
in \cite[S.~867f]{oberonSystem} hat die gleichnamige Routine des Linkers
die Aufgabe, einen Zeiger auf den Deskriptor des Moduls zur"uckzugeben,
dessen Name mit"ubergeben wurde.
Wenn das Modul sich nicht schon im Hauptspeicher befindet, in welchem Fall
der entsprechende Deskriptor leicht festzustellen ist, l"adt {\tt GetMod} es,
sozusagen als Nebeneffekt, in den Speicher.
Nach dem Anlegen des Moduldeskriptors und dem Einlesen der Bl"ocke der
Objektdatei, stellt {\tt GetMod} fest, welche Importe das Modul ben"otigt,
und wendet sich rekursiv auf diese Module an.

Es folgt das Einlesen und die Initialisierung der Typdeskriptoren, die
im Wesentlichen aus dem Ausf"ullen der Zeiger-Tabelle f"ur die Basistypdeskriptoren
besteht.
Dabei wird die Zeiger-Tabelle des Basistyps kopiert und der Eintrag f"ur
den aktuellen Deskriptor angef"ugt.
Die Adressen der Typdeskriptoren in der Zeigertabelle sind absolut.
Daher m"ussen die Zeiger in der Tabelle mit {\tt EnterReloc} indirekt in die
Relozierungstabelle der TOS-Datei aufgenommen werden.
Gleichsam findet die Initialisierung des im {\it constant block\/} abgelegten
{\it constant type tags\/} statt.
Die Bearbeitung der Deskriptoren kann erst nach dem Laden der Importe
begonnen werden, da der Programmierer die Basistypen von Erweiterungen auch
aus importierten Modulen rekrutieren kann.
Der Zugriff auf die Deskriptoren aus anderen Modulen geschieht "uber den
{\it import block\/} des aktuellen Moduls, in dem beim Laden der Importe
die Modulschl"ussel durch die Adresse der Moduldeskriptoren ersetzt wurden.
Von dort kann {\tt GetMod} mit Hilfe der bekannten, zum dortigen constant block
relativen Adresse des constant type tags den gew"unschten Typdeskriptor
erreichen.

\subsubsection{Die Relozierung und das Ende der ersten Phase}

Im Gegensatz zum dynamischen Lader {\tt Modules.GetMod}
reloziert {\tt OP2Link.GetMod} die Orte im Modulblock, an denen absoluten Adressen
gespeichert sind, auf den Anfang des sp"ateren Programmteils der TOS-Datei
und tr"agt sie in die Relozierungstabelle ein, die zun"achst dynamisch
in Form einer einfach verketteten Liste gehalten und erst kurz vor der
Abspeicherung in die TOS-Datei in das dort ben"otigte Format umgewandelt wird.

Zust"andig f"ur die Verwaltung der Relozierungstabelle ist die
Routine~{\tt EnterReloc}, die "uber die globalen Variablen {\tt relocroot} und
{\tt relocrover} einzelne Orte, an denen absolute Adressen stehen, in die
lineare Liste eintr"agt.
Die anf"anglich sehr schlechte Effizienz von {\tt EnterReloc} war darauf
zur"uckzuf"uhren, da"s mit sehr hoher Wahrscheinlichkeit Eintr"age
am Ende der Liste, die nach aufsteigenden Adressen geordnet ist, auftreten.
Dadurch wurde der bei Gleichverteilung der abzulegenden Adressen zu
erwartende Aufwand von $l/2$ Vergleiche auf $l$ Vergleiche verschlechtert,
wobei $l$ die Anzahl der Listenknoten ist.
Ein nat"urlich wachsender bin"arer Baum w"urde wegen der fehlenden Gleichverteilung
nahezu zu einer linearen Liste degenerieren.
Abhilfe sch"ufe nur ein vollst"andig ausgeglichener oder, abschw"achend, ein
AVL-Baum, dessen Repr"asentations- und Realisationsaufwand nicht gering w"are.

Der Verfasser entschied sich daher f"ur die Einrichtung eines "`Schleppzeigers"'
{\tt relocrover}, der stets auf den zuletzt eingef"ugten Listeneintrag
zeigt.
Das Einf"ugen des n"achsten Eintrags wir zun"achst ab der Stelle, auf die
der Schleppzeiger verweist, versucht, was f"ur die im Linker gegebene
Verteilung der Sortierschl"ussel fast immer funktioniert.
Erst nach dem Scheitern des Einf"ugens am Schleppzeiger beginnt {\tt EnterReloc}
mit dem Durchsuchen der gesamten Liste nach einer passenden Stelle.

\medskip
Die zu {\tt GetMod} lokale Prozedur~{\tt Relocate} f"uhrt die Teilrelozierung
der im {\it entry-}, {\it command-}, {\it code-}, {\it constant-} und
{\it import block} vorhanden absoluten Adressen durch und vermerkt die Orte,
an denen sie gespeichert sind, in der Relozierungstabelle.
W"ahrend die relativen Adressen der Speicherpl"atze f"ur absolute Adressen
in den Bl"ocken der Entries, Commands und Imports implizit durch deren
Struktur vorgegeben ist, kann die Relozierung im code- und constant block nur
mit expliziten Ortsangaben angegangen werden, die im {\it link block\/} der
Objektdatei enthalten sind.
Von den drei Listen der zum code block relativen Ortsangaben werden in
{\tt Relocate} nur die beiden Listen {\tt plink} und {\tt clink} verarbeitet.
Die Liste~{\tt dlink} wird von der zu {\tt SavePrg} lokalen
Routine~{\tt RelocateDLinks} erst in der zweiten Phase benutzt,
da die Basisadressen
der Variablenbereiche, zu denen die durch {\tt dlink} beschriebenen Adressen
reloziert werden, durch die Verschiebung ins BSS-Segment in {\tt Relocate}
noch nicht bekannt sind.

\medskip
Abgeschlossen wird {\tt GetMod} mit dem Eintrag des Moduldeskriptors am
Ende der Deskriptorliste.

\subsubsection{Die zweite Phase des Linkers}

Nachdem nach der Beendigung des {\tt GetMod}-Aufrufs f"ur das zu linkende
Modul die Gr"o"se des Programmteils und damit auch die Anfangsadresse des
Datenteils feststeht, k"onnen in der durch die Routine~{\tt SavePrg}
repr"asentierten zweiten Phase die {\it variable blocks\/} in der
Prozedur~{\tt AllocVariables} alloziert werden.
Alleinig die globalen Variablen des Laufzeitsystem finden Platz im
Datenteil, da sie in {\tt SetRuntimeVariables} initialisiert werden und
somit in der TOS-Datei mit abgespeichert werden m"ussen.
{\tt AllocVariables} legt die restlichen Variablenbereiche im auf dem
Datenteil folgenden BSS-Segment ab, das erst beim Programmstart durch das
Betriebssystem alloziert wird.
Nun k"onnen auch die verbleibenden Bl"ocke reloziert werden, als da sind:
die {\it variable-} und {\it pointer blocks} und die absoluten Adressen
in den Moduldeskriptoren.
Das Ende der zweiten Phase wird mit dem Einrichten des TOS-Dateikopfes und
des Sprungs zur Modulinitialisierung des Laufzeitsystems und dem
Abspeichern des Dateikopfes und des Programm- und Datenteils in die
TOS-Datei eingel"autet.
Der vorher durch den Programm- und Datenteil eingenommene Hauptspeicherbereich
wird nun von der Routine~{\tt TransformRelocationTable} benutzt, um die
dynamisch angelegte Relozierungstabelle in das TOS-Format umzuwandeln.

Nach dem Speichern der Relozierungtabelle in der Datei ist der Linkvorgang
beendet.


\section{Das Laufzeitsystem}
\label{Laufzeitsystem}

Das Laufzeitsystem, in dieser Implementation repr"asentiert durch das
Modul~{\tt Runtime}, wird vom Linker grunds"atzlich mit eingebunden.
Dabei setzt der Linker den hinter dem Kopf der ausf"uhrbaren Datei
befindlichen absoluten Sprung auf den Anfang der Modulinitialisierung
von {\tt Runtime}, soda"s sie beim Programmstart als erstes ausgef"uhrt
wird.
Nach dem Reservieren allen verf"ugbaren Speichers (au"ser {\tt Runtime.ResMem}
Bytes), was bei TOS "ublicherweise in zwei Schritten geschieht,
setzt sie den Stackzeiger auf die erste nicht mehr verf"ugbare Speicherstelle
(der Stack w"achst ja in Richtung niedrigerer Adressen) und ruft die
Modulinitialisierungen in der Reihenfolge auf, in der die Moduldeskriptor-Liste
angelegt ist.
Wurde das letzte Modul initialisiert, terminiert {\tt Runtime}.
Die Modulinitialisierung zumindest eines Moduls (meist des Moduls, das gelinkt
wurde) mu"s hier also als Modulrumpf wirken, wie er von \modula\ bekannt ist.

\medskip
Das Modul~{\tt Runtime} ist eine Mischung zwischen in \oberon\ geschriebenen
Prozeduren und Code-Prozeduren, die der Verfasser mit einem Assembler
vor"ubersetzt und dann per Hand in den Quelltext eingetragen hat.
Es kann, wie jedes andere Modul, mit dem \oberon-Compiler "ubersetzt werden,
was eine Anpassung besonders der Konstanten f"ur die Speicherreservierung,
{\tt ResMem}, {\tt MinMem} und {\tt ResStack}, an die besonderen Verh"alnisse
eines gegebenen Rechners m"oglich macht (das ist bei den Laufzeitsystemen anderer
Sprachimplementationen durchaus nicht "ublich).
Allerdings darf die Reihenfolge weder der globalen Variablen noch der
exportierten Prozeduren ver"andert werden, da sonst "Anderungen im Modul~{\tt OPL}
an den Prozedurnummern aus der Symboldatei von {\tt Runtime}, {\tt RTLIntToReal} $\to$
{\tt RTSYSNew}, und im Linker in der Prozedur~{\tt SetRuntimeVariables} notwendig
w"aren.

Wegen der besonderen Art der Initialisierung anderer Module darf {\tt Runtime}
selbst, abgesehen von {\tt SYSTEM}, keine Importe haben.
Deshalb sind Schnittstellenroutinen zum TOS, die zur Ausgabe von Fehlermeldungen o."A.
benutzt werden, explizit am Anfang des Quelltextes aufgef"uhrt.
Die restlichen Routinen lassen sich in die zwei Kategorien {\em mathematische Operation\/}
und {\tt Heap-Verwaltung} aufteilen.
Im Gegensatz zu den Prozeduren f"ur 32-Bit-Ganzzahl-Arithmetik, {\tt IntMul32},
{\tt IntDiv32}, {\tt IntMod32} und {\tt UMul32}, sind die Prozeduren zur
Umwandlung in Gleitkommazahlen beider Typen, {\tt LIntToReal}, {\tt LIntToLReal},
{\tt RealToLInt}, {\tt RealToLReal}, {\tt LRealToLInt} und {\tt LRealToReal},
und die Gleitkomma-Operationen%
\footnote{Alle in {\bf LONGREAL}, da {\bf REAL}-Operanden vor der Rechnung
in {\bf LONGREAL}  und danach wieder in {\bf REAL} umgewandelt werden.}
{\tt Cmp}, {\tt Add}, {\tt Sub}, {\tt Mul} und {\tt Div} noch nicht implementiert.
Vorlagen f"ur diese Routinen stehen aber zur Verf"ugung.
Aus der gleichen Quelle, dem Laufzeitsystem von {\bf Turbo-C}, Version~1.0 der Firma
{\sl Borland/Heimsoeth}, wurden auch die Ganzzahl-Arithmetik-Routinen entnommen.%
\footnote{Aufgrund des hohen Alters der Version~1.0 von {\bf Turbo-C} lie"s
der Verfasser eventuelle Lizenzrechte unber"ucksichtigt.
Neuere {\bf Turbo-C}-Versionen verwenden andere mathematische Routinen.}
Sie sollen deshalb hier nicht weiter behandelt werden.

Ein Importieren von {\tt Runtime} in anderen Modulen ist zwar m"oglich ---
und im Fall des Garbage Collectors%
\footnote{Zu beachten ist beim Aufruf des Garbage Collectors aber, da"s
der Stack leer ist, damit Strukturen, auf die von lokalen Zeigervariablen
verwiesen wird, nicht f"alschlicherweise als frei deklariert werden.}
auch erw"unscht --- , die Module sollten
aber weder Prozeduren direkt aufrufen noch die exportierten Variablen "andern.
Die Variable~{\tt basepage} wurde in der Tat aufgenommen, um den Zugriff auf
die Kommandozeile in {\tt basepage\caret.CmdLine} und die Environment-Variablen in
{\tt basepage\caret.EnvPtr} zu erleichtern.

\subsection{Die Laufzeitroutinen zur Heap-Verwaltung}

Eindeutig den aufwendigsten Teil des Laufzeitsystems stellten die Routinen
zur Verwaltung des dynamischen Speicherbereichs dar.
Sie wurden aus Effizienzgr"unden teilweise oder vollst"andig in Code-Routinen
realisiert.
Der Heap wird von der Modul-Initialisierung von {\tt Runtime} eingerichtet,
er ist anf"anglich leer und beginnt direkt hinter dem BSS-Segment des
Programms.
Diese Adresse ist festgehalten in der Variablen~{\tt lowmem}, w"ahrend die
erste Adresse, die nicht mehr zum Heap geh"ort, in {\tt currmem} Platz
findet.

\medskip
Der Verfasser gab dem Konzept der f"unf Blockklassen f"ur Bl"ocke der
Gr"o"sen 16, 32, 64, 128 und Vielfache von 128 Bytes, das von Wirth und
Gutknecht in \cite[S. 871]{oberonSystem} vorgeschlagen wurde, anderen
Verfahren wegen der als interessanter eingesch"atzten Implementierung
den Vorrang.
Neben den von Wirth und Gutknecht genannten Vorteilen bescheinigte
Knuth in \cite[S.~448]{artProgramming} dem verwandten {\it buddy system\/}
eine sehr gute Leistungsf"ahigkeit.

\subsubsection{Die Freilisten}
\label{Freilisten}

Die Feld-Variable {\it free\/} ist der Kopf der f"unf Freilisten
f"ur die vom Garbage Collector zur"uckgewonnenen Bl"ocke.
Sie hat den Elementtyp~{\bf LONGINT}, da bei der Verwaltung der Listen
nicht mit den "ublichen \oberon-Zeigern und dem Dereferenzier-Operator
\caret\ sondern mit den Routinen~{\tt SYSTEM.GET} und {\tt SYSTEM.PUT},
die als Inline-Code implementiert sind, gearbeitet wird.

Die Listenknoten sind nicht durch dynamisch allozierte Verbunde realisiert,
die als Komponente die Anfangsadresse eines Blocks enthalten, da das eine
rekursive Benutzung der Heap-Ver\-wal\-tungs\-rou\-tinen zur Folge h"atte;
stattdessen beherbergen die Bl"ocke selbst die notwendigen Informationen.
Der Anfang eines freien Blockes hat deshalb die folgende Struktur:
\begin{itemize}
\item (1 Langwort) die Konstante~0, die w"ahrend des Scannens einen schon
  vormals freien Block von einem unmarkierten, also gerade freigewordenen
  Block unterscheidet;
\item (1 Langwort) der Zeiger auf den n"achsten Block in der Liste;
\item (1 Langwort) die Gr"o"se des Blockes.
\end{itemize}


\subsubsection{Die Allozierung von dynamischem Speicher}

Mit der Standardprozedur~{\bf NEW} und der Prozedur {\tt SYSTEM.NEW},
deren Benutzung vom Compiler in Aufrufe der Laufzeitroutinen~{\tt Runtime.New}
und {\tt Runtime.SYSNew} "ubersetzt wird, kann der Programmierer
dynamischen Speicher anfordern.
Dabei "ubergibt der Compiler den Routinen die Adresse der Variablen, in die
die Prozedur die Adresse des Blocks ablegen soll, die Information, ob der
Block f"ur einen Verbund oder ein Feld zur Verf"ugung gestellt wird, die
Adresse des Typdeskriptors und, im Fall {\tt SYSTEM.NEW}, die Gr"o"se
des gew"unschten Blocks.
Die Information "uber den Datentyp schl"agt sich in erster Linie in der
Markierung im zweith"ochstwertigen Bit des type tags nieder: es wird
gesetzt, wenn der Block f"ur ein Feld verwendet wird.

Als erstes wird die Nummer der Freiliste errechnet.
In {\tt New} kann das "uber die im Typdeskriptor gespeicherte Blockgr"o"se
geschehen, w"ahrend in {\tt SYSNew} der Index zu {\tt free} aus der
"ubergebenen Gr"o"se unter Zuschlagung der Gr"o"se eines Typdeskriptors
berechnet wird.
Da der Garbage Collector und die type guards und -tests einen Typdeskriptor
ben"otigen, in dem ja Hinweise auf die Blockgr"o"se abgelegt sind, mu"s
{\tt SYSNew} f"ur jeden zu allozierenden Block einen eigenen Deskriptor
zusammenbauen; der "Ubergabeparameter~{\tt tag} wird in {\tt SYSNew}
also nicht verwendet.
Die Besonderheiten der so erstellten Deskriptoren sind, da"s eventuell in
den Typen vorhandene Zeiger nicht in die Offset- oder Differenzen-Tabelle
"ubernommen werden, soda"s dynamische Strukturen, auf die nur von solchen
Zeiger verwiesen wird, vom Garbage Collector eingesammelt und als frei
markiert werden.
F"ur erweiterte Verbunde werden keine Basistypen eingetragen,
die Verbunde also als nicht erweitert gef"uhrt.
Daraus folgt,
da"s type guards, deren statische "Uberpr"ufung vom Compiler stattgegeben
wurde, immer fehlschlagen und somit der Zugriff von Variablen eines
Basistyps auf Komponenten der Erweiterung nicht m"oglich ist.
Deshalb obliegt dem Programmier, der {\tt SYSTEM.NEW} verwendet, eine
besondere Verantwortung.

Ein wichtiger Punkt f"ur die Konsistenz der Garbage Collection ist
die Initialisierung aller Zeiger in einer dynamischen Struktur mit {\bf NIL},
ohne die der Garbage Collector m"oglicherweise Felder oder Verbunde vor
sich zu sehen glaubt, die nicht existieren.
Der Einfachheit halber l"oschen {\tt New} und {\tt SYSNew} die
gesamte Struktur ({\bf NIL} wird durch die Langwort-Konstante~0 repr"asentiert).
{\tt New} tut das mit der optimierten Code-Prozedur~{\tt New1}, w"ahrend
{\tt SYSNew} eine in \oberon\ geschriebene Schleife verwendet.

Um einen passenden Block zu finden, rufen beide Routinen die Prozedur~{\tt GetBlock}
auf, wo deutlich der erh"ohte Aufwand f"ur Blocke mit Gr"o"sen von mehr als
128~Byte auff"allt.
Der Schein wird allerdings dadurch zunichte gemacht, da"s {\tt GetBlock} sich
selbst aufruft, wenn f"ur Blockgr"o"sen kleiner oder gleich 128~Byte die
entsprechende Freiliste leer ist.
Vom resultierenden Block doppelter Gr"o"se wird der vordere Teil in die
zuvor leere Liste eingef"ugt, w"ahrend der hintere Teil als alloziert
zur"uckgegeben wird --- sozusagen die Aufteilung eines Blocks in die beiden
{\it buddies}.

Hat der Programmierer einen Block gr"o"ser als 128~Byte erfragt, so
sieht {\tt GetBlock} erst einmal in der f"unften Liste nach.
Ist sie leer oder findet sich kein passender Eintrag, so erweitert {\tt GetBlock}
den Heap nach oben durch Erh"ohung von {\tt currmem} unter Beachtung des
herannahenden Stacks.
Wird der Sicherheitsabstand von {\tt ResStack} Bytes "uberschritten,
kann kein dynamischer Speicher dieser Gr"o"se mehr alloziert werden.
Als Folge davon setzen {\bf NEW} oder {\tt SYSTEM.NEW} die "ubergebene
Zeigervariable auf {\bf NIL}.
Weitere Nachfragen nach kleineren Bl"ocken k"onnen aber durchaus noch
erfolgreich sein, wenn die entsprechende Freiliste nicht leer ist.

Die Nachforschung in der f"unften Liste f"uhrt schon zum Erfolg, wenn
ein Block gefunden wird, der gleich gro"s oder gr"o"ser als der
gew"unschte Block ist, also nicht erst nach einem genau passenden Block
gesucht wird.
``{\it In all experiments comparing the best-fit and first-fit methods,
the latter always appeared to be superior.}''\cite[S.~448]{artProgramming}
F"allt die Wahl auf einen gr"o"seren Block, so kann der entstehende Rest
nur ein Vielfaches von oder gleich 128 Bytes gro"s sein, was ihn entweder
in der f"unften oder der vierten Liste verbleiben l"a"st.


\subsubsection{Die R"uckgewinnung von dynamischem Speicher}

Der Garbage Collector (GC) wird gestartet mit dem Aufruf von {\tt Runtime.GC}.
Er l"auft dann im Supervisor-Mode ab, dem priviligierten Zustand des
Prozessors, in dem insbesondere Interrupts gesperrt werden k"onnen.
Hinter {\tt GCInit} werden in der Tat nur noch Interrupts mit einer
h"oheren Priorit"at als 3 ($7\mathrel{\widehat=}$NMI%
\footnote{Non maskable interrupt}%
) durchgelassen.
Daher ist in mit \oberon\ geschriebenen Interrupthandlern ({\bf PROCEDURE+}\ldots)
die Verwendung von dynamischen Strukturen mit Vorsicht zu genie"sen.

Der GC teilt sich, wie schon mehrfach erw"ahnt, in zwei Phasen auf: die
Mark-Phase, repr"asentiert durch die Code-Prozeduren {\tt GCMark1} und
{\tt GCMark2} (wegen der 256-Byte-Beschr"ankung von Code-Prozeduren getrennt),
markiert alle von globalen Variablen aus zug"angliche dynamischen Strukturen,
die nachfolgende Scan-Phase bewegt sich sequentiell "uber den Speicherbereich,
der vom Heap belegt wird, und sammelt alle unmarkierten Strukturen auf.

\paragraph{Die Mark-Phase}

Die Mark-Phase des GC sucht nacheinander die globalen Variablen aller
Module auf, indem sie die Liste der Moduldeskriptoren abschreitet.
Dabei "uberspringt sie das erste Modul in der Liste, {\tt Runtime},
das zwar globale Zeigervariablen enth"alt, die aber nicht traversiert
werden d"urfen und dies auch nicht n"otig haben, da sie nicht in den
Heap verweisen.
In jedem Moduldeskriptor befindet sich ein Zeiger auf eine Tabelle
der absoluten Adressen der globalen Zeigervariablen mit Namen~{\tt pointerRefs.}
Das Ende der Tabelle wird durch einen negativen Eintrag gekennzeichnet, der
auch vorhanden ist, wenn das Modul keine globale Zeigervariable besitzt.
Der GC fragt zun"achst, ob die Variable den Wert~{\bf NIL} hat, in welchem Falle
er zur n"achsten Variablen schreiten k"onnte.
Enth"alt die Variable aber eine echte Adresse, so beginnt der GC mit dem
rekursiven Algorithmus, der in Abschnitt~\ref{Markieren} ausf"uhrlich
behandelt wurde.
Dabei benutzt er zur Sicherung der Moduladresse und der Adresse des aktuell
bearbeiteten Tabelleneintrags die gleiche Methode der invertierten Zeiger,
wie sie auch im rekursiven Teil des Algorithmus Verwendung findet.
Der Tabelleneintrag zeigt dann auf den aktuellen Moduldeskriptor, w"ahrend
die globale Zeigervariable auf den Tabelleneintrag verweist.

\paragraph{Die Scan-Phase}

Das Durchwandern des Heap wurde schon in Abschnitt~\ref{Scannen} besprochen.
Dieser Abschnitt diskutiert das Einf"ugen von Bl"ocken in die Freilisten und
das Verschmelzen von Bl"ocken zu gr"o"seren Einheiten, da"s einer externen
Fragmentierung des Heap entgegenwirkt.

Neben den globalen Freilisten~{\tt free[0]} bis {\tt free[4]} wurde
in {\tt GCScan} das f"unfelementige Feld~{\tt V} eingerichtet, da"s
in jeder Klasse einen Verweis auf den direkt vor dem aktuellen
Block liegenden {\it buddy\/} gleicher Gr"o"se enth"alt.
Die Verwaltung dieses Buddy-Felds soll an einem Beispiel deutlich gemacht
werden.
Am Anfang des Heaps befinden sich freie Bl"ocke der folgenden Gr"o"sen (in Bytes):
16, 16, 32, 64, 64, 32, 32.
Die Freilisten und das Buddy-Feld sind leer.
Der erste Block wird in {\tt V[0]} "ubernommen und kann mit dem zweiten Block zu
einem 32-Byte-Block verschmolzen werden, der in {\tt V[1]} eingesetzt wird.
{\tt V[0]} ist damit wieder leer.
Der dritte Block findet seinen Buddy in {\tt V[1]}, das Resultat kommt in
{\tt V[2]} und w"achst im darauffolgenden Durchlauf der Scan-Schleife mit
dem ersten 64-Byte-Block zusammen.
Das in {\tt V[3]} gespeicherte Ergebnis kann mit dem folgenden 64-Byte-Block
noch nicht verkoppelt werden, letzterer wird in {\tt V[2]} abgelegt.
Gleiches gilt f"ur den vorletzten 32-Byte-Block, der in {\tt V[1]} landet.
Der im n"achsten Schleifen-Durchlauf aktuelle Block der Gr"o"se~32 Byte l"ost
dann eine Lawine aus: er verschmilzt mit {\tt V[1]}, das Ergebnis mit {\tt V[2]}
und der resultierende 128-Byte-Block mit {\tt V[3]}.
Der 256-Byte-Block befindet sich dann in {\tt V[4]}.

Das Verschmelzen zu einem so gro"sen Block funktioniert nat"urlich nicht
immer.
Ein Beispiel sei die Blockfolge 32, 16, 32.
Die beiden vorderen Bl"ocke werden in {\tt V[0]} bzw. {\tt V[1]} abgelegt.
Der folgende 32-Byte-Block kann mit dem kleinsten Block im Buddy-Feld
nicht verschmolzen werden, die Buddy-Feld-Eintr"age m"ussen also in die
entsprechenden Freilisten "ubernommen werden.
Es best"ande zwar die M"oglichkeit, den 32-Byte-Block in zwei Bl"ocke der
halben Gr"o"se aufzuteilen, von denen der vordere sich mit {\tt V[0]} und darauffolgend
mit {\tt V[1]} vereinigen k"onnte.
Um aber aus dem zweiten 16-Byte-Block einen der Gr"o"se 64 Byte zu machen, der
mit {\tt V[2]} verschmelzen k"onnte, bed"urfte es einer Folgekombination
von Bl"ocken, deren Auftreten vom Verfasser als recht unwahrscheinlich angesehen
wird.
Allerdings wurden auch keine weitergehenden wahrscheinlichkeitstheoretischen
Analysen durchgef"uhrt, die vielleicht den zus"atzlichen Aufwand zur Teilung
des Blockes als gerechtfertigt erweisen w"urden.

Die allgemeine Regel f"ur die "Ubernahme der Bl"ocke im Buddy-Feld lautet
demnach: kann der aktuelle Block mit dem kleinsten im Buddy-Feld gespeicherten
Block nicht verschmolzen werden, wird das gesamte Buddy-Feld in die entsprechenden
Freilisten "ubernommen; es werden niemals nur Teile des Buddy-Feldes in die
Freilisten eingeh"angt.
Die Ausnahme bildet das Ende des Heaps, an dem alle unvereinigten Buddies in
den Freilisten Platz finden.


\section{Was noch zu tun ist}

Die folgende Auflistung gibt einen "Uberblick "uber die zur Zeit der Herstellung
dieser schriftlichen Ausarbeitung noch nicht implementierten Eigenschaften
von Compiler und Laufzeitsystem:
\begin{itemize}
\item in {\tt OPC} fehlt die Code-Erzeugung f"ur die "Uberlauf-Checks bei
  {\tt Mul}, {\tt Div} und {\tt Mod};
\item in {\tt OPCa} sind die Parameter"ubergabe und die Funktionswertr"uckgabe
  von {\bf LONGREAL}-Werten zu erg"anzen;
\item in {\tt OPL} ist die "Ubergabe der Operanden an die Laufzeitroutinen
  f"ur die Gleitkomma-Operatoren und -Konversionen noch zu schreiben;
\item in {\tt Runtime} warten die Laufzeitroutinen f"ur die
  Gleitkomma-Operationen und -Konversionen auf ihre Implementierung.
\end{itemize}

Dar"uber hinaus fand der f"ur den Befehl {\tt System.Free} des \oberon-Systems
notwendige Referenzz"ahler noch keinen Eingang in den Moduldeskriptor.

\medskip
Leider stellte (und stellt!) Prof.~Wirth die Quelltexte des \oberon-Systems
nicht zur Verf"ugung, soda"s weder die \oberon-Version des Compiler noch
das \oberon-System als solches auf den Atari-ST angepa"st werden konnten.

Umso besser k"onnen mit der vorliegenden Software die interessanten
Konzepte der neuen Sprache~\oberon\ pur studiert werden.

\newpage
\section{Literatur}

\begin{thebibliography}{999999999999999}
\bibitem[OP90]{op2doc}
  Crelier, R.: {\it OP2: A Portable Oberon Compiler},
  ETH-Bericht 125, 1990, Departement Informatik, Institut f"ur Computer-Systeme,
  ETH Z"urich
\bibitem[MacOberon90]{macOberonImp}
  Franz, M.: {\it The Implementation of MacOberon},
  ETH-Bericht 141, 1990, Departement Informatik, Institut f"ur Computer-Systeme,
  ETH Z"urich
\bibitem[OberonGuide89]{oberonGuide}
  Gutknecht, J.: {\it The Oberon Guide},
  ETH-Bericht 119, 1989, Departement Informatik, Institut f"ur Computer-Systeme,
  ETH Z"urich
\bibitem[ArtProgramm73]{artProgramming}
  Knuth, D.E.: {\it The Art of Computer Programming, Vol.1},
    Addison-Wesley, Reading, Mass., 1973
\bibitem[OberonSystem91]{oberonSystem91}
	Reiser, M.: {\it The Oberon System, user guide and programmer's guide},
	Addison-Wesley, Reading, Mass., 1991
\bibitem[ProgOberon92]{progOberon}
	Reiser, M.; Wirth, N.: {\it Programming in Oberon, Steps beyond Pascal and
	Modula},
	Addison-Wesley, Reading, Mass., 1992
\bibitem[GarbageColl67]{garbColl}
  Schorr, H.; Waite, W.M.: {\it An Efficient Machine-Independent
    Procedure for Garbage Collection in Various List Structures},
    Communications of the ACM, 8, 10(1967), 501--506
\bibitem[SC68000]{SC68000}
  Valvo (Hrsg.): {\it Der 16bit-Mikroprozessor SC68000},
  Bearbeitet von J.~Koch, 1983, Boysen + Maasch
\bibitem[Compilerbau77]{compilerBau}
  Wirth, N.: {\it Compilerbau}, Teubner, Stuttgart, 1977
\bibitem[ModulaOberon88]{modulaToOberon0}
  Wirth, N.: {\it From Modula to Oberon}, Software --- Practice and
  Experience, 18, 7(1988), 650--670
\bibitem[ModulaOberon89]{modulaToOberon1}
  Wirth, N.: {\it From Modula to Oberon},
  ETH-Bericht 111, 1989, Departement Informatik, Institut f"ur Computer-Systeme,
  ETH Z"urich
\bibitem[ModulaOberon90]{modulaToOberon2}
  Wirth, N.: {\it From Modula to Oberon},
  ETH-Bericht 143, 1990, Institut f"ur Computer-Systeme, Departement Informatik,
  ETH Z"urich
\bibitem[Modula85]{modula2}
  Wirth, N.: {\it Programmieren in Modula-2}, Springer, 1985
\bibitem[Oberon88]{oberon0}
  Wirth, N.: {\it The Programming Language Oberon},
  Software --- Practice and Experience, 18, 7(1988), 671--690
\bibitem[Oberon89]{oberon1}
  Wirth, N.: {\it The Programming Language Oberon (revised report)},
  ETH-Bericht 111, 1989, Departement Informatik, Institut f"ur Computer-Systeme,
  ETH Z"urich
\bibitem[Oberon90]{oberon2}
  Wirth, N.: {\it The Programming Language Oberon (revised report)},
  ETH-Bericht 143, 1990, Departement Informatik, Institut f"ur Computer-Systeme,
  ETH Z"urich
\bibitem[OberonSystem88]{oberonSystem}
  Wirth, N.; Gutknecht, J.: {\it The Oberon System},
  Software --- Practice and Experience, 19, 9(1989), 857--893
\bibitem[ProjectOberon92]{projectOberon}
	Wirth, N.; Gutknecht, J.: {\it Project Oberon, the design of an operating system
	and compiler},
	Addison-Wesley, Reading, Mass., 1992
\bibitem[TypeExt88]{typeExtensions}
  Wirth, N.: {\it Type Extensions},
  ACM Trans. on Prog. Languages and Systems, 10, 2(1988), 204--214
\bibitem[Design89]{design}
  Wirth, N.: {\it Designing a system from scratch},
  Structured Programming, 1(1989), 10--18
\end{thebibliography}

\newpage
\appendix

\section{Die backend-spezifischen Fehlermeldungen}

Die folgende Fehlerliste erg"anzt den Teil~2 der offiziellen
\oberon-Fehlerliste f"ur die NS32000-Implementation mit Stand vom 7. Februar 1990.

\medskip
\begin{tabular}{c|l}
Fehlernr.& Beschreibung\\ \hline
     156 & error writing the object file\\
     172 & couln't delete temporary reference file\\
     173 & couln't delete object file after errors\\
     221 & code table full\\
     242 & address to be allocated is too large\\
     243 & number of constants in code procedure is not even\\
     244 & too many link table entries (global data references)\\
     245 & too many link table entries (constants references)\\
     246 & source scan has found the corresponding text position\\
     253 & register is already reserved\\
     254 & internal error (consult backend programmer)
\end{tabular}

\section{Benutzeranleitung Compiler {\tt OP2.TTP}}
\label{Compileranleitung}

Der \oberon-Compiler~{\tt OP2.TTP} "ubersetzt Quelltexte innerhalb von
Dateien mit der vorgegebenen Endung~{\tt .M} in Objektdateien mit der
Endung~{\tt .OBJ} und ggf. in Symboldateien mit der Endung~{\tt .SYM}.

Eventuelle Fehler protkolliert der "Ubersetzer in einer Datei mit
Namen~{\tt ERR.DAT}, die im Verzeichnis der Quelltexte erstellt wird.
Sie kann mit dem Programm~{\tt OP2CONV.TTP} in eine von dem bekannten
Texteditor~{\bf TEMPUS} verarbeitbare Datei mit dem vorgegebenen
Namen~{\tt ERRTEMP.DAT} tranformiert werden (siehe Abschnitt~\ref{Fehlerdatei-Konverter}).
Die Fehlernummern zusammen mit ihren Bedeutungen sind in der
Datei~{\tt ERRLIST.DOK} festgehalten.

W"ahrend die Objektdateien von einem externen Linker zu einem ausf"uhrbaren
Programm gebunden oder mit einem Loadtime-Linker in das
laufende \oberon-System integriert werden k"onnen, dienen die Symboldateien
dem Compiler zur Konsistenzpr"ufung, wenn das zugeh"orige Modul importiert
wird.

Der Compiler arbeitet in zwei Phasen:
\begin{enumerate}
\item der Quelltext wird auf die lexikalisch, syntaktisch und
  semantisch korrekte Verwendung der Sprache gepr"uft und in einen im
  Hauptspeicher gehaltenen Syntaxbaum "uberf"uhrt.
  Die im Laufe der ersten Phase erstellte Symboldatei besitzt den Namen der
  Quelltextdatei mit der Endung~{\tt .TMP}.
  Sie wird mit der m"oglicherweise schon vorhandenen Symboldatei verglichen
  und, wenn sie sich unterscheiden und die Compileroption {\tt /S} (siehe unten)
  gew"ahlt wurde, als neue Symboldatei mit der korrekten Endung~{\tt .SYM}
  abgespeichert.
  Stellt der Compiler Unterschiede zwischen den Dateien fest, die Option
  wurde aber nicht angegeben, so protokolliert der Compiler den Fehler
  {\tt 155 generation of new symbol file not allowed} in der Datei~{\tt ERR.DAT.}
\item anhand des Syntaxbaumes erzeugt der Compiler entsprechende
  Programmst"ucke in der Maschinensprache des Mikroprozessors~68000.
  Zu jeder Prozedur schreibt er Informationen in eine Tempor"ardatei mit
  Namen~{\tt OP2REF.TMP}, deren Inhalt nach der erfolgreichen Bearbeitung des
  Syntaxbaumes in die Objektdatei "ubernommen wird.
  Ihr Name ergibt sich aus dem Namen der Quelltextdatei und der Endung~{\tt .OBJ}.
\end{enumerate}

\subsection{Die Benutzung des Compilers}

Vom Desktop wird der Compiler~{\tt OP2.TTP} durch einen Doppelklick auf sein
Icon gestartet.
Es erscheint zun"achst eine Dialogbox, in der die Eingabe der Kommandozeile
verlangt wird.
Die Namen von mehreren Quelltextdateien, mit oder ohne Endung~{\tt .M},
k"onnen dort, durch Leerzeichen getrennt, angegeben werden.
Sie werden nach dem Dr"ucken von {\tt RETURN} oder Anklicken des OK-Knopfes
nacheinander "ubersetzt.
Vor einen Dateinamen k"onnen, eingeleitet durch einen Schr"agstrich (/),
mehrere Compileroptionen gesetzt werden, die f"ur die nachfolgenden
Dateien bis zur n"achsten Compileroption oder dem Ende der Kommandozeile
gelten.
Ein Leerzeichen zwischen Option und Dateiname ist obligatorisch.
Die Optionen werden im n"achsten Abschnitt erl"autert.

Von einer Shell startet man den Compiler durch Angabe seines Namens~{\tt OP2.TTP}
und der Namen der zu "ubersetzenden Quelltextdateien, jeweils mit Leerzeichen
separiert.
Auch hier d"urfen Compileroptionen vor die Dateinamen der zu beeinflu"senden
Quelltexte geschrieben werden.

Nach dem Starten des Compilers wird der Bildschirm gel"oscht, und eine Versionsmeldung
ausgegeben.
Danach erscheint f"ur jede Datei {\tt <Quelltextname> compiling <Codegr"o"se> <Gr"o"se des Bereichs der globalen Variablen>},
wenn kein Fehler aufgetreten ist, oder {\tt <Quelltextname> compiling -{}- errors detected}
f"ur den Fehlerfall.
Die Ausgabe der Fehlermeldung mu"s durch einen Tastendruck quittiert werden.

\subsection{Die Compileroptionen}

Hinter dem eine Compileroption einleitenden Schr"agstrich k"onnen ein oder
mehrere Buchstaben angegeben werden, die die folgende Bedeutung haben:
\begin{description}
\item[A] der auf der Kommandozeile nachfolgende Parameter wird als
  Dezimalzahl oder, wenn sie mit einem {\tt H} endet, als Hexadezimalzahl
  interpretiert, die die modulrelative Adresse eines Maschinenbefehls
  beschreibt.
  F"ur die nachfolgend zu "ubersetzenden Quelltexte wird in der Fehlerdatei
  die Stelle in den Quelltexten mit der Fehlernummer~246 protokolliert, an denen
  der Maschinenbefehl der angegebenen Adresse generiert wird.
  Die Option kann zur Lokalisierung von Laufzeitfehlern dienen.
\item[B] Nach der ersten Phase wird der Syntaxbaum in linearisierter Form
  ausgegeben.
  Das Ausgabeformat ist schnell einsichtig, wenn man die inneren Strukturen
  des Compilers kennt.
  Deshalb ist die Option weniger f"ur den Anwendungsprogrammierer als f"ur
  den Backend-Entwickler gedacht.
\item[O] Bei der Umsetzung von Ausdr"ucken in Maschinensprache ist
  garantiert, da"s Seiteneffekte, wie das Ver"andern einer globalen Variable,
  die fr"uher oder sp"ater im selben Ausdruck auftaucht, in einer gerade
  aufgerufenen Funktion, die erwartete Wirkung haben.
  Allerdings sch"opft der generierte Code dann oft nicht die durch den
  Mikroprozessor gegebenen Adressierungm"oglichkeiten aus und produziert
  l"angere Codesequenzen.
  Mit der Compileroption~{\tt O} kann nun die optimierte Codegenerierung
  auf Kosten undefinierter Seiteneffekte gew"ahlt werden.
\item[R] Durch Anwahl der Option~{\tt R} erfolgt f"ur Mengenoperationen
  eine Bereichsabpr"ufung, die bei Unter- oder "Uberschreitung des
  erlaubten Bereichs einen Laufzeitfehler Nr.~8 zur Folge hat.
\item[S] Hat sich die Symboldatei, also die Zusammensetzung oder Struktur
  der exportierten Objekte, ge"andert, so wird, bei Angabe der Option~{\tt S},
  die alte Symboldatei durch die neue ersetzt.
  Fehlt die Option, gibt der Compiler einen Fehler mit der Nummer~155 aus.
  Diese Sicherheitsma"snahme ist erforderlich, da m"oglicherweise viele
  Module von der Schnittstelle des eben "ubersetzten Moduls abh"angen,
  deren ungewollte "Anderung zu unn"otigen Inkompatibilit"aten mit diesen Modulen
  f"uhren w"urde.
  Die Generierung einer Symboldatei mu"s daher explizit durch Angabe dieser Option
  herbeigef"uhrt werden.
\item[T] Die Generierung von Code zur Durchf"uhrung von type guards, regional type
  guards und implicit type guards kann durch Angabe der Option~{\tt T} unterdr"uckt werden.
\item[V] Treten bei mathematischen Operationen "Uberl"aufe auf, so erscheint,
  wenn die Option~{\tt V} gew"ahlt wurde, ein Laufzeitfehler mit der Nummer~9.
\item[X] Die Angabe dieser Option unterdr"uckt die Generierung von Code zur
  "Uberpr"ufung von Indexgrenzen bei der Indizierung von Feldern.
  Wird die Option weggelassen, erfolgt bei Unter- oder "Uberschreitung einer
  Indexgrenze der Laufzeitfehler Nr.~6.
\end{description}

\section{Benutzeranleitung Fehlerdatei-Konverter {\tt OP2CONV.TTP}}
\label{Fehlerdatei-Konverter}

Die vom \oberon-Compiler~{\tt OP2.TTP} erzeugte Fehlerdatei~{\tt ERR.DAT}
besteht aus ASCII-Text und hat das folgende Format:
\begin{itemize}
\item in der ersten Zeile befindet sich linksb"undig der Name der Quelltextdatei.
\item in jeder der folgenden Zeilen steht in einem zehnstelligen Feld rechtb"undig
  die Fehlerposition im Quelltext, angegeben in Zeichen ab dem Textanfang,
  gefolgt von einem Leerzeichen und einem sechsstelligen Feld, in dem
  rechtb"undig die Fehlernummer aufgef"uhrt ist.
\end{itemize}
Als Zeichen, die zur Bestimmung der Fehlerposition eingerechnet werden,
z"ahlen auch Wagenr"ucklauf ({\tt 0CX}), Zeilenvorschub ({\tt 0AX}) und
Tabulator ({\tt 09X}).

Im Gegensatz zum {\tt Edit.Locate}-Befehl des \oberon-Systems findet sich
in der Atari-Umgebung kein dem Autor bekannter Texteditor, der anhand
der absoluten Zeichenzahl ab Dateianfang den entsprechenden Ort angeben kann.
Um dennoch die Positionier-F"ahigkeiten des wohl beliebtesten Texteditors auf
dem Atari-ST, dem {\bf TEMPUS} von {\it CCD, Eltville}, nutzen zu k"onnen,
schrieb der Autor ein Hilfsprogramm, da"s die vom Compiler generierte
Fehlerdatei in eine Datei mit Namen~{\tt ERRTEMP.DAT} und dem folgenden Format
umwandelt:
\begin{itemize}
\item die erste Zeile besteht wieder aus dem linksb"undig eingeschriebenen
  Quelltextdateinamen.
\item in jeder weiteren Zeile wird rechtb"undig in ein sechsstelliges Feld
  die Zeilennummer, gefolgt von einem caret (\caret) und der linksb"undigen
  Spaltennummer ausgegeben.
  Ab Spalte~11 findet in einem vierstelligen Feld die Fehlernummer rechtb"undig
  Platz.
\end{itemize}

Ein so spezifizierter Ort kann im {\bf TEMPUS} wie folgt aufgesucht werden:
\begin{enumerate}
\item nach dem Start von {\bf TEMPUS} werden die Quelltextdatei und die
  konvertierte Fehlerdatei~{\tt ERRTEMP.DAT} geladen.
\item Der Fokus wird auf das Fenster mit der Quelltextdatei gesetzt.
\item Mit dem Mauszeiger wird auf die Ortsbezeichnung des Fehlers gezeigt,
  den man aufsuchen will, und die rechte Maustaste gedr"uckt.
\item Der Cursor im Quelltext-Fenster erscheint auf der Fehlerstelle.
\end{enumerate}

\subsection{Die Benutzung des Konverters}

Der Fehlerdatei-Konverter~{\tt OP2CONV.TTP} wird im Desktop durch einen Doppelklick
auf sein Icon oder in einer Shell durch Angabe seines Namens, gefolgt von {\tt RETURN},
gestartet.
Auf dem Desktop erscheint die Dialogbox zur Eingabe einer Kommandozeile,
die aber mit {\tt RETURN} oder Dr"ucken des OK-Knopfes quittiert werden kann.
In der Kommandozeile k"onnte ein anderer Name f"ur die Fehlerdatei angegeben
werden.
Da der Compiler seiner Fehlerdatei immer {\tt ERR.DAT} nennt, kann auf die
Eingabe eines Namens verzichtet werden; in diesem Fall benutzt {\tt OP2CONV.TTP}
den vom Compiler vorgegebenen Namen.

Nach dem Starten l"oscht das Programm den Bildschirm und gibt die Namen der
alten und neuen Fehlerdatei und der Quelltextdatei aus.

\section{Benutzeranleitung Linker {\tt OP2LINK.TTP}}

Der Linker stellt aus der Objektdatei eines Moduls und den Objektdateien
der importierten Module ein unter dem Betriebssystem des Atari-ST, TOS,
lauff"ahiges Programm her.
Dies geschieht in drei Schritten:
\begin{enumerate}
\item das im Modul~{\tt Runtime} untergebrachte Laufzeitsystem wird in
  den Speicher geladen,
\item das zu bindende Modul und seine Importe werden in {\it depth first order\/}
  geladen, d.h. zuerst werden die Importe eines importierten Moduls
  geladen, ehe das n"achste importierte Modul an die Reihe kommt,
\item einige interne Strukturen werden reloziert und die einzelnen
  Teile des neuen TOS-Programms werden in eine Datei abgelegt.
\end{enumerate}

Wichtig ist, da"s die Variablenbereiche aus den Modulbl"ocken heraus in
das BSS-Segment verlagert worden sind und somit in der Datei keinen Platz
in Anspruch nehmen.

\subsection{Die Benutzung des Linkers}
Mit einem Doppelklick auf sein Icon wird der Linker~{\tt OP2LINK.TTP}
vom Desktop aus gestartet, wobei zun"achst eine Dialogbox erscheint,
in die die Namen der zu linkenden Module, getrennt durch Leerzeichen,
geschrieben werden.
Durch Dr"ucken der {\tt RETURN}-Taste oder Anklicken des OK-Knopfes in der
Box wird der Linker entg"ultig geladen und ausgef"uhrt.
In einer Shell wird zum Starten der Linkername {\tt OP2LINK.TTP}, gefolgt
von den Modulnamen, angegeben und {\tt RETURN} gedr"uckt.
Der Bildschirm leert sich, der Programmname wird ausgegeben.
In weiteren Zeilen erscheint f"ur jedes angegebene Modul {\tt <Modulname>
linking <Programmteill"ange> <BSS-Segment-L"ange>}, jeweils nachdem das
vorherige Modul fertig gelinkt wurde.


\subsection{Die Linkeroption}

Zur Zeit ist nur die Option {\tt /D} implementiert, deren Angabe vor
dem betreffenden Modulnamen die Ausgabe von zus"atzlichen Informationen
bewirkt, die hier nicht weiter besprochen werden sollen.

\newpage
\pagenumbering{Roman}
\tableofcontents

\end{document}
