home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-11-30 | 111.7 KB | 3,084 lines |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- *STJ-OBERON-2 *
-
-
- *Eine Oberon-2 Implementation
- für Atari ST/STe/TT *
-
-
-
-
-
-
-
-
- von
- Stephan Junker
-
-
-
-
-
- 28. November 1993
-
-
-
-
-
-
-
-
- Inhaltsverzeichnis
- ==================
-
- 1) Einleitung
- 1.1) Stand der Entwicklung
- 1.2) Geplante Entwicklung
- 1.3) Benutzungsbedingungen
- 1.4) Fehlermeldungen
- 1.5) Kontakt
- 2) Von Modula-2 nach Oberon-2
- 2.1) Streichungen
- 2.1.1) Datentypen
- 2.1.2) Module und Import-/Exportregeln
- 2.1.3) Anweisungen
- 2.1.4) Low-Level Anweisungen
- 2.2) Neue Features
- 2.2.1) Typerweiterung
- 2.2.2) Typgebundene Prozeduren
- 2.2.3) Typinklusion
- 2.3) Sonstige Unterschiede
- 3) Allgemeine Erläuterungen
- 3.1) Suchpfade
- 3.2) Dateien
- 3.3) Einstellung der Shell
- 4) Installation
- 4.1) Start
- 5) Der Compiler
- 5.1) Aufruf, Parameter
- 5.2) Environmentvariablen
- 5.3) Optionen im Quelltext
- 5.4) Ausgabe
- 5.5) Vordefinierte Prozeduren
- 5.6) Unterschiede zum Standard-Oberon-2
- 5.7) Bekannte Fehler
- 6) Der Assembler
- 6.1) Symbolkonventionen
- 6.1.1) Formelausdrücke
- 6.2) Pseudobefehle
- 6.2.1) SET und EQU
- 6.2.2) CHARSET
- 6.2.3) CPU
- 6.2.4) SUPMODE
- 6.2.5) SEGMENT
- 6.2.6) DC,DS
- 6.2.7) ALIGN
- 6.2.8) MACRO
- 6.2.9) IRP
- 6.2.10) REPT
- 6.2.11) Bedingte Assemblierung
- 6.2.12) Lokale Label
- 6.3) Hochsprachenelemente
- 6.3.1) IF cond THEN ... ELSIF ... ELSE ... END
- 6.3.2) REPEAT ... UNTIL cond
- 6.3.3) LOOP ... END
- 6.3.4) EXIT [(Zahl)]
- 6.4) Diverses
- 6.4.1) INCLUDE
- 6.4.2) MESSAGE, WARNING, ERROR und FATAL
- 6.5) Zugriff auf Oberon-Bezeichner
- 7) Der Linker
- 7.1) Aufruf, Parameter
- 7.2) Environmentvariablen
- 8) Die Lader
- 8.1) Aufruf, Parameter
- 8.2) Ausgabe
- 9) Das Make-Utility
- 9.1) Aufruf, Parameter
- 9.2) Environmentvariablen
- 9.3) Hinweise
- 10) Der Scanner
- 10.1) Aufruf, Parameter
- 10.2) Environmentvariablen
- 11) Debugging
- 11.1) DB
- 11.2) Bugaboo
- 11.3) Tips
- 12) Utilities
- 12.1) Der Browser
- 12.2) Inline-Zeilen erzeugen
- 13) Speicherverwaltung
- 13.1) Benutzung in Programmen
- 13.2) Implementierung
- 14) Die Bibliotheken
- 14.1) Betriebssystem
- 14.1.1) BIOS
- 14.1.2) GEMDOS
- 14.1.3) MiNT
- 14.1.4) XBIOS
- 14.2) Abstrakte Datenstrukturen
- 14.2.1) BinTree
- 14.2.2) CDCL
- 14.2.3) DCL
- 14.2.4) FIFO
- 14.2.5) LRU
- 14.2.6) Stack
- 14.3) Standardmodule
- 14.3.1) Buffers
- 14.3.2) CommandLine
- 14.3.3) Cookie
- 14.3.4) Datum
- 14.3.5) Environment
- 14.3.6) Error
- 14.3.7) Exceptions
- 14.3.8) Execute
- 14.3.9) File
- 14.3.10) FileBuffer
- 14.3.11) Filename
- 14.3.12) IO
- 14.3.13) Kernel
- 14.3.14) Key
- 14.3.15) MathCom
- 14.3.16) MathLib0
- 14.3.17) Memory
- 14.3.18) Modules
- 14.3.19) MVC
- 14.3.20) NumStr
- 14.3.21) Paths
- 14.3.22) Strings
- 14.3.23) Supervisor
- 14.3.24) Sys
- 14.3.25) Task
- 14.3.26) VA
- 14.4) VDI-Module
- 14.4.1) VDI
- 14.4.2) VDIAttributes
- 14.4.3) VDIControl
- 14.4.4) VDIExcapes
- 14.4.5) VDIInput
- 14.4.6) VDIInquiry
- 14.4.7) VDIOutput
- 14.4.8) VDIRaster
- 14.5) AES-Module
- 14.5.1) AES
- 14.5.2) Appl
- 14.5.3) Evnt
- 14.5.4) Form
- 14.5.5) Fsel
- 14.5.6) Graf
- 14.5.7) Menu
- 14.5.8) Objc
- 14.5.9) Rsrc
- 14.5.10) Wind
- 14.6) Erweiterte AES-Module
- 14.6.1) Dialogs
- 14.6.2) FontSelect
- 14.6.3) GemApp
- 14.6.4) GEMIO
- 14.6.5) Menus
- 14.6.6) TermWin
- 14.6.7) WindowDialog
- 14.6.8) WinView
- 15) Tutorial
- 15.1) Die Resourcedatei
- 15.2) Der Rumpf
- 15.3) Resourcedatei laden
- 15.4) Die Menüzeile
- 15.5) Ein Fenster öffnen
- 15.6) Einen Dialog darstellen
- 15.7) Das fertige Programm
- 15.8) Zusammenfassung
- 16) Anhang
- 16.1) Literatur
- 16.2) Danksagungen
-
-
- 1) Einleitung
- =============
-
- Die Entstehung dieses Oberon-Systems begann kurz vor Weihnachten '92, als
- Frank Storm mir die Quelltexte zum Oberon-1 Compiler von Niklaus Wirth in
- die Hand drückte. Zunächst mußte ich den in Oberon geschriebenen Compiler
- in Modula umschreiben und den Codegenerator auf 68000 ändern. Der nächste
- Schritt war dann natürlich, das ganze wieder in Oberon umzuschreiben. Dies
- war bis März '93 geschafft, seitdem programmiere ich nur noch in Oberon.
- Inzwischen sind etliche Monate vergangen, in denen ich fleißig Fehler beho-
- ben und Erweiterungen eingebaut habe. Trotzdem wird noch einige Zeit verge-
- hen, bis diese Software den Betateststatus verliert.
-
- 1.1) Stand der Entwicklung
- --------------------------
-
- Der Kern einer Programmiersprache ist natürlich der Compiler. Dieser wird
- ergänzt durch Linker, Lader, Make und Scanner. Zusätzlich gibt es noch ei-
- nige Utilities. Alles wird als Objektmodule ausgeliefert und vom Installa-
- tionsprogramm zu ausführbaren Programmen gelinkt. Aber erst durch umfang-
- reiche Libraries wird eine Programmiersprache benutzbar. Die meisten Module
- sind von mir im Laufe von mehreren Jahren programmiert worden. Einige sind
- auch von anderen Autoren, und weitere Implementationen sind natürlich er-
- wünscht.
-
- Der Compiler hat bereits starke Erweiterungen gegenüber dem von Wirth er-
- fahren. Dies ist zwar unschön, weil dadurch wieder Inkompatibilitäten zu
- anderen Compilern entstehen, aber sie erleichtern die Programmierung. Wenn
- man portable Programme schreiben möchte, muß man auf diese Erweiterungen
- verzichten.
-
- 1.2) Geplante Entwicklung
- -------------------------
-
- Zunächst steht die Entwicklung einer Load-Time-Linking Entwicklungsumgebung
- mit Chatwin auf dem Plan. Dann fehlt noch ein Source-Level-Debugger. Da
- werde ich mich irgenwann mal drangeben. Die Codequalität könnte auch noch
- verbessert werden, dazu gehört auch 68030- und FPU-Unterstützung. Ansonsten
- werden natürlich ständig noch Fehler behoben und Bibliotheksmodule ver-
- bessert.
-
- 1.3) Benutzungsbedingungen
- --------------------------
-
- STJ-Oberon-2 ist Shareware. Die öffentliche Version darf in Mailboxen hoch-
- geladen und auf PD-Disketten bis 5 DM pro Diskette vertrieben werden. Wenn
- man dauerhaft damit arbeiten möchte, muß man den Sharewarebeitrag von 50 DM
- entrichten. Dafür bekommt man die neueste Version auf Diskette zugeschickt
- (also Adresse nicht vergessen!). Diese enthält eine private Version, die
- nicht weitergegeben werden darf. Darauf ist zusätzlich diese Anleitung als
- DVI-File sowie der fehlende optimierende Linker. Auf Wunsch kann ich die
- Anleitung auch in eine Postscriptdatei umwandeln. Möchte jemand eine ge-
- druckte Anleitung (Laserdrucker) mit Ringbindung, kostet dies 20 DM extra.
-
- Wer am System mitarbeitet oder mitgearbeitet hat, kann einen individuel-
- len Rabatt erhalten. Einfach mal anfragen.
-
- 1.4) Fehlermeldungen
- --------------------
-
- Das ganze System ist noch in der Entwicklungs- und Betatestphase. Ich weiß,
- daß es noch einige Macken hat. Ich bemühe mich, sie noch alle zu entfernen.
- Ich übernehme keine Garantie für die Funktionsfähigkeit dieses Programms
- und hafte nicht für Schäden, die dieses Programm verursacht. Falls Fehler
- entdeckt werden, sollte man mich möglichst genau darüber informieren.
-
- 1.5) Kontakt
- ------------
-
- Stephan Junker
- Heuvel 1A
- NL-6291 CP Vaals
-
- E-Mail, MausNet : Stephan Junker @ AC2
-
- Sparkasse Aachen
- Kontonummer : 16013351
- Bankleitzahl: 390 500 00
-
-
- 2) Von Modula-2 nach Oberon-2
- =============================
-
- Für diejenigen, die Modula kennen und evtl. umsteigen möchten, werde ich
- hier kurz die Unterschiede zwischen Modula-2 und Oberon-2 auflisten. Es
- soll keineswegs eine Sprachbeschreibung ersetzen, sondern nur einen Ein-
- druck von den neuen Möglilchkeiten vermitteln, um das Interesse zu wecken.
-
- 2.1) Streichungen
- -----------------
-
- Niklaus Wirth hatte den Mut, einige Features von Modula-2 ersatzlos zu
- streichen. Dahinter stand das Konzept, die Sprache Oberon auf das Wichtig-
- ste zu konzentrieren und damit einen kleinen, schnellen Compiler zu reali-
- sieren. Diese Streichungen sind nicht bei allen Modula-Programmieren auf
- Gegenliebe gestoßen, aber man kann damit leben.
-
- 2.1.1) Datentypen
- .................
-
- _Variante Records_ wurden eliminiert, da sie die Implementation einer Spei-
- cherverwaltung mit Garbage Collector im Wege stand. Ihre Funktionalität
- wurde durch erweiterbare Typen erhalten[1].
- _Opake Typen_ wurden überflüssig, da man Records nicht mehr komplett ex-
- portieren muß. Die Auswahl einzelner Feldelemente ist wesentlich flexibler.
- _Aufzählungstypen_ standen der Erweiterung über Modulgrenzen hinweg im
- Wege. Außerdem führte ein Import des Typbezeichners zum impliziten Import
- aller assoziierten Konstantenbezeichner.
- _Unterbereichstypen_ hatten nicht den Nutzen, der die dafür nötige zusätz-
- liche Komplexität des Compilers rechtfertigt.
- _Mengen_ wurden zu einem einzigen Typ reduziert: SET. Diese Menge be-
- inhaltet alle Zahlen von 0 bis zu einem implementationsabhängigen Maxi-
- mum[2]. Dies resultiert aus der Elimination von Aufzählungs- und Unterbereichstypen.
- Der Typ _CARDINAL_ wurde eliminiert, da die Benutzung von 32-Bit Werten
- dies unnötig macht[3].
- _Zeigertypen_ können nur noch auf Records und Arrays zeigen. Dies hängt da-
- mit zusammen, das der Zeigeroperator '^' nicht mehr benutzt werden muß.
- _Indextypen_ können nicht mehr angegeben werden. Stattdessen gibt man nur
- noch die Anzahl Elemente des Arrays an.
-
- ---------------
-
- [1] nicht ganz, wie ich meine
-
- [2] bei STJ-Oberon-2 ist das Maximum 31
-
- [3] man beachte, daß damit keine vorzeichenlosen Vergleiche möglich sind
-
-
- 2.1.2) Module und Import-/Exportregeln
- ......................................
-
- _Lokale Module_ wurden eliminiert, da sie nur selten benutzt wurden und den
- Compiler unnötig schwierig machten.
- _Unqualifizierter Export_ ist nicht mehr möglich, d.h. man gibt nur noch
- den Namen eines Moduls in der Importliste an und muß immer mit vorange-
- stelltem Modulbezeichner auf die exportierten Bezeichner zugreifen. Um die
- Tipparbeit ein wenig zu reduzieren, ist es möglich, den Import umzube-
- nennen. Dafür schreibt man beim Import 'Abk:=Abkuerzung', z.B. 'WDial:=WindowDialog'.
- Das _Hauptmodul_ als solches gibt es nicht mehr. Alle Module sind gleichbe-
- rechtigt, d.h. daß auch alle Module linkfähig sind.
- _Definitionsmodule_ sind für den Compiler nicht mehr nötig, aber man sollte
- sie natürlich für den Programmierer erzeugen. Dafür ist der Browser vorge-
- sehen. Der Export geschieht jetzt, indem man hinter einem Bezeichner einen
- Stern für normalen oder ein Minuszeichen (bei Variablen und Feldelementen)
- für Read-Only Export angibt.
-
- 2.1.3) Anweisungen
- ..................
-
- Die _WITH-Anweisung_ wurde eliminiert, da der qualifizierte Zugriff zu be-
- vorzugen ist. Diese Anweisung hat in Oberon jetzt eine andere Funktion.
-
- 2.1.4) Low-Level Anweisungen
- ............................
-
- _ADDRESS_ und _WORD_ wurden durch BYTE ersetzt. _Typumwandlungsfunktionen_
- mit vorangestelltem Typbezeichner und _absolute Addressierung_ wurden eli-
- miniert.
-
- 2.2) Neue Features
- ------------------
-
- 2.2.1) Typerweiterung
- .....................
-
- Es ist möglich, einen bestehenden Recordtyp zu erweitern.
- Beispiel: Wenn Typ Point so
-
- Point = RECORD x,y : INTEGER END
-
- definiert ist, kann man ihn so
-
- Rect = RECORD(Point) w,h : INTEGER END
-
- erweitern. Typ Rect hat dann die Elemente x,y,w,h. Dann ist es möglich,
- Prozeduren zu definieren, die einen Typ Point als Parameter erwarten, und
- diesen einen Typ Rect zu übergeben. Analog gilt dies für Zeiger auf solche
- Typen. Mit einem Typeguard der Form var(typ) kann man zur Compilezeit den
- Typen festlegen. Zur Laufzeit wird dann überprüft, ob die Variable var tat-
- sächlich den Typ typ hat. Wenn nicht, wird das Programm abgebrochen. Es ist
- auch möglich, den Typ einer Variablen abzufragen. Der Ausdruck
-
- var IS typ
-
- liefert TRUE, wenn var vom (dynamischen) Typ typ ist.
-
- Diese Abfrage inklusive eines regionalen Typeguards leistet das WITH-
- Statement:
-
- WITH var : Point DO (* wenn var vom typ Point ist *)
- var.x := 0 (* dann x löschen *)
- | var : Rect DO (* ist es ein Rect *)
- var.w := 0 (* dann w löschen *)
- ELSE (* sonst *)
- END; (* nichts *)
-
- 2.2.2) Typgebundene Prozeduren
- ..............................
-
- Es ist möglich, Prozeduren an einen Recordtyp zu binden. In der Sprache des
- OOP sind dies dann Methoden, die auf dem Typ arbeiten, an den sie gebunden
- sind. Im Gegensatz zu anderen Ansätzen werden bei Oberon jedoch keine Be-
- zeichner implizit übergeben, sondern explizit angegeben. Eine solche Proze-
- dur wird so
-
- PROCEDURE (VAR p : Point) Clear;
- BEGIN
- p.x := 0; p.y := 0;
- END;
-
- definiert und mit
-
- point.Clear
-
- aufgerufen. Statt VAR Point könnte man auch einen Zeiger auf Point ohne VAR
- angeben. Man kann jetzt hingehen und eine Prozedur Clear an Rect binden.
- Der Name ist nicht etwa schon benutzt, denn er ist ja nur innerhalb eines
- Typs Point sichtbar.
-
- PROCEDURE (VAR r : Rect) Clear;
- BEGIN
- r.w := 0; r.h := 0;
- r.Clear^;
- END;
-
- Dieses Clear löscht erst w und h, um dann mit r.Clear^die geerbte Prozedur
- Clear aufzurufen, die x und y löscht.
-
- 2.2.3) Typinklusion
- ...................
-
- Die Integer- und Realtypen sind jeweils Teilmengen des nächst größeren Be-
- reichs. Daher ergibt sich folgende Hierarchie:
- LONGREAL > REAL > LONGINT > INTEGER > SHORTINT
- Das bedeutet, daß ein Wert eines untergeordneten Typs einem
- höheren zugewiesen werden kann.
-
- 2.3) Sonstige Unterschiede
- --------------------------
-
- _Prozedurtypen_ werden mit Dummynamen für die Parameter angegeben.
- _Globale Variablendeklarationen_ müssen immer vor der ersten Prozedur erfolgen.
-
-
- 3) Allgemeine Erläuterungen
- ===========================
-
- 3.1) Suchpfade
- --------------
-
- Suchpfade sind solche Pfade, in denen nach Dateien gesucht wird. Viele der
- Systemprogramme benötigen Suchpfade, aber alle bauen auf einem Modul namens
- Paths auf. Daher verlangen alle Programme den gleichen Aufbau der
- Suchpfade. Definiert werden sie mit einer Environmentvariablen. Mehrere
- Suchpfade müssen mit Komma oder Semikolon getrennt werden. Ein Backslash am
- Ende ist möglich, aber nicht nötig. Eine kleine Möglichkeit für Wildcards
- ist vorgesehen: Der letzte Order einer Suchpfaddefinition darf ein '*'
- sein, so daß alle Ordner in diesem Directory durchsucht werden. Die Suche
- beginnt immer mit dem zuletzt angegebenen Pfad.
- Beispiel: MODPATH=E:\OBERON\GEM,E:\OBERON\STD\
- Damit können alle Dateien gefunden werden, die den Mustern E:\OBE-
- RON\GEM\*.*und E:\OBERON\STD\*.*genügen.
- Beispiel: MODPATH=E:\OBERON\LIB\*
- Damit können alle Dateien gefunden werden, die den Mustern E:\OBERON\LIB\*\*.*genügen.
- Wenn im folgenden also von 'Suchpfaden' die Rede ist, sind Environmentva-
- riable mit obigem Inhalt gemeint.
-
- Eine Besonderheit der Suchpfade möchte ich hier schon erwähnen: Eine
- sinnvolle Einstellung ist es, nur MODPATH zu definieren. Dann wird immer
- dort gesucht und Ausgaben des Compilers werden bei den Sourcen gespeichert.
- In dieser Form werden die Dateien auch veröffentlicht. Es ist aber möglich,
- die verschiedenen Dateitypen in getrennten Ordnern zu bewahren. Dazu muß
- man für jeden Dateityp einen Suchpfad definieren und die Ausgaben des Com-
- pilers werden in den letzten Suchpfad geschrieben. Diese Suchpfade heißen
- OBJPATH, SYMPATH und INFPATH.
-
- 3.2) Dateien
- ------------
-
- Das System unterscheidet vier verschiedene Dateien:
-
- 1) Die Quelltexte mit der Extension MOD.
-
- 2) Die Objektmodule mit der Extension OBJ. Diese nehmen den Code eines
- Moduls auf.
-
- 3) Die Symboldateien mit der Extension SYM. Diese enthalten Informationen
- über exportierte Bezeichner.
-
- 4) Die Infodateien mit der Extension INF. Diese enthalten zusätzliche In-
- formationen zu Modulen. Momentan sind das zum Beispiel ein Programm-
- name und Optimierungsinformationen. Später sollen die Infodateien dann
- auch Informationen für den Source Level Debugger aufnehmen.
-
- 5) Die Fehlerdateien mit der Extension ERR. Darin werden Fehler, die der
- Compiler findet, in einem frei wählbaren Format notiert.
-
- 3.3) Einstellung der Shell
- --------------------------
-
- DIe Shell, mit der man arbeitet, sollte man mittels Batchfile beim Starten
- schon vernünftig konfigurieren. Dies ist ein Beispiel-Setup für Chatwin:
-
- alias make e:\oberon\Make.TTP $*
- alias opt e:\oberon\OPTIMIZE.TTP $*
- alias scan e:\oberon\SCAN.TTP $*
- alias lt e:\oberon\LOAD.TTP $*
- alias lg e:\oberon\LOAD.PRG $*
- alias browse e:\oberon\browse.ttp $*
- env OC=e:\oberon\compile.ttp
- env MODPATH=E:\OBERON\LIB\*
- env LINKALSO=Exceptio
-
- Desweiteren empfiehlt es sich, für jedes Projekt eine Batchdatei ein-
- zurichten, in der Pfade, Namen, Extension etc. definiert werden. Hier ist
- mal ein Beispiel, daß ich für das Installationsprogramm verwende:
-
- env MODPATH=E:\OBERON\LIB\*,E:\OBERON\INSTALL\
- env PRGEXT=PRG
- env PRGPATH=E:\OBERON\
- env LINKALSO=Exceptio
- dellist *
- addlist e:/oberon/install/install.mod
- addlist e:/oberon/install/linker.mod
- addlist e:/oberon/install/syminld.mod
-
-
- 4) Installation
- ===============
-
- Das Installationsprogramm INSTALL.PRG ist das einzig lauffähige Programm
- in der Distribution. Es erzeugt alle Programme, die für die Arbeit mit STJ-
- Oberon-2 benötigt werden.
-
- 4.1) Start
- ----------
-
- Beim Start von Install erscheint eine Dialogbox. Dort sieht man zunächst
- neun Buttons mit jeweils einem Namen dran. Selektiert sind alle Programme
- außer Oberon[4]. Wählen sie die Programme, die sie haben wollen.
-
- Stellen sie nun ein, ob die Programme eine Symboltabelle haben oder opti-
- miert[5] werden sollen. Die Symboltabelle kostet nur unnötig Platz, also
- verzichten sie lieber darauf.
-
- Als letztes können sie einen Zielpfad für die Programme angeben. Dieser
- wird anfangs auf den Pfad gesetzt, in dem auch das Installationsprogramm
- steht.
-
- Wenn sie nun den Knopf 'Installieren' anwählen, verschwindet die Dialog-
- box und ein Terminalfenster wird geöffnet. Dort erscheinen die Ausgaben des
- Linkers, der alle selektierten Programme linkt. Dabei sind die Suchpfade so
- eingestellt, wie sie in der Distribution sind, also LIB\*\,SYS\ und TOOLS\,
- jeweils vom Directory ausgehend, in dem das Installationsprogramm steht.
- Wenn sie also gerade erst das Archiv ausgepackt haben und dabei die Ordner-
- struktur nicht verloren ging, müssen die Module auch gefunden werden.
-
- Hinweis: Im Prinzip ist der Linker auch in der Lage, die Tätigkeit des
- Installationsprogramms durchzuführen. Lediglich die Lader und Oberon können
- nicht vom normalen Linker gelinkt werden.
-
- ---------------
-
- [4] denn Oberon gibt's noch nicht
-
- [5] Die Optimierung funktioniert leider noch nicht
-
-
-
- 5) Der Compiler
- ===============
-
- Der Compiler des Oberon-Systems (COMPILE.OBJ/TTP) entstand aus dem Obe-
- ron-1 Compiler von Niklaus Wirth. Er wurde unter anderem um einen Makroas-
- sembler erweitert und ist jetzt weitgehend auf Oberon-2-Standard.
-
- 5.1) Aufruf, Parameter
- ----------------------
-
- Der Compiler sollte von einer Shell aus benutzt werden, die zumindest in
- der Lage ist, Environmentvariablen zu setzen, denn der Compiler liest dort
- seine Optionen. Beim Aufruf kann man als Kommando einige Optionen sowie
- eine Liste von Namen, getrennt mit Leerzeichen, übergeben. Diese Module
- werden nacheinander übersetzt. Die Syntax sieht also so aus:
-
- compile {<Option>} <Name> {<Name>}
-
- Das Format des Namens wird flexibel gehandhabt. Ein Name mit Pfadangabe
- wird dort zuerst gesucht. Danach wird er wie ein Name ohne Pfad in den
- Suchpfaden gesucht. Wird keine Datei gefunden, wird der Compiler wieder
- verlassen. In jedem Fall wird der Name mit der Extension MOD versehen.
- Die Optionen haben die allgemeine Syntax:
-
- -<Option><Parameter>
-
- Die Art der Option wird mit einem Buchstaben (groß oder klein) angegeben,
- eventuelle Parameter folgen ohne Leerzeichen. Einige Optionen sind sowohl
- über Environmentvariablen als auch über Kommandozeile setzbar. Dabei gilt:
- Die Option in der Kommadozeile hat höhere Priorität.
- Folgende Optionen sind implementiert:
-
- -e: Weist den Compiler an, bei dem ersten gefundenen Fehler den Programm-
- lauf abzubrechen. Normalerweise wird die Datei komplett übersetzt und
- die Fehler in einer Datei gespeichert.
-
- -w: Schaltet die Ausgabe von Warnungen ein. Warnungen werden erzeugt, wenn
- ein Fehler des Programmierers vorliegen könnte, die der Compiler aber
- übersetzen kann. Dies wird zum Beispiel bei Schreibzugriffen auf glo-
- bale Variable eines anderen Moduls getan. Warnungen werden normaler-
- weise unterdrückt.
-
- -i: Schaltet den Indexcheck aus, da er defaultmäßig eingeschaltet ist. In-
- dexcheck bewirkt eine Überprüfung der Arraygrenzen von Indizes zur
- Laufzeit und ist mit einer geringfügigen Verlängerung des Codes ver-
- bunden. Ein falscher Index bewirkt eine CHK-Exception.
-
- -t: Schaltet den Typcheck aus, der ebenfalls normalerweise eingeschaltet
- ist. Wenn er eingeschaltet ist, wird bei jedem Typeguard geprüft, ob es
- sich auch um den korrekten Recordtyp handelt. Ein falscher Typ bewirkt
- die Ausgabe einer Fehlermeldung und anschließenden Programmabbruch.
-
- -a: Schaltet den Arithmetikcheck aus, der defaultmäßig eingeschaltet ist.
- Dieser Check soll Über- und Unterlauf von Realzahlen überprüfen, ist
- aber noch nicht implementiert.
-
- -s|<pos>|: Diese Option bewirkt, daß der Compiler bei Erreichen der Posi-
- tion pos im erzeugten Code den Programmlauf mit einer Meldung abbricht.
- Mit dieser Funktion läßt der Scanner die Absturzstelle im Quelltext
- finden.
-
- -o: Wenn die Option -s benutzt wird und der Compiler bricht ab, so gibt er
- einige Zeilen vor und nach dem Abbruchpunkt aus, falls diese Option ge-
- setzt wird.
-
- 5.2) Environmentvariablen
- -------------------------
-
- Der Compiler wertet auch einige Environmentvariablen aus. Sie müssen immer
- großgeschrieben und von einem = gefolgt sein. Gesetzt werden sie in der
- Shell und jedem Programm übergeben, daß von dieser Shell aufgerufen wird.
-
- Es werden folgende Variablen ausgewertet:
-
- MODPATH: Gibt die Suchpfade (Kap.??) an, in denen nach dem zu übersetzenden
- Modul gesucht wird.
-
- SYMPATH: Gibt die Suchpfade an, in denen nach den Symboldateien der impor-
- tierten Module gesucht wird. Ist SYMPATH definiert, wird ein evtl. er-
- zeugtes SYM-File in den letzten Pfad geschrieben, der bei SYMPATH ange-
- geben ist. Ist SYMPATH nicht definiert, werden die Suchpfade von MOD-
- PATH übernommen und das SYM-File wird in denselben Ordner geschrieben,
- in dem die Source war.
-
- Anmerkung: Eine Symboldatei wird nur erzeugt, wenn sie noch nicht
- existiert oder sich geändert hat.
-
- OBJPATH: Die erzeugte Objektdatei wird in den letzten Pfad geschrieben, der
- mit dieser Variablen definiert wird. Ist OBJPATH nicht definiert, wer-
- den die Suchpfade von MODPATH übernommen und das OBJ-File wird in den-
- selben Ordner geschrieben, in dem die Source war.
-
- INFPATH: Die erzeugte Infodatei wird in den letzten Pfad geschrieben, der
- mit dieser Variablen definiert wird. Ist INFPATH nicht definiert, wer-
- den die Suchpfade von MODPATH übernommen und das INF-File wird in den-
- selben Ordner geschrieben, in dem die Source war.
-
- Anmerkung: Ein Info-File wird nur erzeugt, wenn es nötig ist.
-
- INXCHK: Der Inhalt der Variablen darf die Werte ON oder OFF haben. Damit
- wird der Indexcheck ein- oder ausgeschaltet, der normalerweise einge-
- schaltet ist.
-
- TYPCHK: Wie INXCHK, jedoch für den Typcheck.
-
- ARICHK: Wie INXCHK, jedoch für den Arithmetikcheck.
-
- ERRDIST: Der Inhalt der Variablen muß eine Dezimalzahl sein, die den Ab-
- stand zwischen zwei Fehlermeldungen in Zeichen angibt. Dieser Abstand
- bewirkt, daß weniger Folgefehler eines Fehlers ausgegeben werden. Der
- Standardwert ist 20, das bedeutet: Wenn nach einem erkannten Fehler in-
- nerhalb der nächsten 20 Zeichen nochmal ein Fehler auftritt, wird er
- nicht ausgegeben.
-
- MAXERR: Der Inhalt ist wieder eine Dezimalzahl, die angibt, nach wievielen
- ausgegebenen Fehlern keine weiteren Fehler mehr ausgegeben werden sol-
- len. Normalerweise sind dies 100 Fehler.
-
- ERRFORM: Der Inhalt dieser Variablen ist ein String. Damit ist es möglich,
- das Format einer Fehlermeldung einzustellen. Prinzipiell kann man sich
- den Dateinamen mit \d, die Zeilennummer mit \z, die Spalte mit \s
- (beide zählend ab 1), die absolute Position mit \p und natürlich die
- Fehlermeldung selbst mit \f ausgeben lassen. Diese Teile werden dort in
- der Zeile eingefügt, wo die Kürzel mit '\' stehen. Der standardmäßig
- gesetzte String lautet:
-
- "Error \d \z : \s \f"
-
- Damit sieht eine Fehlermeldung so aus:
-
- Error DATEI ZEILE : SPALTE FEHLERMELDUNG
-
- WARNOUT: Werte ON/OFF sind erlaubt. Schaltet die Ausgabe von Warnungen ein
- oder aus. Normalerweise werden keine Warnungen ausgegeben.
-
- 5.3) Optionen im Quelltext
- --------------------------
-
- Für die Angabe von Optionen in Quelltexten ist die übliche Konstruktion
- (*$...*) reserviert. Solche Optionen haben die höchste Priorität. Es kann
- immer nur eine Option angegeben werden. Zwischen $ und dem Kennbuchstaben
- darf kein Leerzeichen sein. Hinter den Parametern darf noch beliebiger Kom-
- mentar folgen.
-
- (*$I?*): Damit kann der Indexcheck bestimmt werden. Das Fragezeichen darf
- '+', '-' oder '=' sein. Hinter dem I darf kein Leerzeichen sein. Ein
- '+' schaltet den Indexcheck ein, '-' aus und '=' stellt den vorigen Zu-
- stand wieder her.
-
- Diese Option ist nur im Oberon-Teil verfügbar.
-
- (*$T?*): Wie I für den Typcheck. Eingeschalteter Typcheck bewirkt eine Ty-
- püberprüfung bei jedem Zugriff auf den gesamten Record. Diese Option
- ist nur im Oberon-Teil verfügbar.
-
- (*$A?*): Wie I für den Arithmetikcheck. Wird im Moment noch nicht unter-
- stützt. Die Routinen im Modul System (Grundrechenarten) melden arithme-
- tische Fehler, auch ohne diesen Check.
-
- Diese Option ist nur im Oberon-Teil verfügbar.
-
- (*$N?*) Diesmal gibt das Fragezeichen einen Dateinamen an. Unter diesem Na-
- men wird später das gelinkte Programm gespeichert. Vor dem Namen dürfen
- ausnahmsweise auch Leerzeichen stehen. Wird der Name mit Pfad angege-
- ben, wird das Programm dort gespeichert, ansonsten im Pfad PRGPATH oder
- beim Modul. Der Name wird dem Linker über die Infodatei mitgeteilt.
-
- Diese Option ist nur im Oberon-Teil verfügbar.
-
- (*$O?*) Wenn ein '-' angegeben wird, wird der folgende Code bei der Opti-
- mierung nicht angerührt. Bei O+ wird die Optimierung wieder zugelassen.
- Es darf keine Verschachtelung stattfinden.
-
- Diese Option ist auch im Assembler verfügbar.
-
- (*$V+?*) Das Fragezeichen muß den Namen einer Environmentvariablen angege-
- ben. Es bedeutet: Der nun folgende Code soll bei der Optimierung nur
- dann im Programm gelassen werden, wenn die Environmentvariable zum
- Zeitpunkt der Optimierung definiert ist. Der Wert ist dabei beliebig.
- Der Compiler kümmert sich nicht weiter darum und übersetzt alles, es
- ist also keine bedingte Compilierung. Es ist nämlich wesentlich fle-
- xibler: Wenn man die Form des Codes (z.B. für verschiedene Zielrechner)
- ändern möchte, muß man nicht irgendwo einen Wert ändern und alle Module
- neu übersetzen und linken. Stattdessen braucht man nur die ent-
- sprechenden Variablen zu setzen oder zu löschen und die Optimierung zu
- starten. Der Linker erzeugt dann das gewünschte Programm.
-
- Diese Option ist auch im Assembler verfügbar.
-
- Beispiel:
-
- (*V+ DEBUG *) (* drinlassen wenn Debugversion *)
- IO.WriteString(...)
- (*V=*)
-
- Wenn die Environmentvariable DEBUG definiert ist, wird beim Optimieren
- die zusätzliche Ausgabe dringelassen.
-
- (*$V-?*) Wie oben, jedoch wird der folgende Code nur dann entfernt, wenn
- die Variable definiert ist.
-
- Diese Option ist auch im Assembler verfügbar.
-
- (*$V+?=...*) und (*$V-?=...*) Wie oben, jedoch wird auch der Inhalt der Va-
- riablen angegeben. Die Bedingung ist also erfüllt, wenn die Variable
- definiert ist und den angegebenen Wert hat (beliebiger String ohne
- Leerzeichen).
-
- Diese Option ist auch im Assembler verfügbar.
-
- (*$V=*) Damit wird die Abhängigkeit von allen vorher angegebenen Variablen
- ausgeschaltet.
-
- Diese Option ist auch im Assembler verfügbar.
-
- 5.4) Ausgabe
- ------------
-
- Der Compiler erzeugt eine neue Objektdatei, wenn die Übersetzung fehlerfrei
- war. Ist die dabei erzeugte Symboldatei anders als die bisherige oder exi-
- stierte bisher Keine, so wird die neue Symboldatei abgespeichert. War die
- Übersetzung fehlerhaft, wird die Fehlerdatei abgespeichert. Die Symbolda-
- teien benötigt der Compiler, um beim Import die dort exportierten Bezeich-
- ner zu lesen. Die Objektdateien benötigt der Linker, wenn er ein Programm
- zusammensetzt. Evtl. wird auch eine Infodatei erzeugt, die unter anderem
- einen Programmnamen aufnimmt.
-
- Das Format der Objektdateien enspricht fast dem eines normalen Programms.
- Es hat einen 28 Byte langen Programmheader, es folgen der Code, die Daten,
- die Symboltabelle und die Reloziertabelle. Die Symboltabelle entspricht dem
- erweiterten GST-Format. Durch dieses Format der Objektdateien ist es mög-
- lich, sowohl komplette Module mit einem beliebigen Assembler zu schreiben,
- als auch vom Compiler erzeugte Objektdateien zu disassemblieren und zu
- überarbeiten. Letzteres kann für die Geschwindigkeitsoptimierung hilfreich
- sein, denn es ist einfacher, einen bestehenden Assemblertext zu verbessern
- als etwas direkt in Assembler zu schreiben. Das Format des Symboltabellen
- ist nicht mehr kompatibel zu dem von N. Wirth, da einige zusätzliche Infor-
- mationen benötigt wurden.
-
- 5.5) Vordefinierte Prozeduren
- -----------------------------
-
- Die folgenden Tabellen zeigen die vordefinierten Funktionen und Prozeduren
- von Oberon-2 inklusive der Erweiterungen bei STJ-Oberon-2. Diese sind mit
- einem Stern markiert und sind nicht portabel. v steht für eine Variable, x
- und n für Ausdrücke, a für Adresse und T für einen Typ. Integer bedeutet
- einen der Integertypen SHORTINT, INTEGER oder LONGINT.
-
- _Funktionen:_
-
- +-------------+--------------+-------------+-----------------------+
- | Name | Argumenttyp | Ergebnistyp | Funktion |
- +-------------+--------------+-------------+-----------------------+
- | ABS(x) | Numerische | Typ von x | Absolutwert |
- | | Typen | | |
- | ASH(x,n) | x,n: Integer | Typ von x | x * 2^n |
- | CAP(x) | CHAR | CHAR | Großbuchstabe |
- | CHR(x) | Integer | CHAR | Zahl in CHAR |
- | | | | umwandeln |
- | ENTIER(x) | Realtyp | LONGINT | Größtes Integer nicht |
- | | | | größer als x |
- | TRUNC(x) * | Realtyp | LONGINT | Integeranteil |
- | LEN(v,n) | v: Array; | INTEGER | Länge von v in |
- | | n: Integer- | | Dimension n |
- | | konstante | | (0 = erste Dim.) |
- | LEN(v) | v: Array | INTEGER | entspricht LEN(v,0) |
- | LONG(x) | SHORTINT | INTEGER | erweitern |
- | | INTEGER | LONGINT | |
- | | REAL | LONGREAL | |
- | MAX(T) | T = Basistyp | T | Maximalwert von T |
- | | T = SET | INTEGER | Maximales |
- | | | | Mengenelement |
- | MIN(T) | T = Basistyp | T | Minimalwert von T |
- | | T = SET | INTEGER | 0 |
- | ODD(x) | Integer | BOOLEAN | x MOD 2 = 1 |
- | ORD(x) | CHAR | INTEGER | Ordinalzahl von x |
- | SHORT(x) | LONGINT | INTEGER | nächst kleinerer Typ |
- | | INTEGER | SHORTINT | |
- | | LONGREAL | REAL | |
- | SIZE(T) | jeder Typ | Integer | Anzahl Bytes, |
- | | | | die T belegt |
- +-------------+--------------+-------------+-----------------------+
-
- _Prozeduren:_
-
- +--------------------+-------------------------------+---------------------+
- | Name | Argumenttyp | Funktion |
- +--------------------+-------------------------------+---------------------+
- | COPY(x,v) | x: Char. Array, String; | v := x |
- | | v: Char. Array | |
- | DEC(v) | Integer | v := v-1 |
- | DEC(v,n) | v,n: Integer | v := v-n |
- | EXCL(v,x) | v: SET; x: Integer | v := v - {x} |
- | HALT(x) | Integerkonstante | Programm beenden |
- | INC(v) | Integer | v := v+1 |
- | INC(v,n) | v,n: Integer | v := v+n |
- | INCL(v,x) | v: SET; x: Integer | v := v + {x} |
- | NEW(v) | Zeiger | v^ allozieren |
- | NEW(v,x_0,...,x_n) | v : Zeiger auf offenes Array; | v^ mit Längen |
- | | x_i: Integer | x_0..x_n allozieren |
- +--------------------+-------------------------------+---------------------+
-
-
- _Funktionen in SYSTEM:_
-
- +-------------+------------------+-------------+-------------------------+
- | Name | Argumenttyp | Ergebnistyp | Funktion |
- +-------------+------------------+-------------+-------------------------+
- | ADR(v) | alle | LONGINT | Adresse von v |
- | ANL(a,b) * | a,b: Integer | wie a,b | bitweise Und |
- | BIT(a,n) | a: LONGINT | BOOLEAN | Bit n von Mem[a] |
- | | n: Integer | | |
- | CC(n) | Integerkonstante | BOOLEAN | Bedingung n (0≤n≤15) |
- | LONG(a) * | SHORTINT | INTEGER | vorzeichenlos erweitern |
- | | INTEGER | LONGINT | |
- | LSH(x,n) | x: Integer, | Typ von x | logischer Shift |
- | | CHAR,BYTE | | |
- | | n: Integer | | |
- | NTL(a) * | a: Integer | wie a | bitweise invertieren |
- | ORL(a,b) * | a,b: Integer | wie a,b | bitweise Oder |
- | ROT(x,n) | x: Integer | Typ von x | Rotation |
- | | CHAR,BYTE | | |
- | | n: Integer | | |
- | VAL(T,x) | T,x: alle Typen | T | x als Typ T auffassen |
- | XOL(a,b) * | a,b: Integer | wie a,b | bitweise Exklusiv Oder |
- +-------------+------------------+-------------+-------------------------+
-
- _Prozeduren in SYSTEM:_
-
- +----------------+---------------------+------------------------+
- | Name | Argumenttyp | Funktion |
- +----------------+---------------------+------------------------+
- | DISPOSE(p) | Zeiger | gibt den Speicher frei |
- | GET(a,v) | a: LONGINT | v := Mem[a] |
- | | v: einfache Typen | |
- | GETREG(n,v) | n: Integerkonstante | v := Register n |
- | | v: einfache Typen | (0≤n≤15) |
- | INLINE(...) * | Wortkonstanten | fügt die Konstanten |
- | | | in den Code ein |
- | MOVE(a0,a1,n) | a0,a1: LONGINT | n Bytes bei a0 |
- | | n: Integer | nach a1 kopieren |
- | NEW(v,n) | v: Zeiger, LONGINT | n Bytes allozieren |
- | | n: Integer | und Adresse nach v |
- | PUT(a,v) | a: LONGINT | Mem[a] := v |
- | | v: einfache Typen | |
- | PUTREG(n,v) | n: Integerkonstante | Register n := v |
- | | v: einfache Typen | (0≤n≤15) |
- +----------------+---------------------+------------------------+
-
- 5.6) Unterschiede zum Standard-Oberon-2
- ---------------------------------------
-
- - Der Compiler wurde erweitert um AND und NOT, die identisch mit & und
- ~sind.
-
- - SYSTEM.ADR kann auch die Adressen von Prozeduren und konstanten Strings
- zurückgeben.
-
- - Es gibt eine Abart von Prozeduren, die für Betriebssystemaufrufe benutzt
- werden. Bei Wirth wurden sie anders benutzt.
- Beispiel :
-
- PROCEDURE- Fclose(Handle : INTEGER) : INTEGER 62,1;
-
- Bei Benutzung dieser Prozedur wird das Handle und die Funktionsnummer 62
- auf den Stack geschrieben, TRAP #1 aufgerufen und der Stack korrigiert.
- Da das Betriebssystem genau wie normale Prozeduren den Returnwert in Re-
- gister D0 zurückgeben, funktioniert dies also auch. Lediglich die Rei-
- henfolge der Parameter müssen vertauscht werden.
-
- - Bei Wirth müssen Prozeduren, die einer Prozedurvariablen zugewiesen wer-
- den, eine Funktionsnummer haben. Prozeduren bekommen Funktionsnummern,
- wenn sie einen Stern hinter dem Namen haben (dann sind sie exportiert),
- wenn sie einen Stern hinter 'PROCEDURE' stehen haben (soll wohl einen
- Far-Aufruf erzwingen) oder wenn sie forward deklariert werden (ein '^'
- hinter 'PROCEDURE'). Bei STJ-O2 ist keine Funktionsnummer mehr nötig für
- die Zuweisung an eine Prozedurvariable.
-
- - Laut Wirth waren Strings nur in Gänsefüßchen zulässig. Dabei wird ein
- Zeichen als CHAR, mehr oder weniger Zeichen als ARRAY OF CHAR erkannt.
- Um nun auch einzelne Zeichen als Strings zu deklarieren, kann man sie in
- Hochkommata einschließen.
-
- 5.7) Bekannte Fehler
- --------------------
-
- - Nicht für alle Fehlermeldungen ist eine Klartextmeldung gespeichert.
- Dann erscheint nur eine Fehlernummer. Einige Fehlermeldungen passen
- nicht immer ganz zu dem bemerkten Fehler. Man möge mir das verzeihen.
-
- - Zeiger auf offene Arrays in komplexen Strukturen (Arrays, Records) ma-
- chen Probleme. Besonders der Indexcheck funktioniert dann nicht.
-
- - Die Anzahl Prozeduren, die an einen Typ und dessen Erweiterungen gebun-
- den werden, ist noch auf 100 begrenzt.
-
- - Zeiger auf mehrdimensional offene Arrays sind noch nicht möglich.
-
- - LEN liefert nur INTEGER zurück statt LONGINT, da die Indizes auf 32K be-
- grenzt sind.
-
- - Wenn schon eine Infodatei existiert, deren Inhalt aber Unsinn ist oder
- deren Format veraltet ist oder die 0 Bytes lang ist, stürzt der Compiler
- nach der Übersetzung ab.
-
-
-
-
- 6) Der Assembler
- ================
-
- Im Compiler ist ein Makroassembler integriert. Dieser ist ursprünglich als
- eigenständiges Programm zur Assemblerprogrammierung gedacht gewesen und da-
- her sehr viel leistungsfähiger als nötig. Daher ist er auch nur gering mit
- dem Oberon-Teil des Compilers verbunden. Er hat einen eigenen Parser und
- arbeitet im Gegensatz zum Compiler mit 2 Passes. Bei der Programmierung
- habe ich mich an AS orientiert, ein PD-Assembler für PC's, so daß hier ei-
- nige Ähnlichkeiten bestehen. Mit dem Befehl
-
- ASSEMBLER
- ...
- END;
-
- wird der Assembler aktiviert. Alles zwischen ASSEMBLER und END wird dann
- nicht mehr vom Compiler, sondern vom Assembler bearbeitet. Dabei können die
- meisten Symbole des Oberon-Teils verwendet werden, jedoch kann der Oberon-
- Teil nicht auf im Assembler definierte Symbole zugreifen. Der Assembler
- kann soweit mit Oberon-Strukturen arbeiten, solange kein Code dabei erzeugt
- werden muß.
-
- Für A7 kann alternativ auch SP verwendet werden. Alle Befehle sind auch
- ohne Längenangabe definiert. Wenn der Befehl in Wortgröße existiert, wird
- dies als Größe angenommen.
-
- Der Assembler ist genau wie der Compiler streng Case-Sensitiv. Alle Ma-
- schinenbefehle und Pseudobefehle müssen groß geschrieben werden. Bei Labeln
- wird zwischen Groß- und Kleinschreibung unterschieden.
-
- Achtung : Es sind längst nicht alle Maschinenbefehle getestet und bei
- Problemen sollte ein Disassembler prüfen, ob der Assembler nicht vielleicht
- Unsinn kodiert hat.
-
- 6.1) Symbolkonventionen
- -----------------------
-
- Symbole werden mit einer Länge von 22 Byte gespeichert, alle weiteren Zei-
- chen werden ignoriert. Wenn ein Label definiert werden soll, muß es in der
- ersten Spalte beginnen, darf kein vordefinierter Bezeichner sein und muß
- mit einem Buchstaben beginnen. Alle weiteren Zeichen können Buchstaben,
- Ziffern und Unterstrich sein. Ein Doppelpunkt hinter einem Label ist er-
- laubt, aber nicht erforderlich. Alle vordefinierten Bezeichner dürfen auch
- in der ersten Spalte anfangen. Die Parameterliste eines Makros muß mit ei-
- nem Zeilenende oder Kommentar beendet werden. Außer diesen beiden Forderun-
- gen ist in einem Quelltext alles erlaubt, auch mehrere Befehle in einer
- Zeile. Sicherheitshalber sollten sie mit ';;' getrennt werden, auch wenn es
- nicht immer nötig ist. Ein Semikolon leitet Kommentar ein, zwei hingegen
- trennen Befehle. Die Spalte hinter dem zweiten Semikolon wird wieder als
- erste Spalte einer neuen Zeile interpretiert, so daß dort auch ein Label
- definiert werden kann.
-
- Neben dem üblichen Kommentar mit einem Semikolon bis zum Zeilenende kann
- man auch mehrere Zeilen mit der in Oberon üblichen Konstruktion (* ...*)
- Kommentar definieren.
-
- Bei Labels und Befehlen wird immer zwischen Groß- und Kleinschreibung un-
- terschieden. Alle Maschinenbefehle, Register und Pseudooperationen müssen
- groß geschrieben werden.
- Folgende Symbole definiert der Assembler vor:
-
-
-
-
- +------+------------------------+
- | Name | Bedeutung |
- +------+------------------------+
- | * | mom. Programmzähler |
- | CPU | der gewählte Prozessor |
- +------+------------------------+
-
-
- Desweiteren einige Pseudobefehle, deren Parameter und natürlich alle
- 68000 Befehle. Befehle der anderen 680X0 Prozessoren sind z.T. implemen-
- tiert.
-
- 6.1.1) Formelausdrücke
- ......................
-
- An den meisten Stellen, an denen der Assembler Zahlenangaben erwartet, kön-
- nen nicht nur einfache Symbole oder Konstanten angegeben werden, sondern
- ganze Formelausdrücke. Bei den Komponenten der Formelausdrücke kann es sich
- sowohl um ein einzelnes Symbol als auch um eine Konstante handeln. Die
- Schreibweise von Integerkonstanten kann in verschiedenen Zahlensystemen er-
- folgen:
-
-
-
-
- +-------------+-------------------------------------+
- | dezimal | direkt |
- | hexadezimal | nachgestelltes H, vorangestelltes $ |
- | binär | nachgestelltes B, vorangestelltes % |
- | oktal | nachgestelltes O, vorangestelltes @ |
- +-------------+-------------------------------------+
-
-
- Damit hexadezimale Kostanten im Intel-Modus nicht als Symbolnamen fehl-
- interpretiert werden können, müssen sie immer mit einer Ziffer beginnen;
- anstelle z.B. F0H muβ also 0F0H geschrieben werden. Die Werte A-F müssen
- großgeschrieben werden, ebenso die nachgestellten Buchstaben. Beim
- Motorola-Modus entfällt dies. Integerkonstanten können auch als ASCII-Werte
- geschrieben werden, so entsprechen
-
- 'A' == $00000041
- 'AB' == $00004142
- 'ABC' == $00414243
- 'ABCD' == $41414244
-
- Dabei müssen die Zeichen in Hochkommata eingeschlossen sein, um sie von
- Strings zu unterscheiden. Ihre Länge darf maximal 4 Zeichen betragen. Um
- nun aber auch Gänsefüβchen und Sonderzeichen ohne Verrenkungen in Strings
- (und als Ascii-Werte geschriebene Integerkonstanten) schreiben zu können,
- wurde ein "Escape-Mechanismus" eingebaut, der C-Programmierer(inne)n be-
- kannt vorkommen dürfte: Schreibt man einen Backslash (\) mit einer maximal
- dreiziffrigen Zahl im String, so versteht der Assembler dies als Zeichen
- mit dem entsprechenden dezimalen ASCII-Wert. So kann man mit \0ein NUL-
- Zeichen definieren.
-
- Einige besonders häufig gebrauchte Steuerzeichen kann man auch mit fol-
- genden Abkürzungen erreichen:
-
- \b : Backspace \a : Klingel \e : Escape
- \t : Tabulator \n : Zeilenvorschub \r : Wagenrücklauf
- \\ : Backslash \' : Hochkomma \" : Gänsefüβchen
-
- Die Kennbuchstaben dürfen sowohl groβ als auch klein geschrieben werden.
-
- Über dieses Escape-Zeichen können sogar Formelausdrücke in den String
- eingebaut werden, wenn sie in geschweifte Klammern eingefaβt werden: z.B.
- bewirkt
-
- Wert1 equ 1
- Wert2 equ 2
- message "Wert = \{Wert1+Wert2}"
-
- die Ausgabe von 'Wert = 3'.
- Der Assembler stellt zur Verknüpfung folgende Operanden zur Verfügung:
-
-
-
-
- +--------------------------------------------------+
- | Operand Funktion #Operanden Rang |
- +--------------------------------------------------+
- | ~ log. NOT 1 hoch |
- | ~~ binäres NOT 1 ^ |
- +--------------------------------------------------+
- | * Produkt 2 | |
- | / Quotient 2 | |
- | # Modulodivision 2 | |
- | ^ Potenz 2 | |
- | !,!! binäres XOR 2 | |
- | &,&& binäres AND 2 | |
- +--------------------------------------------------+
- | - Differenz 2 | |
- | + Summe 2 | |
- | |,|| binäres OR 2 | |
- +--------------------------------------------------+
- | <> Ungleichheit 2 | |
- | >= gröβer oder gleich 2 | |
- | <= kleiner oder gleich 2 | |
- | < echt kleiner 2 | |
- | > echt gröβer 2 v |
- | = Gleichheit 2 niedrig |
- +--------------------------------------------------+
-
-
- Die angedeuteten Gruppen haben jeweils gleichen Rang. Die Reihenfolge der
- Evaluierung läβt sich durch Klammerung neu festlegen.
-
- Die Vergleichsoperatoren liefern TRUE, falls die Bedingung zutrifft, und
- FALSE falls nicht. Für die logischen Operatoren ist ein Ausdruck TRUE,
- falls er ungleich 0 ist, ansonsten FALSE. Deshalb ist auch ein separater
- "logisch Nicht" Operator nötig, denn eine Zahl ungleich 0 kann binär in-
- vertiert immer noch ungleich 0 sein. Beim "logisch Nicht" wird eine 0 zur
- 1, eine Zahl ungleich 0 zur 0. Alle anderen logischen Operationen sind mit
- den Binären identisch.
-
- Für Strings sind alle Vergleichsoperatoren sowie die Summe definiert. Die
- Summe zweier Strings ergibt einen String, der die beiden aneinandergehängt
- erhält. Vergleiche von Strings liefern 0 (FALSE) oder 1 (TRUE). Überall, wo
- Zahlen erwartet werden, dürfen also auch Stringvergleiche benutzt werden.
-
- Als einzige Funktion, die ein Stringargument zuläβt, ist die Funktion
- UPSTRING definiert. Sie wandelt alle Zeichen in Groβbuchstaben um. Dabei
- werden auch Umlaute in Großbuchstaben gewandelt, aber Änderungen des Zei-
- chensatzes mit CHARSET werden nicht korrekt berücksichtigt. Wer nur ein
- einzelnes Zeichen (als Integer gespeichert) umwandeln will, kann dies mit
- der Funktion TOUPPER tun.
-
- 6.2) Pseudobefehle
- ------------------
-
- 6.2.1) SET und EQU
- ..................
-
- SET und EQU erlauben die Definition typenloser Konstanten, d.h. sie werden
- keinem Segment zugeordnet und ihre Verwendung erzeugt in keinem Fall eine
- Warnung wegen Segmentverquickung. Während EQU Konstanten definiert, die
- nicht wieder (mit EQU) geändert werden können, erlaubt SET die Definition
- von Variablen, die sich während des Assemblerlaufes verändern lassen. In-
- tern werden Konstanten und Variablen identisch gespeichert, der einzige Un-
- terschied ist, daβ sie mit SET umdefiniert werden können und mit EQU nicht.
- Es ist daher möglich, ein Symbol mit EQU zu definieren und es mit SET zu
- ändern (auch wenn das nicht der Sinn der Sache ist).
-
- 6.2.2) CHARSET
- ..............
-
- Einplatinensysteme, zumal wenn sie LCDs ansteuern, benutzen häufig einen
- anderen Zeichensatz als ASCII, und daβ die Umlautkodierung mit der im Be-
- fehl übereinstimmt, dürfte wohl reiner Zufall sein. Um nun aber keine feh-
- lerträchtigen Handumkodierungen vornehmen zu müssen, enthält der Assembler
- eine Umsetzungstabelle für Zeichen, die jedem Quellcode ein Zielzeichen zu-
- ordnet. Zur Modifikation dieser Tabelle (die initial 1:1 übersetzt), dient
- der Befehl CHARSET. Der Befehl erwartet eine Bereichsangabe für die zu
- übersetzenden Zeichen als ersten bzw. ersten/zweiten Parameter und als
- letzten Parameter den Bereich, in den die Zeichen umgemappt werden sollen.
- Zur Klarstel- lung zwei Beispiele:
-
- CHARSET 'ä',128
-
- bedeutet, daβ das Zielsystem das ä mit der Zahl 128 kodiert. Falls das
- Zielsystem keine Kleinbuchstaben unterstützt, können mit
-
- CHARSET 'a','z','A'
-
- alle Kleinbuchstaben auf die passenden Groβbuchtaben automatisch umgemappt
- werden.
-
- ACHTUNG! CHARSET beeinfluβt nicht nur im Speicher abgelegte Stringkon-
- stanten, sondern auch als 'ASCII' formulierte Integerkonstanten. Dies be-
- deutet, daβ eine evtl. bereits modifizierte Umsetzungstabelle in den obigen
- Beispielen zu anderen Ergebnissen führt!
-
- 6.2.3) CPU
- ..........
-
- Speichert die nachfolgende Zahl als Bezeichnung für eine CPU. Kann wie je-
- der andere Bezeichner in Ausdrücken verwendet werden und ist bei der be-
- dingten Assemblierung verwendbar. Der Assembler prüft, ob ein Maschinenbe-
- fehl auf der gewählten CPU verfügbar ist und verweigert sie wenn nicht. De-
- faultwert ist 68000.
-
- 6.2.4) SUPMODE
- ..............
-
- Diese Variable kann nur ein- oder ausgeschaltet werden. Sie teilt dem As-
- sembler mit, ob der Supervisormode gerade eingeschaltet ist oder nicht. Am
- Anfang ist die Variable ausgeschaltet.
-
- Beispiel :
-
- SUPMODE ON
- MOVE #0,SR ; nur im Supervisormode zulässig
- SUPMODE OFF
- MOVE #0,SR ; führt zu einer Warnung des Assemblers
-
- 6.2.5) SEGMENT
- ..............
-
- Der Atari unterscheidet verschiedene Adreβbereiche, die nicht miteinander
- mischbar sind und jeweils auch verschiedene Befehle zur Ansprache benöti-
- gen. Um auch diese verwalten zu können, stellt der Assembler mehrere Pro-
- grammzähler zur Verfügung, zwischen denen mit dem SEGMENT-Befehl hin- und
- hergeschaltet werden kann. Dies erlaubt es, sowohl in mit INCLUDE eingebun-
- denen Unterprogrammen als auch im Hauptprogramm benötigte Daten an der
- Stelle zu definieren, an denen sie benutzt werden. Im einzelnen werden fol-
- gende Segmente mit folgenden Namen verwaltet:
-
- CODE: Programmcode
-
- DATA: Datenbereich
-
- BSS: Block storage segment, zu 0 initialisierte Daten, die nicht im Pro-
- grammcode auftauchen, sondern vom TOS angehängt werden.
-
- Labels, die in einem Segment eines bestimmten Typs definiert werden, erhal-
- ten diesen Typ als Attribut. Damit hat der Assembler eine begrenzte Prüfmö-
- glichkeit, ob mit den falschen Befehlen auf Symbole in einem Segment zuge-
- griffen wird. In solchen Fällen sollte der Assembler eine Warnung ausgeben.
-
- Achtung : Die Segmente werden natürlich auseinandergezogen und vom Linker
- richtig zusammengesetzt, daher darf man natürlich keine PC-relative Adres-
- sierung über Segmentgrenzen anwenden.
-
- 6.2.6) DC,DS
- ............
-
- Damit werden Konstanten im Code oder im Datensegment abgelegt oder Speicher
- reserviert. Als Längen sind .B, .W und .L möglich, keine Angabe wird als
- Wortlänge interpretiert.
-
- Bei allen dreien sind Strings erlaubt, evtl. wird ein String mit Nullen
- verlängert, um auf ein Vielfaches der Bytezahl zu kommen. Eine Reservierung
- von Speicher wird durch DS gemacht:
-
- DS.B 10 ; reserviert 10 Bytes
- DS.W 1 ; reserviert ein Wort
- DS.L 2,$FF ; reserviert 2 Langworte
- ; mit Inhalt $FF
-
- Speicherreservierung ohne Inhaltsangabe ist in allen Segmenten erlaubt. Der
- Inhalt ist dann jeweils 0. Eine Inhaltsangabe ist natürlich nur im Code und
- im Datensegment erlaubt.
-
- 6.2.7) ALIGN
- ............
-
- ALIGN mit einem dahinterstehenden Integerausdruck erlaubt es, den Programm-
- zähler auf eine bestimmte Adresse auszurichten. Die Ausrichtung erfolgt
- dergestalt, daβ der Programmzähler so weit erhöht wird, daβ er ein ganzzah-
- liges vielfaches des Arguments wird :
-
- align 2
-
- macht den Programmzähler gerade. Der Freiraum wird mit 0 gefüllt. Stattdes-
- sen kann man auch EVEN ohne Wert benutzen.
-
- 6.2.8) MACRO
- ............
-
- Dies ist der wohl wichtigste Befehl zur Makroprogrammierung. Mit der Be-
- fehlsfolge
-
- <Name> MACRO [Parameterliste]
- <Befehle>
- ENDM
-
- wird das Makro <Name>als die eingeschlossene Befehlsfolge definiert. Diese
- Definition alleine erzeugt noch keinen Code! Dafür kann fortan die Befehls-
- folge einfach durch den Namen abgerufen werden, das ganze stellt also eine
- Schreiberleichterung dar. Um die ganze Sache etwas nützlicher zu machen,
- kann man bei der Makrodefinition eine Parameterliste mitgeben. Die Parame-
- ternamen werden wie üblich durch Kommas getrennt und müssen - wie der Ma-
- kroname selber - den Konventionen für Symbolnamen genügen.
-
- Beim Aufruf eines Makros werden die beim Aufruf angegebenen Parameterna-
- men überall textuell im Befehlsblock eingesetzt und der sich so ergebende
- Assemblercode wird normal assembliert. Sollten beim Aufruf zu wenige Para-
- meter angegeben werden, werden sie als leere Strings übergeben. Soll mit-
- tendrin ein Parameter weggelassen werden, kann man zwei aufeinanderfolgende
- Kommas schreiben.
-
- Für die übergebenen Parameter gelten besondere Regeln : Eine zusammenhän-
- gende Kette von Zeichen ohne Komma gilt als ein Parameter, egal um welche
- Zeichen es sich handelt. Es können also auch spezielle Adressierungsarten
- wie (A0)+ übergeben werden. Wenn bewußt Strings übergeben werden sollen,
- müssen sie in Hochkommata eingeschlossen werden, der Parameter besteht dann
- aus dem String mit Hochkommata. Wird ein String in Gänsefüßchen einge-
- schlossen, besteht der Parameter nur aus dem String ohne Gänsefüßchen. So
- ist es auch möglich, Kommas und Leerzeichen in einem Parameter unterzubrin-
- gen.
- Beispiele :
-
- mac1 MACRO par1
- MOVE D0,par1
- ENDM
- mac1 A0 ; entspricht "MOVE D0,A0"
- mac2 MACRO par2,par3
- par2 par3
- ENDM
- mac2 MOVE,"D0,A0" ; entspricht wiederum
- ; "MOVE D0,A0"
-
- Es kann also praktisch alles durch Makroparameter ersetzt werden, auch Be-
- fehle !
-
- In Makrorümpfen definierte Labels werden immer als lokal betrachtet, ein
- expliziter LOCAL-Befehl ist also nicht erforderlich. Sollen Label global
- bekannt sein, müssen sie mit einem Stern gekennzeichnet sein. Da auf diese
- Weise das Label mit jedem Makroaufruf neu definiert wird, darf es sich nur
- um Definitionen mit 'SET' handeln, damit keine Fehlermeldungen wie 'Label
- schon definiert' kommen. Aus technischen Gründen ist es momentan nötig, ein
- Makro vor der ersten Benutzung zu deklarieren. Wenn ein Makroparameter in
- Gänsefüßchen eingeschlossen wird, wird er ebenfalls ersetzt, so daß das
- Aussehen des Parameters überprüft werden kann.
- Beispiel :
-
- Test MACRO Par
- IF "Par" = "A"
- ...
-
- Wenn als Parameter 'a' oder 'A' übergeben wurde, ergibt der Vergleich true.
- Es wird aber nicht generell in Strings ersetzt, sondern nur, wenn der ge-
- samte String gleich einem Makroparameter ist. Der Parameter wird *immer* in
- Großbuchstaben umgewandelt.
-
- 6.2.9) IRP
- ..........
-
- Dies ist die eine vereinfachte Form von Makrodefinitionen für den Fall, daβ
- eine Befehlsfolge einmal auf mehrere Operanden angewendet werden soll und
- danach nicht mehr gebraucht wird. IRP benötigt als ersten Parameter ein
- Symbol für den Operanden, und danach eine (fast) beliebige Menge von Para-
- metern, die nacheinander in den Befehlsblock eingesetzt werden. Um eine
- Menge von Registern auf den Stack zu schieben, kann man z.B. schreiben
-
- IRP op, D0,D1,D3
- MOVE op,-(SP)
- ENDM
-
- was in folgendem resultiert:
-
- MOVE D0,-(SP)
- MOVE D1,-(SP)
- MOVE D3,-(SP)
-
- Benutzte Labels sind wieder für jeden Durchgang automatisch lokal.
-
- Soll ein Label global sichtbar sein, muß es einen Stern hinter dem Namen
- haben. Dies geht nur bei Labels, die mit SET definiert werden, denn andere
- würden eine Fehlermeldung erzeugen, daß das Label schon definiert ist.
-
- 6.2.10) REPT
- ............
-
- Dies ist die einfachste Form der Makrobenutzung. Der im Rumpf angegebene
- Code wird einfach sooft assembliert, wie der Integerparameter von REPT an-
- gibt. Dieser Befehl wird häufig in kleinen Schleifen anstelle einer pro-
- grammierten Schleife verwendet, um den Schleifenoverhead zu sparen.
-
- Der Vollständigkeit halber ein Beispiel:
- REPT 3
- ROR #1,(A0)
- ENDM
- rotiert den Wert um 3 Stellen nach rechts.
-
- Symbole sind wiederum für jede einzelne Repetition lokal.
-
- 6.2.11) Bedingte Assemblierung
- ..............................
-
- Der Assembler unterstützt die bedingte Assemblierung mit Hilfe der Befehle
- IFC.. / ELSIFC / ENDC. Diese Befehle wirken zur Assemblierzeit, indem ent-
- sprechend der Bedingung Teile übersetzt oder übersprungen werden. Diese Be-
- fehle sind also nicht mit den IF-Statements höherer Programmiersprachen zu vergleichen.
- Die allgemeine Form eines IF-Befehles ist folgendermaβen:
-
- IFC <Ausdruck> THEN
- .
- .
- <Block 1>
- .
- .
- ELSIFC
- .
- .
- <Block 2>
- .
- .
- ELSEC
- .
- .
- <Block 3>
- .
- .
- ENDC
-
- Falls der hinter IFC angegebene Ausdruck wahr (d.h. ungleich 0) ist, wird
- Block 1 assembliert. Es können dann beliebig viele ELSIFC folgen, mit denen
- genauso verfahren wird. Falls keine Bedingung zutrifft, wird der ELSEC-
- Zweig assembliert, falls er vorhanden ist.
-
- IF-Anweisungen dürfen beliebig verschachtelt werden, ein ELSEC bezieht
- sich immer auf das letzte vorangegangene, noch nicht abgeschlossene IFC.
-
- Wenn in der Bedingung Symbole auftauchen, müssen diese unbedingt vorher
- definiert worden sein, damit im Pass 1 der richtige Block übersetzt wird.
-
- Für den Test, ob ein Symbol definiert ist, wurde die Funktion DEF einge-
- führt. Sie gibt TRUE (=1), wenn das angegebene Symbol definiert ist, sonst
- FALSE (=0).
- Dies ist nützlich für Include Dateien :
-
- IFC NOT DEF(thisfile) THEN; wenn nicht definiert
- thisfile EQU 1 ; dann definieren
- ... ; und übersetzen
- ENDC
-
- 6.2.12) Lokale Label
- ....................
-
- Die bedeutendste Erweiterung zu AS sind lokale Label. Damit können in-
- nerhalb eines Bereichs alle Label eingekapselt werden, so daß sie in der
- Umgebung nicht mehr sichtbar sind.
-
- Beispiel :
- LOCAL
- Proc1*: ...
- Loop: ...
- END
- LOCAL
- Proc2*: ...
- Loop: ...
- END
-
- können so in derselben Datei stehen. Loop ist jeweils nur innerhalb von LO-
- CAL und END sichtbar. Ein * hinter einem Label (vor dem Doppelpunkt falls
- einer gesetzt wird) bedeutet, daß das Label global sein soll. Egal auf wel-
- cher Verschachtelungsebene von LOCAL man sich befindet, ein solches Label
- ist überall sichtbar. Includedateien sollten alle Label lokal machen und
- nur diese Label global definieren, die auch von anderen benutzt werden sol-
- len. Damit vermeidet man die Doppelbenutzung von Labels, die unwissentlich
- in einer Includedatei definiert sind.
-
- Alle Label ohne Stern sind außerhalb der ASSEMBLER ... END Struktur nicht
- bekannt, d.h. sie sind automatisch lokal.
-
- Durch die Lokalisierung innerhalb von ASSEMBLER bis END ist dieser Befehl
- nicht nötig, aber für reine Assemblerprojekte ist er wichtig.
-
- 6.3) Hochsprachenelemente
- -------------------------
-
- Der Assembler beherrscht auch einige der Oberon-Strukturen, wenn auch we-
- sentlich primitiver. Trotzdem kann man mit ihnen ein wenig Struktur in ein
- Assemblerprogramm bringen und auch Labeldefinitionen wie Loop o.ä. sparen.
-
- 6.3.1) IF cond THEN ... ELSIF ... ELSE ... END
- ..............................................
-
- Die übliche If-Abfrage darf natürlich nicht fehlen. Als Bedingungen sind
- aber lediglich die üblichen Condition Codes HI, LS, CC, HS, CS, LO, NE, EQ,
- VC, VS, PL, MI, GE, LT, GT und LE zugelassen.
- Beispiel :
-
- CMP D0,D1
- IF EQ THEN ; wenn D0 = D1
- ... ; tu dies
- ELSIF LO THEN ; wenn D1 < D0
- ... ; tu dies
- ELSE
- ... ; sonst dies
- END
-
- 6.3.2) REPEAT ... UNTIL cond
- ............................
-
- Entspricht einer Repeat-Schleife in Oberon. Bedingungen wie bei IF.
-
- Beispiel :
- REPEAT
- SUBQ #1,D0
- UNTIL EQ ; zählt D0 bis auf 0 runter
-
- 6.3.3) LOOP ... END
- ...................
-
- Entspricht LOOP in Oberon.
-
- 6.3.4) EXIT [(Zahl)]
- ....................
-
- Mit Hilfe der Exit-Anweisung kann man REPEAT-Schleifen und LOOP- Schleifen
- mittendrin verlassen. Es wird ein Branch an das Ende der Struktur einge-
- fügt. Wenn man eine Zahl in Klammern angibt, kann man gleich mehrere Struk-
- turen verlassen. Dabei einspricht EXIT einem EXIT(0).
- Beispiel :
-
- LOOP
- REPEAT
- TST D0
- IF EQ THEN EXIT END ; verläßt die
- ; REPEAT-Schleife
- IF MI THEN EXIT(1) END; verläßt die
- ; LOOP-Schleife
- UNTIL PL
- END
-
- 6.4) Diverses
- -------------
-
- 6.4.1) INCLUDE
- ..............
-
- Dieser Befehl fügt die im Parameter angegebene Datei so im Text ein, als ob
- sie dort stehen würde. Dieser Befehl ist sinnvoll, um Quelldateien aufzu-
- spalten, die alleine nicht in den Speicher passen würden oder um sich
- "Toolboxen" zu erzeugen.
-
- Aus Kompatibilitätsgründen ist es erlaubt, den Dateinamen in Gänse-
- füβchen zu schreiben,
-
- include stddef51.asm
-
- und
-
- include "stddef51.asm"
-
- sind also äquivalent.
-
- 6.4.2) MESSAGE, WARNING, ERROR und FATAL
- ........................................
-
- Der Assembler prüft zwar die Quelltexte so streng wie möglich und liefert
- diffenzierte Fehlermeldungen, je nach Anwendung kann es aber sinnvoll sein,
- unter bestimmten Bedingungen zusätzliche Fehlermeldungen auszugeben, mit
- denen sich logische Fehler automatisch prüfen lassen. Der Assembler unter-
- scheidet drei Typen von Fehlermeldungen, die über drei Befehle auch dem
- Programmierer zugänglich sind:
-
- - WARNING : Fehler, die auf möglicherweise falschen oder ineffizienten
- Code hinweisen. Die Assemblierung läuft weiter, eine Codedatei wird er-
- zeugt.
-
- - ERROR : Echte Fehler im Programm. Die Assemblierung läuft weiter, um mö-
- gliche weitere Fehler in einem Durchgang entdecken und korrigieren zu
- können. Eine Codedatei wird nicht erzeugt.
-
- - FATAL : Schwerwiegende Fehler, die einen sofortigen Abbruch des Assem-
- blers bedingen. Eine Codedatei kann möglicherweise entstehen, ist aber
- unvollständig.
-
- Alle Befehle erwarten eine String als Argument.
-
- Diese Anweisungen ergeben nur in Zusammenhang mit bedingter Assemblierung
- Sinn. So kann man fehlerhafte Bedingungen abtesten und mit einer Fehler-
- meldung abbrechen. Der String einer Fehlermeldung wird anstatt einer Assem-
- blermeldung in die Fehlerdatei geschrieben und mit Zeile und Spalte verse-
- hen, in der der Befehl steht.
-
- Der Befehl MESSAGE gibt den angegebenen String lediglich aus und erzeugt
- einen Zeilenvorschub.
-
- 6.5) Zugriff auf Oberon-Bezeichner
- ----------------------------------
-
- Der Assembler hat eine begrenzte Zugriffsmöglichkeit auf Bezeichner, die in
- Oberon definiert wurden. Dabei gilt allgemein, daß nur solche Zugriffe un-
- terstützt werden, die keinen zusätzlichen Code erfordern.
- Beispiel :
-
- CONST con = 10;
- TYPE rec = RECORD
- var1 : INTEGER;
- var2 : ARRAY 10 OF CHAR;
- END;
- arr = ARRAY 10 OF LONGINT;
- VAR a : rec;
- b : POINTER TO rec;
- c : arr;
- PROCEDURE proc1;
- ...
- PROCEDURE proc2*;
- ...
- Dann sind folgende Zugriffe möglich:
- MOVE #con,D0 ; lädt D0 mit 10
- MOVE.L a,A0 ; lädt Adresse von a in A0
- ; (geht auch mit Prozeduren
- ; und Stringkonstanten)
- MOVE a.var1,D0 ; geht weil a globale
- ; Variable ist
- MOVE.B a.var2[5],D1 ; dito
- MOVE.L c[8],D2 ; dito
- BSR proc ; innerhalb eines Moduls
- JSR proc2 ; bei importierten und
- ; exportierten Prozeduren
- Dagegen geht dies nicht:
- MOVE b.var1,D0 ; b ist ein Zeiger und muß erst
- ; geladen werden
- Dies kann so gelöst werden:
- MOVE.L b,A0 ; Inhalt von b = Zeiger auf rec
- MOVE rec.var1(A0),D0 ; typ.var ergibt Offset von var
- MOVE.B rec.var2[5](A0),D0; genauso
- MOVE.L arr[2](A1),D0 ; geht genauso mit Arrays
-
- Man kann also mit dem Typbezeichner die Offsets der Variablen innerhalb des
- Records bekommen. Dies sollte immer der direkten Angabe von Zahlen vorgezo-
- gen werden, damit bei einer Änderung der Datenstruktur nicht alle Zahlen
- geändert werden müssen.
-
-
- 7) Der Linker
- =============
-
- Der Oberon-Linker (LINK.OBJ/TTP) dient dazu, vom Compiler erzeugte Ob-
- jektmodule zu einem lauffähigen Programm zusammenzubinden. Dafür benötigt
- er nur die Objektmodule, die Symboldateien nicht.
-
- 7.1) Aufruf, Parameter
- ----------------------
-
- Der Linker sollte von einer Shell aus benutzt werden, die zumindest in der
- Lage ist, Environmentvariablen zu setzen, denn der Linker liest dort seine
- Optionen. Beim Aufruf kann man als Kommando einige Optionen sowie einen Na-
- men eines Objektmoduls übergeben. Dieses Modul wird mit den von ihm impor-
- tierten Modulen zusammengelinkt und unter seinem Namen mit passender Exten-
- sion gespeichert. Die Syntax sieht also so aus:
-
- link {<Option>} <Name>
-
- Es wird nur der Name ohne Extension beachtet, ein eventueller Pfad wird ab-
- geschnitten. Dieser Name wird mit der Extension OBJ in den Suchpfaden ge-
- sucht. Wird keine Datei gefunden, wird der Linker wieder verlassen.
- Die Optionen haben die allgemeine Syntax:
-
- -<Option><Parameter>
-
- Die Art der Option wird mit einem Buchstaben (groß oder klein) angegeben,
- eventuelle Parameter folgen ohne Leerzeichen. Einige Optionen sind sowohl
- über Environmentvariablen als auch über Kommandozeile setzbar. Dabei gilt:
- Die Optionen in der Kommadozeile haben höhere Priorität.
- Folgende Optionen sind implementiert:
-
- -t: Schaltet die Erzeugung einer Symboltabelle aus, die normalerweise immer
- an das Programm angehängt wird. Eine Symboltabelle ist wichtig, wenn
- man ein Programm debuggen muß. Sowohl Bugaboo als auch DB verstehen das
- Format der Symboltabelle.
-
- -e: Schaltet die Erzeugung einer erweiterten Symboltabelle ab. Normaler-
- weise wird eine Symboltabelle im erweiterten GST-Format erzeugt, die
- eine Symbollänge von 22 Zeichen zuläßt, während das Standardformat nur
- 8 Zeichen hat. Diese Option stellt also nur das Format ein, die Option
- -t schaltet die Symboltabelle ganz aus.
-
- -s|<size>|: Normalerweise erhält ein Programm einen Stack von 32K Größe.
- Mit dieser Option kann man den Stack beliebig einstellen.
-
- -x|<ext>|: Damit kann die Extension eingestellt werden, die das Programm
- erhalten soll. Normalerweise ist das PRG, aber bei TOS-Programmen kann
- man TOS oder TTP angeben.
-
- Ist von einem Modul eine Infodatei vorhanden und darin ist ein Programmname
- definiert, wird dieser beim Speichern des Programmes benutzt. Wenn ein Pfad
- angegeben ist, wird dort gespeichert, sonst in PRGPATH bzw. beim Modul. Der
- Name kann im Quelltext mit (*$N ...*) gesetzt werden, siehe Kap. ??.
-
- 7.2) Environmentvariablen
- -------------------------
-
- Der Linker wertet auch einige Environmentvariablen aus. Sie müssen immer
- großgeschrieben sein und von einem '=' gefolgt sein. Gesetzt werden sie in
- der Shell und werden jedem Programm übergeben, daß von dieser Shell aufge-
- rufen wird.
- Es werden folgende Variablen ausgewertet:
-
- OBJPATH: Gibt die Suchpfade an, in denen nach importierten Modulen gesucht
- wird. Zum Linken werden nur die Objektdateien benötigt.
- Wenn OBJPATH nicht definiert ist, wird MODPATH genommen.
-
- INFPATH: Gibt die Suchpfade an, in denen nach Infodateien gesucht wird.
- Wenn INFPATH nicht definiert ist, wird MODPATH genommen.
-
- TOSPATH: Gibt ebenfalls Suchpfade an, in denen Module stehen, die in TOS-
- Programmen benutzt werden dürfen. Diese Pfade werden vor denen in OB-
- JPATH durchsucht. Die Unterscheidung erfolgt anhand der Extension, die
- das zu erzeugende Programm erhält. Fängt sie mit 'T' an, werden die Mo-
- dule aus TOSPATH und OBJPATH gelinkt. Ist TOSPATH nicht definiert, wird
- wie bisher nur OBJPATH bzw. MODPATH genommen.
-
- GEMPATH: Gibt ebenfalls Suchpfade an, in denen Module stehen, die in GEM-
- Programmen benutzt werden dürfen. Diese Pfade werden vor denen in OB-
- JPATH durchsucht. Die Unterscheidung erfolgt anhand der Extension, die
- das zu erzeugende Programm erhält. Fängt sie nicht mit 'T' an, werden
- die Module aus GEMPATH und OBJPATH gelinkt. Ist GEMPATH nicht defi-
- niert, wird wie bisher nur OBJPATH bzw. MODPATH genommen.
-
- PRGPATH: Gibt einen mit Backslash beendeten Pfad an, in den das erzeugte
- Programm geschrieben werden soll. Wenn die Variable nicht existiert,
- wird das Programm in denselben Pfad geschrieben, in dem das Objektmodul
- stand.
-
- SYMTAB: Darf als Werte ON und OFF annehmen. Damit wird die Ausgabe einer
- Symboltabelle ein- oder ausgeschaltet. Normalerweise wird eine Symbol-
- tabelle erzeugt.
-
- EXTSYM: Wieder Werte ON/OFF. Schaltet das erweiterte GST-Format der Symbol-
- tabelle ein oder aus. Ist normalerweise eingeschaltet.
-
- PRGEXT: Gibt die Extension an, die das gelinkte Programm erhalten soll.
- Beispiel : 'PRGEXT=TOS' erzeugt ein TOS-Programm (der Code muß dafür
- natürlich geeignet sein). Standardmäßig wird die Extension PRG benutzt.
-
- STACKSIZE: Der Inhalt dieser Variablen muß eine Dezimalzahl sein, die die
- Größe des Stacks angibt. Normalerweise ist dies 32K.
-
- LINKALSO: Diese Variable darf eine Liste von Dateinamen, getrennt mit Kom-
- mata, enthalten. Diese Objektmodule werden dann auch gelinkt, wenn sie
- nicht importiert werden. Damit ist es z.B. möglich, während der Test-
- phase ein Debugmodul mitzulinken, daß sich in Exceptions einklinkt oder
- ähnliches. Ein Name sollte immer nur 8 Zeichen lang sein, Extensions
- sind nicht nötig. Es sind nur maximal 5 Module möglich. Müssen es mehr
- sein, so muß man ein Leermodul definieren, daß diese Module importiert,
- und dieses kann man bei LINKALSO angeben.
-
- LINK_ ...: Alle Variablen, die mit LINK_ anfangen, dienen zum Umbenennen
- von importierten Modulen. Wird z.B. LINK_IO=GEMIO definiert, wird bei
- jedem Import von IO stattdessen GEMIO gelinkt. Diese Module müssen na-
- türlich gleiche Schnittstellen haben.
-
-
- 8) Die Lader
- ============
-
- Die Lader wurden zu einer Zeit entwickelt, als es noch keine Shell für
- Load-Time-Linking gab. Sie sind daher in der Lage, Objektmodule direkt zu
- linken und zu starten. Es gibt zwei Lader, einen für GEM-Applikationen
- (LOAD.PRG) und einen für TOS-Applikationen (LOAD.TTP). Inzwischen gibt es
- allerdings keinen Unterschied mehr. Man braucht nur jeweils die richtige
- Extension, damit beim Start die richtige Umgebung gewählt wird.
-
- 8.1) Aufruf, Parameter
- ----------------------
-
- Die Lader erhalten mindestens den Namen eines Moduls als Argument. Dieses
- Modul darf keine Extension haben, also nur der Name. Das Modul wird zuerst
- im Lader selbst gesucht, dann in den Suchpfaden, die in der Environmentva-
- riablen OBJPATH definiert sind. Ist sie nicht definiert, wird MODPATH ge-
- nommen. Wenn ein Modul nicht gefunden wird, wird mit einer Meldung abgebro-
- chen. Sind alle Module geladen und gelinkt, wird das Hauptmodul gestartet.
- Dabei ist die Variable Sys.Loader TRUE, so daß man erkennen kann, wenn man
- unter dem Lader läuft. Folgt auf den Namen des Moduls ein Punkt und ein
- weiterer Name, so wird dieser Name in der Liste der exportierten Prozeduren
- gesucht und eine gefundene Prozedur wird gestartet. Dies realisiert die un-
- ter Wirths Oberon übliche Art des Load-Time-Linking. Das geladene Modul
- kann dies erkennen, denn die Variable Sys.ModuleCall wird auf TRUE gesetzt,
- wenn nur das Modul gestartet wurde. In so einem Fall muß der Modulrumpf die
- Aktion auslösen. Sie wird auf FALSE gesetzt, wenn eine Prozedur angegeben
- wurde. Dann dient der Modulrumpf nur zur Initalisierung. Alles was hinter
- dem Modul- bzw. Prozedurnamen folgt, wird als Kommando an das Modul weiter-
- gegeben. Man findet dies wie immer in Sys.Basepage.Command, genau so als
- wäre das Modul als Programm gestartet worden.
-
- 8.2) Ausgabe
- ------------
-
- Die Lader machen keine Ausgaben, solange keine Fehler auftreten.
-
- Eine mögliche Fehlermeldung lautet: 'Objectmodule defect'. Dies deutet
- auf einen Versionskonflikt hin.
-
- Wird ein Modul mit Extension übergeben (z.B. Icon auf Loader gezogen), so
- wird das Modul normal gestartet mit Sys.ModuleCall FALSE. Nach Beendigung
- des Moduls erscheint dann die Meldung 'Procedure OBJ not found', falls die
- Extension OBJ war. Dies ist nicht weiter schädlich.
-
- Die Lader haben ein angepaßtes Modul für die Exceptionbehandlung inte-
- griert. Es gibt die Art des Fehlers, die Adresse, das Modul, die Prozedur
- mit Offset und die Parameter aus, mit denen der Compiler aufgerufen werden
- muß.
- Beispiel:
-
- Bus error
- Address: 1ABEA0
- Module: Test
- Procedure: test + 8
- Call Compiler with '-e-o-s64'
-
- Der Absturz fand also in der Prozedur Test.test statt, 8 Bytes vom Anfang
- der Prozedur entfernt. Wenn man jetzt den Compiler mit '-e-o-s64 Test' auf-
- ruft, sucht er im Modul Test die Position 64 (64 Bytes vom Anfang entfernt,
- hexadezimal!) und gibt ein paar Zeilen rund um die Position aus. Die Bedeu-
- tung der Optionen ist in Kap. ?? erklärt.
-
-
- 9) Das Make-Utility
- ===================
-
- Der Begriff Make dürfte von C her bekannt sein. Hier ist es jedoch nicht
- nötig, ein Makefile zu erzeugen. Make (MAKE.OBJ/TTP) liest die importierten
- Module aus dem Quelltext und übersetzt alle Dateien, bei denen dies nötig
- ist.
-
- 9.1) Aufruf, Parameter
- ----------------------
-
- Make kann ohne Parameter oder mit einem Modulnamen gestartet werden. Wird
- Make ohne Parameter gestartet, so werden alle Suchpfade nach zu übersetzen-
- den Modulen durchsucht. Wird ein Modul genannt, werden nur solche Module
- überprüft, die in den Suchpfaden stehen und für das Linken des angegebenen
- Moduls benötigt werden.
-
- 9.2) Environmentvariablen
- -------------------------
-
- Mit der Environmentvariablen OC kann man den Compiler angeben.
- Beispiel: OC=E:\OBERON\SYS\COMPILE.TTP
- Ist OC nicht definiert, wird 'COMPILE.TTP' im aktuellen Verzeichnis ge-
- sucht. Die Suchpfade für Sourcen, Objekt- und Symboldateien werden über die
- Environmentvariable 'MAKEPATH' definiert.
-
- 9.3) Hinweise
- -------------
-
- Wenn Module sich gegenseitig importieren, bleibt Make in einer Endlos-
- schleife hängen. Man erkennt dies daran, daß ständig dieselben Dateinamen
- ausgegeben werden. Mit Control-C kann man die Ausführung abbrechen.
-
-
- 10) Der Scanner
- ===============
-
- Der Scanner (SCAN.OBJ/TTP) dient dazu, von einer Position in einem Pro-
- gramm die Stelle im richtigen Quelltext zu finden. Dies erfordert eine er-
- weiterte Symboltabelle am Programm. Diese erzeugt der Linker normalerweise,
- wenn nichts anderes verlangt wird.
-
- 10.1) Aufruf, Parameter
- -----------------------
-
- Scan erwartet zwei Parameter in der Kommandozeile, die mit Leerzeichen ge-
- trennt sind:
-
- 65) Der Name des Programms. Der Name muß so angegeben werden, daß Scan das
- Programm auch findet.
-
- 66) Die Position im Programm. Sie wird hexadezimal ohne Zusätze wie $ oder
- H angegeben. Mit Position ist der Abstand von dem Codeanfang gemeint.
- Diese wird zum Beispiel von Exceptions ausgegeben.
-
- Scan liest das Programm, bestimmt mit Hilfe der Symboltabelle das Modul und
- die Position relativ zum Modulanfang und ruft den Compiler auf. Als Optio-
- nen werden -e, -o und -s<pos>angegeben. Der Compiler übersetzt das be-
- stimmte Modul, bis er an die Position gelangt, an der der Absturz statt-
- fand. Es werden einige Zeilen davor und dahinter sowie eine Kennzeichnung
- der Stelle ausgegeben. Diese Stelle wird auch als Fehlermeldung ausgegeben
- und kann in der Fehlerdatei nachgelesen werden. Dann beenden sich Compiler
- und Scan.
-
- Falls das Programm keine Symboltabelle hat, macht Scan eine Meldung und
- terminiert.
-
- 10.2) Environmentvariablen
- --------------------------
-
- Mit der Environmentvariablen OC kann man den Compiler angeben.
- Beispiel: OC=E:\OBERON\SYS\COMPILE.TTP
- Ist OC nicht definiert, wird 'COMPILE.TTP' im aktuellen Verzeichnis ge-
- sucht.
-
-
- 11) Debugging
- =============
-
- Bis jetzt gibt es leider keinen Source Level Debugger für STJ-Oberon-2.
- Dies ist aber geplant und wird irgendwann kommen. Bis dahin muß man sich
- mit Low Level Debuggern herumplagen.
-
- 11.1) DB
- --------
-
- Der Debugger DB von Atari eignet sich einigermaßen zum Debuggen. Ich möchte
- hier besonders auf den Befehl 'stack' hinweisen: Dieser Befehl versucht
- über den Stack die Aufrufkette von Subroutinen zurückzuverfolgen. Dies geht
- auch mit Oberon-Programmen, da diese genau wie C-Programme mit Register A6
- lokale Stacks aufbauen.
-
- 11.2) Bugaboo
- -------------
-
- Bugaboo (aus dem TurboAss-Paket) eignet sich ebenfalls zum Debuggen. Er
- kennt leider den Befehl 'stack' nicht, ist dafür aber wesentlich komforta-
- bler. Leider arbeitet er nicht auf dem TT mit Großbildschirm.
-
- 11.3) Tips
- ----------
-
- Zum Debuggen wird immer eine Symboltabelle benötigt.
-
- Eine globale Variable kann man über den Namen ansprechen, lokale Variable
- einer Prozedur findet man bei Adressen ab (A6) abwärts, deren Parameter ab
- 8(A6) aufwärts.
-
- Die Namen der Symboltabelle sind nicht immer eindeutig. Wenn man also ein
- Symbol ansprechen will, muß man erst prüfen, ob es das Gewünschte ist. Bei-
- spielsweise findet man die Prozedur 'Read' in File und in Paths.
-
- Einen Befehl sollte man immer im Hinterkopf haben: Wenn nämlich ein Pro-
- gramm abgestürzt ist und man aus dem Debugger raus möchte, sollte man noch
- die Exitprozedur aufrufen, damit alle Betriebsmittel freigegeben werden.
- Dazu muß man den PC auf das Symbol 'Exit' stellen und die Ausführung star-
- ten. Wenn der Exit nicht abstürzt, müßte eine Meldung über die Terminierung
- des Programms kommen. Bei DB lautet der Befehl 'x pc .Exit', bei Bugaboo
- 'let pc=.Exit'.
-
-
- 12) Utilities
- =============
-
- 12.1) Der Browser
- -----------------
-
- Ein Browser ist ein Programm, daß aus der Symboldatei und der Source eine
- Definitionsdatei erzeugt. Die vorliegende Version ist noch in der Entwick-
- lung. Sie wertet lediglich die Symboldatei aus, so daß keine Kommentare in
- der Definitionosdatei sind.
- Der Browser wurde von Dirk Theisen geschrieben.
-
- 12.2) Inline-Zeilen erzeugen
- ----------------------------
-
- Für den Fall, daß jemand eine Datei als INLINE-Zeilen in eine Source inte-
- grieren will (z.B. eine Resourcedatei), kann man dies mit Inline tun. In-
- line fragt nach der zu konvertierenden Datei und speichert die erzeugte Da-
- tei mit der Extension INL ab. Im Editor muß man dann noch den Modulnamen
- SYSTEM bzw. eine Abkürzung davon mittels Suchen und Ersetzen vor INLINE
- setzen.
-
-
- 13) Speicherverwaltung
- ======================
-
- Die Speicherverwaltung implementiert Funktionen zum Allozieren und Freige-
- ben dynamischen Speichers. Solcher Speicher ist grundsätzlich nicht initia-
- lisiert[6].
-
- ---------------
-
- [6] wie auch lokale Variable, lediglich globale Variable werden zu 0 in-
- itialisiert
-
-
- 13.1) Benutzung in Programmen
- -----------------------------
-
- Für die dynamische Speicherverwaltung stehen mehrere Funktionen zur Verfü-
- gung:
-
- |NEW(<pointer>)|: Wenn als Argument ein Zeiger auf einen Record oder ein
- konstantes Array übergeben wird, wird diese Struktur alloziert. Bei Re-
- cords werden 4 Bytes zusätzlich alloziert, die den Typdeskriptor auf-
- nehmen. Dieser steht immer _vor_ dem Record, d.h. der Zeiger zeigt im-
- mer auf das erste Element des Records, wohingegen er bei anderen Compi-
- lern auf den Deskriptor zeigt.
-
- |NEW(<pointer>,<len>)|: Eine Länge kann nur angegeben werden, wenn es sich
- bei dem Zeiger um einen Zeiger auf ein offenes Array handelt. Dabei ist
- len die Anzahl Indizes.
-
- |SYSTEM.NEW(<pointer>,<len>)|: SYSTEM.NEW kümmert sich nicht um den Typ des
- Zeigers. Es wird soviel Speicher alloziert, wie len in Bytes angibt. So
- allozierter Speicher wird niemals am Garbage Collect teilnehmen.
-
- |SYSTEM.DISPOSE(<pointer>)|: Gibt den Speicher, auf den der übergebene Zei-
- ger zeigt, wieder frei.
-
- Der Garbage Collector wird mit Kernel.GC aufgerufen. Dies führt einen
- kompletten Collect durch. Es gibt auch eine Möglichkeit, den Collect in
- kleine Teile zerhackt nebenher laufen zu lassen. Dies würde mit Obe-
- ron.Collect unter Chatwin gehen. Dort sehe ich auch die einzige sinnvolle
- Anwendung. Im Moment kann ich von beidem nur abraten, da es noch nicht aus-
- gereift ist.
-
- Hinweis: Am Ende eines Programms oder Modulstarts wird automatisch aller
- Speicher freigegeben.
-
- 13.2) Implementierung
- ---------------------
-
- Die Implementierung versucht den Kompromiß zwischen Geschwindigkeit und
- Overhead zu finden. Der Overhead wird minimal, wenn bei jeder Speicher-
- anforderung genau der angeforderte Speicher alloziert wird (plus ein Ein-
- trag in einer Liste). Die Verwaltung der Liste hat aber so viel Zeit benö-
- tigt, daß der Compiler merklich langsamer wurde. Effizienter wird das, wenn
- man den benötigten Speicher ein wenig aufrundet und in einem Array unter-
- bringt. Das kostet natürlich Speicher. Um diesen Overhead nicht zu groß
- werden zu lassen, habe ich Speicheranforderungen in 16 Klassen unter-
- teilt[7]. Größere Objekte ab 256 Byte werden in einer Liste verwaltet. Ob-
- jekte zwischen 2 und 256 Byte werden in Arrays verwaltet, deren Elem-
- entgröße zwischen 16 und 256 Byte in 15 Stufen unterteilt ist.
-
- Gegenüber GEMDOS stellt sich die Speicherverwaltung anders dar. Dort wird
- immer mindestens 32K alloziert, so daß die Anzahl GEMDOS-Blöcke nicht allzu
- groß wird und damit die Geschwindigkeit abnimmt. Es kann auch nicht passie-
- ren, daß die Speicherverwaltung des GEMDOS keine Einträge mehr hat.
-
- ---------------
-
- [7] Mombergs Oberon verwendet nur 5 Klassen und hat damit mehr Overhead
-
-
-
- 14) Die Bibliotheken
- ====================
-
- Die Bibliotheken ermöglichen eigentlich erst ein vernünftiges Programmieren
- mit einer Programmiersprache. Hier soll eine Übersicht der vorhandenen Mo-
- dule gegeben werden, nähere Informationen müssen den Definitionsdateien
- entnommen werden.
-
- 14.1) Betriebssystem
- --------------------
-
- Alle Betriebssystemmodule implementieren die Aufrufe als Makros, d.h. der
- Code für den Trap wird beim Aufruf in den Code integriert. Es erfolgt kein
- Prozeduraufruf. Der Nachteil dieser Methode ist, daß alle Parameter in der
- Reihenfolge vertauscht sind. Der Oberon-Compiler legt den ersten Parameter
- auch als ersten auf den Stack, während C-Compiler den letzten Parameter als
- erstes auf den Stack legen.
-
- 14.1.1) BIOS
- ............
-
- Die üblichen BIOS-Funktionen.
-
- 14.1.2) GEMDOS
- ..............
-
- Die üblichen GEMDOS-Funktionen.
-
- 14.1.3) MiNT
- ............
-
- Die neuen Funktionen unter MiNT sind eigentlich auch GEMDOS-Aufrufe. Sie
- sind aber hier separat verfügbar. Sys.MiNT gibt an, ob MiNT installiert
- ist.
-
- 14.1.4) XBIOS
- .............
-
- Die üblichen XBIOS-Funktionen. Es fehlen Erweiterungen von TT und Falcon,
- über die ich keine Informationen habe.
-
- 14.2) Abstrakte Datenstrukturen
- -------------------------------
-
- 14.2.1) BinTree
- ...............
-
- BinTree implementiert einen binären Baum.
- BinTree wurde von H. Mössenböck und Dirk Theisen geschrieben.
-
- 14.2.2) CDCL
- ............
-
- CDCL steht für Circular Double Chained List. Es handelt sich also um eine
- doppelt verkettete Liste, deren erstes und letztes Element aufeinander zei-
- gen.
-
- 14.2.3) DCL
- ...........
-
- DCL steht für Double Chained List. Es handelt sich also um eine doppelt
- verkettete Liste.
-
- 14.2.4) FIFO
- ............
-
- FIFO (First in first out) implementiert eine Liste, an deren Anfang Ele-
- mente eingefügt und an deren Ende sie wieder entnommen werden können.
- FIFO wurde von Dirk Theisen geschrieben.
-
- 14.2.5) LRU
- ...........
-
- LRU (Least recently used) implementiert eine Prioritätenliste nach dem
- Prinzip 'am längsten nicht mehr benutzt zuerst'.
- LRU wurde von Dirk Theisen geschrieben.
-
- 14.2.6) Stack
- .............
-
- Stack implementiert eine Liste, an deren Anfang Elemente eingefügt und wie-
- der entnommen werden können.
- Stack wurde von Dirk Theisen geschrieben.
-
- 14.3) Standardmodule
- --------------------
-
- Unter diesem Abschnitt werden alle Module zusammengefaßt, die in beliebigen
- Applikationen (TOS oder GEM) benutzt werden können.
-
- 14.3.1) Buffers
- ...............
-
- Buffers implementiert einen einfachen flexiblen Puffer, der als Grundlage
- für gepufferte Ausgabe dienen soll.
-
- 14.3.2) CommandLine
- ...................
-
- CommandLine implementiert die Auswertung eines per ARGV übergebenen Kom-
- mandos, kann aber auch mit der normalen Commandline arbeiten.
- CommandLine wurde von Dirk Theisen geschrieben.
-
- 14.3.3) Cookie
- ..............
-
- Suchen, Setzen und Löschen von Einträgen im Cookie Jar.
-
- 14.3.4) Datum
- .............
-
- Das Modul Datum arbeitet mit Daten.
- Datum wurde von Wolfgang Radtke geschrieben.
-
- 14.3.5) Environment
- ...................
-
- Suchen von Einträgen im Environment.
-
- 14.3.6) Error
- .............
-
- Standardisierte Ausgabe von Fehlermeldungen, insbesondere des Be-
- triebssystems, über eine Alertbox.
-
- 14.3.7) Exceptions
- ..................
-
- Exceptions fängt Softwarefehler wie Bus Error etc. ab und gibt eine pas-
- sende Meldung aus. Es genügt, Exceptions zu importieren oder mit LINKALSO
- hinzuzulinken.
-
- 14.3.8) Execute
- ...............
-
- Execute ist immer dann zu verwenden, wenn man nicht genau weiß, in welcher
- Form (Modul oder Programm) etwas gestartet werden soll. Daher gibt es ein
- Execute im Lader, das Module startet, und ein kompatibles zum Linken, das
- Programme startet.
-
- 14.3.9) File
- ............
-
- Hoffnungslos veraltetes Modul zur Dateibehandlung.
-
- 14.3.10) FileBuffer
- ...................
-
- Ebenfalls veraltetes Modul zur Dateibehandlung mit zwischengeschaltetem
- Puffer.
-
- 14.3.11) Filename
- .................
-
- Zusammensetzen und Aufteilen von Dateinamen.
-
- 14.3.12) IO
- ...........
-
- IO implementiert Standardprozeduren zur Ein- und Ausgabe auf dem TOS-Bild-
- schirm. Die Benutzung in GEM-Programmen sollte vermieden werden, da dann
- unschön auf den Bildschirm geschrieben wird. Im Lader ist ein kompatibles
- Modul mit anderer Implementierung integriert, daß die Ausgabe in das CLI-
- Fenster von Chatwin umlenkt.
-
- 14.3.13) Kernel
- ...............
-
- Kernel stellt hauptsächlich die Speicherverwaltung, aber auch einige
- Hilfsprozeduren zur Verfügung.
-
- 14.3.14) Key
- ............
-
- War mal die Grundlage für die Zuweisung von Prozeduren zu Tastenkombi-
- nationen. Wird im Moment nicht benutzt.
-
- 14.3.15) MathCom
- ................
-
- Grundlegende Prozeduren für mathematische Funktionen. Entstammt LPR-Modula.
-
- 14.3.16) MathLib0
- .................
-
- Übliche mathematische Funktionen. Entstammt LPR-Modula.
-
- 14.3.17) Memory
- ...............
-
- Sehr schnelle Prozeduren zum Kopieren und Füllen von Speicher.
-
- 14.3.18) Modules
- ................
-
- Modules ist für das Nachladen von Modulen in den Ladern zuständig.
-
- 14.3.19) MVC
- ............
-
- MVC steht für Model View Controller. Es implementiert Viewer, deren Ausgabe
- vom Inhalt eines Models abhängen. WinView baut darauf auf. Theoretisch ist
- es aber nicht an Fenster gebunden, man könnte auch Pseudofenster auf einem
- TOS-Bildschirm darauf aufbauen.
-
- 14.3.20) NumStr
- ...............
-
- Umwandlung von Zahlen in Strings und umgekehrt.
-
- 14.3.21) Paths
- ..............
-
- Suchpfadverwaltung.
-
- 14.3.22) Strings
- ................
-
- Was man so braucht um mit Strings umzugehen.
-
- 14.3.23) Supervisor
- ...................
-
- Ein- und Ausschalten des Supervisormodus.
-
- 14.3.24) Sys
- ............
-
- Die Grundlage aller Programme. Enthält alle Standardfunktionen des Compi-
- lers sowie die Programminitialisierung.
-
- 14.3.25) Task
- .............
-
- Enthält den Mechanismus zur sauberen Terminierung von Programmen oder Pro-
- grammteilen. Normalerweise uninteressant für Anwender.
-
- 14.3.26) VA
- ...........
-
- VA enthält die Konstanten, die für das AV-Protokoll (Accessory <-> Venus)
- benötigt werden.
-
- 14.4) VDI-Module
- ----------------
-
- Das VDI implementiert alles zur Ausgabe auf beliebigen Geräten. Es ist mir
- nicht bekannt, ob es auch in TOS-Programmen benutzt werden darf.
-
- 14.4.1) VDI
- ...........
-
- Die grundlegenden Strukturen und Variablen zur Arbeit mit dem VDI.
-
- 14.4.2) VDIAttributes
- .....................
-
- Einstellen von Attributen für die Ausgabe.
-
- 14.4.3) VDIControl
- ..................
-
- Kontrollfunktionen des VDI. Es existiert eine zusätzliche Funktion zum
- Test, ob GDOS installiert ist.
-
- 14.4.4) VDIExcapes
- ..................
-
- Escaperoutinen des VDI.
-
- 14.4.5) VDIInput
- ................
-
- Eingaberoutinen des VDI.
-
- 14.4.6) VDIInquiry
- ..................
-
- Abfrageroutinen des VDI.
-
- 14.4.7) VDIOutput
- .................
-
- Ausgaberoutinen des VDI.
-
- 14.4.8) VDIRaster
- .................
-
- Rasterfunktionen des VDI. Zusätzlich gibt es hier ein paar Kopierroutinen
- zum Scrollen von Bildschirmausschnitten.
-
- 14.5) AES-Module
- ----------------
-
- Das AES implementiert das, was man so liebgewonnen hat auf dem Atari: Me-
- nüs, Fenster und und und. Bis auf Form.Alert führen diese Prozeduren in ei-
- nem TOS-Programm zum Absturz.
-
- 14.5.1) AES
- ...........
-
- Die grundlegenden Strukturen und Variablen zur Arbeit mit dem AES.
-
- 14.5.2) Appl
- ............
-
- Die Funktionen der Application Library.
-
- 14.5.3) Evnt
- ............
-
- Die Funktionen der Event Library.
-
- 14.5.4) Form
- ............
-
- Die Funktionen der Form Library. Form.Alert darf auch in TOS-Programmen
- verwendet werden.
-
- 14.5.5) Fsel
- ............
-
- Fileselectbox darstellen. Die neue Funktion mit Titel ist auch vorhanden.
-
- 14.5.6) Graf
- ............
-
- Die Funktionen der Graphics Library. Graf.Mouse wurde auf vier Prozeduren
- verteilt und Graf.Mkstate in Evnt verlegt.
-
- 14.5.7) Menu
- ............
-
- Die Funktionen der Menu Library.
-
- 14.5.8) Objc
- ............
-
- Die Funktionen der Object Library, stark erweitert um Funktionen zum Umgang
- mit den Objekten.
-
- 14.5.9) Rsrc
- ............
-
- Die Funktionen der Resource Library. Rsrc.Load ist auch in der Lage,
- selbständig zu suchen, wenn ein Resourcefile nicht gefunden wurde.
-
- 14.5.10) Wind
- .............
-
- Die Funktionen der Window Library.
-
- 14.6) Erweiterte AES-Module
- ---------------------------
-
- Zum einfacheren Umgang mit dem AES wurden folgende Module entwickelt:
-
- 14.6.1) Dialogs
- ...............
-
- Dialogs enthält alle Prozeduren, um ganz einfach eine Dialogbox darzu-
- stellen und den Dialog mit dem Anwender zu führen.
-
- 14.6.2) FontSelect
- ..................
-
- FontSelect bietet eine einfache Möglichkeit, mit einer Dialogbox den Benut-
- zer einen Font auswählen zu lassen.
-
- 14.6.3) GemApp
- ..............
-
- GemApp bildet die Grundlage zur Programmierung von GEM-Applikationen. Es
- muß unbedingt benutzt werden, wenn die erweiterten AES-Module verwendet
- werden.
-
- 14.6.4) GEMIO
- .............
-
- GEMIO ist das Pendant zu IO für TOS. Die Schnittstellen sind identisch, so
- daß man statt IO auch GEMIO linken kann.
-
- 14.6.5) Menus
- .............
-
- Menus automatisiert den Aufruf von Prozeduren über Menüpunkte oder Tasten-
- kombinationen. Die Tastenkombinationen werden aus dem Eintrag des Menüs ge-
- lesen und können dadurch von Benutzern individuell geändert werden!
-
- 14.6.6) TermWin
- ...............
-
- TermWin erweitert WinView derart, daß mit üblichen Schreibbefehlen (Write-
- String...) Text in einem Fenster ausgegeben werden kann. Desweiteren wird
- ein Event STRING eingeführt.
-
- 14.6.7) WindowDialog
- ....................
-
- WindowDialog verlegt einen Dialog in ein Fenster.
-
- 14.6.8) WinView
- ...............
-
- WinView ist die Grundlage für Fensterapplikationen. Fast das gesamte Hand-
- ling von Fensters ist automatisiert. Im einfachsten Fall muß man nur noch
- eine Redrawprozedur implementieren.
-
-
- 15) Tutorial
- ============
-
- Im nun folgenden Kapitel soll ein GEM-Programm entwickelt werden, daß eine
- Menüleiste hat, über einen Dialog in einem Fenster Eingaben ermöglicht und
- diese Eingaben graphisch in beliebig vielen Fenstern ausgeben kann. Eine
- neue Eingabe muß dann natürlich in allen Fenstern gezeichnet werden.
-
- 15.1) Die Resourcedatei
- -----------------------
-
- Die Resourcedatei wird mit einem Resource Construction Set erstellt. Die
- Resourcedatei für unser Projekt heißt GEMDEMO.RSC. Wer noch nie eine Re-
- sourcedatei erzeugt hat, sollte sich erstmal mit einem RCS GEMDEMO.RSCan-
- gucken und mal etwas damit spielen. Aber bitte nicht verändert abspeichern
- und mir dann eine Mail schicken, das Demo würde nicht funktionieren!
-
- 15.2) Der Rumpf
- ---------------
-
- [hbpt]
-
- MODULE Tutor1;
-
- IMPORT GemApp;
-
- VAR
- myApp : GemApp.Application;
-
- BEGIN
- NEW( myApp);
- myApp.Init; myApp.Run; myApp.Exit
- END Tutor1.
-
-
-
- Abb. ?? zeigt den prinzipiellen Aufbau einer Applikation: Definition ei-
- ner Variablen vom Typ Application, deren Initialisierung und Aufruf der
- daran gebundenen Prozeduren Init, Run und Exit. Init initialisiert das Pro-
- gramm. Dazu gehört z.B. die Anmeldung beim AES. Run implementiert die
- Event-Schleife, also warten auf Events vom AES und Aufruf von HandleEvent,
- das ebenfalls an Application gebunden ist. Exit meldet die Applikation dann
- wieder ab und sorgt auch für eine saubere Terminierung, z.B. Schließen
- evtl. offen gebliebener Fenster etc. Sollte jemand dieses Programm starten,
- wird er in die Eventschleife gelangen. Diese kann mit Control-Qverlassen
- werden, diese Taste wird immer ausgewertet.
-
- 15.3) Resourcedatei laden
- -------------------------
-
- Als nächstes müssen wir die Resourcedatei laden. Abb. ?? zeigt die Erweite-
- rungen.
-
- [hbpt]
-
- TYPE
- Application = POINTER TO ApplDesc;
- ApplDesc = RECORD(GemApp.ApplDesc)
- END;
-
- VAR
- myApp : Application;
-
- PROCEDURE (app : Application) Init;
- BEGIN
- app.Init^;
- Graf.ChangeMouse( Graf.ARROW);
- IF NOT Rsrc.Load("GEMDEMO.RSC") THEN
- app.Exit
- END;
- END Init;
-
-
-
- Zunächst wurde eine Erweiterung von GemApp.ApplDesc definiert, damit eine
- neue Prozedur Init daran gebunden werden kann. Diese muß unbedingt als er-
- stes die geerbte Prozedur Init aufrufen. Als nächstes wird der Mauszeiger
- als Pfeil dargstellt, da er beim Programmstart immer auf 'Biene' steht. Der
- Aufruf von Rsrc.Load bewirkt das Laden und evtl. auch Suchen der Resource-
- datei. Wenn der Benutzer in der Fileselectbox 'Abbruch' anklickt, gibt
- Rsrc.Load FALSE zurück und die Applikation wird terminiert. app.Exit wird
- nicht mehr verlassen, deshalb geht das. Wenn man das Programm startet, ver-
- hält es sich wie Tutor1, nur daß die Maus auf Pfeil umgeschaltet wird.
-
- 15.4) Die Menüzeile
- -------------------
-
- Nun wollen wir die Menüzeile anzeigen. Abb. ?? zeigt die Erweiterung von
- Init.
-
- [hbpt]
-
- TYPE
- Application = POINTER TO ApplDesc;
- ApplDesc = RECORD(GemApp.ApplDesc)
- END;
-
- PROCEDURE ShowInfo;
- VAR d : INTEGER;
- BEGIN
- d := Form.Alert(1, "[1][Tutor3 by Stephan Junker][Ok]");
- END ShowInfo;
-
- PROCEDURE Exit;
- BEGIN
- GemApp.exit := TRUE;
- END Exit;
-
- PROCEDURE (app : Application) Init;
- VAR menu : Menus.Menu;
- BEGIN
- [...]
- NEW(menu); menu.Init( Rsrc.GetAddr(MENU) );
- menu.Set( FILE, QUIT, Exit );
- menu.Set( DESK, INFO, ShowInfo );
- menu.Show;
- END Init;
-
-
-
- Zunächst alloziert man das Objekt menu und initialisiert es. Sodann emp-
- fiehlt es sich, eine Prozedur für den Menüpunkt QUIT anzumelden, damit man
- das Programm auch wieder verlassen kann. Dann kann man mit menu.Show die
- Menüzeile darstellen.
-
- Beim Start werden sie feststellen, daß sowohl beim Anklicken von 'Quit'
- als auch bei Drücken von Control-Qdas Programm verlassen wird. Wie funktio-
- niert das? Ganz einfach: Menus hat mit GemApp.StoreEventHandler eine Proze-
- dur angemeldet, die Events verarbeitet. Diese wird immer aufgerufen, wenn
- ein Ereignis vom AES gemeldet wird, und filtert die Ereignisse heraus, die
- für das Menü benötigt werden.
-
- 15.5) Ein Fenster öffnen
- ------------------------
-
- Beim Aufruf des Menüpunktes 'Ausgabefenster' soll nun ein Fenster geöffnet
- werden. Der Einfachheit halber wird es nur eine weiße Fläche darstellen.
- Abb. ?? zeigt die Änderungen.
-
-
-
-
- TYPE
- Viewer = POINTER TO ViewDesc;
- ViewDesc = RECORD(WinView.ViewDesc)
- END;
- MyModel = POINTER TO ModelDesc;
- ModelDesc = RECORD(MVC.ModelDesc)
- END;
-
- VAR
- myModel : MyModel;
- Station : INTEGER;
- Workout : VC.workout;
-
- PROCEDURE(v : Viewer) Redraw(x,y,w,h : INTEGER);
- VAR x2, y2 : INTEGER;
- BEGIN
- x2 := x+w-1; y2 := y+h-1;
- VC.VsClip( Station, TRUE, x, y, x2, y2);
- VO.VBar( Station, x, y, x2, y2 );
- END Redraw;
-
- PROCEDURE OpenOutput;
- VAR outWin : Viewer;
- BEGIN
- NEW( outWin); outWin.Init;
- outWin.model := myModel;
- outWin.SetTitle("Objektfenster");
- outWin.SetFullSize( 0, 19, Workout.MaxX - 1,
- Workout.MaxY - 20);
- outWin.Open;
- END OpenOutput;
-
- PROCEDURE (app : Application) Init;
- VAR Workin : VC.workin;
- menu : Menus.Menu;
- BEGIN
- [...]
- NEW( menu); menu.Init( Rsrc.GetAddr(MENU) );
- menu.Set( FILE, QUIT, Exit );
- menu.Set( DESK, INFO, ShowInfo );
- menu.Set( WORK, OUTPUT2, OpenOutput );
- menu.Show;
- Station := 1;
- Workin.Id := 1; Workin.LineType := 1;
- Workin.LineColor := 1; Workin.MarkType := 1;
- Workin.MarkColor := 1; Workin.Font := 1;
- Workin.TextColor := 1; Workin.FillStyle := 0;
- Workin.FillPat := 0; Workin.FillColor := 1;
- Workin.KoorType := 2;
- VC.VOpnvwk(Workin,Station,Workout);
- VA.VswrMode(Station,VA.REPLACE);
- VA.VsfPerimeter(Station,FALSE);
- NEW( myModel); myModel.Init;
- END Init;
-
- [hbpt]
-
-
- Zunächst wird die Prozedur OpenOutput für den Menüpunkt angemeldet. Es
- folgt die Öffnung einer virtuellen Workstation, die zum Zeichnen des Fen-
- sterinhaltes benötigt wird. Als letztes wird noch ein Model initialisiert,
- das später die Daten für die Ausgabefenster aufnimmt. OpenOutput muß ein
- Fenster initialisieren, das Model, Titel und maximale Größe festlegen. Dann
- kann es geöffnet werden. outWin ist tatsächlich eine lokale Variable! Wie
- das gehen soll? Ganz einfach, die Verwaltung der Fenster übernimmt WinView!
- Das einzige, was wir noch machen müssen, ist den Inhalt neuzeichnen. Dies
- übernimmt die Prozedur Redraw, die an einen Typ Viewer gebunden werden muß.
- Diese wird von WinView immer automatisch aufgerufen, wenn das AES eine Re-
- draw-Message verschickt. Die Ereignisse, die Fenster betreffen, werden wie-
- der durch einen EventHandler bearbeitet, der bei GemApp angemeldet wurde.
- Deshalb funktionieren auch Mover, Closer, Fuller etc. ohne das wir uns
- darum gekümmert haben!
-
- 15.6) Einen Dialog darstellen
- -----------------------------
-
- Nun wollen wir einen Dialog mit dem Benutzer in einem Fenster führen. Die
- Änderungen sind in Abb. ?? skizziert.
-
- [hbpt]
-
- VAR
- infoDial : WDial.Viewer;
-
- PROCEDURE ShowInfo;
- BEGIN
- infoDial.Open;
- END ShowInfo;
-
- PROCEDURE (app : Application) Init;
- BEGIN
- [...]
- NEW( infoDial);
- infoDial.InitDialog( Rsrc.GetAddr(BOX) , 0, TRUE);
- infoDial.SetWork(OK, NIL, { WDial.DESELECT,
- WDial.EXITONLY } );
- infoDial.SetWork(OUTPUT1, OpenOutput,
- { WDial.DESELECT, WDial.REDRAWOBJ } );
- infoDial.SetTitle("Information");
- END Init;
-
-
-
- Die Initialisierung eines Dialog erfolgt wieder in Init. Mit InitDialog
- wird der Viewer initialialisiert. Dabei wird ihm auch der zugehörige Ob-
- jektbaum mitgeteilt. Mit SetWork werden den Buttons im Dialog, die den Sta-
- tus Exit haben, Prozeduren zugewiesen, die beim Anklicken aufgerufen werden
- sollen. An dieser Stelle ist auch schon eine zweite Möglichkeit vorgesehen,
- ein Ausgabefenster zu öffnen. Geöffnet wird der Dialog über den Eintrag
- 'Information'.
-
- 15.7) Das fertige Programm
- --------------------------
-
- Was noch fehlt, ist eine Dialogbox zur Eingabe von Objekten und der Redraw
- dieser Objekte. Abb. ?? zeigt das komplette Programm.
-
-
-
- MODULE GemDemo;
-
-
- IMPORT S:=SYSTEM, GemApp, MVC, WinView, Evnt,
- Graf, VC:=VDIControl, VA:=VDIAttributes,
- VO:=VDIOutput, Menus, Rsrc, Form, Objc,
- WDial:=WindowDialog, NumStr;
-
-
- CONST
- BOX = 0; (* form/dialog *)
- OK = 4; (* BUTTON in tree BOX *)
- INPUT1 = 5; (* BUTTON in tree BOX *)
- OUTPUT1 = 6; (* BUTTON in tree BOX *)
-
- MENU = 1; (* menu *)
- DESK = 3; (* TITLE in tree MENU *)
- FILE = 4; (* TITLE in tree MENU *)
- WORK = 5; (* TITLE in tree MENU *)
- INFO = 8; (* STRING in tree MENU *)
- QUIT = 17; (* STRING in tree MENU *)
- INPUT2 = 19; (* STRING in tree MENU *)
- OUTPUT2 = 20; (* STRING in tree MENU *)
-
- INPUTBOX = 2; (* form/dialog *)
- CIRCLE = 2; (* BUTTON in tree INPUTBOX *)
- RECT = 3; (* BUTTON in tree INPUTBOX *)
- XPOS = 4; (* FTEXT in tree INPUTBOX *)
- YPOS = 5; (* FTEXT in tree INPUTBOX *)
- RADIUS = 6; (* FTEXT in tree INPUTBOX *)
- WIDTH = 7; (* FTEXT in tree INPUTBOX *)
- HEIGHT = 8; (* FTEXT in tree INPUTBOX *)
- DRAW = 9; (* BUTTON in tree INPUTBOX *)
-
-
-
- TYPE
- Viewer = POINTER TO ViewDesc;
- ViewDesc = RECORD(WinView.ViewDesc)
- END;
- Application = POINTER TO ApplDesc;
- ApplDesc = RECORD(GemApp.ApplDesc)
- END;
- Object = POINTER TO ObjDesc;
- ObjDesc = RECORD
- next : Object;
- x,y : INTEGER;
- END;
- Circle = POINTER TO CircleDesc;
- CircleDesc= RECORD(ObjDesc)
- r : INTEGER;
- END;
- Rect = POINTER TO RectDesc;
- RectDesc = RECORD(ObjDesc)
- w,h : INTEGER;
- END;
- MyModel = POINTER TO ModelDesc;
- ModelDesc = RECORD(MVC.ModelDesc)
- objects : Object;
- END;
-
-
- VAR myApp : Application;
- infoDial,inputDial : WDial.Dialog;
- myModel : MyModel;
- Station : INTEGER;
- Workout : VC.workout;
-
-
- PROCEDURE(o : Object) Draw(v : Viewer);
- BEGIN
- END Draw;
-
-
- PROCEDURE(c : Circle) Draw(v : Viewer);
- BEGIN
- VO.VArc( Station, v.x - SHORT( v.xOff) + c.x,
- v.y - SHORT( v.yOff) + c.y, c.r, 0, 3600 );
- END Draw;
-
-
- PROCEDURE(r : Rect) Draw(v : Viewer);
- VAR Edges : ARRAY 10 OF INTEGER;
- BEGIN
- Edges[0] := v.x - SHORT( v.xOff) + r.x;
- Edges[1] := v.y - SHORT( v.yOff) + r.y;
- Edges[2] := Edges[0];
- Edges[3] := Edges[1] + r.h - 1;
- Edges[4] := Edges[0] + r.w - 1;
- Edges[5] := Edges[3];
- Edges[6] := Edges[4];
- Edges[7] := Edges[1];
- Edges[8] := Edges[0];
- Edges[9] := Edges[1];
- VO.VPline( Station, 5, Edges);
- END Draw;
-
-
- PROCEDURE(v : Viewer) Redraw(x,y,w,h : INTEGER);
- VAR x2, y2 : INTEGER;
- obj : Object;
- BEGIN
- x2 := x+w-1; y2 := y+h-1;
- VC.VsClip( Station, TRUE, x, y, x2, y2);
- VO.VBar( Station, x, y, x2, y2 );
- obj := myModel.objects;
- WHILE obj # NIL DO
- obj.Draw(v); obj := obj.next;
- END;
- END Redraw;
-
-
- PROCEDURE(m : MyModel) Init;
- BEGIN
- m.objects := NIL; m.Init^;
- END Init;
-
-
- PROCEDURE ShowInfo;
- BEGIN
- infoDial.Open;
- END ShowInfo;
-
-
- PROCEDURE Exit;
- BEGIN
- GemApp.exit := TRUE; (* die saubere Methode *)
- END Exit;
-
-
- PROCEDURE OpenInput;
- BEGIN
- inputDial.Open;
- END OpenInput;
-
-
- PROCEDURE SetDWH(v : Viewer);
- VAR obj : Object; maxX, maxY, dw, dh : INTEGER;
- BEGIN
- obj := myModel.objects;
- dw := SHORT(v.dw); dh := SHORT(v.dh);
- WHILE obj # NIL DO
- IF obj IS Rect THEN
- maxX := obj.x + obj(Rect).w;
- maxY := obj.y + obj(Rect).h;
- ELSE
- maxX := obj.x + obj(Circle).r;
- maxY := obj.y + obj(Circle).r;
- END;
- IF maxX > dw THEN dw := maxX END;
- IF maxY > dh THEN dh := maxY END;
- obj := obj.next;
- END;
- IF dw # v.dw THEN v.dw := dw; v.HSlider END;
- IF dh # v.dh THEN v.dh := dh; v.VSlider END;
- END SetDWH;
-
-
- PROCEDURE OpenOutput;
- VAR outWin : Viewer;
- BEGIN
- NEW( outWin); outWin.Init;
- outWin.model := myModel; SetDWH(outWin);
- outWin.SetTitle("Objektfenster");
- outWin.SetFullSize( 0, 19, Workout.MaxX - 1,
- Workout.MaxY - 20);
- outWin.Open;
- END OpenOutput;
-
-
- PROCEDURE(v : Viewer) Update( aspect : LONGINT);
- BEGIN
- v.Update^( aspect); SetDWH(v);
- END Update;
-
- (*$T- wegen NEW( obj(Rect) ) bzw. NEW( obj(Circle) ),
- denn Typcheck geht nur wenn das Objekt schon
- alloziert ist ... *)
-
- PROCEDURE EnterNewObject;
- VAR x,y : INTEGER; obj : Object;
- tep : Objc.tedinfoptr;
- BEGIN
- IF Objc.SELECTED IN
- Objc.GetState( inputDial.objTree, RECT) THEN
- NEW( obj(Rect) );
- tep := Objc.GetSpec( inputDial.objTree, WIDTH);
- obj(Rect).w := NumStr.ToInt( 10, tep.Text^);
- tep := Objc.GetSpec( inputDial.objTree, HEIGHT);
- obj(Rect).h := NumStr.ToInt( 10, tep.Text^);
- ELSE
- NEW( obj(Circle) );
- tep := Objc.GetSpec( inputDial.objTree, RADIUS);
- obj(Circle).r := NumStr.ToInt( 10, tep.Text^);
- END;
- tep := Objc.GetSpec( inputDial.objTree, XPOS);
- obj.x := NumStr.ToInt( 10, tep.Text^);
- tep := Objc.GetSpec( inputDial.objTree, YPOS);
- obj.y := NumStr.ToInt( 10, tep.Text^);
- obj.next := myModel.objects;
- myModel.objects := obj;
- myModel.Changed( 0);
- END EnterNewObject;
-
- (*$T= *)
-
- PROCEDURE EnableCircle;
- BEGIN
- inputDial.SetCursor( XPOS);
- Objc.SetFlags( inputDial.objTree, WIDTH,
- {Objc.EDITABLE, Objc.HIDDEN} );
- inputDial.RedrawObj( WIDTH);
- Objc.SetFlags( inputDial.objTree, HEIGHT,
- {Objc.EDITABLE, Objc.HIDDEN} );
- inputDial.RedrawObj( HEIGHT);
- Objc.SetFlags( inputDial.objTree, RADIUS,
- {Objc.EDITABLE} );
- inputDial.RedrawObj( RADIUS);
- END EnableCircle;
-
-
- PROCEDURE EnableRect;
- BEGIN
- inputDial.SetCursor( XPOS);
- Objc.SetFlags( inputDial.objTree, RADIUS,
- {Objc.EDITABLE, Objc.HIDDEN} );
- inputDial.RedrawObj( RADIUS);
- Objc.SetFlags( inputDial.objTree, WIDTH,
- {Objc.EDITABLE} );
- inputDial.RedrawObj( WIDTH);
- Objc.SetFlags( inputDial.objTree, HEIGHT,
- {Objc.EDITABLE} );
- inputDial.RedrawObj( HEIGHT);
- END EnableRect;
-
-
- PROCEDURE(app: Application) Init;
- VAR menu : Menus.Menu;
- Workin : VC.workin;
- BEGIN
- app.Init^; (* must come first! *)
- Graf.ChangeMouse( Graf.ARROW);
- IF NOT Rsrc.Load("GEMDEMO.RSC") THEN
- app.Exit
- END;
- NEW(menu); menu.Init( Rsrc.GetAddr(MENU) );
- menu.Set( FILE, QUIT, Exit );
- menu.Set( DESK, INFO, ShowInfo );
- menu.Set( WORK, OUTPUT2, OpenOutput );
- menu.Set( WORK, INPUT2, OpenInput );
- menu.Show;
- Station := 1;
- Workin.Id := 1; Workin.LineType := 1;
- Workin.LineColor := 1; Workin.MarkType := 1;
- Workin.MarkColor := 1; Workin.Font := 1;
- Workin.TextColor := 1; Workin.FillStyle := 0;
- Workin.FillPat := 0; Workin.FillColor := 1;
- Workin.KoorType := 2;
- VC.VOpnvwk(Workin,Station,Workout);
- VA.VswrMode(Station,VA.REPLACE);
- VA.VsfPerimeter(Station,FALSE);
- NEW( myModel); myModel.Init;
- NEW( infoDial);
- infoDial.InitDialog( Rsrc.GetAddr(BOX) , 0, TRUE);
- infoDial.SetWork(OK, NIL, { WDial.DESELECT,
- WDial.EXITONLY } );
- infoDial.SetWork(INPUT1, OpenInput,
- { WDial.DESELECT, WDial.REDRAWOBJ } );
- infoDial.SetWork(OUTPUT1, OpenOutput,
- { WDial.DESELECT, WDial.REDRAWOBJ } );
- infoDial.SetTitle("Information");
- NEW( inputDial);
- inputDial.InitDialog( Rsrc.GetAddr(INPUTBOX),
- XPOS, TRUE);
- inputDial.SetWork(DRAW, EnterNewObject,
- { WDial.DESELECT, WDial.REDRAWOBJ } );
- inputDial.SetWork(CIRCLE, EnableCircle, {} );
- inputDial.SetWork(RECT, EnableRect, {} );
- inputDial.SetTitle("Neues Objekt");
- inputDial.SetText( XPOS, "");
- inputDial.SetText( YPOS, "");
- inputDial.SetText( WIDTH, "");
- inputDial.SetText( HEIGHT, "");
- inputDial.SetText( RADIUS, "");
- Objc.SetState( inputDial.objTree, RECT,
- {Objc.SELECTED} );
- END Init;
-
-
- BEGIN
- NEW(myApp);
- myApp.Init; myApp.Run; myApp.Exit
- END GemDemo.
-
-
- [hbpt]
-
-
- Was hat sich getan? Nun, der Typ ModelDesc nimmt jetzt die Objekte auf,
- die dargestellt werden sollen. Redraw wurde erweitert, damit es die Objekte
- zeichnen kann. Eine weitere Dialogbox, mit der die Objekte vom Anwender
- eingegeben werden, wurde erzeugt. EnterNewObject liest die Eingaben aus
- dieser Box und erzeugt daraus ein neues Objekt. Mit EnableCircle bzw. Ena-
- bleRect wird die Darstellung der Box geändert, je nachdem ob der Benutzer
- Kreis oder Rechteck verlangt. SetDWH paßt die Größe der Zeichnung (also
- dessen was insgesamt dargestellt werden soll) immer an die Größe der einge-
- gebenen Objekte an. So kann man auch Zeichnungen darstellen, die größer als
- ein Fenster sind. Die Slider, Pfeile etc. werden alle automatisch durch
- WinView bedient. Man kann praktisch unbegrenzt Fenster öffnen (zumindest
- wenn man Winx oder MultiTOS installiert hat), und bei Eingabe eines neuen
- Objektes werden alle auf den neuesten Stand gebracht. Aber jedes Fenster
- kann natürlich einen anderen Ausschnitt darstellen.
-
- 15.8) Zusammenfassung
- ---------------------
-
- Dieses Kapitel sollte einige Möglichkeiten von Oberon und der GEM-Module
- zeigen. Das Ergebnis war ein 300 Zeilen langes Programm, daß hoffentlich
- einen guten Eindruck hinterlassen hat.
-
-
- 16) Anhang
- ==========
-
- 16.1) Literatur
- ---------------
-
- N. Wirth, J. Gutknecht: <Project Oberon: The design of an Operating System
- and Compiler,> Addison-Wesley (1992), ISBN 0-201-54428-8.
-
- M. Reiser: <The Oberon System: Usesr Guide and Programmer's Manual> Addi-
- son-Wesley (1991), ISBN 0-201-54422-9.
-
- M. Reiser, N. Wirth: <Programming in Oberon: Steps beyond Pascal and
- Modula>, Addison-Wesley (1992)
-
- 16.2) Danksagungen
- ------------------
-
- Dank an Frank Storm, der mich darauf gebracht hat, statt einem Modula- ei-
- nen Oberon-Compiler zu schreiben und anfangs auch die E-Mail erledigt hat.
-
- Dank an den Chefbetatester Dirk Theisen für den Browser und sonstige Unter-
- stützung.
-
- Dank an alle, die über Fehler berichten und neue Module implementieren.
-
- Dank an Christian Strunk für seine TeX-Implementierung.
-
- Dank an Roman Hodek für TeX2TXT, mit dem diese Anleitung in einen ganz pas-
- sablen Asciitext konvertiert werden konnte.
-
- Ach ja, dann sollte ich wohl auch noch Niklaus Wirth und seinem Team dan-
- ken, daß er Oberon erdacht hat und die Sourcen frei weitergibt.