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