Oberon-2

From Atari Wiki
Revision as of 09:54, 24 October 2006 by Zorro 2 (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search














                              *STJ-OBERON-2 *


                      *Eine Oberon-2 Implementation
                          fr Atari ST/STe/TT *








                                     von
                              Stephan Junker





                             28. November 1993








Inhaltsverzeichnis
==================

1) Einleitung
  1.1) Stand der Entwicklung
  1.2) Geplante Entwicklung
  1.3) Benutzungsbedingungen
  1.4) Fehlermeldungen
  1.5) Kontakt
2) Von Modula-2 nach Oberon-2
  2.1) Streichungen
    2.1.1) Datentypen
    2.1.2) Module und Import-/Exportregeln
    2.1.3) Anweisungen
    2.1.4) Low-Level Anweisungen
  2.2) Neue Features
    2.2.1) Typerweiterung
    2.2.2) Typgebundene Prozeduren
    2.2.3) Typinklusion
  2.3) Sonstige Unterschiede
3) Allgemeine Erl„uterungen
  3.1) Suchpfade
  3.2) Dateien
  3.3) Einstellung der Shell
4) Installation
  4.1) Start
5) Der Compiler
  5.1) Aufruf, Parameter
  5.2) Environmentvariablen
  5.3) Optionen im Quelltext
  5.4) Ausgabe
  5.5) Vordefinierte Prozeduren
  5.6) Unterschiede zum Standard-Oberon-2
  5.7) Bekannte Fehler
6) Der Assembler
  6.1) Symbolkonventionen
    6.1.1) Formelausdrcke
  6.2) Pseudobefehle
    6.2.1) SET und EQU
    6.2.2) CHARSET
    6.2.3) CPU
    6.2.4) SUPMODE
    6.2.5) SEGMENT
    6.2.6) DC,DS
    6.2.7) ALIGN
    6.2.8) MACRO
    6.2.9) IRP
    6.2.10) REPT
    6.2.11) Bedingte Assemblierung
    6.2.12) Lokale Label
  6.3) Hochsprachenelemente
    6.3.1) IF cond THEN ... ELSIF ... ELSE ... END
    6.3.2) REPEAT ... UNTIL cond
    6.3.3) LOOP ... END
    6.3.4) EXIT [(Zahl)]
  6.4) Diverses
    6.4.1) INCLUDE
    6.4.2) MESSAGE, WARNING, ERROR und FATAL
  6.5) Zugriff auf Oberon-Bezeichner
7) Der Linker
  7.1) Aufruf, Parameter
  7.2) Environmentvariablen
8) Die Lader
  8.1) Aufruf, Parameter
  8.2) Ausgabe
9) Das Make-Utility
  9.1) Aufruf, Parameter
  9.2) Environmentvariablen
  9.3) Hinweise
10) Der Scanner
  10.1) Aufruf, Parameter
  10.2) Environmentvariablen
11) Debugging
  11.1) DB
  11.2) Bugaboo
  11.3) Tips
12) Utilities
  12.1) Der Browser
  12.2) Inline-Zeilen erzeugen
13) Speicherverwaltung
  13.1) Benutzung in Programmen
  13.2) Implementierung
14) Die Bibliotheken
  14.1) Betriebssystem
    14.1.1) BIOS
    14.1.2) GEMDOS
    14.1.3) MiNT
    14.1.4) XBIOS
  14.2) Abstrakte Datenstrukturen
    14.2.1) BinTree
    14.2.2) CDCL
    14.2.3) DCL
    14.2.4) FIFO
    14.2.5) LRU
    14.2.6) Stack
  14.3) Standardmodule
    14.3.1) Buffers
    14.3.2) CommandLine
    14.3.3) Cookie
    14.3.4) Datum
    14.3.5) Environment
    14.3.6) Error
    14.3.7) Exceptions
    14.3.8) Execute
    14.3.9) File
    14.3.10) FileBuffer
    14.3.11) Filename
    14.3.12) IO
    14.3.13) Kernel
    14.3.14) Key
    14.3.15) MathCom
    14.3.16) MathLib0
    14.3.17) Memory
    14.3.18) Modules
    14.3.19) MVC
    14.3.20) NumStr
    14.3.21) Paths
    14.3.22) Strings
    14.3.23) Supervisor
    14.3.24) Sys
    14.3.25) Task
    14.3.26) VA
  14.4) VDI-Module
    14.4.1) VDI
    14.4.2) VDIAttributes
    14.4.3) VDIControl
    14.4.4) VDIExcapes
    14.4.5) VDIInput
    14.4.6) VDIInquiry
    14.4.7) VDIOutput
    14.4.8) VDIRaster
  14.5) AES-Module
    14.5.1) AES
    14.5.2) Appl
    14.5.3) Evnt
    14.5.4) Form
    14.5.5) Fsel
    14.5.6) Graf
    14.5.7) Menu
    14.5.8) Objc
    14.5.9) Rsrc
    14.5.10) Wind
  14.6) Erweiterte AES-Module
    14.6.1) Dialogs
    14.6.2) FontSelect
    14.6.3) GemApp
    14.6.4) GEMIO
    14.6.5) Menus
    14.6.6) TermWin
    14.6.7) WindowDialog
    14.6.8) WinView
15) Tutorial
  15.1) Die Resourcedatei
  15.2) Der Rumpf
  15.3) Resourcedatei laden
  15.4) Die Menzeile
  15.5) Ein Fenster ”ffnen
  15.6) Einen Dialog darstellen
  15.7) Das fertige Programm
  15.8) Zusammenfassung
16) Anhang
  16.1) Literatur
  16.2) Danksagungen


1) Einleitung
=============

Die Entstehung dieses Oberon-Systems begann kurz vor Weihnachten  '92,  als
Frank Storm mir die Quelltexte zum Oberon-1 Compiler von Niklaus  Wirth  in
die Hand drckte.  Zun„chst mužte ich den in Oberon geschriebenen  Compiler
in Modula umschreiben und den Codegenerator auf 68000 „ndern.  Der  n„chste
Schritt war dann natrlich,  das ganze wieder in Oberon umzuschreiben. Dies
war bis M„rz '93 geschafft,  seitdem programmiere ich nur noch  in  Oberon.
Inzwischen sind etliche Monate vergangen, in denen ich fleižig Fehler beho-
ben und Erweiterungen eingebaut habe. Trotzdem wird noch einige Zeit verge-
hen, bis diese Software den Betateststatus verliert.

1.1) Stand der Entwicklung
--------------------------

Der Kern einer Programmiersprache ist natrlich der Compiler.  Dieser  wird
erg„nzt durch Linker,  Lader, Make und Scanner. Zus„tzlich gibt es noch ei-
nige Utilities.  Alles wird als Objektmodule ausgeliefert und vom Installa-
tionsprogramm zu ausfhrbaren Programmen gelinkt.   Aber erst durch umfang-
reiche Libraries wird eine Programmiersprache benutzbar. Die meisten Module
sind von mir im Laufe von mehreren Jahren programmiert worden.  Einige sind
auch von anderen Autoren,  und weitere Implementationen sind natrlich  er-
wnscht.

  Der Compiler hat bereits starke Erweiterungen gegenber dem von Wirth er-
fahren.  Dies ist zwar unsch”n,  weil dadurch wieder Inkompatibilit„ten  zu
anderen Compilern entstehen,  aber sie erleichtern die Programmierung. Wenn
man portable Programme schreiben m”chte,  muž man auf  diese  Erweiterungen
verzichten.

1.2) Geplante Entwicklung
-------------------------

Zun„chst steht die Entwicklung einer Load-Time-Linking Entwicklungsumgebung
mit Chatwin auf dem Plan.  Dann fehlt noch  ein  Source-Level-Debugger.  Da
werde ich mich irgenwann mal drangeben.  Die Codequalit„t k”nnte auch  noch
verbessert werden, dazu geh”rt auch 68030- und FPU-Untersttzung. Ansonsten
werden natrlich st„ndig noch Fehler  behoben  und  Bibliotheksmodule  ver-
bessert.

1.3) Benutzungsbedingungen
--------------------------

STJ-Oberon-2 ist Shareware. Die ”ffentliche Version darf in Mailboxen hoch-
geladen und auf PD-Disketten bis 5 DM pro Diskette vertrieben werden.  Wenn
man dauerhaft damit arbeiten m”chte, muž man den Sharewarebeitrag von 50 DM
entrichten.  Dafr bekommt man die neueste Version auf Diskette zugeschickt
(also Adresse nicht vergessen!).  Diese enth„lt eine private  Version,  die
nicht weitergegeben werden darf.  Darauf ist zus„tzlich diese Anleitung als
DVI-File sowie der fehlende optimierende Linker.  Auf Wunsch kann  ich  die
Anleitung auch in eine Postscriptdatei umwandeln.  M”chte jemand  eine  ge-
druckte Anleitung (Laserdrucker) mit Ringbindung, kostet dies 20 DM extra.

  Wer am System mitarbeitet oder mitgearbeitet hat,  kann einen individuel-
len Rabatt erhalten. Einfach mal anfragen.

1.4) Fehlermeldungen
--------------------

Das ganze System ist noch in der Entwicklungs- und Betatestphase. Ich weiž,
daž es noch einige Macken hat. Ich bemhe mich, sie noch alle zu entfernen.
Ich bernehme keine Garantie fr die  Funktionsf„higkeit  dieses  Programms
und hafte nicht fr Sch„den,  die dieses Programm verursacht.  Falls Fehler
entdeckt werden, sollte man mich m”glichst genau darber informieren.

1.5) Kontakt
------------

  Stephan Junker
  Heuvel 1A
  NL-6291 CP Vaals

  E-Mail, MausNet : Stephan Junker @ AC2

    Sparkasse Aachen
  Kontonummer : 16013351
  Bankleitzahl: 390 500 00


2) Von Modula-2 nach Oberon-2
=============================

Fr diejenigen,  die Modula kennen und evtl.  umsteigen m”chten,  werde ich
hier kurz die Unterschiede zwischen Modula-2  und  Oberon-2  auflisten.  Es
soll keineswegs eine Sprachbeschreibung ersetzen,  sondern nur  einen  Ein-
druck von den neuen M”glilchkeiten vermitteln, um das Interesse zu wecken.

2.1) Streichungen
-----------------

Niklaus Wirth hatte den Mut,  einige Features  von  Modula-2  ersatzlos  zu
streichen.  Dahinter stand das Konzept, die Sprache Oberon auf das Wichtig-
ste zu konzentrieren und damit einen kleinen,  schnellen Compiler zu reali-
sieren.  Diese Streichungen sind nicht bei allen  Modula-Programmieren  auf
Gegenliebe gestožen, aber man kann damit leben.

2.1.1) Datentypen
.................

_Variante Records_ wurden eliminiert, da sie die Implementation einer Spei-
cherverwaltung mit Garbage Collector im  Wege  stand.  Ihre  Funktionalit„t
wurde durch erweiterbare Typen erhalten[1].
_Opake Typen_ wurden berflssig,  da man Records nicht mehr  komplett  ex-
portieren muž. Die Auswahl einzelner Feldelemente ist wesentlich flexibler.
_Aufz„hlungstypen_ standen der  Erweiterung  ber  Modulgrenzen  hinweg  im
Wege.  Aužerdem fhrte ein Import des Typbezeichners zum impliziten  Import
aller assoziierten Konstantenbezeichner.
_Unterbereichstypen_ hatten nicht den Nutzen,  der die dafr n”tige zus„tz-
liche Komplexit„t des Compilers rechtfertigt.
_Mengen_ wurden zu einem einzigen  Typ  reduziert:  SET.  Diese  Menge  be-
inhaltet alle Zahlen von 0 bis  zu  einem  implementationsabh„ngigen  Maxi-
mum[2]. Dies resultiert aus der Elimination von Aufz„hlungs- und Unterbereichstypen.
Der Typ _CARDINAL_ wurde eliminiert,  da die Benutzung  von  32-Bit  Werten
dies unn”tig macht[3].
_Zeigertypen_ k”nnen nur noch auf Records und Arrays zeigen. Dies h„ngt da-
mit zusammen, das der Zeigeroperator '^' nicht mehr benutzt werden muž.
_Indextypen_ k”nnen nicht mehr angegeben werden.  Stattdessen gibt man  nur
noch die Anzahl Elemente des Arrays an.

---------------

 [1]  nicht ganz, wie ich meine

 [2]  bei STJ-Oberon-2 ist das Maximum 31

 [3]  man beachte, daž damit keine vorzeichenlosen Vergleiche m”glich sind


2.1.2) Module und Import-/Exportregeln
......................................

_Lokale Module_ wurden eliminiert, da sie nur selten benutzt wurden und den
Compiler unn”tig schwierig machten.
_Unqualifizierter Export_ ist nicht mehr m”glich,  d.h.  man gibt nur  noch
den Namen eines Moduls in der Importliste an und  muž  immer  mit  vorange-
stelltem Modulbezeichner auf die exportierten Bezeichner zugreifen.  Um die
Tipparbeit ein wenig zu reduzieren,  ist es  m”glich,  den  Import  umzube-
nennen. Dafr schreibt man beim Import 'Abk:=Abkuerzung', z.B. 'WDial:=WindowDialog'.
Das _Hauptmodul_ als solches gibt es nicht mehr. Alle Module sind gleichbe-
rechtigt, d.h. daž auch alle Module linkf„hig sind.
_Definitionsmodule_ sind fr den Compiler nicht mehr n”tig, aber man sollte
sie natrlich fr den Programmierer erzeugen.  Dafr ist der Browser vorge-
sehen.  Der Export geschieht jetzt, indem man hinter einem Bezeichner einen
Stern fr normalen oder ein Minuszeichen (bei Variablen und  Feldelementen)
fr Read-Only Export angibt.

2.1.3) Anweisungen
..................

Die _WITH-Anweisung_ wurde eliminiert,  da der qualifizierte Zugriff zu be-
vorzugen ist. Diese Anweisung hat in Oberon jetzt eine andere Funktion.

2.1.4) Low-Level Anweisungen
............................

_ADDRESS_ und _WORD_ wurden durch BYTE ersetzt.  _Typumwandlungsfunktionen_
mit vorangestelltem Typbezeichner und _absolute Addressierung_ wurden  eli-
miniert.

2.2) Neue Features
------------------

2.2.1) Typerweiterung
.....................

Es ist m”glich, einen bestehenden Recordtyp zu erweitern.
Beispiel: Wenn Typ Point so

Point = RECORD x,y : INTEGER END

definiert ist, kann man ihn so

Rect = RECORD(Point)  w,h : INTEGER END

erweitern.  Typ Rect hat dann die Elemente x,y,w,h.  Dann ist  es  m”glich,
Prozeduren zu definieren,  die einen Typ Point als Parameter erwarten,  und
diesen einen Typ Rect zu bergeben.  Analog gilt dies fr Zeiger auf solche
Typen.  Mit einem Typeguard der Form var(typ) kann man zur Compilezeit  den
Typen festlegen. Zur Laufzeit wird dann berprft, ob die Variable var tat-
s„chlich den Typ typ hat. Wenn nicht, wird das Programm abgebrochen. Es ist
auch m”glich, den Typ einer Variablen abzufragen. Der Ausdruck

var IS typ

liefert TRUE, wenn var vom (dynamischen) Typ typ ist.

  Diese Abfrage inklusive eines regionalen  Typeguards  leistet  das  WITH-
Statement:

WITH var : Point DO (* wenn var vom typ Point ist *)
       var.x := 0      (* dann x l”schen *)
   | var : Rect DO     (* ist es ein Rect *)
       var.w := 0      (* dann w l”schen *)
   ELSE                (* sonst *)
   END;                (* nichts *)

2.2.2) Typgebundene Prozeduren
..............................

Es ist m”glich, Prozeduren an einen Recordtyp zu binden. In der Sprache des
OOP sind dies dann Methoden,  die auf dem Typ arbeiten, an den sie gebunden
sind.  Im Gegensatz zu anderen Ans„tzen werden bei Oberon jedoch keine  Be-
zeichner implizit bergeben, sondern explizit angegeben. Eine solche Proze-
dur wird so

PROCEDURE (VAR p : Point) Clear;
 BEGIN
  p.x := 0; p.y := 0;
 END;

definiert und mit

point.Clear

aufgerufen. Statt VAR Point k”nnte man auch einen Zeiger auf Point ohne VAR
angeben.  Man kann jetzt hingehen und eine Prozedur Clear an  Rect  binden.
Der Name ist nicht etwa schon benutzt,  denn er ist ja nur innerhalb  eines
Typs Point sichtbar.

PROCEDURE (VAR r : Rect) Clear;
 BEGIN
  r.w := 0; r.h := 0;
  r.Clear^;
 END;

Dieses Clear l”scht erst w und h,  um dann mit r.Clear^die geerbte Prozedur
Clear aufzurufen, die x und y l”scht.

2.2.3) Typinklusion
...................

Die Integer- und Realtypen sind jeweils Teilmengen des n„chst gr”žeren  Be-
reichs. Daher ergibt sich folgende Hierarchie:
LONGREAL > REAL > LONGINT > INTEGER > SHORTINT
Das bedeutet,  daž ein Wert eines untergeordneten Typs  einem
h”heren zugewiesen werden kann.

2.3) Sonstige Unterschiede
--------------------------

_Prozedurtypen_ werden mit Dummynamen fr die Parameter angegeben.
_Globale Variablendeklarationen_ mssen immer vor der ersten Prozedur erfolgen.


3) Allgemeine Erl„uterungen
===========================

3.1) Suchpfade
--------------

 Suchpfade sind solche Pfade, in denen nach Dateien gesucht wird. Viele der
Systemprogramme ben”tigen Suchpfade, aber alle bauen auf einem Modul namens
Paths  auf.   Daher  verlangen  alle  Programme  den  gleichen  Aufbau  der
Suchpfade.  Definiert werden sie mit  einer  Environmentvariablen.  Mehrere
Suchpfade mssen mit Komma oder Semikolon getrennt werden. Ein Backslash am
Ende ist m”glich,  aber nicht n”tig.  Eine kleine M”glichkeit fr Wildcards
ist vorgesehen:  Der letzte Order einer  Suchpfaddefinition  darf  ein  '*'
sein,  so daž alle Ordner in diesem Directory durchsucht werden.  Die Suche
beginnt immer mit dem zuletzt angegebenen Pfad.
Beispiel: MODPATH=E:\OBERON\GEM,E:\OBERON\STD\
Damit  k”nnen  alle  Dateien  gefunden  werden,  die  den  Mustern  E:\OBE-
RON\GEM\*.*und E:\OBERON\STD\*.*gengen.
Beispiel: MODPATH=E:\OBERON\LIB\*
Damit k”nnen alle Dateien gefunden werden, die den Mustern E:\OBERON\LIB\*\*.*gengen.
Wenn im folgenden also von 'Suchpfaden' die Rede ist,  sind  Environmentva-
riable mit obigem Inhalt gemeint.

  Eine Besonderheit der Suchpfade m”chte  ich  hier  schon  erw„hnen:  Eine
sinnvolle Einstellung ist es,  nur MODPATH zu definieren.  Dann wird  immer
dort gesucht und Ausgaben des Compilers werden bei den Sourcen gespeichert.
In dieser Form werden die Dateien auch ver”ffentlicht. Es ist aber m”glich,
die verschiedenen Dateitypen in getrennten Ordnern zu  bewahren.  Dazu  muž
man fr jeden Dateityp einen Suchpfad definieren und die Ausgaben des  Com-
pilers werden in den letzten Suchpfad geschrieben.  Diese Suchpfade  heižen
OBJPATH, SYMPATH und INFPATH.

3.2) Dateien
------------

Das System unterscheidet vier verschiedene Dateien:

  1) Die Quelltexte mit der Extension MOD.

  2) Die Objektmodule mit der Extension OBJ.  Diese nehmen den  Code  eines
     Moduls auf.

  3) Die Symboldateien mit der Extension SYM. Diese enthalten Informationen
     ber exportierte Bezeichner.

  4) Die Infodateien mit der Extension INF. Diese enthalten zus„tzliche In-
     formationen zu Modulen.  Momentan sind das zum Beispiel ein  Programm-
     name und Optimierungsinformationen. Sp„ter sollen die Infodateien dann
     auch Informationen fr den Source Level Debugger aufnehmen.

  5) Die Fehlerdateien mit der Extension ERR.  Darin werden Fehler, die der
     Compiler findet, in einem frei w„hlbaren Format notiert.

3.3) Einstellung der Shell
--------------------------

DIe Shell,  mit der man arbeitet, sollte man mittels Batchfile beim Starten
schon vernnftig konfigurieren. Dies ist ein Beispiel-Setup fr Chatwin:

alias make e:\oberon\Make.TTP $*
    alias opt e:\oberon\OPTIMIZE.TTP $*
    alias scan e:\oberon\SCAN.TTP $*
    alias lt e:\oberon\LOAD.TTP $*
    alias lg e:\oberon\LOAD.PRG $*
    alias browse e:\oberon\browse.ttp $*
    env OC=e:\oberon\compile.ttp
    env MODPATH=E:\OBERON\LIB\*
    env LINKALSO=Exceptio

  Desweiteren empfiehlt es sich,  fr jedes Projekt  eine  Batchdatei  ein-
zurichten,  in der Pfade,  Namen, Extension etc. definiert werden. Hier ist
mal ein Beispiel, daž ich fr das Installationsprogramm verwende:

env MODPATH=E:\OBERON\LIB\*,E:\OBERON\INSTALL\
    env PRGEXT=PRG
    env PRGPATH=E:\OBERON\
    env LINKALSO=Exceptio
    dellist *
    addlist e:/oberon/install/install.mod
    addlist e:/oberon/install/linker.mod
    addlist e:/oberon/install/syminld.mod


4) Installation
===============

 Das Installationsprogramm INSTALL.PRG ist das einzig  lauff„hige  Programm
in der Distribution. Es erzeugt alle Programme, die fr die Arbeit mit STJ-
Oberon-2 ben”tigt werden.

4.1) Start
----------

Beim Start von Install erscheint eine Dialogbox.  Dort sieht  man  zun„chst
neun Buttons mit jeweils einem Namen dran.  Selektiert sind alle  Programme
aužer Oberon[4]. W„hlen sie die Programme, die sie haben wollen.

  Stellen sie nun ein, ob die Programme eine Symboltabelle haben oder opti-
miert[5] werden sollen.  Die Symboltabelle kostet nur unn”tig  Platz,  also
verzichten sie lieber darauf.

  Als letztes k”nnen sie einen Zielpfad fr die Programme  angeben.  Dieser
wird anfangs auf den Pfad gesetzt,  in dem auch  das  Installationsprogramm
steht.

  Wenn sie nun den Knopf 'Installieren' anw„hlen,  verschwindet die Dialog-
box und ein Terminalfenster wird ge”ffnet. Dort erscheinen die Ausgaben des
Linkers, der alle selektierten Programme linkt. Dabei sind die Suchpfade so
eingestellt, wie sie in der Distribution sind, also LIB\*\,SYS\ und TOOLS\,
jeweils vom Directory ausgehend,  in dem das  Installationsprogramm  steht.
Wenn sie also gerade erst das Archiv ausgepackt haben und dabei die Ordner-
struktur nicht verloren ging, mssen die Module auch gefunden werden.

  Hinweis:  Im Prinzip ist der Linker auch in der Lage,  die T„tigkeit  des
Installationsprogramms durchzufhren. Lediglich die Lader und Oberon k”nnen
nicht vom normalen Linker gelinkt werden.

---------------

 [4]  denn Oberon gibt's noch nicht

 [5]  Die Optimierung funktioniert leider noch nicht



5) Der Compiler
===============

  Der Compiler des Oberon-Systems (COMPILE.OBJ/TTP) entstand aus  dem  Obe-
ron-1 Compiler von Niklaus Wirth.  Er wurde unter anderem um einen Makroas-
sembler erweitert und ist jetzt weitgehend auf Oberon-2-Standard.

5.1) Aufruf, Parameter
----------------------

  Der Compiler sollte von einer Shell aus benutzt werden,  die zumindest in
der Lage ist,  Environmentvariablen zu setzen, denn der Compiler liest dort
seine Optionen.  Beim Aufruf kann man als Kommando  einige  Optionen  sowie
eine Liste von Namen,  getrennt mit Leerzeichen,  bergeben.  Diese  Module
werden nacheinander bersetzt. Die Syntax sieht also so aus:

compile {<Option>} <Name> {<Name>}

Das Format des Namens wird flexibel gehandhabt.  Ein  Name  mit  Pfadangabe
wird dort zuerst gesucht.  Danach wird er wie ein Name  ohne  Pfad  in  den
Suchpfaden gesucht.  Wird keine Datei gefunden,  wird der  Compiler  wieder
verlassen. In jedem Fall wird der Name mit der Extension MOD versehen.
Die Optionen haben die allgemeine Syntax:

-<Option><Parameter>

Die Art der Option wird mit einem Buchstaben (grož oder  klein)  angegeben,
eventuelle Parameter folgen ohne Leerzeichen.  Einige Optionen sind  sowohl
ber Environmentvariablen als auch ber Kommandozeile setzbar.  Dabei gilt:
Die Option in der Kommadozeile hat h”here Priorit„t.
Folgende Optionen sind implementiert:

-e: Weist den Compiler an,  bei dem ersten gefundenen Fehler den  Programm-
    lauf abzubrechen.  Normalerweise wird die Datei komplett bersetzt  und
    die Fehler in einer Datei gespeichert.

-w: Schaltet die Ausgabe von Warnungen ein.  Warnungen werden erzeugt, wenn
    ein Fehler des Programmierers vorliegen k”nnte,  die der Compiler  aber
    bersetzen kann.  Dies wird zum Beispiel bei Schreibzugriffen auf  glo-
    bale Variable eines anderen Moduls getan.  Warnungen  werden  normaler-
    weise unterdrckt.

-i: Schaltet den Indexcheck aus,  da er defaultm„žig eingeschaltet ist. In-
    dexcheck bewirkt eine šberprfung  der  Arraygrenzen  von  Indizes  zur
    Laufzeit und ist mit einer geringfgigen Verl„ngerung  des  Codes  ver-
    bunden. Ein falscher Index bewirkt eine CHK-Exception.

-t: Schaltet den Typcheck aus,  der ebenfalls  normalerweise  eingeschaltet
    ist. Wenn er eingeschaltet ist, wird bei jedem Typeguard geprft, ob es
    sich auch um den korrekten Recordtyp handelt.  Ein falscher Typ bewirkt
    die Ausgabe einer Fehlermeldung und anschlieženden Programmabbruch.

-a: Schaltet den Arithmetikcheck aus,  der defaultm„žig eingeschaltet  ist.
    Dieser Check soll šber- und Unterlauf von  Realzahlen  berprfen,  ist
    aber noch nicht implementiert.

-s|<pos>|: Diese Option bewirkt,  daž der Compiler bei Erreichen der  Posi-
    tion pos im erzeugten Code den Programmlauf mit einer Meldung abbricht.
    Mit dieser Funktion l„žt der Scanner  die  Absturzstelle  im  Quelltext
    finden.

-o: Wenn die Option -s benutzt wird und der Compiler bricht ab,  so gibt er
    einige Zeilen vor und nach dem Abbruchpunkt aus, falls diese Option ge-
    setzt wird.

5.2) Environmentvariablen
-------------------------

Der Compiler wertet auch einige Environmentvariablen aus.  Sie mssen immer
grožgeschrieben und von einem = gefolgt sein.  Gesetzt werden  sie  in  der
Shell und jedem Programm bergeben, daž von dieser Shell aufgerufen wird.

Es werden folgende Variablen ausgewertet:

MODPATH: Gibt die Suchpfade (Kap.??) an, in denen nach dem zu bersetzenden
    Modul gesucht wird.

SYMPATH: Gibt die Suchpfade an,  in denen nach den Symboldateien der impor-
    tierten Module gesucht wird.  Ist SYMPATH definiert, wird ein evtl. er-
    zeugtes SYM-File in den letzten Pfad geschrieben, der bei SYMPATH ange-
    geben ist.  Ist SYMPATH nicht definiert,  werden die Suchpfade von MOD-
    PATH bernommen und das SYM-File wird in denselben Ordner  geschrieben,
    in dem die Source war.

      Anmerkung:  Eine Symboldatei wird nur erzeugt,  wenn sie  noch  nicht
    existiert oder sich ge„ndert hat.

OBJPATH: Die erzeugte Objektdatei wird in den letzten Pfad geschrieben, der
    mit dieser Variablen definiert wird.  Ist OBJPATH nicht definiert, wer-
    den die Suchpfade von MODPATH bernommen und das OBJ-File wird in  den-
    selben Ordner geschrieben, in dem die Source war.

INFPATH: Die erzeugte Infodatei wird in den letzten Pfad  geschrieben,  der
    mit dieser Variablen definiert wird.  Ist INFPATH nicht definiert, wer-
    den die Suchpfade von MODPATH bernommen und das INF-File wird in  den-
    selben Ordner geschrieben, in dem die Source war.

    Anmerkung: Ein Info-File wird nur erzeugt, wenn es n”tig ist.

INXCHK: Der Inhalt der Variablen darf die Werte ON oder  OFF  haben.  Damit
    wird der Indexcheck ein- oder ausgeschaltet,  der normalerweise  einge-
    schaltet ist.

TYPCHK: Wie INXCHK, jedoch fr den Typcheck.

ARICHK: Wie INXCHK, jedoch fr den Arithmetikcheck.

ERRDIST: Der Inhalt der Variablen muž eine Dezimalzahl sein,  die  den  Ab-
    stand zwischen zwei Fehlermeldungen in Zeichen angibt.  Dieser  Abstand
    bewirkt,  daž weniger Folgefehler eines Fehlers ausgegeben werden.  Der
    Standardwert ist 20, das bedeutet: Wenn nach einem erkannten Fehler in-
    nerhalb der n„chsten 20 Zeichen nochmal ein Fehler  auftritt,  wird  er
    nicht ausgegeben.

MAXERR: Der Inhalt ist wieder eine Dezimalzahl,  die angibt, nach wievielen
    ausgegebenen Fehlern keine weiteren Fehler mehr ausgegeben werden  sol-
    len. Normalerweise sind dies 100 Fehler.

ERRFORM: Der Inhalt dieser Variablen ist ein String.  Damit ist es m”glich,
    das Format einer Fehlermeldung einzustellen.  Prinzipiell kann man sich
    den Dateinamen mit \d,  die Zeilennummer mit  \z,  die  Spalte  mit  \s
    (beide z„hlend ab 1),  die absolute Position mit \p und  natrlich  die
    Fehlermeldung selbst mit \f ausgeben lassen. Diese Teile werden dort in
    der Zeile eingefgt,  wo die Krzel mit '\' stehen.  Der  standardm„žig
    gesetzte String lautet:

    "Error \d \z : \s \f"

    Damit sieht eine Fehlermeldung so aus:

      Error DATEI ZEILE : SPALTE FEHLERMELDUNG

WARNOUT: Werte ON/OFF sind erlaubt.  Schaltet die Ausgabe von Warnungen ein
    oder aus. Normalerweise werden keine Warnungen ausgegeben.

5.3) Optionen im Quelltext
--------------------------

  Fr die Angabe von Optionen in Quelltexten ist die  bliche  Konstruktion
(*$...*) reserviert.  Solche Optionen haben die h”chste Priorit„t.  Es kann
immer nur eine Option angegeben werden.  Zwischen $ und dem  Kennbuchstaben
darf kein Leerzeichen sein. Hinter den Parametern darf noch beliebiger Kom-
mentar folgen.

(*$I?*): Damit kann der Indexcheck bestimmt werden.  Das Fragezeichen  darf
    '+',  '-' oder '=' sein.  Hinter dem I darf kein Leerzeichen sein.  Ein
    '+' schaltet den Indexcheck ein, '-' aus und '=' stellt den vorigen Zu-
    stand wieder her.

    Diese Option ist nur im Oberon-Teil verfgbar.

(*$T?*): Wie I fr den Typcheck.  Eingeschalteter Typcheck bewirkt eine Ty-
    pberprfung bei jedem Zugriff auf den gesamten  Record.  Diese  Option
    ist nur im Oberon-Teil verfgbar.

(*$A?*): Wie I fr den Arithmetikcheck.  Wird im Moment noch  nicht  unter-
    sttzt. Die Routinen im Modul System (Grundrechenarten) melden arithme-
    tische Fehler, auch ohne diesen Check.

    Diese Option ist nur im Oberon-Teil verfgbar.

(*$N?*) Diesmal gibt das Fragezeichen einen Dateinamen an. Unter diesem Na-
    men wird sp„ter das gelinkte Programm gespeichert. Vor dem Namen drfen
    ausnahmsweise auch Leerzeichen stehen.  Wird der Name mit Pfad  angege-
    ben, wird das Programm dort gespeichert, ansonsten im Pfad PRGPATH oder
    beim Modul. Der Name wird dem Linker ber die Infodatei mitgeteilt.

    Diese Option ist nur im Oberon-Teil verfgbar.

(*$O?*) Wenn ein '-' angegeben wird,  wird der folgende Code bei der  Opti-
    mierung nicht angerhrt. Bei O+ wird die Optimierung wieder zugelassen.
    Es darf keine Verschachtelung stattfinden.

    Diese Option ist auch im Assembler verfgbar.

(*$V+?*) Das Fragezeichen muž den Namen einer Environmentvariablen  angege-
    ben.  Es bedeutet:  Der nun folgende Code soll bei der Optimierung  nur
    dann im Programm gelassen  werden,  wenn  die  Environmentvariable  zum
    Zeitpunkt der Optimierung definiert ist.  Der Wert ist dabei  beliebig.
    Der Compiler kmmert sich nicht weiter darum und  bersetzt  alles,  es
    ist also keine bedingte Compilierung.  Es ist n„mlich  wesentlich  fle-
    xibler: Wenn man die Form des Codes (z.B. fr verschiedene Zielrechner)
    „ndern m”chte, muž man nicht irgendwo einen Wert „ndern und alle Module
    neu bersetzen  und  linken.  Stattdessen  braucht  man  nur  die  ent-
    sprechenden Variablen zu setzen oder zu l”schen und die Optimierung  zu
    starten. Der Linker erzeugt dann das gewnschte Programm.

    Diese Option ist auch im Assembler verfgbar.

    Beispiel:

    (*V+ DEBUG *) (* drinlassen wenn Debugversion *)
      IO.WriteString(...)
    (*V=*)

    Wenn die Environmentvariable DEBUG definiert ist,  wird beim Optimieren
    die zus„tzliche Ausgabe dringelassen.

(*$V-?*) Wie oben,  jedoch wird der folgende Code nur dann  entfernt,  wenn
    die Variable definiert ist.

    Diese Option ist auch im Assembler verfgbar.

(*$V+?=...*) und (*$V-?=...*) Wie oben, jedoch wird auch der Inhalt der Va-
    riablen angegeben.  Die Bedingung ist also erfllt,  wenn die  Variable
    definiert ist und den angegebenen  Wert  hat  (beliebiger  String  ohne
    Leerzeichen).

    Diese Option ist auch im Assembler verfgbar.

(*$V=*) Damit wird die Abh„ngigkeit von allen vorher angegebenen  Variablen
    ausgeschaltet.

    Diese Option ist auch im Assembler verfgbar.

5.4) Ausgabe
------------

Der Compiler erzeugt eine neue Objektdatei, wenn die šbersetzung fehlerfrei
war.  Ist die dabei erzeugte Symboldatei anders als die bisherige oder exi-
stierte bisher Keine,  so wird die neue Symboldatei abgespeichert.  War die
šbersetzung fehlerhaft,  wird die Fehlerdatei abgespeichert.  Die Symbolda-
teien ben”tigt der Compiler,  um beim Import die dort exportierten Bezeich-
ner zu lesen.  Die Objektdateien ben”tigt der Linker,  wenn er ein Programm
zusammensetzt.  Evtl.  wird auch eine Infodatei erzeugt,  die unter anderem
einen Programmnamen aufnimmt.

  Das Format der Objektdateien enspricht fast dem eines normalen Programms.
Es hat einen 28 Byte langen Programmheader,  es folgen der Code, die Daten,
die Symboltabelle und die Reloziertabelle. Die Symboltabelle entspricht dem
erweiterten GST-Format.  Durch dieses Format der Objektdateien ist es  m”g-
lich,  sowohl komplette Module mit einem beliebigen Assembler zu schreiben,
als auch vom Compiler erzeugte  Objektdateien  zu  disassemblieren  und  zu
berarbeiten.  Letzteres kann fr die Geschwindigkeitsoptimierung hilfreich
sein,  denn es ist einfacher, einen bestehenden Assemblertext zu verbessern
als etwas direkt in Assembler zu schreiben.  Das Format des  Symboltabellen
ist nicht mehr kompatibel zu dem von N. Wirth, da einige zus„tzliche Infor-
mationen ben”tigt wurden.

5.5) Vordefinierte Prozeduren
-----------------------------

Die folgenden Tabellen zeigen die vordefinierten Funktionen und  Prozeduren
von Oberon-2 inklusive der Erweiterungen bei STJ-Oberon-2.  Diese sind  mit
einem Stern markiert und sind nicht portabel.  v steht fr eine Variable, x
und n fr Ausdrcke,  a fr Adresse und T fr einen Typ.  Integer  bedeutet
einen der Integertypen SHORTINT, INTEGER oder LONGINT.

  _Funktionen:_

+-------------+--------------+-------------+-----------------------+
| Name        | Argumenttyp  | Ergebnistyp | Funktion              |
+-------------+--------------+-------------+-----------------------+
| ABS(x)      | Numerische   | Typ von x   | Absolutwert           |
|             | Typen        |             |                       |
| ASH(x,n)    | x,n: Integer | Typ von x   | x * 2^n               |
| CAP(x)      | CHAR         | CHAR        | Grožbuchstabe         |
| CHR(x)      | Integer      | CHAR        | Zahl in CHAR          |
|             |              |             | umwandeln             |
| ENTIER(x)   | Realtyp      | LONGINT     | Gr”žtes Integer nicht |
|             |              |             | gr”žer als x          |
| TRUNC(x) *  | Realtyp      | LONGINT     | Integeranteil         |
| LEN(v,n)    | v: Array;    | INTEGER     | L„nge von v in        |
|             | n: Integer-  |             | Dimension n           |
|             | konstante    |             | (0 = erste Dim.)      |
| LEN(v)      | v: Array     | INTEGER     | entspricht LEN(v,0)   |
| LONG(x)     | SHORTINT     | INTEGER     | erweitern             |
|             | INTEGER      | LONGINT     |                       |
|             | REAL         | LONGREAL    |                       |
| MAX(T)      | T = Basistyp | T           | Maximalwert von T     |
|             | T = SET      | INTEGER     | Maximales             |
|             |              |             | Mengenelement         |
| MIN(T)      | T = Basistyp | T           | Minimalwert von T     |
|             | T = SET      | INTEGER     | 0                     |
| ODD(x)      | Integer      | BOOLEAN     | x MOD 2 = 1           |
| ORD(x)      | CHAR         | INTEGER     | Ordinalzahl von x     |
| SHORT(x)    | LONGINT      | INTEGER     | n„chst kleinerer Typ  |
|             | INTEGER      | SHORTINT    |                       |
|             | LONGREAL     | REAL        |                       |
| SIZE(T)     | jeder Typ    | Integer     | Anzahl Bytes,         |
|             |              |             | die T belegt          |
+-------------+--------------+-------------+-----------------------+

_Prozeduren:_

+--------------------+-------------------------------+---------------------+
| Name               | Argumenttyp                   | Funktion            |
+--------------------+-------------------------------+---------------------+
| COPY(x,v)          | x: Char. Array, String;       | v := x              |
|                    | v: Char. Array                |                     |
| DEC(v)             | Integer                       | v := v-1            |
| DEC(v,n)           | v,n: Integer                  | v := v-n            |
| EXCL(v,x)          | v: SET; x: Integer            | v := v - {x}        |
| HALT(x)            | Integerkonstante              | Programm beenden    |
| INC(v)             | Integer                       | v := v+1            |
| INC(v,n)           | v,n: Integer                  | v := v+n            |
| INCL(v,x)          | v: SET; x: Integer            | v := v + {x}        |
| NEW(v)             | Zeiger                        | v^   allozieren     |
| NEW(v,x_0,...,x_n) | v : Zeiger auf offenes Array; | v^   mit L„ngen     |
|                    | x_i: Integer                  | x_0..x_n allozieren |
+--------------------+-------------------------------+---------------------+


  _Funktionen in SYSTEM:_

+-------------+------------------+-------------+-------------------------+
| Name        | Argumenttyp      | Ergebnistyp | Funktion                |
+-------------+------------------+-------------+-------------------------+
| ADR(v)      | alle             | LONGINT     | Adresse von v           |
| ANL(a,b) *  | a,b: Integer     | wie a,b     | bitweise Und            |
| BIT(a,n)    | a: LONGINT       | BOOLEAN     | Bit n von Mem[a]        |
|             | n: Integer       |             |                         |
| CC(n)       | Integerkonstante | BOOLEAN     | Bedingung n (0ónó15)    |
| LONG(a) *   | SHORTINT         | INTEGER     | vorzeichenlos erweitern |
|             | INTEGER          | LONGINT     |                         |
| LSH(x,n)    | x: Integer,      | Typ von x   | logischer Shift         |
|             | CHAR,BYTE        |             |                         |
|             | n: Integer       |             |                         |
| NTL(a) *    | a: Integer       | wie a       | bitweise invertieren    |
| ORL(a,b) *  | a,b: Integer     | wie a,b     | bitweise Oder           |
| ROT(x,n)    | x: Integer       | Typ von x   | Rotation                |
|             | CHAR,BYTE        |             |                         |
|             | n: Integer       |             |                         |
| VAL(T,x)    | T,x: alle Typen  | T           | x als Typ T auffassen   |
| XOL(a,b) *  | a,b: Integer     | wie a,b     | bitweise Exklusiv Oder  |
+-------------+------------------+-------------+-------------------------+

_Prozeduren in SYSTEM:_

+----------------+---------------------+------------------------+
| Name           | Argumenttyp         | Funktion               |
+----------------+---------------------+------------------------+
| DISPOSE(p)     | Zeiger              | gibt den Speicher frei |
| GET(a,v)       | a: LONGINT          | v := Mem[a]            |
|                | v: einfache Typen   |                        |
| GETREG(n,v)    | n: Integerkonstante | v := Register n        |
|                | v: einfache Typen   | (0ónó15)               |
| INLINE(...) *  | Wortkonstanten      | fgt die Konstanten    |
|                |                     | in den Code ein        |
| MOVE(a0,a1,n)  | a0,a1: LONGINT      | n Bytes bei a0         |
|                | n: Integer          | nach a1 kopieren       |
| NEW(v,n)       | v: Zeiger, LONGINT  | n Bytes allozieren     |
|                | n: Integer          | und Adresse nach v     |
| PUT(a,v)       | a: LONGINT          | Mem[a] := v            |
|                | v: einfache Typen   |                        |
| PUTREG(n,v)    | n: Integerkonstante | Register n := v        |
|                | v: einfache Typen   | (0ónó15)               |
+----------------+---------------------+------------------------+

5.6) Unterschiede zum Standard-Oberon-2
---------------------------------------

 - Der Compiler wurde erweitert um AND und NOT,  die identisch  mit  &  und
   ~sind.

 - SYSTEM.ADR kann auch die Adressen von Prozeduren und konstanten  Strings
   zurckgeben.

 - Es gibt eine Abart von Prozeduren, die fr Betriebssystemaufrufe benutzt
   werden. Bei Wirth wurden sie anders benutzt.
   Beispiel :

   PROCEDURE- Fclose(Handle : INTEGER) : INTEGER 62,1;

   Bei Benutzung dieser Prozedur wird das Handle und die Funktionsnummer 62
   auf den Stack geschrieben,  TRAP #1 aufgerufen und der Stack korrigiert.
   Da das Betriebssystem genau wie normale Prozeduren den Returnwert in Re-
   gister D0 zurckgeben,  funktioniert dies also auch.  Lediglich die Rei-
   henfolge der Parameter mssen vertauscht werden.

 - Bei Wirth mssen Prozeduren, die einer Prozedurvariablen zugewiesen wer-
   den,  eine Funktionsnummer haben.  Prozeduren bekommen Funktionsnummern,
   wenn sie einen Stern hinter dem Namen haben (dann sind sie  exportiert),
   wenn sie einen Stern hinter 'PROCEDURE' stehen haben  (soll  wohl  einen
   Far-Aufruf erzwingen) oder wenn sie forward deklariert werden  (ein  '^'
   hinter 'PROCEDURE'). Bei STJ-O2 ist keine Funktionsnummer mehr n”tig fr
   die Zuweisung an eine Prozedurvariable.

 - Laut Wirth waren Strings nur in G„nsefžchen zul„ssig.  Dabei  wird  ein
   Zeichen als CHAR,  mehr oder weniger Zeichen als ARRAY OF CHAR  erkannt.
   Um nun auch einzelne Zeichen als Strings zu deklarieren, kann man sie in
   Hochkommata einschliežen.

5.7) Bekannte Fehler
--------------------

 - Nicht fr alle Fehlermeldungen  ist  eine  Klartextmeldung  gespeichert.
   Dann erscheint nur  eine  Fehlernummer.  Einige  Fehlermeldungen  passen
   nicht immer ganz zu dem bemerkten Fehler. Man m”ge mir das verzeihen.

 - Zeiger auf offene Arrays in komplexen Strukturen (Arrays,  Records)  ma-
   chen Probleme. Besonders der Indexcheck funktioniert dann nicht.

 - Die Anzahl Prozeduren,  die an einen Typ und dessen Erweiterungen gebun-
   den werden, ist noch auf 100 begrenzt.

 - Zeiger auf mehrdimensional offene Arrays sind noch nicht m”glich.

 - LEN liefert nur INTEGER zurck statt LONGINT, da die Indizes auf 32K be-
   grenzt sind.

 - Wenn schon eine Infodatei existiert,  deren Inhalt aber Unsinn ist  oder
   deren Format veraltet ist oder die 0 Bytes lang ist, strzt der Compiler
   nach der šbersetzung ab.




6) Der Assembler
================

Im Compiler ist ein Makroassembler integriert.  Dieser ist ursprnglich als
eigenst„ndiges Programm zur Assemblerprogrammierung gedacht gewesen und da-
her sehr viel leistungsf„higer als n”tig.  Daher ist er auch nur gering mit
dem Oberon-Teil des Compilers verbunden.  Er hat einen eigenen  Parser  und
arbeitet im Gegensatz zum Compiler mit 2  Passes.  Bei  der  Programmierung
habe ich mich an AS orientiert,  ein PD-Assembler fr PC's, so daž hier ei-
nige Žhnlichkeiten bestehen. Mit dem Befehl

ASSEMBLER
     ...
   END;

wird der Assembler aktiviert.  Alles zwischen ASSEMBLER und END  wird  dann
nicht mehr vom Compiler, sondern vom Assembler bearbeitet. Dabei k”nnen die
meisten Symbole des Oberon-Teils verwendet werden,  jedoch kann der Oberon-
Teil nicht auf im Assembler definierte  Symbole  zugreifen.  Der  Assembler
kann soweit mit Oberon-Strukturen arbeiten, solange kein Code dabei erzeugt
werden muž.

  Fr A7 kann alternativ auch SP verwendet werden.  Alle Befehle sind  auch
ohne L„ngenangabe definiert.  Wenn der Befehl in Wortgr”že existiert,  wird
dies als Gr”že angenommen.

  Der Assembler ist genau wie der Compiler streng Case-Sensitiv.  Alle  Ma-
schinenbefehle und Pseudobefehle mssen grož geschrieben werden. Bei Labeln
wird zwischen Grož- und Kleinschreibung unterschieden.

  Achtung :  Es sind l„ngst nicht alle Maschinenbefehle  getestet  und  bei
Problemen sollte ein Disassembler prfen, ob der Assembler nicht vielleicht
Unsinn kodiert hat.

6.1) Symbolkonventionen
-----------------------

Symbole werden mit einer L„nge von 22 Byte gespeichert,  alle weiteren Zei-
chen werden ignoriert.  Wenn ein Label definiert werden soll, muž es in der
ersten Spalte beginnen,  darf kein vordefinierter Bezeichner sein  und  muž
mit einem Buchstaben beginnen.  Alle weiteren  Zeichen  k”nnen  Buchstaben,
Ziffern und Unterstrich sein.  Ein Doppelpunkt hinter einem Label  ist  er-
laubt,  aber nicht erforderlich. Alle vordefinierten Bezeichner drfen auch
in der ersten Spalte anfangen.  Die Parameterliste eines Makros muž mit ei-
nem Zeilenende oder Kommentar beendet werden. Aužer diesen beiden Forderun-
gen ist in einem Quelltext alles erlaubt,  auch mehrere  Befehle  in  einer
Zeile. Sicherheitshalber sollten sie mit ';;' getrennt werden, auch wenn es
nicht immer n”tig ist.  Ein Semikolon leitet Kommentar ein,  zwei  hingegen
trennen Befehle.  Die Spalte hinter dem zweiten Semikolon wird  wieder  als
erste Spalte einer neuen Zeile interpretiert,  so daž dort auch  ein  Label
definiert werden kann.

  Neben dem blichen Kommentar mit einem Semikolon bis zum Zeilenende  kann
man auch mehrere Zeilen mit der in Oberon blichen  Konstruktion  (*  ...*)
Kommentar definieren.

  Bei Labels und Befehlen wird immer zwischen Grož- und Kleinschreibung un-
terschieden.  Alle Maschinenbefehle,  Register und Pseudooperationen mssen
grož geschrieben werden.
Folgende Symbole definiert der Assembler vor:




+------+------------------------+
| Name | Bedeutung              |
+------+------------------------+
| *    | mom. Programmz„hler    |
| CPU  | der gew„hlte Prozessor |
+------+------------------------+


  Desweiteren einige Pseudobefehle,  deren  Parameter  und  natrlich  alle
68000 Befehle.  Befehle der anderen 680X0 Prozessoren sind  z.T.  implemen-
tiert.

6.1.1) Formelausdrcke
......................

An den meisten Stellen, an denen der Assembler Zahlenangaben erwartet, k”n-
nen nicht nur einfache Symbole oder Konstanten  angegeben  werden,  sondern
ganze Formelausdrcke. Bei den Komponenten der Formelausdrcke kann es sich
sowohl um ein einzelnes Symbol als auch  um  eine  Konstante  handeln.  Die
Schreibweise von Integerkonstanten kann in verschiedenen Zahlensystemen er-
folgen:




+-------------+-------------------------------------+
| dezimal     | direkt                              |
| hexadezimal | nachgestelltes H, vorangestelltes $ |
| bin„r       | nachgestelltes B, vorangestelltes % |
| oktal       | nachgestelltes O, vorangestelltes @ |
+-------------+-------------------------------------+


  Damit hexadezimale Kostanten im Intel-Modus nicht als  Symbolnamen  fehl-
interpretiert werden k”nnen,  mssen sie immer mit einer  Ziffer  beginnen;
anstelle z.B.  F0H muá also 0F0H geschrieben werden.  Die Werte A-F  mssen
grožgeschrieben  werden,   ebenso  die  nachgestellten   Buchstaben.   Beim
Motorola-Modus entf„llt dies. Integerkonstanten k”nnen auch als ASCII-Werte
geschrieben werden, so entsprechen

'A'    == $00000041
  'AB'   == $00004142
  'ABC'  == $00414243
  'ABCD' == $41414244

Dabei mssen die Zeichen in Hochkommata eingeschlossen  sein,  um  sie  von
Strings zu unterscheiden.  Ihre L„nge darf maximal 4 Zeichen  betragen.  Um
nun aber auch G„nsefáchen und Sonderzeichen ohne Verrenkungen  in  Strings
(und als Ascii-Werte geschriebene Integerkonstanten) schreiben  zu  k”nnen,
wurde ein "Escape-Mechanismus" eingebaut,  der  C-Programmierer(inne)n  be-
kannt vorkommen drfte:  Schreibt man einen Backslash (\) mit einer maximal
dreiziffrigen Zahl im String,  so versteht der Assembler dies  als  Zeichen
mit dem entsprechenden dezimalen ASCII-Wert.  So kann man  mit  \0ein  NUL-
Zeichen definieren.

  Einige besonders h„ufig gebrauchte Steuerzeichen kann man auch  mit  fol-
genden Abkrzungen erreichen:

\b : Backspace    \a : Klingel         \e : Escape
 \t : Tabulator    \n : Zeilenvorschub  \r : Wagenrcklauf
 \\ : Backslash    \' : Hochkomma       \" : G„nsefáchen

Die Kennbuchstaben drfen sowohl groá als auch klein geschrieben werden.

  šber dieses Escape-Zeichen k”nnen sogar  Formelausdrcke  in  den  String
eingebaut werden,  wenn sie in geschweifte Klammern eingefaát werden:  z.B.
bewirkt

Wert1   equ 1
  Wert2   equ 2
  message "Wert = \{Wert1+Wert2}"

die Ausgabe von 'Wert = 3'.
Der Assembler stellt zur Verknpfung folgende Operanden zur Verfgung:




+--------------------------------------------------+
| Operand Funktion            #Operanden    Rang   |
+--------------------------------------------------+
| ~       log. NOT                 1        hoch   |
| ~~      bin„res NOT              1          ^    |
+--------------------------------------------------+
| *       Produkt                  2          |    |
| /       Quotient                 2          |    |
| #       Modulodivision           2          |    |
| ^       Potenz                   2          |    |
| !,!!    bin„res XOR              2          |    |
| &,&&    bin„res AND              2          |    |
+--------------------------------------------------+
| -       Differenz                2          |    |
| +       Summe                    2          |    |
| |,||    bin„res OR               2          |    |
+--------------------------------------------------+
| <>      Ungleichheit             2          |    |
| >=      grӇer oder gleich       2          |    |
| <=      kleiner oder gleich      2          |    |
| <       echt kleiner             2          |    |
| >       echt grӇer              2          v    |
| =       Gleichheit               2       niedrig |
+--------------------------------------------------+


  Die angedeuteten Gruppen haben jeweils gleichen Rang. Die Reihenfolge der
Evaluierung l„át sich durch Klammerung neu festlegen.

  Die Vergleichsoperatoren liefern TRUE,  falls die Bedingung zutrifft, und
FALSE falls nicht.  Fr die logischen Operatoren  ist  ein  Ausdruck  TRUE,
falls er ungleich 0 ist,  ansonsten FALSE.  Deshalb ist auch ein  separater
"logisch Nicht" Operator n”tig,  denn eine Zahl ungleich 0 kann  bin„r  in-
vertiert immer noch ungleich 0 sein.  Beim "logisch Nicht" wird eine 0  zur
1,  eine Zahl ungleich 0 zur 0. Alle anderen logischen Operationen sind mit
den Bin„ren identisch.

  Fr Strings sind alle Vergleichsoperatoren sowie die Summe definiert. Die
Summe zweier Strings ergibt einen String,  der die beiden aneinandergeh„ngt
erh„lt. Vergleiche von Strings liefern 0 (FALSE) oder 1 (TRUE). šberall, wo
Zahlen erwartet werden, drfen also auch Stringvergleiche benutzt werden.

  Als einzige Funktion,  die ein Stringargument zul„át,  ist  die  Funktion
UPSTRING definiert.  Sie wandelt alle Zeichen in Groábuchstaben  um.  Dabei
werden auch Umlaute in Grožbuchstaben gewandelt,  aber Žnderungen des  Zei-
chensatzes mit CHARSET werden nicht korrekt  bercksichtigt.  Wer  nur  ein
einzelnes Zeichen (als Integer gespeichert) umwandeln will,  kann dies  mit
der Funktion TOUPPER tun.

6.2) Pseudobefehle
------------------

6.2.1) SET und EQU
..................

SET und EQU erlauben die Definition typenloser Konstanten,  d.h. sie werden
keinem Segment zugeordnet und ihre Verwendung erzeugt in keinem  Fall  eine
Warnung wegen Segmentverquickung.  W„hrend EQU  Konstanten  definiert,  die
nicht wieder (mit EQU) ge„ndert werden k”nnen,  erlaubt SET die  Definition
von Variablen,  die sich w„hrend des Assemblerlaufes ver„ndern lassen.  In-
tern werden Konstanten und Variablen identisch gespeichert, der einzige Un-
terschied ist, daá sie mit SET umdefiniert werden k”nnen und mit EQU nicht.
Es ist daher m”glich,  ein Symbol mit EQU zu definieren und es mit  SET  zu
„ndern (auch wenn das nicht der Sinn der Sache ist).

6.2.2) CHARSET
..............

Einplatinensysteme,  zumal wenn sie LCDs ansteuern,  benutzen h„ufig  einen
anderen Zeichensatz als ASCII,  und daá die Umlautkodierung mit der im  Be-
fehl bereinstimmt,  drfte wohl reiner Zufall sein. Um nun aber keine feh-
lertr„chtigen Handumkodierungen vornehmen zu mssen,  enth„lt der Assembler
eine Umsetzungstabelle fr Zeichen, die jedem Quellcode ein Zielzeichen zu-
ordnet.  Zur Modifikation dieser Tabelle (die initial 1:1 bersetzt), dient
der Befehl CHARSET.  Der Befehl erwartet eine  Bereichsangabe  fr  die  zu
bersetzenden Zeichen als ersten  bzw.  ersten/zweiten  Parameter  und  als
letzten Parameter den Bereich,  in den die Zeichen umgemappt werden sollen.
Zur Klarstel- lung zwei Beispiele:

  CHARSET '„',128

bedeutet,  daá das Zielsystem das „ mit der Zahl  128  kodiert.  Falls  das
Zielsystem keine Kleinbuchstaben untersttzt, k”nnen mit

  CHARSET 'a','z','A'

alle Kleinbuchstaben auf die passenden Groábuchtaben automatisch  umgemappt
werden.

  ACHTUNG! CHARSET beeinfluát nicht nur im  Speicher  abgelegte  Stringkon-
stanten,  sondern auch als 'ASCII' formulierte Integerkonstanten.  Dies be-
deutet, daá eine evtl. bereits modifizierte Umsetzungstabelle in den obigen
Beispielen zu anderen Ergebnissen fhrt!

6.2.3) CPU
..........

Speichert die nachfolgende Zahl als Bezeichnung fr eine CPU.  Kann wie je-
der andere Bezeichner in Ausdrcken verwendet werden und ist  bei  der  be-
dingten Assemblierung verwendbar.  Der Assembler prft, ob ein Maschinenbe-
fehl auf der gew„hlten CPU verfgbar ist und verweigert sie wenn nicht. De-
faultwert ist 68000.

6.2.4) SUPMODE
..............

Diese Variable kann nur ein- oder ausgeschaltet werden.  Sie teilt dem  As-
sembler mit,  ob der Supervisormode gerade eingeschaltet ist oder nicht. Am
Anfang ist die Variable ausgeschaltet.

Beispiel :

SUPMODE ON
 	MOVE	#0,SR	; nur im Supervisormode zul„ssig
 	SUPMODE OFF
 	MOVE	#0,SR	; fhrt zu einer Warnung des Assemblers

6.2.5) SEGMENT
..............

Der Atari unterscheidet verschiedene Adreábereiche,  die nicht  miteinander
mischbar sind und jeweils auch verschiedene Befehle zur  Ansprache  ben”ti-
gen.  Um auch diese verwalten zu k”nnen,  stellt der Assembler mehrere Pro-
grammz„hler zur Verfgung,  zwischen denen mit dem SEGMENT-Befehl hin-  und
hergeschaltet werden kann. Dies erlaubt es, sowohl in mit INCLUDE eingebun-
denen Unterprogrammen als auch im  Hauptprogramm  ben”tigte  Daten  an  der
Stelle zu definieren, an denen sie benutzt werden. Im einzelnen werden fol-
gende Segmente mit folgenden Namen verwaltet:

CODE: Programmcode

DATA: Datenbereich

BSS: Block storage segment,  zu 0 initialisierte Daten,  die nicht im  Pro-
    grammcode auftauchen, sondern vom TOS angeh„ngt werden.

Labels, die in einem Segment eines bestimmten Typs definiert werden, erhal-
ten diesen Typ als Attribut. Damit hat der Assembler eine begrenzte Prfm”-
glichkeit,  ob mit den falschen Befehlen auf Symbole in einem Segment zuge-
griffen wird. In solchen F„llen sollte der Assembler eine Warnung ausgeben.

  Achtung : Die Segmente werden natrlich auseinandergezogen und vom Linker
richtig zusammengesetzt,  daher darf man natrlich keine PC-relative Adres-
sierung ber Segmentgrenzen anwenden.

6.2.6) DC,DS
............

Damit werden Konstanten im Code oder im Datensegment abgelegt oder Speicher
reserviert.  Als L„ngen sind .B,  .W und .L m”glich,  keine Angabe wird als
Wortl„nge interpretiert.

  Bei allen dreien sind Strings erlaubt,  evtl.  wird ein String mit Nullen
verl„ngert, um auf ein Vielfaches der Bytezahl zu kommen. Eine Reservierung
von Speicher wird durch DS gemacht:

DS.B    10      ; reserviert 10 Bytes
        DS.W    1       ; reserviert ein Wort
        DS.L    2,$FF   ; reserviert 2 Langworte
                        ; mit Inhalt $FF

Speicherreservierung ohne Inhaltsangabe ist in allen Segmenten erlaubt. Der
Inhalt ist dann jeweils 0. Eine Inhaltsangabe ist natrlich nur im Code und
im Datensegment erlaubt.

6.2.7) ALIGN
............

ALIGN mit einem dahinterstehenden Integerausdruck erlaubt es, den Programm-
z„hler auf eine bestimmte Adresse  auszurichten.  Die  Ausrichtung  erfolgt
dergestalt, daá der Programmz„hler so weit erh”ht wird, daá er ein ganzzah-
liges vielfaches des Arguments wird :

  align 2

macht den Programmz„hler gerade. Der Freiraum wird mit 0 gefllt. Stattdes-
sen kann man auch EVEN ohne Wert benutzen.

6.2.8) MACRO
............

Dies ist der wohl wichtigste Befehl zur Makroprogrammierung.  Mit  der  Be-
fehlsfolge

<Name>	MACRO	[Parameterliste]
        <Befehle>
        ENDM

wird das Makro <Name>als die eingeschlossene Befehlsfolge definiert.  Diese
Definition alleine erzeugt noch keinen Code! Dafr kann fortan die Befehls-
folge einfach durch den Namen abgerufen werden,  das ganze stellt also eine
Schreiberleichterung dar.  Um die ganze Sache etwas ntzlicher  zu  machen,
kann man bei der Makrodefinition eine Parameterliste mitgeben.  Die Parame-
ternamen werden wie blich durch Kommas getrennt und mssen - wie  der  Ma-
kroname selber - den Konventionen fr Symbolnamen gengen.

  Beim Aufruf eines Makros werden die beim Aufruf angegebenen  Parameterna-
men berall textuell im Befehlsblock eingesetzt und der sich  so  ergebende
Assemblercode wird normal assembliert.  Sollten beim Aufruf zu wenige Para-
meter angegeben werden,  werden sie als leere Strings bergeben.  Soll mit-
tendrin ein Parameter weggelassen werden, kann man zwei aufeinanderfolgende
Kommas schreiben.

  Fr die bergebenen Parameter gelten besondere Regeln : Eine zusammenh„n-
gende Kette von Zeichen ohne Komma gilt als ein Parameter,  egal um  welche
Zeichen es sich handelt.  Es k”nnen also auch spezielle  Adressierungsarten
wie (A0)+ bergeben werden.  Wenn bewužt Strings bergeben  werden  sollen,
mssen sie in Hochkommata eingeschlossen werden, der Parameter besteht dann
aus dem String mit Hochkommata.  Wird ein  String  in  G„nsefžchen  einge-
schlossen,  besteht der Parameter nur aus dem String ohne G„nsefžchen.  So
ist es auch m”glich, Kommas und Leerzeichen in einem Parameter unterzubrin-
gen.
Beispiele :

mac1   MACRO   par1
        MOVE    D0,par1
        ENDM
        mac1    A0             ; entspricht "MOVE D0,A0"
 mac2   MACRO   par2,par3
        par2    par3
        ENDM
        mac2    MOVE,"D0,A0"  ; entspricht wiederum
                              ; "MOVE D0,A0"

Es kann also praktisch alles durch Makroparameter ersetzt werden,  auch Be-
fehle !

  In Makrormpfen definierte Labels werden immer als lokal betrachtet,  ein
expliziter LOCAL-Befehl ist also nicht erforderlich.  Sollen  Label  global
bekannt sein,  mssen sie mit einem Stern gekennzeichnet sein. Da auf diese
Weise das Label mit jedem Makroaufruf neu definiert wird,  darf es sich nur
um Definitionen mit 'SET' handeln,  damit keine Fehlermeldungen wie  'Label
schon definiert' kommen. Aus technischen Grnden ist es momentan n”tig, ein
Makro vor der ersten Benutzung zu deklarieren.  Wenn ein Makroparameter  in
G„nsefžchen eingeschlossen wird,  wird er ebenfalls ersetzt,  so  daž  das
Aussehen des Parameters berprft werden kann.
Beispiel :

Test   MACRO Par
        IF "Par" = "A"
        ...

Wenn als Parameter 'a' oder 'A' bergeben wurde, ergibt der Vergleich true.
Es wird aber nicht generell in Strings ersetzt,  sondern nur,  wenn der ge-
samte String gleich einem Makroparameter ist. Der Parameter wird *immer* in
Grožbuchstaben umgewandelt.

6.2.9) IRP
..........

Dies ist die eine vereinfachte Form von Makrodefinitionen fr den Fall, daá
eine Befehlsfolge einmal auf mehrere Operanden angewendet werden  soll  und
danach nicht mehr gebraucht wird.  IRP ben”tigt als  ersten  Parameter  ein
Symbol fr den Operanden,  und danach eine (fast) beliebige Menge von Para-
metern,  die nacheinander in den Befehlsblock eingesetzt  werden.  Um  eine
Menge von Registern auf den Stack zu schieben, kann man z.B. schreiben

IRP     op, D0,D1,D3
        MOVE    op,-(SP)
        ENDM

was in folgendem resultiert:

MOVE    D0,-(SP)
        MOVE    D1,-(SP)
        MOVE    D3,-(SP)

Benutzte Labels sind wieder fr jeden Durchgang automatisch lokal.

  Soll ein Label global sichtbar sein,  muž es einen Stern hinter dem Namen
haben.  Dies geht nur bei Labels, die mit SET definiert werden, denn andere
wrden eine Fehlermeldung erzeugen, daž das Label schon definiert ist.

6.2.10) REPT
............

Dies ist die einfachste Form der Makrobenutzung.  Der im  Rumpf  angegebene
Code wird einfach sooft assembliert,  wie der Integerparameter von REPT an-
gibt.  Dieser Befehl wird h„ufig in kleinen Schleifen anstelle  einer  pro-
grammierten Schleife verwendet, um den Schleifenoverhead zu sparen.

Der Vollst„ndigkeit halber ein Beispiel:
        REPT    3
        ROR     #1,(A0)
        ENDM
 rotiert den Wert um 3 Stellen nach rechts.

Symbole sind wiederum fr jede einzelne Repetition lokal.

6.2.11) Bedingte Assemblierung
..............................

Der Assembler untersttzt die bedingte Assemblierung mit Hilfe der  Befehle
IFC..  / ELSIFC / ENDC. Diese Befehle wirken zur Assemblierzeit, indem ent-
sprechend der Bedingung Teile bersetzt oder bersprungen werden. Diese Be-
fehle sind also nicht mit den IF-Statements h”herer Programmiersprachen zu vergleichen.
Die allgemeine Form eines IF-Befehles ist folgendermaáen:

IFC <Ausdruck> THEN
         .
         .
         <Block 1>
         .
         .
        ELSIFC
         .
         .
         <Block 2>
         .
         .
        ELSEC
         .
         .
         <Block 3>
         .
         .
        ENDC

Falls der hinter IFC angegebene Ausdruck wahr (d.h.  ungleich 0) ist,  wird
Block 1 assembliert. Es k”nnen dann beliebig viele ELSIFC folgen, mit denen
genauso verfahren wird.  Falls keine Bedingung zutrifft,  wird  der  ELSEC-
Zweig assembliert, falls er vorhanden ist.

  IF-Anweisungen drfen beliebig verschachtelt werden,  ein  ELSEC  bezieht
sich immer auf das letzte vorangegangene, noch nicht abgeschlossene IFC.

  Wenn in der Bedingung Symbole auftauchen,  mssen diese unbedingt  vorher
definiert worden sein, damit im Pass 1 der richtige Block bersetzt wird.

  Fr den Test,  ob ein Symbol definiert ist, wurde die Funktion DEF einge-
fhrt.  Sie gibt TRUE (=1), wenn das angegebene Symbol definiert ist, sonst
FALSE (=0).
Dies ist ntzlich fr Include Dateien :

IFC NOT DEF(thisfile) THEN; wenn nicht definiert
 thisfile       EQU 1             ; dann definieren
        ...                       ; und bersetzen
        ENDC

6.2.12) Lokale Label
....................

Die bedeutendste Erweiterung zu AS sind  lokale  Label.  Damit  k”nnen  in-
nerhalb eines Bereichs alle Label eingekapselt werden,  so daž sie  in  der
Umgebung nicht mehr sichtbar sind.

Beispiel :
        LOCAL
 Proc1*: ...
 Loop:   ...
        END
        LOCAL
 Proc2*: ...
 Loop:	 ...
        END

k”nnen so in derselben Datei stehen. Loop ist jeweils nur innerhalb von LO-
CAL und END sichtbar.  Ein * hinter einem Label (vor dem Doppelpunkt  falls
einer gesetzt wird) bedeutet, daž das Label global sein soll. Egal auf wel-
cher Verschachtelungsebene von LOCAL man sich befindet,  ein solches  Label
ist berall sichtbar.  Includedateien sollten alle Label lokal  machen  und
nur diese Label global definieren, die auch von anderen benutzt werden sol-
len.  Damit vermeidet man die Doppelbenutzung von Labels, die unwissentlich
in einer Includedatei definiert sind.

  Alle Label ohne Stern sind aužerhalb der ASSEMBLER ... END Struktur nicht
bekannt, d.h. sie sind automatisch lokal.

  Durch die Lokalisierung innerhalb von ASSEMBLER bis END ist dieser Befehl
nicht n”tig, aber fr reine Assemblerprojekte ist er wichtig.

6.3) Hochsprachenelemente
-------------------------

Der Assembler beherrscht auch einige der Oberon-Strukturen,  wenn auch  we-
sentlich primitiver.  Trotzdem kann man mit ihnen ein wenig Struktur in ein
Assemblerprogramm bringen und auch Labeldefinitionen wie Loop o.„. sparen.

6.3.1) IF cond THEN ... ELSIF ... ELSE ... END
..............................................

Die bliche If-Abfrage darf natrlich nicht fehlen.  Als  Bedingungen  sind
aber lediglich die blichen Condition Codes HI, LS, CC, HS, CS, LO, NE, EQ,
VC, VS, PL, MI, GE, LT, GT und LE zugelassen.
Beispiel :

CMP D0,D1
        IF EQ THEN      ; wenn D0 = D1
          ...           ; tu dies
        ELSIF LO THEN   ; wenn D1 < D0
          ...           ; tu dies
        ELSE
          ...           ; sonst dies
        END

6.3.2) REPEAT ... UNTIL cond
............................

Entspricht einer Repeat-Schleife in Oberon. Bedingungen wie bei IF.

Beispiel :
        REPEAT
          SUBQ #1,D0
        UNTIL EQ        ; z„hlt D0 bis auf 0 runter

6.3.3) LOOP ... END
...................

Entspricht LOOP in Oberon.

6.3.4) EXIT [(Zahl)]
....................

Mit Hilfe der Exit-Anweisung kann man REPEAT-Schleifen und LOOP-  Schleifen
mittendrin verlassen.  Es wird ein Branch an das Ende der  Struktur  einge-
fgt. Wenn man eine Zahl in Klammern angibt, kann man gleich mehrere Struk-
turen verlassen. Dabei einspricht EXIT einem EXIT(0).
Beispiel :

LOOP
          REPEAT
            TST D0
            IF EQ THEN EXIT END   ; verl„žt die
                                  ; REPEAT-Schleife
            IF MI THEN EXIT(1) END; verl„žt die
                                  ; LOOP-Schleife
          UNTIL PL
        END

6.4) Diverses
-------------

6.4.1) INCLUDE
..............

Dieser Befehl fgt die im Parameter angegebene Datei so im Text ein, als ob
sie dort stehen wrde.  Dieser Befehl ist sinnvoll,  um Quelldateien aufzu-
spalten,  die alleine nicht in den Speicher  passen  wrden  oder  um  sich
"Toolboxen" zu erzeugen.

  Aus Kompatibilit„tsgrnden ist  es  erlaubt,  den  Dateinamen  in  G„nse-
fáchen zu schreiben,

include stddef51.asm

und

include "stddef51.asm"

sind also „quivalent.

6.4.2) MESSAGE, WARNING, ERROR und FATAL
........................................

Der Assembler prft zwar die Quelltexte so streng wie m”glich  und  liefert
diffenzierte Fehlermeldungen, je nach Anwendung kann es aber sinnvoll sein,
unter bestimmten Bedingungen zus„tzliche  Fehlermeldungen  auszugeben,  mit
denen sich logische Fehler automatisch prfen lassen.  Der Assembler unter-
scheidet drei Typen von Fehlermeldungen,  die ber drei  Befehle  auch  dem
Programmierer zug„nglich sind:

 - WARNING :  Fehler,  die auf m”glicherweise falschen  oder  ineffizienten
   Code hinweisen.  Die Assemblierung l„uft weiter, eine Codedatei wird er-
   zeugt.

 - ERROR : Echte Fehler im Programm. Die Assemblierung l„uft weiter, um m”-
   gliche weitere Fehler in einem Durchgang entdecken  und  korrigieren  zu
   k”nnen. Eine Codedatei wird nicht erzeugt.

 - FATAL :  Schwerwiegende Fehler,  die einen sofortigen Abbruch des Assem-
   blers bedingen.  Eine Codedatei kann m”glicherweise entstehen,  ist aber
   unvollst„ndig.

Alle Befehle erwarten eine String als Argument.

  Diese Anweisungen ergeben nur in Zusammenhang mit bedingter Assemblierung
Sinn.  So kann man fehlerhafte Bedingungen abtesten und mit  einer  Fehler-
meldung abbrechen. Der String einer Fehlermeldung wird anstatt einer Assem-
blermeldung in die Fehlerdatei geschrieben und mit Zeile und Spalte  verse-
hen, in der der Befehl steht.

  Der Befehl MESSAGE gibt den angegebenen String lediglich aus und  erzeugt
einen Zeilenvorschub.

6.5) Zugriff auf Oberon-Bezeichner
----------------------------------

Der Assembler hat eine begrenzte Zugriffsm”glichkeit auf Bezeichner, die in
Oberon definiert wurden.  Dabei gilt allgemein, daž nur solche Zugriffe un-
tersttzt werden, die keinen zus„tzlichen Code erfordern.
Beispiel :

CONST con = 10;
 TYPE rec = RECORD
              var1 : INTEGER;
              var2 : ARRAY 10 OF CHAR;
            END;
      arr = ARRAY 10 OF LONGINT;
 VAR a : rec;
     b : POINTER TO rec;
     c : arr;
 PROCEDURE proc1;
  ...
 PROCEDURE proc2*;
  ...
Dann sind folgende Zugriffe m”glich:
        MOVE    #con,D0         ; l„dt D0 mit 10
        MOVE.L  a,A0            ; l„dt Adresse von a in A0
                                ; (geht auch mit Prozeduren
                                ; und Stringkonstanten)
        MOVE    a.var1,D0       ; geht weil a globale
                                ; Variable ist
        MOVE.B  a.var2[5],D1    ; dito
        MOVE.L  c[8],D2         ; dito
        BSR     proc            ; innerhalb eines Moduls
        JSR     proc2           ; bei importierten und
                                ; exportierten Prozeduren
Dagegen geht dies nicht:
        MOVE    b.var1,D0       ; b ist ein Zeiger und muž erst
                                ; geladen werden
Dies kann so gel”st werden:
        MOVE.L  b,A0            ; Inhalt von b = Zeiger auf rec
        MOVE    rec.var1(A0),D0 ; typ.var ergibt Offset von var
        MOVE.B  rec.var2[5](A0),D0; genauso
        MOVE.L  arr[2](A1),D0   ; geht genauso mit Arrays

Man kann also mit dem Typbezeichner die Offsets der Variablen innerhalb des
Records bekommen. Dies sollte immer der direkten Angabe von Zahlen vorgezo-
gen werden,  damit bei einer Žnderung der Datenstruktur nicht  alle  Zahlen
ge„ndert werden mssen.


7) Der Linker
=============

  Der Oberon-Linker (LINK.OBJ/TTP) dient dazu,  vom Compiler  erzeugte  Ob-
jektmodule zu einem lauff„higen Programm zusammenzubinden.  Dafr  ben”tigt
er nur die Objektmodule, die Symboldateien nicht.

7.1) Aufruf, Parameter
----------------------

Der Linker sollte von einer Shell aus benutzt werden,  die zumindest in der
Lage ist,  Environmentvariablen zu setzen, denn der Linker liest dort seine
Optionen. Beim Aufruf kann man als Kommando einige Optionen sowie einen Na-
men eines Objektmoduls bergeben.  Dieses Modul wird mit den von ihm impor-
tierten Modulen zusammengelinkt und unter seinem Namen mit passender Exten-
sion gespeichert. Die Syntax sieht also so aus:

link {<Option>} <Name>

Es wird nur der Name ohne Extension beachtet, ein eventueller Pfad wird ab-
geschnitten.  Dieser Name wird mit der Extension OBJ in den Suchpfaden  ge-
sucht. Wird keine Datei gefunden, wird der Linker wieder verlassen.
Die Optionen haben die allgemeine Syntax:

-<Option><Parameter>

Die Art der Option wird mit einem Buchstaben (grož oder  klein)  angegeben,
eventuelle Parameter folgen ohne Leerzeichen.  Einige Optionen sind  sowohl
ber Environmentvariablen als auch ber Kommandozeile setzbar.  Dabei gilt:
Die Optionen in der Kommadozeile haben h”here Priorit„t.
Folgende Optionen sind implementiert:

-t: Schaltet die Erzeugung einer Symboltabelle aus, die normalerweise immer
    an das Programm angeh„ngt wird.  Eine Symboltabelle ist  wichtig,  wenn
    man ein Programm debuggen muž. Sowohl Bugaboo als auch DB verstehen das
    Format der Symboltabelle.

-e: Schaltet die Erzeugung einer erweiterten  Symboltabelle  ab.  Normaler-
    weise wird eine Symboltabelle im erweiterten  GST-Format  erzeugt,  die
    eine Symboll„nge von 22 Zeichen zul„žt,  w„hrend das Standardformat nur
    8 Zeichen hat.  Diese Option stellt also nur das Format ein, die Option
    -t schaltet die Symboltabelle ganz aus.

-s|<size>|: Normalerweise erh„lt ein Programm einen Stack  von  32K  Gr”že.
    Mit dieser Option kann man den Stack beliebig einstellen.

-x|<ext>|: Damit kann die Extension eingestellt werden,  die  das  Programm
    erhalten soll.  Normalerweise ist das PRG, aber bei TOS-Programmen kann
    man TOS oder TTP angeben.

Ist von einem Modul eine Infodatei vorhanden und darin ist ein Programmname
definiert, wird dieser beim Speichern des Programmes benutzt. Wenn ein Pfad
angegeben ist, wird dort gespeichert, sonst in PRGPATH bzw. beim Modul. Der
Name kann im Quelltext mit (*$N ...*) gesetzt werden, siehe Kap. ??.

7.2) Environmentvariablen
-------------------------

Der Linker wertet auch einige Environmentvariablen aus.  Sie  mssen  immer
grožgeschrieben sein und von einem '=' gefolgt sein.  Gesetzt werden sie in
der Shell und werden jedem Programm bergeben,  daž von dieser Shell aufge-
rufen wird.
Es werden folgende Variablen ausgewertet:

OBJPATH: Gibt die Suchpfade an,  in denen nach importierten Modulen gesucht
    wird. Zum Linken werden nur die Objektdateien ben”tigt.
    Wenn OBJPATH nicht definiert ist, wird MODPATH genommen.

INFPATH: Gibt die Suchpfade an, in denen nach Infodateien gesucht wird.
    Wenn INFPATH nicht definiert ist, wird MODPATH genommen.

TOSPATH: Gibt ebenfalls Suchpfade an,  in denen Module stehen,  die in TOS-
    Programmen benutzt werden drfen.  Diese Pfade werden vor denen in  OB-
    JPATH durchsucht.  Die Unterscheidung erfolgt anhand der Extension, die
    das zu erzeugende Programm erh„lt. F„ngt sie mit 'T' an, werden die Mo-
    dule aus TOSPATH und OBJPATH gelinkt. Ist TOSPATH nicht definiert, wird
    wie bisher nur OBJPATH bzw. MODPATH genommen.

GEMPATH: Gibt ebenfalls Suchpfade an,  in denen Module stehen,  die in GEM-
    Programmen benutzt werden drfen.  Diese Pfade werden vor denen in  OB-
    JPATH durchsucht.  Die Unterscheidung erfolgt anhand der Extension, die
    das zu erzeugende Programm erh„lt.  F„ngt sie nicht mit 'T' an,  werden
    die Module aus GEMPATH und OBJPATH gelinkt.  Ist  GEMPATH  nicht  defi-
    niert, wird wie bisher nur OBJPATH bzw. MODPATH genommen.

PRGPATH: Gibt einen mit Backslash beendeten Pfad an,  in den  das  erzeugte
    Programm geschrieben werden soll.  Wenn die Variable  nicht  existiert,
    wird das Programm in denselben Pfad geschrieben, in dem das Objektmodul
    stand.

SYMTAB: Darf als Werte ON und OFF annehmen.  Damit wird die  Ausgabe  einer
    Symboltabelle ein- oder ausgeschaltet.  Normalerweise wird eine Symbol-
    tabelle erzeugt.

EXTSYM: Wieder Werte ON/OFF. Schaltet das erweiterte GST-Format der Symbol-
    tabelle ein oder aus. Ist normalerweise eingeschaltet.

PRGEXT: Gibt die Extension an,  die das gelinkte  Programm  erhalten  soll.
    Beispiel :  'PRGEXT=TOS' erzeugt ein TOS-Programm (der Code  muž  dafr
    natrlich geeignet sein). Standardm„žig wird die Extension PRG benutzt.

STACKSIZE: Der Inhalt dieser Variablen muž eine Dezimalzahl sein,  die  die
    Gr”že des Stacks angibt. Normalerweise ist dies 32K.

LINKALSO: Diese Variable darf eine Liste von Dateinamen,  getrennt mit Kom-
    mata,  enthalten. Diese Objektmodule werden dann auch gelinkt, wenn sie
    nicht importiert werden.  Damit ist es z.B.  m”glich, w„hrend der Test-
    phase ein Debugmodul mitzulinken, daž sich in Exceptions einklinkt oder
    „hnliches.  Ein Name sollte immer nur 8 Zeichen lang  sein,  Extensions
    sind nicht n”tig.  Es sind nur maximal 5 Module m”glich. Mssen es mehr
    sein, so muž man ein Leermodul definieren, daž diese Module importiert,
    und dieses kann man bei LINKALSO angeben.

LINK_ ...: Alle Variablen,  die mit LINK_ anfangen,  dienen zum  Umbenennen
    von importierten Modulen.  Wird z.B.  LINK_IO=GEMIO definiert, wird bei
    jedem Import von IO stattdessen GEMIO gelinkt.  Diese Module mssen na-
    trlich gleiche Schnittstellen haben.


8) Die Lader
============

 Die Lader wurden zu einer Zeit entwickelt,  als es noch  keine  Shell  fr
Load-Time-Linking gab.  Sie sind daher in der Lage,  Objektmodule direkt zu
linken und zu starten.  Es gibt zwei  Lader,  einen  fr  GEM-Applikationen
(LOAD.PRG) und einen fr TOS-Applikationen (LOAD.TTP).  Inzwischen gibt  es
allerdings keinen Unterschied mehr.  Man braucht nur jeweils  die  richtige
Extension, damit beim Start die richtige Umgebung gew„hlt wird.

8.1) Aufruf, Parameter
----------------------

Die Lader erhalten mindestens den Namen eines Moduls als  Argument.  Dieses
Modul darf keine Extension haben,  also nur der Name. Das Modul wird zuerst
im Lader selbst gesucht,  dann in den Suchpfaden, die in der Environmentva-
riablen OBJPATH definiert sind.  Ist sie nicht definiert,  wird MODPATH ge-
nommen. Wenn ein Modul nicht gefunden wird, wird mit einer Meldung abgebro-
chen.  Sind alle Module geladen und gelinkt, wird das Hauptmodul gestartet.
Dabei ist die Variable Sys.Loader TRUE,  so daž man erkennen kann, wenn man
unter dem Lader l„uft.  Folgt auf den Namen des Moduls ein  Punkt  und  ein
weiterer Name, so wird dieser Name in der Liste der exportierten Prozeduren
gesucht und eine gefundene Prozedur wird gestartet. Dies realisiert die un-
ter Wirths Oberon bliche Art des  Load-Time-Linking.  Das  geladene  Modul
kann dies erkennen, denn die Variable Sys.ModuleCall wird auf TRUE gesetzt,
wenn nur das Modul gestartet wurde. In so einem Fall muž der Modulrumpf die
Aktion ausl”sen.  Sie wird auf FALSE gesetzt,  wenn eine Prozedur angegeben
wurde.  Dann dient der Modulrumpf nur zur Initalisierung.  Alles was hinter
dem Modul- bzw. Prozedurnamen folgt, wird als Kommando an das Modul weiter-
gegeben.  Man findet dies wie immer in Sys.Basepage.Command,  genau so  als
w„re das Modul als Programm gestartet worden.

8.2) Ausgabe
------------

Die Lader machen keine Ausgaben, solange keine Fehler auftreten.

  Eine m”gliche Fehlermeldung lautet:  'Objectmodule defect'.  Dies  deutet
auf einen Versionskonflikt hin.

  Wird ein Modul mit Extension bergeben (z.B. Icon auf Loader gezogen), so
wird das Modul normal gestartet mit Sys.ModuleCall FALSE.  Nach  Beendigung
des Moduls erscheint dann die Meldung 'Procedure OBJ not found',  falls die
Extension OBJ war. Dies ist nicht weiter sch„dlich.

  Die Lader haben ein angepažtes Modul fr  die  Exceptionbehandlung  inte-
griert.  Es gibt die Art des Fehlers,  die Adresse, das Modul, die Prozedur
mit Offset und die Parameter aus,  mit denen der Compiler aufgerufen werden
muž.
Beispiel:

  Bus error
  Address: 1ABEA0
  Module: Test
  Procedure: test + 8
  Call Compiler with '-e-o-s64'

Der Absturz fand also in der Prozedur Test.test statt,  8 Bytes vom  Anfang
der Prozedur entfernt. Wenn man jetzt den Compiler mit '-e-o-s64 Test' auf-
ruft, sucht er im Modul Test die Position 64 (64 Bytes vom Anfang entfernt,
hexadezimal!) und gibt ein paar Zeilen rund um die Position aus. Die Bedeu-
tung der Optionen ist in Kap. ?? erkl„rt.


9) Das Make-Utility
===================

  Der Begriff Make drfte von C her bekannt sein.  Hier ist es jedoch nicht
n”tig, ein Makefile zu erzeugen. Make (MAKE.OBJ/TTP) liest die importierten
Module aus dem Quelltext und bersetzt alle Dateien,  bei denen dies  n”tig
ist.

9.1) Aufruf, Parameter
----------------------

Make kann ohne Parameter oder mit einem Modulnamen gestartet  werden.  Wird
Make ohne Parameter gestartet, so werden alle Suchpfade nach zu bersetzen-
den Modulen durchsucht.  Wird ein Modul genannt,  werden nur solche  Module
berprft,  die in den Suchpfaden stehen und fr das Linken des angegebenen
Moduls ben”tigt werden.

9.2) Environmentvariablen
-------------------------

Mit der Environmentvariablen OC kann man den Compiler angeben.
Beispiel: OC=E:\OBERON\SYS\COMPILE.TTP
Ist OC nicht definiert,  wird 'COMPILE.TTP' im  aktuellen  Verzeichnis  ge-
sucht. Die Suchpfade fr Sourcen, Objekt- und Symboldateien werden ber die
Environmentvariable 'MAKEPATH' definiert.

9.3) Hinweise
-------------

Wenn Module sich gegenseitig importieren,  bleibt  Make  in  einer  Endlos-
schleife h„ngen.  Man erkennt dies daran,  daž st„ndig dieselben Dateinamen
ausgegeben werden. Mit Control-C kann man die Ausfhrung abbrechen.


10) Der Scanner
===============

  Der Scanner (SCAN.OBJ/TTP) dient dazu,  von einer Position in einem  Pro-
gramm die Stelle im richtigen Quelltext zu finden.  Dies erfordert eine er-
weiterte Symboltabelle am Programm. Diese erzeugt der Linker normalerweise,
wenn nichts anderes verlangt wird.

10.1) Aufruf, Parameter
-----------------------

Scan erwartet zwei Parameter in der Kommandozeile,  die mit Leerzeichen ge-
trennt sind:

 65) Der Name des Programms. Der Name muž so angegeben werden, daž Scan das
     Programm auch findet.

 66) Die Position im Programm. Sie wird hexadezimal ohne Zus„tze wie $ oder
     H angegeben.  Mit Position ist der Abstand von dem Codeanfang gemeint.
     Diese wird zum Beispiel von Exceptions ausgegeben.

Scan liest das Programm, bestimmt mit Hilfe der Symboltabelle das Modul und
die Position relativ zum Modulanfang und ruft den Compiler auf.  Als Optio-
nen werden -e,  -o und -s<pos>angegeben.  Der Compiler  bersetzt  das  be-
stimmte Modul,  bis er an die Position gelangt,  an der der Absturz  statt-
fand.  Es werden einige Zeilen davor und dahinter sowie eine  Kennzeichnung
der Stelle ausgegeben.  Diese Stelle wird auch als Fehlermeldung ausgegeben
und kann in der Fehlerdatei nachgelesen werden.  Dann beenden sich Compiler
und Scan.

  Falls das Programm keine Symboltabelle hat,  macht Scan eine Meldung  und
terminiert.

10.2) Environmentvariablen
--------------------------

Mit der Environmentvariablen OC kann man den Compiler angeben.
Beispiel: OC=E:\OBERON\SYS\COMPILE.TTP
Ist OC nicht definiert,  wird 'COMPILE.TTP' im  aktuellen  Verzeichnis  ge-
sucht.


11) Debugging
=============

Bis jetzt gibt es leider keinen Source  Level  Debugger  fr  STJ-Oberon-2.
Dies ist aber geplant und wird irgendwann kommen.  Bis dahin muž  man  sich
mit Low Level Debuggern herumplagen.

11.1) DB
--------

Der Debugger DB von Atari eignet sich einigermažen zum Debuggen. Ich m”chte
hier besonders auf den Befehl 'stack'  hinweisen:  Dieser  Befehl  versucht
ber den Stack die Aufrufkette von Subroutinen zurckzuverfolgen. Dies geht
auch mit Oberon-Programmen,  da diese genau wie C-Programme mit Register A6
lokale Stacks aufbauen.

11.2) Bugaboo
-------------

Bugaboo (aus dem TurboAss-Paket) eignet sich  ebenfalls  zum  Debuggen.  Er
kennt leider den Befehl 'stack' nicht,  ist dafr aber wesentlich komforta-
bler. Leider arbeitet er nicht auf dem TT mit Grožbildschirm.

11.3) Tips
----------

Zum Debuggen wird immer eine Symboltabelle ben”tigt.

  Eine globale Variable kann man ber den Namen ansprechen, lokale Variable
einer Prozedur findet man bei Adressen ab (A6) abw„rts,  deren Parameter ab
8(A6) aufw„rts.

  Die Namen der Symboltabelle sind nicht immer eindeutig. Wenn man also ein
Symbol ansprechen will, muž man erst prfen, ob es das Gewnschte ist. Bei-
spielsweise findet man die Prozedur 'Read' in File und in Paths.

  Einen Befehl sollte man immer im Hinterkopf haben:  Wenn n„mlich ein Pro-
gramm abgestrzt ist und man aus dem Debugger raus m”chte,  sollte man noch
die Exitprozedur aufrufen,  damit alle Betriebsmittel  freigegeben  werden.
Dazu muž man den PC auf das Symbol 'Exit' stellen und die Ausfhrung  star-
ten. Wenn der Exit nicht abstrzt, mžte eine Meldung ber die Terminierung
des Programms kommen.  Bei DB lautet der Befehl 'x pc .Exit',  bei  Bugaboo
'let pc=.Exit'.


12) Utilities
=============

12.1) Der Browser
-----------------

Ein Browser ist ein Programm,  daž aus der Symboldatei und der Source  eine
Definitionsdatei erzeugt.  Die vorliegende Version ist noch in der Entwick-
lung.  Sie wertet lediglich die Symboldatei aus, so daž keine Kommentare in
der Definitionosdatei sind.
Der Browser wurde von Dirk Theisen geschrieben.

12.2) Inline-Zeilen erzeugen
----------------------------

Fr den Fall,  daž jemand eine Datei als INLINE-Zeilen in eine Source inte-
grieren will (z.B.  eine Resourcedatei),  kann man dies mit Inline tun. In-
line fragt nach der zu konvertierenden Datei und speichert die erzeugte Da-
tei mit der Extension INL ab.  Im Editor muž man dann noch  den  Modulnamen
SYSTEM bzw.  eine Abkrzung davon mittels Suchen und  Ersetzen  vor  INLINE
setzen.


13) Speicherverwaltung
======================

Die Speicherverwaltung implementiert Funktionen zum Allozieren und  Freige-
ben dynamischen Speichers. Solcher Speicher ist grunds„tzlich nicht initia-
lisiert[6].

---------------

 [6]  wie auch lokale Variable,  lediglich globale Variable werden zu 0 in-
      itialisiert


13.1) Benutzung in Programmen
-----------------------------

Fr die dynamische Speicherverwaltung stehen mehrere Funktionen zur  Verf-
gung:

|NEW(<pointer>)|: Wenn als Argument ein Zeiger auf einen  Record  oder  ein
    konstantes Array bergeben wird, wird diese Struktur alloziert. Bei Re-
    cords werden 4 Bytes zus„tzlich alloziert,  die den Typdeskriptor  auf-
    nehmen.  Dieser steht immer _vor_ dem Record, d.h. der Zeiger zeigt im-
    mer auf das erste Element des Records, wohingegen er bei anderen Compi-
    lern auf den Deskriptor zeigt.

|NEW(<pointer>,<len>)|: Eine L„nge kann nur angegeben werden,  wenn es sich
    bei dem Zeiger um einen Zeiger auf ein offenes Array handelt. Dabei ist
    len die Anzahl Indizes.

|SYSTEM.NEW(<pointer>,<len>)|: SYSTEM.NEW kmmert sich nicht um den Typ des
    Zeigers. Es wird soviel Speicher alloziert, wie len in Bytes angibt. So
    allozierter Speicher wird niemals am Garbage Collect teilnehmen.

|SYSTEM.DISPOSE(<pointer>)|: Gibt den Speicher, auf den der bergebene Zei-
    ger zeigt, wieder frei.

  Der Garbage Collector wird mit Kernel.GC  aufgerufen.  Dies  fhrt  einen
kompletten Collect durch.  Es gibt auch eine M”glichkeit,  den  Collect  in
kleine Teile zerhackt nebenher  laufen  zu  lassen.  Dies  wrde  mit  Obe-
ron.Collect unter Chatwin gehen.  Dort sehe ich auch die einzige  sinnvolle
Anwendung. Im Moment kann ich von beidem nur abraten, da es noch nicht aus-
gereift ist.

  Hinweis:  Am Ende eines Programms oder Modulstarts wird automatisch aller
Speicher freigegeben.

13.2) Implementierung
---------------------

Die Implementierung versucht den  Kompromiž  zwischen  Geschwindigkeit  und
Overhead zu finden.  Der Overhead wird minimal,  wenn bei  jeder  Speicher-
anforderung genau der angeforderte Speicher alloziert wird (plus  ein  Ein-
trag in einer Liste).  Die Verwaltung der Liste hat aber so viel Zeit ben”-
tigt, daž der Compiler merklich langsamer wurde. Effizienter wird das, wenn
man den ben”tigten Speicher ein wenig aufrundet und in einem  Array  unter-
bringt.  Das kostet natrlich Speicher.  Um diesen Overhead nicht  zu  grož
werden zu lassen,  habe ich  Speicheranforderungen  in  16  Klassen  unter-
teilt[7].  Gr”žere Objekte ab 256 Byte werden in einer Liste verwaltet. Ob-
jekte zwischen 2 und 256 Byte  werden  in  Arrays  verwaltet,  deren  Elem-
entgr”že zwischen 16 und 256 Byte in 15 Stufen unterteilt ist.

  Gegenber GEMDOS stellt sich die Speicherverwaltung anders dar. Dort wird
immer mindestens 32K alloziert, so daž die Anzahl GEMDOS-Bl”cke nicht allzu
grož wird und damit die Geschwindigkeit abnimmt. Es kann auch nicht passie-
ren, daž die Speicherverwaltung des GEMDOS keine Eintr„ge mehr hat.

---------------

 [7]  Mombergs Oberon verwendet nur 5 Klassen und hat damit mehr Overhead



14) Die Bibliotheken
====================

Die Bibliotheken erm”glichen eigentlich erst ein vernnftiges Programmieren
mit einer Programmiersprache.  Hier soll eine šbersicht der vorhandenen Mo-
dule gegeben werden,  n„here Informationen  mssen  den  Definitionsdateien
entnommen werden.

14.1) Betriebssystem
--------------------

Alle Betriebssystemmodule implementieren die Aufrufe als Makros,  d.h.  der
Code fr den Trap wird beim Aufruf in den Code integriert.  Es erfolgt kein
Prozeduraufruf.  Der Nachteil dieser Methode ist, daž alle Parameter in der
Reihenfolge vertauscht sind.  Der Oberon-Compiler legt den ersten Parameter
auch als ersten auf den Stack, w„hrend C-Compiler den letzten Parameter als
erstes auf den Stack legen.

14.1.1) BIOS
............

Die blichen BIOS-Funktionen.

14.1.2) GEMDOS
..............

Die blichen GEMDOS-Funktionen.

14.1.3) MiNT
............

Die neuen Funktionen unter MiNT sind eigentlich  auch  GEMDOS-Aufrufe.  Sie
sind aber hier separat verfgbar.  Sys.MiNT gibt an,  ob  MiNT  installiert
ist.

14.1.4) XBIOS
.............

Die blichen XBIOS-Funktionen.  Es fehlen Erweiterungen von TT und  Falcon,
ber die ich keine Informationen habe.

14.2) Abstrakte Datenstrukturen
-------------------------------

14.2.1) BinTree
...............

BinTree implementiert einen bin„ren Baum.
BinTree wurde von H. M”ssenb”ck und Dirk Theisen geschrieben.

14.2.2) CDCL
............

CDCL steht fr Circular Double Chained List.  Es handelt sich also um  eine
doppelt verkettete Liste, deren erstes und letztes Element aufeinander zei-
gen.

14.2.3) DCL
...........

DCL steht fr Double Chained List.  Es handelt sich also  um  eine  doppelt
verkettete Liste.

14.2.4) FIFO
............

FIFO (First in first out) implementiert eine Liste,  an deren  Anfang  Ele-
mente eingefgt und an deren Ende sie wieder entnommen werden k”nnen.
FIFO wurde von Dirk Theisen geschrieben.

14.2.5) LRU
...........

LRU (Least recently used)  implementiert  eine  Priorit„tenliste  nach  dem
Prinzip 'am l„ngsten nicht mehr benutzt zuerst'.
LRU wurde von Dirk Theisen geschrieben.

14.2.6) Stack
.............

Stack implementiert eine Liste, an deren Anfang Elemente eingefgt und wie-
der entnommen werden k”nnen.
Stack wurde von Dirk Theisen geschrieben.

14.3) Standardmodule
--------------------

Unter diesem Abschnitt werden alle Module zusammengefažt, die in beliebigen
Applikationen (TOS oder GEM) benutzt werden k”nnen.

14.3.1) Buffers
...............

Buffers implementiert einen einfachen flexiblen Puffer,  der als  Grundlage
fr gepufferte Ausgabe dienen soll.

14.3.2) CommandLine
...................

CommandLine implementiert die Auswertung eines per  ARGV  bergebenen  Kom-
mandos, kann aber auch mit der normalen Commandline arbeiten.
CommandLine wurde von Dirk Theisen geschrieben.

14.3.3) Cookie
..............

Suchen, Setzen und L”schen von Eintr„gen im Cookie Jar.

14.3.4) Datum
.............

Das Modul Datum arbeitet mit Daten.
Datum wurde von Wolfgang Radtke geschrieben.

14.3.5) Environment
...................

Suchen von Eintr„gen im Environment.

14.3.6) Error
.............

Standardisierte  Ausgabe  von   Fehlermeldungen,   insbesondere   des   Be-
triebssystems, ber eine Alertbox.

14.3.7) Exceptions
..................

Exceptions f„ngt Softwarefehler wie Bus Error etc.  ab und gibt  eine  pas-
sende Meldung aus.  Es gengt,  Exceptions zu importieren oder mit LINKALSO
hinzuzulinken.

14.3.8) Execute
...............

Execute ist immer dann zu verwenden,  wenn man nicht genau weiž, in welcher
Form (Modul oder Programm) etwas gestartet werden soll.  Daher gibt es  ein
Execute im Lader,  das Module startet,  und ein kompatibles zum Linken, das
Programme startet.

14.3.9) File
............

Hoffnungslos veraltetes Modul zur Dateibehandlung.

14.3.10) FileBuffer
...................

Ebenfalls veraltetes Modul  zur  Dateibehandlung  mit  zwischengeschaltetem
Puffer.

14.3.11) Filename
.................

Zusammensetzen und Aufteilen von Dateinamen.

14.3.12) IO
...........

IO implementiert Standardprozeduren zur Ein- und Ausgabe auf dem  TOS-Bild-
schirm.  Die Benutzung in GEM-Programmen sollte vermieden werden,  da  dann
unsch”n auf den Bildschirm geschrieben wird.  Im Lader ist ein  kompatibles
Modul mit anderer Implementierung integriert,  daž die Ausgabe in das  CLI-
Fenster von Chatwin umlenkt.

14.3.13) Kernel
...............

Kernel  stellt  haupts„chlich  die  Speicherverwaltung,  aber  auch  einige
Hilfsprozeduren zur Verfgung.

14.3.14) Key
............

War mal die Grundlage fr die  Zuweisung  von  Prozeduren  zu  Tastenkombi-
nationen. Wird im Moment nicht benutzt.

14.3.15) MathCom
................

Grundlegende Prozeduren fr mathematische Funktionen. Entstammt LPR-Modula.

14.3.16) MathLib0
.................

šbliche mathematische Funktionen. Entstammt LPR-Modula.

14.3.17) Memory
...............

Sehr schnelle Prozeduren zum Kopieren und Fllen von Speicher.

14.3.18) Modules
................

Modules ist fr das Nachladen von Modulen in den Ladern zust„ndig.

14.3.19) MVC
............

MVC steht fr Model View Controller. Es implementiert Viewer, deren Ausgabe
vom Inhalt eines Models abh„ngen.  WinView baut darauf auf. Theoretisch ist
es aber nicht an Fenster gebunden,  man k”nnte auch Pseudofenster auf einem
TOS-Bildschirm darauf aufbauen.

14.3.20) NumStr
...............

Umwandlung von Zahlen in Strings und umgekehrt.

14.3.21) Paths
..............

Suchpfadverwaltung.

14.3.22) Strings
................

Was man so braucht um mit Strings umzugehen.

14.3.23) Supervisor
...................

Ein- und Ausschalten des Supervisormodus.

14.3.24) Sys
............

Die Grundlage aller Programme.  Enth„lt alle Standardfunktionen des  Compi-
lers sowie die Programminitialisierung.

14.3.25) Task
.............

Enth„lt den Mechanismus zur sauberen Terminierung von Programmen oder  Pro-
grammteilen. Normalerweise uninteressant fr Anwender.

14.3.26) VA
...........

VA enth„lt die Konstanten,  die fr das AV-Protokoll (Accessory <->  Venus)
ben”tigt werden.

14.4) VDI-Module
----------------

Das VDI implementiert alles zur Ausgabe auf beliebigen Ger„ten.  Es ist mir
nicht bekannt, ob es auch in TOS-Programmen benutzt werden darf.

14.4.1) VDI
...........

Die grundlegenden Strukturen und Variablen zur Arbeit mit dem VDI.

14.4.2) VDIAttributes
.....................

Einstellen von Attributen fr die Ausgabe.

14.4.3) VDIControl
..................

Kontrollfunktionen des VDI.  Es existiert  eine  zus„tzliche  Funktion  zum
Test, ob GDOS installiert ist.

14.4.4) VDIExcapes
..................

Escaperoutinen des VDI.

14.4.5) VDIInput
................

Eingaberoutinen des VDI.

14.4.6) VDIInquiry
..................

Abfrageroutinen des VDI.

14.4.7) VDIOutput
.................

Ausgaberoutinen des VDI.

14.4.8) VDIRaster
.................

Rasterfunktionen des VDI.  Zus„tzlich gibt es hier ein paar  Kopierroutinen
zum Scrollen von Bildschirmausschnitten.

14.5) AES-Module
----------------

Das AES implementiert das,  was man so liebgewonnen hat auf dem Atari:  Me-
ns, Fenster und und und. Bis auf Form.Alert fhren diese Prozeduren in ei-
nem TOS-Programm zum Absturz.

14.5.1) AES
...........

Die grundlegenden Strukturen und Variablen zur Arbeit mit dem AES.

14.5.2) Appl
............

Die Funktionen der Application Library.

14.5.3) Evnt
............

Die Funktionen der Event Library.

14.5.4) Form
............

Die Funktionen der Form Library.  Form.Alert darf  auch  in  TOS-Programmen
verwendet werden.

14.5.5) Fsel
............

Fileselectbox darstellen. Die neue Funktion mit Titel ist auch vorhanden.

14.5.6) Graf
............

Die Funktionen der Graphics Library.  Graf.Mouse wurde auf vier  Prozeduren
verteilt und Graf.Mkstate in Evnt verlegt.

14.5.7) Menu
............

Die Funktionen der Menu Library.

14.5.8) Objc
............

Die Funktionen der Object Library, stark erweitert um Funktionen zum Umgang
mit den Objekten.

14.5.9) Rsrc
............

Die Funktionen der Resource  Library.  Rsrc.Load  ist  auch  in  der  Lage,
selbst„ndig zu suchen, wenn ein Resourcefile nicht gefunden wurde.

14.5.10) Wind
.............

Die Funktionen der Window Library.

14.6) Erweiterte AES-Module
---------------------------

Zum einfacheren Umgang mit dem AES wurden folgende Module entwickelt:

14.6.1) Dialogs
...............

Dialogs enth„lt alle Prozeduren,  um ganz  einfach  eine  Dialogbox  darzu-
stellen und den Dialog mit dem Anwender zu fhren.

14.6.2) FontSelect
..................

FontSelect bietet eine einfache M”glichkeit, mit einer Dialogbox den Benut-
zer einen Font ausw„hlen zu lassen.

14.6.3) GemApp
..............

GemApp bildet die Grundlage zur Programmierung  von  GEM-Applikationen.  Es
muž unbedingt benutzt werden,  wenn die  erweiterten  AES-Module  verwendet
werden.

14.6.4) GEMIO
.............

GEMIO ist das Pendant zu IO fr TOS.  Die Schnittstellen sind identisch, so
daž man statt IO auch GEMIO linken kann.

14.6.5) Menus
.............

Menus automatisiert den Aufruf von Prozeduren ber Menpunkte oder  Tasten-
kombinationen. Die Tastenkombinationen werden aus dem Eintrag des Mens ge-
lesen und k”nnen dadurch von Benutzern individuell ge„ndert werden!

14.6.6) TermWin
...............

TermWin erweitert WinView derart,  daž mit blichen Schreibbefehlen (Write-
String...) Text in einem Fenster ausgegeben werden kann.  Desweiteren  wird
ein Event STRING eingefhrt.

14.6.7) WindowDialog
....................

WindowDialog verlegt einen Dialog in ein Fenster.

14.6.8) WinView
...............

WinView ist die Grundlage fr Fensterapplikationen.  Fast das gesamte Hand-
ling von Fensters ist automatisiert.  Im einfachsten Fall muž man nur  noch
eine Redrawprozedur implementieren.


15) Tutorial
============

Im nun folgenden Kapitel soll ein GEM-Programm entwickelt werden,  daž eine
Menleiste hat,  ber einen Dialog in einem Fenster Eingaben erm”glicht und
diese Eingaben graphisch in beliebig vielen Fenstern  ausgeben  kann.  Eine
neue Eingabe muž dann natrlich in allen Fenstern gezeichnet werden.

15.1) Die Resourcedatei
-----------------------

Die Resourcedatei wird mit einem Resource Construction  Set  erstellt.  Die
Resourcedatei fr unser Projekt heižt GEMDEMO.RSC.  Wer noch nie  eine  Re-
sourcedatei erzeugt hat,  sollte sich erstmal mit einem RCS  GEMDEMO.RSCan-
gucken und mal etwas damit spielen.  Aber bitte nicht ver„ndert abspeichern
und mir dann eine Mail schicken, das Demo wrde nicht funktionieren!

15.2) Der Rumpf
---------------

[hbpt]

MODULE Tutor1;

IMPORT GemApp;

VAR
  myApp : GemApp.Application;

BEGIN
  NEW( myApp);
  myApp.Init; myApp.Run; myApp.Exit
END Tutor1.



  Abb. ?? zeigt den prinzipiellen Aufbau einer Applikation:  Definition ei-
ner Variablen vom Typ Application,  deren Initialisierung  und  Aufruf  der
daran gebundenen Prozeduren Init, Run und Exit. Init initialisiert das Pro-
gramm.  Dazu geh”rt z.B.  die Anmeldung beim  AES.  Run  implementiert  die
Event-Schleife,  also warten auf Events vom AES und Aufruf von HandleEvent,
das ebenfalls an Application gebunden ist. Exit meldet die Applikation dann
wieder ab und sorgt auch fr  eine  saubere  Terminierung,  z.B.  Schliežen
evtl. offen gebliebener Fenster etc. Sollte jemand dieses Programm starten,
wird er in die Eventschleife gelangen.  Diese kann  mit  Control-Qverlassen
werden, diese Taste wird immer ausgewertet.

15.3) Resourcedatei laden
-------------------------

Als n„chstes mssen wir die Resourcedatei laden. Abb. ?? zeigt die Erweite-
rungen.

[hbpt]

TYPE
  Application = POINTER TO ApplDesc;
  ApplDesc    = RECORD(GemApp.ApplDesc)
                END;

VAR
  myApp : Application;

PROCEDURE (app : Application) Init;
 BEGIN
  app.Init^;
  Graf.ChangeMouse( Graf.ARROW);
  IF NOT Rsrc.Load("GEMDEMO.RSC") THEN
    app.Exit
  END;
 END Init;



  Zun„chst wurde eine Erweiterung von GemApp.ApplDesc definiert, damit eine
neue Prozedur Init daran gebunden werden kann.  Diese muž unbedingt als er-
stes die geerbte Prozedur Init aufrufen.  Als n„chstes wird der  Mauszeiger
als Pfeil dargstellt, da er beim Programmstart immer auf 'Biene' steht. Der
Aufruf von Rsrc.Load bewirkt das Laden und evtl.  auch Suchen der Resource-
datei.  Wenn der Benutzer in der  Fileselectbox  'Abbruch'  anklickt,  gibt
Rsrc.Load FALSE zurck und die Applikation wird terminiert.  app.Exit  wird
nicht mehr verlassen, deshalb geht das. Wenn man das Programm startet, ver-
h„lt es sich wie Tutor1, nur daž die Maus auf Pfeil umgeschaltet wird.

15.4) Die Menzeile
-------------------

Nun wollen wir die Menzeile anzeigen.  Abb. ?? zeigt die  Erweiterung  von
Init.

[hbpt]

TYPE
  Application = POINTER TO ApplDesc;
  ApplDesc    = RECORD(GemApp.ApplDesc)
                END;

PROCEDURE ShowInfo;
  VAR d : INTEGER;
 BEGIN
  d := Form.Alert(1, "[1][Tutor3 by Stephan Junker][Ok]");
 END ShowInfo;

PROCEDURE Exit;
 BEGIN
  GemApp.exit := TRUE;
 END Exit;

PROCEDURE (app : Application) Init;
  VAR menu : Menus.Menu;
 BEGIN
  [...]
  NEW(menu); menu.Init( Rsrc.GetAddr(MENU) );
  menu.Set( FILE, QUIT, Exit );
  menu.Set( DESK, INFO, ShowInfo );
  menu.Show;
 END Init;



  Zun„chst alloziert man das Objekt menu und initialisiert es.  Sodann emp-
fiehlt es sich,  eine Prozedur fr den Menpunkt QUIT anzumelden, damit man
das Programm auch wieder verlassen kann.  Dann kann man mit  menu.Show  die
Menzeile darstellen.

  Beim Start werden sie feststellen,  daž sowohl beim Anklicken von  'Quit'
als auch bei Drcken von Control-Qdas Programm verlassen wird. Wie funktio-
niert das? Ganz einfach: Menus hat mit GemApp.StoreEventHandler eine Proze-
dur angemeldet,  die Events verarbeitet.  Diese wird immer aufgerufen, wenn
ein Ereignis vom AES gemeldet wird,  und filtert die Ereignisse heraus, die
fr das Men ben”tigt werden.

15.5) Ein Fenster ”ffnen
------------------------

Beim Aufruf des Menpunktes 'Ausgabefenster' soll nun ein Fenster  ge”ffnet
werden.  Der Einfachheit halber wird es nur eine weiže  Fl„che  darstellen.
Abb. ?? zeigt die Žnderungen.




TYPE
  Viewer    = POINTER TO ViewDesc;
  ViewDesc  = RECORD(WinView.ViewDesc)
              END;
  MyModel   = POINTER TO ModelDesc;
  ModelDesc = RECORD(MVC.ModelDesc)
              END;

VAR
  myModel : MyModel;
  Station : INTEGER;
  Workout : VC.workout;

PROCEDURE(v : Viewer) Redraw(x,y,w,h : INTEGER);
  VAR x2, y2 : INTEGER;
 BEGIN
  x2 := x+w-1; y2 := y+h-1;
  VC.VsClip( Station, TRUE, x, y, x2, y2);
  VO.VBar( Station, x, y, x2, y2 );
 END Redraw;

PROCEDURE OpenOutput;
  VAR outWin  : Viewer;
 BEGIN
  NEW( outWin); outWin.Init;
  outWin.model := myModel;
  outWin.SetTitle("Objektfenster");
  outWin.SetFullSize( 0, 19, Workout.MaxX - 1,
                      Workout.MaxY - 20);
  outWin.Open;
 END OpenOutput;

PROCEDURE (app : Application) Init;
  VAR Workin : VC.workin;
      menu : Menus.Menu;
 BEGIN
  [...]
  NEW( menu); menu.Init( Rsrc.GetAddr(MENU) );
  menu.Set( FILE, QUIT, Exit );
  menu.Set( DESK, INFO, ShowInfo );
  menu.Set( WORK, OUTPUT2, OpenOutput );
  menu.Show;
  Station := 1;
  Workin.Id := 1; Workin.LineType := 1;
  Workin.LineColor := 1; Workin.MarkType := 1;
  Workin.MarkColor := 1; Workin.Font := 1;
  Workin.TextColor := 1; Workin.FillStyle := 0;
  Workin.FillPat := 0; Workin.FillColor := 1;
  Workin.KoorType := 2;
  VC.VOpnvwk(Workin,Station,Workout);
  VA.VswrMode(Station,VA.REPLACE);
  VA.VsfPerimeter(Station,FALSE);
  NEW( myModel); myModel.Init;
 END Init;

[hbpt]


  Zun„chst wird die Prozedur OpenOutput fr den  Menpunkt  angemeldet.  Es
folgt die ™ffnung einer virtuellen Workstation,  die zum Zeichnen des  Fen-
sterinhaltes ben”tigt wird.  Als letztes wird noch ein Model initialisiert,
das sp„ter die Daten fr die Ausgabefenster aufnimmt.  OpenOutput  muž  ein
Fenster initialisieren, das Model, Titel und maximale Gr”že festlegen. Dann
kann es ge”ffnet werden.  outWin ist tats„chlich eine lokale Variable!  Wie
das gehen soll? Ganz einfach, die Verwaltung der Fenster bernimmt WinView!
Das einzige,  was wir noch machen mssen,  ist den Inhalt neuzeichnen. Dies
bernimmt die Prozedur Redraw, die an einen Typ Viewer gebunden werden muž.
Diese wird von WinView immer automatisch aufgerufen,  wenn das AES eine Re-
draw-Message verschickt. Die Ereignisse, die Fenster betreffen, werden wie-
der durch einen EventHandler bearbeitet,  der bei GemApp angemeldet  wurde.
Deshalb funktionieren auch Mover,  Closer,  Fuller etc.  ohne das  wir  uns
darum gekmmert haben!

15.6) Einen Dialog darstellen
-----------------------------

Nun wollen wir einen Dialog mit dem Benutzer in einem Fenster  fhren.  Die
Žnderungen sind in Abb. ?? skizziert.

[hbpt]

VAR
  infoDial : WDial.Viewer;

PROCEDURE ShowInfo;
 BEGIN
  infoDial.Open;
 END ShowInfo;

PROCEDURE (app : Application) Init;
 BEGIN
  [...]
  NEW( infoDial);
  infoDial.InitDialog( Rsrc.GetAddr(BOX) , 0, TRUE);
  infoDial.SetWork(OK, NIL, { WDial.DESELECT,
                              WDial.EXITONLY } );
  infoDial.SetWork(OUTPUT1, OpenOutput,
             { WDial.DESELECT, WDial.REDRAWOBJ } );
  infoDial.SetTitle("Information");
 END Init;



  Die Initialisierung eines Dialog erfolgt wieder in Init.  Mit  InitDialog
wird der Viewer initialialisiert.  Dabei wird ihm auch der  zugeh”rige  Ob-
jektbaum mitgeteilt. Mit SetWork werden den Buttons im Dialog, die den Sta-
tus Exit haben, Prozeduren zugewiesen, die beim Anklicken aufgerufen werden
sollen. An dieser Stelle ist auch schon eine zweite M”glichkeit vorgesehen,
ein Ausgabefenster zu ”ffnen.  Ge”ffnet wird der Dialog  ber  den  Eintrag
'Information'.

15.7) Das fertige Programm
--------------------------

Was noch fehlt,  ist eine Dialogbox zur Eingabe von Objekten und der Redraw
dieser Objekte. Abb. ?? zeigt das komplette Programm.



MODULE GemDemo;


IMPORT S:=SYSTEM, GemApp, MVC, WinView, Evnt,
       Graf, VC:=VDIControl, VA:=VDIAttributes,
       VO:=VDIOutput, Menus, Rsrc, Form, Objc,
       WDial:=WindowDialog, NumStr;


CONST
    BOX        = 0; (* form/dialog *)
    OK         = 4; (* BUTTON in tree BOX *)
    INPUT1     = 5; (* BUTTON in tree BOX *)
    OUTPUT1    = 6; (* BUTTON in tree BOX *)

    MENU       = 1; (* menu *)
    DESK       = 3; (* TITLE in tree MENU *)
    FILE       = 4; (* TITLE in tree MENU *)
    WORK       = 5; (* TITLE in tree MENU *)
    INFO       = 8; (* STRING in tree MENU *)
    QUIT       = 17; (* STRING in tree MENU *)
    INPUT2     = 19; (* STRING in tree MENU *)
    OUTPUT2    = 20; (* STRING in tree MENU *)

    INPUTBOX   = 2; (* form/dialog *)
    CIRCLE     = 2; (* BUTTON in tree INPUTBOX *)
    RECT       = 3; (* BUTTON in tree INPUTBOX *)
    XPOS       = 4; (* FTEXT in tree INPUTBOX *)
    YPOS       = 5; (* FTEXT in tree INPUTBOX *)
    RADIUS     = 6; (* FTEXT in tree INPUTBOX *)
    WIDTH      = 7; (* FTEXT in tree INPUTBOX *)
    HEIGHT     = 8; (* FTEXT in tree INPUTBOX *)
    DRAW       = 9; (* BUTTON in tree INPUTBOX *)



TYPE
  Viewer    = POINTER TO ViewDesc;
  ViewDesc  = RECORD(WinView.ViewDesc)
              END;
  Application = POINTER TO ApplDesc;
  ApplDesc  = RECORD(GemApp.ApplDesc)
              END;
  Object    = POINTER TO ObjDesc;
  ObjDesc   = RECORD
                next : Object;
                x,y  : INTEGER;
              END;
  Circle    = POINTER TO CircleDesc;
  CircleDesc= RECORD(ObjDesc)
                r : INTEGER;
              END;
  Rect      = POINTER TO RectDesc;
  RectDesc  = RECORD(ObjDesc)
                w,h  : INTEGER;
              END;
  MyModel   = POINTER TO ModelDesc;
  ModelDesc = RECORD(MVC.ModelDesc)
                objects : Object;
              END;


VAR myApp : Application;
    infoDial,inputDial : WDial.Dialog;
    myModel : MyModel;
    Station : INTEGER;
    Workout : VC.workout;


PROCEDURE(o : Object) Draw(v : Viewer);
 BEGIN
 END Draw;


PROCEDURE(c : Circle) Draw(v : Viewer);
 BEGIN
  VO.VArc( Station, v.x - SHORT( v.xOff) + c.x,
         v.y - SHORT( v.yOff) + c.y, c.r, 0, 3600 );
 END Draw;


PROCEDURE(r : Rect) Draw(v : Viewer);
  VAR Edges : ARRAY 10 OF INTEGER;
 BEGIN
  Edges[0] := v.x - SHORT( v.xOff) + r.x;
  Edges[1] := v.y - SHORT( v.yOff) + r.y;
  Edges[2] := Edges[0];
  Edges[3] := Edges[1] + r.h - 1;
  Edges[4] := Edges[0] + r.w - 1;
  Edges[5] := Edges[3];
  Edges[6] := Edges[4];
  Edges[7] := Edges[1];
  Edges[8] := Edges[0];
  Edges[9] := Edges[1];
  VO.VPline( Station, 5, Edges);
 END Draw;


PROCEDURE(v : Viewer) Redraw(x,y,w,h : INTEGER);
  VAR x2, y2 : INTEGER;
      obj : Object;
 BEGIN
  x2 := x+w-1; y2 := y+h-1;
  VC.VsClip( Station, TRUE, x, y, x2, y2);
  VO.VBar( Station, x, y, x2, y2 );
  obj := myModel.objects;
  WHILE obj # NIL DO
    obj.Draw(v); obj := obj.next;
  END;
 END Redraw;


PROCEDURE(m : MyModel) Init;
 BEGIN
  m.objects := NIL; m.Init^;
 END Init;


PROCEDURE ShowInfo;
 BEGIN
  infoDial.Open;
 END ShowInfo;


PROCEDURE Exit;
 BEGIN
  GemApp.exit := TRUE; (* die saubere Methode *)
 END Exit;


PROCEDURE OpenInput;
 BEGIN
  inputDial.Open;
 END OpenInput;


PROCEDURE SetDWH(v : Viewer);
  VAR obj : Object; maxX, maxY, dw, dh : INTEGER;
 BEGIN
  obj := myModel.objects;
  dw := SHORT(v.dw); dh := SHORT(v.dh);
  WHILE obj # NIL DO
    IF obj IS Rect THEN
      maxX := obj.x + obj(Rect).w;
      maxY := obj.y + obj(Rect).h;
    ELSE
      maxX := obj.x + obj(Circle).r;
      maxY := obj.y + obj(Circle).r;
    END;
    IF maxX > dw THEN dw := maxX END;
    IF maxY > dh THEN dh := maxY END;
    obj := obj.next;
  END;
  IF dw # v.dw THEN v.dw := dw; v.HSlider END;
  IF dh # v.dh THEN v.dh := dh; v.VSlider END;
 END SetDWH;


PROCEDURE OpenOutput;
  VAR outWin  : Viewer;
 BEGIN
  NEW( outWin); outWin.Init;
  outWin.model := myModel; SetDWH(outWin);
  outWin.SetTitle("Objektfenster");
  outWin.SetFullSize( 0, 19, Workout.MaxX - 1,
                      Workout.MaxY - 20);
  outWin.Open;
 END OpenOutput;


PROCEDURE(v : Viewer) Update( aspect : LONGINT);
 BEGIN
  v.Update^( aspect); SetDWH(v);
 END Update;

(*$T- wegen NEW( obj(Rect) ) bzw. NEW( obj(Circle) ),
      denn Typcheck geht nur wenn das Objekt schon
      alloziert ist ... *)

PROCEDURE EnterNewObject;
  VAR x,y : INTEGER; obj : Object;
      tep : Objc.tedinfoptr;
 BEGIN
  IF Objc.SELECTED IN
     Objc.GetState( inputDial.objTree, RECT) THEN
    NEW( obj(Rect) );
    tep := Objc.GetSpec( inputDial.objTree, WIDTH);
    obj(Rect).w := NumStr.ToInt( 10, tep.Text^);
    tep := Objc.GetSpec( inputDial.objTree, HEIGHT);
    obj(Rect).h := NumStr.ToInt( 10, tep.Text^);
  ELSE
    NEW( obj(Circle) );
    tep := Objc.GetSpec( inputDial.objTree, RADIUS);
    obj(Circle).r := NumStr.ToInt( 10, tep.Text^);
  END;
  tep := Objc.GetSpec( inputDial.objTree, XPOS);
  obj.x := NumStr.ToInt( 10, tep.Text^);
  tep := Objc.GetSpec( inputDial.objTree, YPOS);
  obj.y := NumStr.ToInt( 10, tep.Text^);
  obj.next := myModel.objects;
  myModel.objects := obj;
  myModel.Changed( 0);
 END EnterNewObject;

(*$T= *)

PROCEDURE EnableCircle;
 BEGIN
  inputDial.SetCursor( XPOS);
  Objc.SetFlags( inputDial.objTree, WIDTH,
                 {Objc.EDITABLE, Objc.HIDDEN} );
  inputDial.RedrawObj( WIDTH);
  Objc.SetFlags( inputDial.objTree, HEIGHT,
                 {Objc.EDITABLE, Objc.HIDDEN} );
  inputDial.RedrawObj( HEIGHT);
  Objc.SetFlags( inputDial.objTree, RADIUS,
                 {Objc.EDITABLE} );
  inputDial.RedrawObj( RADIUS);
 END EnableCircle;


PROCEDURE EnableRect;
 BEGIN
  inputDial.SetCursor( XPOS);
  Objc.SetFlags( inputDial.objTree, RADIUS,
                {Objc.EDITABLE, Objc.HIDDEN} );
  inputDial.RedrawObj( RADIUS);
  Objc.SetFlags( inputDial.objTree, WIDTH,
                {Objc.EDITABLE} );
  inputDial.RedrawObj( WIDTH);
  Objc.SetFlags( inputDial.objTree, HEIGHT,
                {Objc.EDITABLE} );
  inputDial.RedrawObj( HEIGHT);
 END EnableRect;


PROCEDURE(app: Application) Init;
  VAR menu : Menus.Menu;
      Workin  : VC.workin;
 BEGIN
  app.Init^; (* must come first! *)
  Graf.ChangeMouse( Graf.ARROW);
  IF NOT Rsrc.Load("GEMDEMO.RSC") THEN
    app.Exit
  END;
  NEW(menu); menu.Init( Rsrc.GetAddr(MENU) );
  menu.Set( FILE, QUIT, Exit );
  menu.Set( DESK, INFO, ShowInfo );
  menu.Set( WORK, OUTPUT2, OpenOutput );
  menu.Set( WORK, INPUT2, OpenInput );
  menu.Show;
  Station := 1;
  Workin.Id := 1; Workin.LineType := 1;
  Workin.LineColor := 1; Workin.MarkType := 1;
  Workin.MarkColor := 1; Workin.Font := 1;
  Workin.TextColor := 1; Workin.FillStyle := 0;
  Workin.FillPat := 0; Workin.FillColor := 1;
  Workin.KoorType := 2;
  VC.VOpnvwk(Workin,Station,Workout);
  VA.VswrMode(Station,VA.REPLACE);
  VA.VsfPerimeter(Station,FALSE);
  NEW( myModel); myModel.Init;
  NEW( infoDial);
  infoDial.InitDialog( Rsrc.GetAddr(BOX) , 0, TRUE);
  infoDial.SetWork(OK, NIL, { WDial.DESELECT,
                              WDial.EXITONLY } );
  infoDial.SetWork(INPUT1, OpenInput,
             { WDial.DESELECT, WDial.REDRAWOBJ } );
  infoDial.SetWork(OUTPUT1, OpenOutput,
             { WDial.DESELECT, WDial.REDRAWOBJ } );
  infoDial.SetTitle("Information");
  NEW( inputDial);
  inputDial.InitDialog( Rsrc.GetAddr(INPUTBOX),
                       XPOS, TRUE);
  inputDial.SetWork(DRAW, EnterNewObject,
             { WDial.DESELECT, WDial.REDRAWOBJ } );
  inputDial.SetWork(CIRCLE, EnableCircle, {} );
  inputDial.SetWork(RECT, EnableRect, {} );
  inputDial.SetTitle("Neues Objekt");
  inputDial.SetText( XPOS, "");
  inputDial.SetText( YPOS, "");
  inputDial.SetText( WIDTH, "");
  inputDial.SetText( HEIGHT, "");
  inputDial.SetText( RADIUS, "");
  Objc.SetState( inputDial.objTree, RECT,
                 {Objc.SELECTED} );
 END Init;


BEGIN
  NEW(myApp);
  myApp.Init; myApp.Run; myApp.Exit
END GemDemo.


[hbpt]


  Was hat sich getan? Nun,  der Typ ModelDesc nimmt jetzt die Objekte  auf,
die dargestellt werden sollen. Redraw wurde erweitert, damit es die Objekte
zeichnen kann.  Eine weitere Dialogbox,  mit der die Objekte  vom  Anwender
eingegeben werden,  wurde erzeugt.  EnterNewObject liest die  Eingaben  aus
dieser Box und erzeugt daraus ein neues Objekt.  Mit EnableCircle bzw. Ena-
bleRect wird die Darstellung der Box ge„ndert,  je nachdem ob der  Benutzer
Kreis oder Rechteck verlangt.  SetDWH pažt die Gr”že  der  Zeichnung  (also
dessen was insgesamt dargestellt werden soll) immer an die Gr”že der einge-
gebenen Objekte an. So kann man auch Zeichnungen darstellen, die gr”žer als
ein Fenster sind.  Die Slider,  Pfeile etc.  werden alle automatisch  durch
WinView bedient.  Man kann praktisch unbegrenzt Fenster  ”ffnen  (zumindest
wenn man Winx oder MultiTOS installiert hat),  und bei Eingabe eines  neuen
Objektes werden alle auf den neuesten Stand gebracht.  Aber  jedes  Fenster
kann natrlich einen anderen Ausschnitt darstellen.

15.8) Zusammenfassung
---------------------

Dieses Kapitel sollte einige M”glichkeiten von Oberon  und  der  GEM-Module
zeigen.  Das Ergebnis war ein 300 Zeilen langes Programm,  daž  hoffentlich
einen guten Eindruck hinterlassen hat.


16) Anhang
==========

16.1) Literatur
---------------

N.  Wirth, J. Gutknecht: <Project Oberon: The design of an Operating System
and Compiler,> Addison-Wesley (1992), ISBN 0-201-54428-8.

M.  Reiser:  <The Oberon System: Usesr Guide and Programmer's Manual> Addi-
son-Wesley (1991), ISBN 0-201-54422-9.

M.  Reiser,  N.  Wirth:  <Programming in Oberon:  Steps beyond  Pascal  and
Modula>, Addison-Wesley (1992)

16.2) Danksagungen
------------------

Dank an Frank Storm,  der mich darauf gebracht hat, statt einem Modula- ei-
nen Oberon-Compiler zu schreiben und anfangs auch die E-Mail erledigt hat.

Dank an den Chefbetatester Dirk Theisen fr den Browser und sonstige Unter-
sttzung.

Dank an alle, die ber Fehler berichten und neue Module implementieren.

Dank an Christian Strunk fr seine TeX-Implementierung.

Dank an Roman Hodek fr TeX2TXT, mit dem diese Anleitung in einen ganz pas-
sablen Asciitext konvertiert werden konnte.

Ach ja,  dann sollte ich wohl auch noch Niklaus Wirth und seinem Team  dan-
ken, daž er Oberon erdacht hat und die Sourcen frei weitergibt.