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