*STJ-OBERON-2 *
*Eine Oberon-2 Implementation
fr 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) Formelausdrcke
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 Menzeile
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 drckte. 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 natrlich, 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 natrlich 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 ausfhrbaren 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 natrlich er-
wnscht.
Der Compiler hat bereits starke Erweiterungen gegenber 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-Untersttzung. Ansonsten
werden natrlich 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. Dafr 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 bemhe mich, sie noch alle zu entfernen.
Ich bernehme keine Garantie fr die Funktionsf„higkeit dieses Programms
und hafte nicht fr Sch„den, die dieses Programm verursacht. Falls Fehler
entdeckt werden, sollte man mich m”glichst genau darber 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
=============================
Fr 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 berflssig, 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 fhrte ein Import des Typbezeichners zum impliziten Import
aller assoziierten Konstantenbezeichner.
_Unterbereichstypen_ hatten nicht den Nutzen, der die dafr 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. Dafr 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 fr den Compiler nicht mehr n”tig, aber man sollte
sie natrlich fr den Programmierer erzeugen. Dafr ist der Browser vorge-
sehen. Der Export geschieht jetzt, indem man hinter einem Bezeichner einen
Stern fr normalen oder ein Minuszeichen (bei Variablen und Feldelementen)
fr 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 fr Zeiger auf solche
Typen. Mit einem Typeguard der Form var(typ) kann man zur Compilezeit den
Typen festlegen. Zur Laufzeit wird dann berprft, 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 fr die Parameter angegeben.
_Globale Variablendeklarationen_ mssen 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 mssen mit Komma oder Semikolon getrennt werden. Ein Backslash am
Ende ist m”glich, aber nicht n”tig. Eine kleine M”glichkeit fr 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\*.*gengen.
Beispiel: MODPATH=E:\OBERON\LIB\*
Damit k”nnen alle Dateien gefunden werden, die den Mustern E:\OBERON\LIB\*\*.*gengen.
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 fr 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 fr 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 vernnftig konfigurieren. Dies ist ein Beispiel-Setup fr 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, fr jedes Projekt eine Batchdatei ein-
zurichten, in der Pfade, Namen, Extension etc. definiert werden. Hier ist
mal ein Beispiel, daž ich fr 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 fr 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 fr 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, mssen die Module auch gefunden werden.
Hinweis: Im Prinzip ist der Linker auch in der Lage, die T„tigkeit des
Installationsprogramms durchzufhren. 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 unterdrckt.
-i: Schaltet den Indexcheck aus, da er defaultm„žig eingeschaltet ist. In-
dexcheck bewirkt eine šberprfung der Arraygrenzen von Indizes zur
Laufzeit und ist mit einer geringfgigen 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 geprft, 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 berprfen, 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 mssen 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 fr den Typcheck.
ARICHK: Wie INXCHK, jedoch fr 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 natrlich die
Fehlermeldung selbst mit \f ausgeben lassen. Diese Teile werden dort in
der Zeile eingefgt, wo die Krzel 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
--------------------------
Fr 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 verfgbar.
(*$T?*): Wie I fr den Typcheck. Eingeschalteter Typcheck bewirkt eine Ty-
pberprfung bei jedem Zugriff auf den gesamten Record. Diese Option
ist nur im Oberon-Teil verfgbar.
(*$A?*): Wie I fr den Arithmetikcheck. Wird im Moment noch nicht unter-
sttzt. Die Routinen im Modul System (Grundrechenarten) melden arithme-
tische Fehler, auch ohne diesen Check.
Diese Option ist nur im Oberon-Teil verfgbar.
(*$N?*) Diesmal gibt das Fragezeichen einen Dateinamen an. Unter diesem Na-
men wird sp„ter das gelinkte Programm gespeichert. Vor dem Namen drfen
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 verfgbar.
(*$O?*) Wenn ein '-' angegeben wird, wird der folgende Code bei der Opti-
mierung nicht angerhrt. Bei O+ wird die Optimierung wieder zugelassen.
Es darf keine Verschachtelung stattfinden.
Diese Option ist auch im Assembler verfgbar.
(*$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 kmmert 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. fr 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 gewnschte Programm.
Diese Option ist auch im Assembler verfgbar.
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 verfgbar.
(*$V+?=...*) und (*$V-?=...*) Wie oben, jedoch wird auch der Inhalt der Va-
riablen angegeben. Die Bedingung ist also erfllt, wenn die Variable
definiert ist und den angegebenen Wert hat (beliebiger String ohne
Leerzeichen).
Diese Option ist auch im Assembler verfgbar.
(*$V=*) Damit wird die Abh„ngigkeit von allen vorher angegebenen Variablen
ausgeschaltet.
Diese Option ist auch im Assembler verfgbar.
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 fr 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 fr eine Variable, x
und n fr Ausdrcke, a fr Adresse und T fr 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 | fgt 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
zurckgeben.
- Es gibt eine Abart von Prozeduren, die fr 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 zurckgeben, funktioniert dies also auch. Lediglich die Rei-
henfolge der Parameter mssen vertauscht werden.
- Bei Wirth mssen 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 fr
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 fr 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 zurck 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, strzt der Compiler
nach der šbersetzung ab.
6) Der Assembler
================
Im Compiler ist ein Makroassembler integriert. Dieser ist ursprnglich 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 fr 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ž.
Fr 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 mssen 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 prfen, 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 drfen 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 mssen
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 natrlich alle
68000 Befehle. Befehle der anderen 680X0 Prozessoren sind z.T. implemen-
tiert.
6.1.1) Formelausdrcke
......................
An den meisten Stellen, an denen der Assembler Zahlenangaben erwartet, k”n-
nen nicht nur einfache Symbole oder Konstanten angegeben werden, sondern
ganze Formelausdrcke. Bei den Komponenten der Formelausdrcke 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, mssen sie immer mit einer Ziffer beginnen;
anstelle z.B. F0H muá also 0F0H geschrieben werden. Die Werte A-F mssen
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 mssen 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 drfte: 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 Abkrzungen erreichen:
\b : Backspace \a : Klingel \e : Escape
\t : Tabulator \n : Zeilenvorschub \r : Wagenrcklauf
\\ : Backslash \' : Hochkomma \" : G„nsefáchen
Die Kennbuchstaben drfen sowohl groá als auch klein geschrieben werden.
šber dieses Escape-Zeichen k”nnen sogar Formelausdrcke 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 Verknpfung folgende Operanden zur Verfgung:
+--------------------------------------------------+
| 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. Fr 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.
Fr 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, drfen 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 bercksichtigt. 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, drfte wohl reiner Zufall sein. Um nun aber keine feh-
lertr„chtigen Handumkodierungen vornehmen zu mssen, enth„lt der Assembler
eine Umsetzungstabelle fr 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 fr 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 untersttzt, 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 fhrt!
6.2.3) CPU
..........
Speichert die nachfolgende Zahl als Bezeichnung fr eine CPU. Kann wie je-
der andere Bezeichner in Ausdrcken verwendet werden und ist bei der be-
dingten Assemblierung verwendbar. Der Assembler prft, ob ein Maschinenbe-
fehl auf der gew„hlten CPU verfgbar 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 ; fhrt 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 Verfgung, 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 Prfm”-
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 natrlich auseinandergezogen und vom Linker
richtig zusammengesetzt, daher darf man natrlich 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 natrlich 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 gefllt. 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! Dafr kann fortan die Befehls-
folge einfach durch den Namen abgerufen werden, das ganze stellt also eine
Schreiberleichterung dar. Um die ganze Sache etwas ntzlicher zu machen,
kann man bei der Makrodefinition eine Parameterliste mitgeben. Die Parame-
ternamen werden wie blich durch Kommas getrennt und mssen - wie der Ma-
kroname selber - den Konventionen fr Symbolnamen gengen.
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.
Fr 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,
mssen 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 Makrormpfen definierte Labels werden immer als lokal betrachtet, ein
expliziter LOCAL-Befehl ist also nicht erforderlich. Sollen Label global
bekannt sein, mssen 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 Grnden 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 berprft 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 fr 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 fr 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 fr 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
wrden 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 fr jede einzelne Repetition lokal.
6.2.11) Bedingte Assemblierung
..............................
Der Assembler untersttzt 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 drfen beliebig verschachtelt werden, ein ELSEC bezieht
sich immer auf das letzte vorangegangene, noch nicht abgeschlossene IFC.
Wenn in der Bedingung Symbole auftauchen, mssen diese unbedingt vorher
definiert worden sein, damit im Pass 1 der richtige Block bersetzt wird.
Fr den Test, ob ein Symbol definiert ist, wurde die Funktion DEF einge-
fhrt. Sie gibt TRUE (=1), wenn das angegebene Symbol definiert ist, sonst
FALSE (=0).
Dies ist ntzlich fr 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 fr 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 natrlich 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-
fgt. 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 fgt die im Parameter angegebene Datei so im Text ein, als ob
sie dort stehen wrde. Dieser Befehl ist sinnvoll, um Quelldateien aufzu-
spalten, die alleine nicht in den Speicher passen wrden oder um sich
"Toolboxen" zu erzeugen.
Aus Kompatibilit„tsgrnden 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 prft 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 prfen 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-
tersttzt 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 mssen.
7) Der Linker
=============
Der Oberon-Linker (LINK.OBJ/TTP) dient dazu, vom Compiler erzeugte Ob-
jektmodule zu einem lauff„higen Programm zusammenzubinden. Dafr 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 mssen 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 drfen. 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 drfen. 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ž dafr
natrlich 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. Mssen 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 mssen na-
trlich gleiche Schnittstellen haben.
8) Die Lader
============
Die Lader wurden zu einer Zeit entwickelt, als es noch keine Shell fr
Load-Time-Linking gab. Sie sind daher in der Lage, Objektmodule direkt zu
linken und zu starten. Es gibt zwei Lader, einen fr GEM-Applikationen
(LOAD.PRG) und einen fr 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 fr 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 drfte 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
berprft, die in den Suchpfaden stehen und fr 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 fr 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 Ausfhrung 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 fr 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 zurckzuverfolgen. 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 dafr 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 prfen, ob es das Gewnschte 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 abgestrzt 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 Ausfhrung star-
ten. Wenn der Exit nicht abstrzt, 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
----------------------------
Fr 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 Abkrzung 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
-----------------------------
Fr 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 kmmert 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 fhrt einen
kompletten Collect durch. Es gibt auch eine M”glichkeit, den Collect in
kleine Teile zerhackt nebenher laufen zu lassen. Dies wrde 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 natrlich 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.
Gegenber 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 vernnftiges Programmieren
mit einer Programmiersprache. Hier soll eine šbersicht der vorhandenen Mo-
dule gegeben werden, n„here Informationen mssen den Definitionsdateien
entnommen werden.
14.1) Betriebssystem
--------------------
Alle Betriebssystemmodule implementieren die Aufrufe als Makros, d.h. der
Code fr 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 verfgbar. 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 fr 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 fr 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 eingefgt 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 eingefgt 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
fr 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 gengt, 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 Verfgung.
14.3.14) Key
............
War mal die Grundlage fr die Zuweisung von Prozeduren zu Tastenkombi-
nationen. Wird im Moment nicht benutzt.
14.3.15) MathCom
................
Grundlegende Prozeduren fr 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 Fllen von Speicher.
14.3.18) Modules
................
Modules ist fr das Nachladen von Modulen in den Ladern zust„ndig.
14.3.19) MVC
............
MVC steht fr 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 fr Anwender.
14.3.26) VA
...........
VA enth„lt die Konstanten, die fr 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 fr 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-
ns, Fenster und und und. Bis auf Form.Alert fhren 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 fhren.
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 fr 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 Menpunkte oder Tasten-
kombinationen. Die Tastenkombinationen werden aus dem Eintrag des Mens 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 eingefhrt.
14.6.7) WindowDialog
....................
WindowDialog verlegt einen Dialog in ein Fenster.
14.6.8) WinView
...............
WinView ist die Grundlage fr 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
Menleiste 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 natrlich in allen Fenstern gezeichnet werden.
15.1) Die Resourcedatei
-----------------------
Die Resourcedatei wird mit einem Resource Construction Set erstellt. Die
Resourcedatei fr 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 wrde 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 fr 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 mssen 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 zurck 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 Menzeile
-------------------
Nun wollen wir die Menzeile 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 fr den Menpunkt QUIT anzumelden, damit man
das Programm auch wieder verlassen kann. Dann kann man mit menu.Show die
Menzeile darstellen.
Beim Start werden sie feststellen, daž sowohl beim Anklicken von 'Quit'
als auch bei Drcken 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
fr das Men ben”tigt werden.
15.5) Ein Fenster ”ffnen
------------------------
Beim Aufruf des Menpunktes '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 fr den Menpunkt 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 fr 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 mssen, 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 gekmmert haben!
15.6) Einen Dialog darstellen
-----------------------------
Nun wollen wir einen Dialog mit dem Benutzer in einem Fenster fhren. 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 natrlich 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 fr den Browser und sonstige Unter-
sttzung.
Dank an alle, die ber Fehler berichten und neue Module implementieren.
Dank an Christian Strunk fr seine TeX-Implementierung.
Dank an Roman Hodek fr 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.