STJ-OBERON-2 * * Eine Oberon-2 Implementation für Atari ST/STe

Werbung
*STJ-OBERON-2 *
*Eine Oberon-2 Implementation
f•r Atari ST/STe/TT *
von
Stephan Junker
28. November 1993
Inhaltsverzeichnis
==================
1) Einleitung
1.1) Stand der Entwicklung
1.2) Geplante Entwicklung
1.3) Benutzungsbedingungen
1.4) Fehlermeldungen
1.5) Kontakt
2) Von Modula-2 nach Oberon-2
2.1) Streichungen
2.1.1) Datentypen
2.1.2) Module und Import-/Exportregeln
2.1.3) Anweisungen
2.1.4) Low-Level Anweisungen
2.2) Neue Features
2.2.1) Typerweiterung
2.2.2) Typgebundene Prozeduren
2.2.3) Typinklusion
2.3) Sonstige Unterschiede
3) Allgemeine Erl„uterungen
3.1) Suchpfade
3.2) Dateien
3.3) Einstellung der Shell
4) Installation
4.1) Start
5) Der Compiler
5.1) Aufruf, Parameter
5.2) Environmentvariablen
5.3) Optionen im Quelltext
5.4) Ausgabe
5.5) Vordefinierte Prozeduren
5.6) Unterschiede zum Standard-Oberon-2
5.7) Bekannte Fehler
6) Der Assembler
6.1) Symbolkonventionen
6.1.1) Formelausdr•cke
6.2) Pseudobefehle
6.2.1) SET und EQU
6.2.2) CHARSET
6.2.3) CPU
6.2.4) SUPMODE
6.2.5) SEGMENT
6.2.6) DC,DS
6.2.7) ALIGN
6.2.8) MACRO
6.2.9) IRP
6.2.10) REPT
6.2.11) Bedingte Assemblierung
6.2.12) Lokale Label
6.3) Hochsprachenelemente
6.3.1) IF cond THEN ... ELSIF ... ELSE ... END
6.3.2) REPEAT ... UNTIL cond
6.3.3) LOOP ... END
6.3.4) EXIT [(Zahl)]
6.4) Diverses
6.4.1) INCLUDE
6.4.2) MESSAGE, WARNING, ERROR und FATAL
6.5) Zugriff auf Oberon-Bezeichner
7) Der Linker
7.1) Aufruf, Parameter
7.2) Environmentvariablen
8) Die Lader
8.1) Aufruf, Parameter
8.2) Ausgabe
9) Das Make-Utility
9.1) Aufruf, Parameter
9.2) Environmentvariablen
9.3) Hinweise
10) Der Scanner
10.1) Aufruf, Parameter
10.2) Environmentvariablen
11) Debugging
11.1) DB
11.2) Bugaboo
11.3) Tips
12) Utilities
12.1) Der Browser
12.2) Inline-Zeilen erzeugen
13) Speicherverwaltung
13.1) Benutzung in Programmen
13.2) Implementierung
14) Die Bibliotheken
14.1) Betriebssystem
14.1.1) BIOS
14.1.2) GEMDOS
14.1.3) MiNT
14.1.4) XBIOS
14.2) Abstrakte Datenstrukturen
14.2.1) BinTree
14.2.2) CDCL
14.2.3) DCL
14.2.4) FIFO
14.2.5) LRU
14.2.6) Stack
14.3) Standardmodule
14.3.1) Buffers
14.3.2) CommandLine
14.3.3) Cookie
14.3.4) Datum
14.3.5) Environment
14.3.6) Error
14.3.7) Exceptions
14.3.8) Execute
14.3.9) File
14.3.10) FileBuffer
14.3.11) Filename
14.3.12) IO
14.3.13) Kernel
14.3.14) Key
14.3.15) MathCom
14.3.16) MathLib0
14.3.17) Memory
14.3.18) Modules
14.3.19) MVC
14.3.20) NumStr
14.3.21) Paths
14.3.22) Strings
14.3.23) Supervisor
14.3.24) Sys
14.3.25) Task
14.3.26) VA
14.4) VDI-Module
14.4.1) VDI
14.4.2) VDIAttributes
14.4.3) VDIControl
14.4.4) VDIExcapes
14.4.5) VDIInput
14.4.6) VDIInquiry
14.4.7) VDIOutput
14.4.8) VDIRaster
14.5) AES-Module
14.5.1) AES
14.5.2) Appl
14.5.3) Evnt
14.5.4) Form
14.5.5) Fsel
14.5.6) Graf
14.5.7) Menu
14.5.8) Objc
14.5.9) Rsrc
14.5.10) Wind
14.6) Erweiterte AES-Module
14.6.1) Dialogs
14.6.2) FontSelect
14.6.3) GemApp
14.6.4) GEMIO
14.6.5) Menus
14.6.6) TermWin
14.6.7) WindowDialog
14.6.8) WinView
15) Tutorial
15.1) Die Resourcedatei
15.2) Der Rumpf
15.3) Resourcedatei laden
15.4) Die Men•zeile
15.5) Ein Fenster ”ffnen
15.6) Einen Dialog darstellen
15.7) Das fertige Programm
15.8) Zusammenfassung
16) Anhang
16.1) Literatur
16.2) Danksagungen
1) Einleitung
=============
Die Entstehung dieses Oberon-Systems begann kurz vor Weihnachten
als
Frank Storm mir die Quelltexte zum Oberon-1 Compiler von Niklaus
in
'92,
Wirth
die Hand drckte. Zun„chst mužte ich den in Oberon geschriebenen
Compiler
in Modula umschreiben und den Codegenerator auf 68000 „ndern. Der
n„chste
Schritt war dann nat•rlich, das ganze wieder in Oberon umzuschreiben.
Dies
war bis M„rz '93 geschafft, seitdem programmiere ich nur noch in
Oberon.
Inzwischen sind etliche Monate vergangen, in denen ich fleižig Fehler
behoben und Erweiterungen eingebaut habe. Trotzdem wird noch einige Zeit
vergehen, bis diese Software den Betateststatus verliert.
1.1) Stand der Entwicklung
-------------------------Der Kern einer Programmiersprache ist nat•rlich der Compiler. Dieser
wird
erg„nzt durch Linker, Lader, Make und Scanner. Zus„tzlich gibt es noch
einige Utilities. Alles wird als Objektmodule ausgeliefert und vom
Installationsprogramm zu ausf•hrbaren Programmen gelinkt.
Aber erst durch
umfangreiche Libraries wird eine Programmiersprache benutzbar. Die meisten
Module
sind von mir im Laufe von mehreren Jahren programmiert worden. Einige
sind
auch von anderen Autoren, und weitere Implementationen sind nat•rlich
erw•nscht.
Der Compiler hat bereits starke Erweiterungen gegen•ber dem von Wirth
erfahren. Dies ist zwar unsch”n, weil dadurch wieder Inkompatibilit„ten
zu
anderen Compilern entstehen, aber sie erleichtern die Programmierung.
Wenn
man portable Programme schreiben m”chte, muž man auf diese
Erweiterungen
verzichten.
1.2) Geplante Entwicklung
------------------------Zun„chst steht die Entwicklung einer Load-Time-Linking
Entwicklungsumgebung
mit Chatwin auf dem Plan. Dann fehlt noch ein Source-Level-Debugger.
Da
werde ich mich irgenwann mal drangeben. Die Codequalit„t k”nnte auch
noch
verbessert werden, dazu geh”rt auch 68030- und FPU-Unterst•tzung.
Ansonsten
werden natrlich st„ndig noch Fehler
verbessert.
behoben
und
Bibliotheksmodule
1.3) Benutzungsbedingungen
-------------------------STJ-Oberon-2 ist Shareware. Die ”ffentliche Version darf in Mailboxen
hochgeladen und auf PD-Disketten bis 5 DM pro Diskette vertrieben werden.
Wenn
man dauerhaft damit arbeiten m”chte, muž man den Sharewarebeitrag von 50
DM
entrichten. Daf•r bekommt man die neueste Version auf Diskette
zugeschickt
(also Adresse nicht vergessen!). Diese enth„lt eine private Version,
die
nicht weitergegeben werden darf. Darauf ist zus„tzlich diese Anleitung
als
DVI-File sowie der fehlende optimierende Linker. Auf Wunsch kann ich
die
Anleitung auch in eine Postscriptdatei umwandeln. M”chte jemand eine
gedruckte Anleitung (Laserdrucker) mit Ringbindung, kostet dies 20 DM
extra.
Wer am System mitarbeitet oder mitgearbeitet hat,
individuellen Rabatt erhalten. Einfach mal anfragen.
kann einen
1.4) Fehlermeldungen
-------------------Das ganze System ist noch in der Entwicklungs- und Betatestphase. Ich
weiž,
daž es noch einige Macken hat. Ich bem•he mich, sie noch alle zu
entfernen.
Ich bernehme keine Garantie fr die Funktionsf„higkeit dieses
Programms
und hafte nicht fr Sch„den, die dieses Programm verursacht. Falls
Fehler
entdeckt werden, sollte man mich m”glichst genau dar•ber informieren.
1.5) Kontakt
-----------Stephan Junker
Heuvel 1A
NL-6291 CP Vaals
E-Mail, MausNet : Stephan Junker @ AC2
Sparkasse Aachen
Kontonummer : 16013351
Bankleitzahl: 390 500 00
2) Von Modula-2 nach Oberon-2
=============================
Fr diejenigen, die Modula kennen und evtl. umsteigen m”chten, werde
ich
hier kurz die Unterschiede zwischen Modula-2 und Oberon-2 auflisten.
Es
soll keineswegs eine Sprachbeschreibung ersetzen, sondern nur einen
Eindruck 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
Wichtigste zu konzentrieren und damit einen kleinen, schnellen Compiler zu
realisieren. 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
Speicherverwaltung mit Garbage Collector im Wege stand. Ihre
Funktionalit„t
wurde durch erweiterbare Typen erhalten[1].
_Opake Typen_ wurden •berfl•ssig, da man Records nicht mehr komplett
exportieren muž. Die Auswahl einzelner Feldelemente ist wesentlich
flexibler.
_Aufz„hlungstypen_ standen der Erweiterung •ber Modulgrenzen hinweg
im
Wege. Aužerdem f•hrte ein Import des Typbezeichners zum impliziten
Import
aller assoziierten Konstantenbezeichner.
_Unterbereichstypen_ hatten nicht den Nutzen, der die dafr n”tige
zus„tzliche Komplexit„t des Compilers rechtfertigt.
_Mengen_ wurden zu einem einzigen Typ reduziert: SET. Diese Menge
beinhaltet alle Zahlen von 0 bis zu einem implementationsabh„ngigen
Maximum[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
damit 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]
sind
man beachte, daž damit keine vorzeichenlosen Vergleiche m”glich
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
vorangestelltem Modulbezeichner auf die exportierten Bezeichner zugreifen. Um
die
Tipparbeit ein wenig zu reduzieren, ist es m”glich, den Import
umzubenennen. Daf•r schreibt man beim Import 'Abk:=Abkuerzung', z.B.
'WDial:=WindowDialog'.
Das _Hauptmodul_ als solches gibt es nicht mehr. Alle Module sind
gleichberechtigt, d.h. daž auch alle Module linkf„hig sind.
_Definitionsmodule_ sind fr den Compiler nicht mehr n”tig, aber man
sollte
sie nat•rlich f•r den Programmierer erzeugen. Daf•r ist der Browser
vorgesehen. Der Export geschieht jetzt, indem man hinter einem Bezeichner
einen
Stern f•r normalen oder ein Minuszeichen (bei Variablen und
Feldelementen)
f•r Read-Only Export angibt.
2.1.3) Anweisungen
..................
Die _WITH-Anweisung_ wurde eliminiert,
be-
da der qualifizierte Zugriff zu
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
eliminiert.
2.2) Neue Features
-----------------2.2.1) Typerweiterung
.....................
Es ist m”glich, einen bestehenden Recordtyp zu erweitern.
Beispiel: Wenn Typ Point so
Point = RECORD x,y : INTEGER END
definiert ist, kann man ihn so
Rect = RECORD(Point)
w,h : INTEGER END
erweitern. Typ Rect hat dann die Elemente x,y,w,h. Dann ist es
m”glich,
Prozeduren zu definieren, die einen Typ Point als Parameter erwarten,
und
diesen einen Typ Rect zu •bergeben. Analog gilt dies f•r Zeiger auf
solche
Typen. Mit einem Typeguard der Form var(typ) kann man zur Compilezeit
den
Typen festlegen. Zur Laufzeit wird dann •berpr•ft, ob die Variable var
tats„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
WITHStatement:
Typeguards
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 *)
leistet
das
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
Bezeichner implizit •bergeben, sondern explizit angegeben. Eine solche
Prozedur 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
Bereichs. Daher ergibt sich folgende Hierarchie:
LONGREAL > REAL > LONGINT > INTEGER > SHORTINT
Das bedeutet, daž ein Wert eines untergeordneten Typs einem
h”heren zugewiesen werden kann.
2.3) Sonstige Unterschiede
--------------------------
_Prozedurtypen_ werden mit Dummynamen f•r die Parameter angegeben.
_Globale Variablendeklarationen_ m•ssen immer vor der ersten Prozedur
erfolgen.
3) Allgemeine Erl„uterungen
===========================
3.1) Suchpfade
-------------Suchpfade sind solche Pfade, in denen nach Dateien gesucht wird. Viele
der
Systemprogramme ben”tigen Suchpfade, aber alle bauen auf einem Modul
namens
Paths auf.
Daher verlangen alle Programme den gleichen Aufbau
der
Suchpfade. Definiert werden sie mit einer Environmentvariablen.
Mehrere
Suchpfade m•ssen mit Komma oder Semikolon getrennt werden. Ein Backslash
am
Ende ist m”glich, aber nicht n”tig. Eine kleine M”glichkeit f•r
Wildcards
ist vorgesehen: Der letzte Order einer Suchpfaddefinition darf ein
'*'
sein, so daž alle Ordner in diesem Directory durchsucht werden. Die
Suche
beginnt immer mit dem zuletzt angegebenen Pfad.
Beispiel: MODPATH=E:\OBERON\GEM,E:\OBERON\STD\
Damit k”nnen alle Dateien gefunden werden, die den Mustern
E:\OBERON\GEM\*.*und E:\OBERON\STD\*.*gen•gen.
Beispiel: MODPATH=E:\OBERON\LIB\*
Damit k”nnen alle Dateien gefunden werden, die den Mustern
E:\OBERON\LIB\*\*.*gen•gen.
Wenn im folgenden also von 'Suchpfaden' die Rede ist, sind
Environmentvariable mit obigem Inhalt gemeint.
Eine Besonderheit der Suchpfade m”chte ich hier schon erw„hnen:
Eine
sinnvolle Einstellung ist es, nur MODPATH zu definieren. Dann wird
immer
dort gesucht und Ausgaben des Compilers werden bei den Sourcen
gespeichert.
In dieser Form werden die Dateien auch ver”ffentlicht. Es ist aber
m”glich,
die verschiedenen Dateitypen in getrennten Ordnern zu bewahren. Dazu
muž
man f•r jeden Dateityp einen Suchpfad definieren und die Ausgaben des
Compilers 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.
eines
Moduls auf.
Diese nehmen den
Code
3) Die Symboldateien mit der Extension SYM. Diese enthalten
Informationen
•ber exportierte Bezeichner.
4) Die Infodateien mit der Extension INF. Diese enthalten zus„tzliche
Informationen zu Modulen. Momentan sind das zum Beispiel ein
Programmname und Optimierungsinformationen. Sp„ter sollen die Infodateien
dann
auch Informationen f•r den Source Level Debugger aufnehmen.
5) Die Fehlerdateien mit der Extension ERR. Darin werden Fehler, die
der
Compiler findet, in einem frei w„hlbaren Format notiert.
3.3) Einstellung der Shell
-------------------------DIe Shell, mit der man arbeitet, sollte man mittels Batchfile beim
Starten
schon vern•nftig konfigurieren. Dies ist ein Beispiel-Setup f•r Chatwin:
alias make e:\oberon\Make.TTP $*
alias opt e:\oberon\OPTIMIZE.TTP $*
alias scan e:\oberon\SCAN.TTP $*
alias lt e:\oberon\LOAD.TTP $*
alias lg e:\oberon\LOAD.PRG $*
alias browse e:\oberon\browse.ttp $*
env OC=e:\oberon\compile.ttp
env MODPATH=E:\OBERON\LIB\*
env LINKALSO=Exceptio
Desweiteren empfiehlt es sich, f•r jedes Projekt eine Batchdatei
einzurichten, in der Pfade, Namen, Extension etc. definiert werden. Hier
ist
mal ein Beispiel, daž ich f•r das Installationsprogramm verwende:
env MODPATH=E:\OBERON\LIB\*,E:\OBERON\INSTALL\
env PRGEXT=PRG
env PRGPATH=E:\OBERON\
env LINKALSO=Exceptio
dellist *
addlist e:/oberon/install/install.mod
addlist e:/oberon/install/linker.mod
addlist e:/oberon/install/syminld.mod
4) Installation
===============
Das Installationsprogramm INSTALL.PRG ist das einzig lauff„hige
Programm
in der Distribution. Es erzeugt alle Programme, die f•r die Arbeit mit
STJOberon-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
optimiert[5] werden sollen. Die Symboltabelle kostet nur unn”tig Platz,
also
verzichten sie lieber darauf.
Als letztes k”nnen sie einen Zielpfad f•r die Programme
Dieser
wird anfangs auf den Pfad gesetzt, in dem auch das
Installationsprogramm
steht.
angeben.
Wenn sie nun den Knopf 'Installieren' anw„hlen, verschwindet die
Dialogbox 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
Ordnerstruktur nicht verloren ging, m•ssen die Module auch gefunden werden.
Hinweis:
des
Im Prinzip ist der Linker auch in der Lage,
die T„tigkeit
Installationsprogramms durchzuf•hren. Lediglich die Lader und Oberon
k”nnen
nicht vom normalen Linker gelinkt werden.
--------------[4]
denn Oberon gibt's noch nicht
[5]
Die Optimierung funktioniert leider noch nicht
5) Der Compiler
===============
Der Compiler des Oberon-Systems (COMPILE.OBJ/TTP) entstand aus dem
Oberon-1 Compiler von Niklaus Wirth. Er wurde unter anderem um einen
Makroassembler 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
Programmlauf 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
globale Variable eines anderen Moduls getan. Warnungen werden
normalerweise unterdr•ckt.
-i: Schaltet den Indexcheck aus, da er defaultm„žig eingeschaltet ist.
Indexcheck bewirkt eine šberpr•fung der Arraygrenzen von Indizes
zur
Laufzeit und ist mit einer geringfgigen Verl„ngerung des Codes
verbunden. Ein falscher Index bewirkt eine CHK-Exception.
-t: Schaltet den Typcheck aus, der ebenfalls normalerweise
eingeschaltet
ist. Wenn er eingeschaltet ist, wird bei jedem Typeguard gepr•ft, ob
es
sich auch um den korrekten Recordtyp handelt. Ein falscher Typ
bewirkt
die Ausgabe einer Fehlermeldung und anschlieženden Programmabbruch.
-a: Schaltet den Arithmetikcheck aus, der defaultm„žig eingeschaltet
ist.
Dieser Check soll šber- und Unterlauf von Realzahlen •berpr•fen,
ist
aber noch nicht implementiert.
-s|<pos>|: Diese Option bewirkt, daž der Compiler bei Erreichen der
Position 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
gesetzt wird.
5.2) Environmentvariablen
------------------------Der Compiler wertet auch einige Environmentvariablen aus. Sie m•ssen
immer
grožgeschrieben und von einem = gefolgt sein. Gesetzt werden sie in
der
Shell und jedem Programm bergeben, daž von dieser Shell aufgerufen wird.
Es werden folgende Variablen ausgewertet:
MODPATH: Gibt die Suchpfade (Kap.??) an, in denen nach dem zu
•bersetzenden
Modul gesucht wird.
SYMPATH: Gibt die Suchpfade an, in denen nach den Symboldateien der
importierten Module gesucht wird. Ist SYMPATH definiert, wird ein evtl.
erzeugtes SYM-File in den letzten Pfad geschrieben, der bei SYMPATH
angegeben ist. Ist SYMPATH nicht definiert, werden die Suchpfade von
MODPATH •bernommen und das SYM-File wird in denselben Ordner
geschrieben,
in dem die Source war.
Anmerkung: Eine Symboldatei wird nur erzeugt,
nicht
existiert oder sich ge„ndert hat.
wenn sie
noch
OBJPATH: Die erzeugte Objektdatei wird in den letzten Pfad geschrieben,
der
mit dieser Variablen definiert wird. Ist OBJPATH nicht definiert,
werden die Suchpfade von MODPATH •bernommen und das OBJ-File wird in
denselben 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,
werden die Suchpfade von MODPATH •bernommen und das INF-File wird in
denselben 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
eingeschaltet ist.
TYPCHK: Wie INXCHK, jedoch f•r den Typcheck.
ARICHK: Wie INXCHK, jedoch f•r den Arithmetikcheck.
ERRDIST: Der Inhalt der Variablen muž eine Dezimalzahl sein, die den
Abstand 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
innerhalb 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
sollen. Normalerweise sind dies 100 Fehler.
ERRFORM: Der Inhalt dieser Variablen ist ein String. Damit ist es
m”glich,
das Format einer Fehlermeldung einzustellen. Prinzipiell kann man
sich
den Dateinamen mit \d, die Zeilennummer mit \z, die Spalte mit
\s
(beide z„hlend ab 1), die absolute Position mit \p und nat•rlich
die
Fehlermeldung selbst mit \f ausgeben lassen. Diese Teile werden dort
in
der Zeile eingef•gt, wo die K•rzel mit '\' stehen. Der
standardm„žig
gesetzte String lautet:
"Error \d \z : \s \f"
Damit sieht eine Fehlermeldung so aus:
Error DATEI ZEILE : SPALTE FEHLERMELDUNG
WARNOUT: Werte ON/OFF sind erlaubt. Schaltet die Ausgabe von Warnungen
ein
oder aus. Normalerweise werden keine Warnungen ausgegeben.
5.3) Optionen im Quelltext
-------------------------F•r die Angabe von Optionen in Quelltexten ist die •bliche
Konstruktion
(*$...*) reserviert. Solche Optionen haben die h”chste Priorit„t.
kann
Es
immer nur eine Option angegeben werden. Zwischen $ und dem
Kennbuchstaben
darf kein Leerzeichen sein. Hinter den Parametern darf noch beliebiger
Kommentar 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
Zustand wieder her.
Diese Option ist nur im Oberon-Teil verf•gbar.
(*$T?*): Wie I f•r den Typcheck. Eingeschalteter Typcheck bewirkt eine
Typ•berpr•fung bei jedem Zugriff auf den gesamten Record. Diese
Option
ist nur im Oberon-Teil verf•gbar.
(*$A?*): Wie I f•r den Arithmetikcheck. Wird im Moment noch nicht
unterst•tzt. Die Routinen im Modul System (Grundrechenarten) melden
arithmetische Fehler, auch ohne diesen Check.
Diese Option ist nur im Oberon-Teil verf•gbar.
(*$N?*) Diesmal gibt das Fragezeichen einen Dateinamen an. Unter diesem
Namen wird sp„ter das gelinkte Programm gespeichert. Vor dem Namen
d•rfen
ausnahmsweise auch Leerzeichen stehen. Wird der Name mit Pfad
angegeben, wird das Programm dort gespeichert, ansonsten im Pfad PRGPATH
oder
beim Modul. Der Name wird dem Linker •ber die Infodatei mitgeteilt.
Diese Option ist nur im Oberon-Teil verf•gbar.
(*$O?*) Wenn ein '-' angegeben wird, wird der folgende Code bei der
Optimierung nicht anger•hrt. Bei O+ wird die Optimierung wieder
zugelassen.
Es darf keine Verschachtelung stattfinden.
Diese Option ist auch im Assembler verf•gbar.
(*$V+?*) Das Fragezeichen muž den Namen einer Environmentvariablen
angegeben. Es bedeutet: Der nun folgende Code soll bei der Optimierung
nur
dann im Programm gelassen
werden,
wenn
die
Environmentvariable
zum
Zeitpunkt der Optimierung definiert ist. Der Wert ist dabei
beliebig.
Der Compiler k•mmert sich nicht weiter darum und •bersetzt alles,
es
ist also keine bedingte Compilierung. Es ist n„mlich wesentlich
flexibler: Wenn man die Form des Codes (z.B. f•r verschiedene
Zielrechner)
„ndern m”chte, muž man nicht irgendwo einen Wert „ndern und alle
Module
neu •bersetzen und linken. Stattdessen braucht man nur die
entsprechenden Variablen zu setzen oder zu l”schen und die Optimierung
zu
starten. Der Linker erzeugt dann das gew•nschte Programm.
Diese Option ist auch im Assembler verf•gbar.
Beispiel:
(*V+ DEBUG *) (* drinlassen wenn Debugversion *)
IO.WriteString(...)
(*V=*)
Wenn die Environmentvariable DEBUG definiert ist,
Optimieren
die zus„tzliche Ausgabe dringelassen.
wird beim
(*$V-?*) Wie oben, jedoch wird der folgende Code nur dann
wenn
die Variable definiert ist.
entfernt,
Diese Option ist auch im Assembler verf•gbar.
(*$V+?=...*) und (*$V-?=...*) Wie oben, jedoch wird auch der Inhalt der
Variablen angegeben. Die Bedingung ist also erf•llt, wenn die
Variable
definiert ist und den angegebenen Wert hat (beliebiger String
ohne
Leerzeichen).
Diese Option ist auch im Assembler verf•gbar.
(*$V=*) Damit wird die Abh„ngigkeit von allen vorher angegebenen
Variablen
ausgeschaltet.
Diese Option ist auch im Assembler verf•gbar.
5.4) Ausgabe
------------
Der Compiler erzeugt eine neue Objektdatei, wenn die šbersetzung
fehlerfrei
war. Ist die dabei erzeugte Symboldatei anders als die bisherige oder
existierte bisher Keine, so wird die neue Symboldatei abgespeichert. War
die
šbersetzung fehlerhaft, wird die Fehlerdatei abgespeichert. Die
Symboldateien ben”tigt der Compiler, um beim Import die dort exportierten
Bezeichner 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”glich, sowohl komplette Module mit einem beliebigen Assembler zu
schreiben,
als auch vom Compiler erzeugte Objektdateien zu disassemblieren und
zu
•berarbeiten. Letzteres kann f•r die Geschwindigkeitsoptimierung
hilfreich
sein, denn es ist einfacher, einen bestehenden Assemblertext zu
verbessern
als etwas direkt in Assembler zu schreiben. Das Format des
Symboltabellen
ist nicht mehr kompatibel zu dem von N. Wirth, da einige zus„tzliche
Informationen ben”tigt wurden.
5.5) Vordefinierte Prozeduren
----------------------------Die folgenden Tabellen zeigen die vordefinierten Funktionen und
Prozeduren
von Oberon-2 inklusive der Erweiterungen bei STJ-Oberon-2. Diese sind
mit
einem Stern markiert und sind nicht portabel. v steht f•r eine Variable,
x
und n f•r Ausdr•cke, a f•r Adresse und T f•r einen Typ. Integer
bedeutet
einen der Integertypen SHORTINT, INTEGER oder LONGINT.
_Funktionen:_
+-------------+--------------+-------------+-----------------------+
| Name
| Argumenttyp | Ergebnistyp | Funktion
|
+-------------+--------------+-------------+-----------------------+
| ABS(x)
| Numerische
| Typ von x
| Absolutwert
|
|
| Typen
|
|
|
| ASH(x,n)
| x,n: Integer | Typ von x
| x * 2^n
|
| CAP(x)
| CHAR
| CHAR
| Grožbuchstabe
|
| CHR(x)
| Integer
| CHAR
| Zahl in CHAR
|
|
|
|
| umwandeln
|
| ENTIER(x)
| Realtyp
| LONGINT
| Gr”žtes Integer nicht |
|
|
|
| gr”žer als x
|
| TRUNC(x) * | Realtyp
| LONGINT
| Integeranteil
|
| LEN(v,n)
| v: Array;
| INTEGER
| L„nge von v in
|
|
| n: Integer- |
| Dimension n
|
|
| konstante
|
| (0 = erste Dim.)
|
| LEN(v)
| v: Array
| INTEGER
| entspricht LEN(v,0)
|
| LONG(x)
| SHORTINT
| INTEGER
| erweitern
|
|
| INTEGER
| LONGINT
|
|
|
| REAL
| LONGREAL
|
|
| MAX(T)
| T = Basistyp | T
| Maximalwert von T
|
|
| T = SET
| INTEGER
| Maximales
|
|
|
|
| Mengenelement
|
| MIN(T)
| T = Basistyp | T
| Minimalwert von T
|
|
| T = SET
| INTEGER
| 0
|
| ODD(x)
| Integer
| BOOLEAN
| x MOD 2 = 1
|
| ORD(x)
| CHAR
| INTEGER
| Ordinalzahl von x
|
| SHORT(x)
| LONGINT
| INTEGER
| n„chst kleinerer Typ |
|
| INTEGER
| SHORTINT
|
|
|
| LONGREAL
| REAL
|
|
| SIZE(T)
| jeder Typ
| Integer
| Anzahl Bytes,
|
|
|
|
| die T belegt
|
+-------------+--------------+-------------+-----------------------+
_Prozeduren:_
+--------------------+-------------------------------+--------------------+
| Name
| Argumenttyp
| Funktion
|
+--------------------+-------------------------------+--------------------+
| COPY(x,v)
| x: Char. Array, String;
| v := x
|
|
| v: Char. Array
|
|
| DEC(v)
| Integer
| v := v-1
|
| DEC(v,n)
| v,n: Integer
| v := v-n
|
| EXCL(v,x)
| v: SET; x: Integer
| v := v - {x}
|
| HALT(x)
| Integerkonstante
| Programm beenden
|
| INC(v)
| Integer
| v := v+1
|
| INC(v,n)
| v,n: Integer
| v := v+n
|
| INCL(v,x)
| v: SET; x: Integer
| v := v + {x}
|
| NEW(v)
| Zeiger
| v^
allozieren
|
| NEW(v,x_0,...,x_n) | v : Zeiger auf offenes Array; | v^
mit L„ngen
|
|
| x_i: Integer
| x_0..x_n
allozieren |
+--------------------+-------------------------------+--------------------+
_Funktionen in SYSTEM:_
+-------------+------------------+-------------+------------------------+
| Name
| Argumenttyp
| Ergebnistyp | Funktion
|
+-------------+------------------+-------------+------------------------+
| ADR(v)
| alle
| LONGINT
| Adresse von v
|
| ANL(a,b) * | a,b: Integer
| wie a,b
| bitweise Und
|
| BIT(a,n)
| a: LONGINT
| BOOLEAN
| Bit n von Mem[a]
|
|
| n: Integer
|
|
|
| CC(n)
| Integerkonstante | BOOLEAN
| Bedingung n (0ónó15)
|
| LONG(a) *
| SHORTINT
| INTEGER
| vorzeichenlos erweitern
|
|
| INTEGER
| LONGINT
|
|
| LSH(x,n)
| x: Integer,
| Typ von x
| logischer Shift
|
|
| CHAR,BYTE
|
|
|
|
| n: Integer
|
|
|
| NTL(a) *
| a: Integer
| wie a
| bitweise invertieren
|
| ORL(a,b) * | a,b: Integer
| wie a,b
| bitweise Oder
|
| ROT(x,n)
| x: Integer
| Typ von x
| Rotation
|
|
| CHAR,BYTE
|
|
|
|
| n: Integer
|
|
|
| VAL(T,x)
| T,x: alle Typen | T
| x als Typ T auffassen
|
| XOL(a,b) * | a,b: Integer
| wie a,b
| bitweise Exklusiv Oder
|
+-------------+------------------+-------------+------------------------+
_Prozeduren in SYSTEM:_
+----------------+---------------------+------------------------+
| Name
| Argumenttyp
| Funktion
|
+----------------+---------------------+------------------------+
| DISPOSE(p)
| Zeiger
| gibt den Speicher frei |
| GET(a,v)
| a: LONGINT
| v := Mem[a]
|
|
| v: einfache Typen
|
|
| GETREG(n,v)
| n: Integerkonstante | v := Register n
|
|
| v: einfache Typen
| (0ónó15)
|
| INLINE(...) * | Wortkonstanten
| f•gt die Konstanten
|
|
|
| in den Code ein
|
| MOVE(a0,a1,n) | a0,a1: LONGINT
| n Bytes bei a0
|
|
| n: Integer
| nach a1 kopieren
|
| NEW(v,n)
| v: Zeiger, LONGINT | n Bytes allozieren
|
|
| n: Integer
| und Adresse nach v
|
| PUT(a,v)
| a: LONGINT
| Mem[a] := v
|
|
| v: einfache Typen
|
|
| PUTREG(n,v)
| n: Integerkonstante | Register n := v
|
|
| v: einfache Typen
| (0ónó15)
|
+----------------+---------------------+------------------------+
5.6) Unterschiede zum Standard-Oberon-2
--------------------------------------- Der Compiler wurde erweitert um AND und NOT,
und
~sind.
die identisch
mit
&
- SYSTEM.ADR kann auch die Adressen von Prozeduren und konstanten
Strings
zur•ckgeben.
- Es gibt eine Abart von Prozeduren, die f•r Betriebssystemaufrufe
benutzt
werden. Bei Wirth wurden sie anders benutzt.
Beispiel :
PROCEDURE- Fclose(Handle : INTEGER) : INTEGER 62,1;
Bei Benutzung dieser Prozedur wird das Handle und die Funktionsnummer
62
auf den Stack geschrieben, TRAP #1 aufgerufen und der Stack
korrigiert.
Da das Betriebssystem genau wie normale Prozeduren den Returnwert in
Re-
gister D0 zur•ckgeben, funktioniert dies also auch.
Reihenfolge der Parameter m•ssen vertauscht werden.
Lediglich die
- Bei Wirth m•ssen Prozeduren, die einer Prozedurvariablen zugewiesen
werden, eine Funktionsnummer haben. Prozeduren bekommen
Funktionsnummern,
wenn sie einen Stern hinter dem Namen haben (dann sind sie
exportiert),
wenn sie einen Stern hinter 'PROCEDURE' stehen haben (soll wohl
einen
Far-Aufruf erzwingen) oder wenn sie forward deklariert werden (ein
'^'
hinter 'PROCEDURE'). Bei STJ-O2 ist keine Funktionsnummer mehr n”tig
f•r
die Zuweisung an eine Prozedurvariable.
- Laut Wirth waren Strings nur in G„nsefžchen zul„ssig. Dabei wird
ein
Zeichen als CHAR, mehr oder weniger Zeichen als ARRAY OF CHAR
erkannt.
Um nun auch einzelne Zeichen als Strings zu deklarieren, kann man sie
in
Hochkommata einschliežen.
5.7) Bekannte Fehler
-------------------- Nicht f•r alle Fehlermeldungen ist eine Klartextmeldung
gespeichert.
Dann erscheint nur eine Fehlernummer. Einige Fehlermeldungen
passen
nicht immer ganz zu dem bemerkten Fehler. Man m”ge mir das verzeihen.
- Zeiger auf offene Arrays in komplexen Strukturen (Arrays, Records)
machen Probleme. Besonders der Indexcheck funktioniert dann nicht.
- Die Anzahl Prozeduren, die an einen Typ und dessen Erweiterungen
gebunden werden, ist noch auf 100 begrenzt.
- Zeiger auf mehrdimensional offene Arrays sind noch nicht m”glich.
- LEN liefert nur INTEGER zur•ck statt LONGINT, da die Indizes auf 32K
begrenzt sind.
- Wenn schon eine Infodatei existiert, deren Inhalt aber Unsinn ist
oder
deren Format veraltet ist oder die 0 Bytes lang ist, st•rzt der
Compiler
nach der šbersetzung ab.
6) Der Assembler
================
Im Compiler ist ein Makroassembler integriert. Dieser ist urspr•nglich
als
eigenst„ndiges Programm zur Assemblerprogrammierung gedacht gewesen und
daher sehr viel leistungsf„higer als n”tig. Daher ist er auch nur gering
mit
dem Oberon-Teil des Compilers verbunden. Er hat einen eigenen Parser
und
arbeitet im Gegensatz zum Compiler mit 2 Passes. Bei der
Programmierung
habe ich mich an AS orientiert, ein PD-Assembler fr PC's, so daž hier
einige Ž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
OberonTeil nicht auf im Assembler definierte Symbole zugreifen. Der
Assembler
kann soweit mit Oberon-Strukturen arbeiten, solange kein Code dabei
erzeugt
werden muž.
F•r A7 kann alternativ auch SP verwendet werden. Alle Befehle sind
auch
ohne L„ngenangabe definiert. Wenn der Befehl in Wortgr”že existiert,
wird
dies als Gr”že angenommen.
Der Assembler ist genau wie der Compiler streng Case-Sensitiv. Alle
Maschinenbefehle und Pseudobefehle mssen grož geschrieben werden. Bei
Labeln
wird zwischen Grož- und Kleinschreibung unterschieden.
Achtung : Es sind l„ngst nicht alle Maschinenbefehle getestet
bei
Problemen sollte ein Disassembler pr•fen, ob der Assembler nicht
vielleicht
Unsinn kodiert hat.
und
6.1) Symbolkonventionen
----------------------Symbole werden mit einer L„nge von 22 Byte gespeichert, alle weiteren
Zeichen 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
erlaubt, aber nicht erforderlich. Alle vordefinierten Bezeichner d•rfen
auch
in der ersten Spalte anfangen. Die Parameterliste eines Makros muž mit
einem Zeilenende oder Kommentar beendet werden. Aužer diesen beiden
Forderungen 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
unterschieden. Alle Maschinenbefehle, Register und Pseudooperationen
m•ssen
grož geschrieben werden.
Folgende Symbole definiert der Assembler vor:
+------+------------------------+
| Name | Bedeutung
|
+------+------------------------+
| *
| mom. Programmz„hler
|
| CPU | der gew„hlte Prozessor |
+------+------------------------+
Desweiteren einige Pseudobefehle, deren Parameter und
alle
68000 Befehle. Befehle der anderen 680X0 Prozessoren sind
implementiert.
nat•rlich
z.T.
6.1.1) Formelausdr•cke
......................
An den meisten Stellen, an denen der Assembler Zahlenangaben erwartet,
k”nnen nicht nur einfache Symbole oder Konstanten angegeben werden,
sondern
ganze Formelausdr•cke. Bei den Komponenten der Formelausdr•cke kann es
sich
sowohl um ein einzelnes Symbol als auch um eine Konstante handeln.
Die
Schreibweise von Integerkonstanten kann in verschiedenen Zahlensystemen
erfolgen:
+-------------+-------------------------------------+
| dezimal
| direkt
|
| hexadezimal | nachgestelltes H, vorangestelltes $ |
| bin„r
| nachgestelltes B, vorangestelltes % |
| oktal
| nachgestelltes O, vorangestelltes @ |
+-------------+-------------------------------------+
Damit hexadezimale Kostanten im Intel-Modus nicht als Symbolnamen
fehlinterpretiert werden k”nnen, m•ssen sie immer mit einer Ziffer
beginnen;
anstelle z.B. F0H muá also 0F0H geschrieben werden. Die Werte A-F
m•ssen
grožgeschrieben werden,
ebenso die nachgestellten
Buchstaben.
Beim
Motorola-Modus entf„llt dies. Integerkonstanten k”nnen auch als ASCIIWerte
geschrieben werden, so entsprechen
'A'
== $00000041
'AB'
== $00004142
'ABC' == $00414243
'ABCD' == $41414244
Dabei m•ssen die Zeichen in Hochkommata eingeschlossen
von
sein,
um
sie
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
bekannt vorkommen d•rfte: Schreibt man einen Backslash (\) mit einer
maximal
dreiziffrigen Zahl im String, so versteht der Assembler dies als
Zeichen
mit dem entsprechenden dezimalen ASCII-Wert. So kann man mit \0ein
NULZeichen definieren.
Einige besonders h„ufig gebrauchte Steuerzeichen kann man auch
folgenden Abk•rzungen erreichen:
\b : Backspace
\t : Tabulator
\\ : Backslash
mit
\a : Klingel
\e : Escape
\n : Zeilenvorschub \r : Wagenr•cklauf
\' : Hochkomma
\" : G„nsef•áchen
Die Kennbuchstaben d•rfen sowohl groá als auch klein geschrieben werden.
šber dieses Escape-Zeichen k”nnen sogar Formelausdr•cke in den
String
eingebaut werden, wenn sie in geschweifte Klammern eingefaát werden:
z.B.
bewirkt
Wert1
equ 1
Wert2
equ 2
message "Wert = \{Wert1+Wert2}"
die Ausgabe von 'Wert = 3'.
Der Assembler stellt zur Verkn•pfung folgende Operanden zur Verf•gung:
+--------------------------------------------------+
| Operand Funktion
#Operanden
Rang
|
+--------------------------------------------------+
| ~
log. NOT
1
hoch
|
| ~~
bin„res NOT
1
^
|
+--------------------------------------------------+
| *
Produkt
2
|
|
| /
Quotient
2
|
|
| #
Modulodivision
2
|
|
| ^
Potenz
2
|
|
| !,!!
bin„res XOR
2
|
|
| &,&&
bin„res AND
2
|
|
+--------------------------------------------------+
| Differenz
2
|
|
| +
Summe
2
|
|
| |,||
bin„res OR
2
|
|
+--------------------------------------------------+
| <>
Ungleichheit
2
|
|
| >=
grӇer oder gleich
2
|
|
| <=
kleiner oder gleich
2
|
|
| <
echt kleiner
2
|
|
| >
echt grӇer
2
v
|
| =
Gleichheit
2
niedrig |
+--------------------------------------------------+
Die angedeuteten Gruppen haben jeweils gleichen Rang. Die Reihenfolge
der
Evaluierung l„át sich durch Klammerung neu festlegen.
Die Vergleichsoperatoren liefern TRUE, falls die Bedingung zutrifft,
und
FALSE falls nicht. F•r die logischen Operatoren ist ein Ausdruck
TRUE,
falls er ungleich 0 ist, ansonsten FALSE. Deshalb ist auch ein
separater
"logisch Nicht" Operator n”tig, denn eine Zahl ungleich 0 kann bin„r
invertiert immer noch ungleich 0 sein. Beim "logisch Nicht" wird eine 0
zur
1, eine Zahl ungleich 0 zur 0. Alle anderen logischen Operationen sind
mit
den Bin„ren identisch.
F•r Strings sind alle Vergleichsoperatoren sowie die Summe definiert.
Die
Summe zweier Strings ergibt einen String, der die beiden
aneinandergeh„ngt
erh„lt. Vergleiche von Strings liefern 0 (FALSE) oder 1 (TRUE). šberall,
wo
Zahlen erwartet werden, d•rfen also auch Stringvergleiche benutzt werden.
Als einzige Funktion, die ein Stringargument zul„át, ist die
Funktion
UPSTRING definiert. Sie wandelt alle Zeichen in Groábuchstaben um.
Dabei
werden auch Umlaute in Grožbuchstaben gewandelt, aber Žnderungen des
Zeichensatzes mit CHARSET werden nicht korrekt ber•cksichtigt. Wer nur
ein
einzelnes Zeichen (als Integer gespeichert) umwandeln will, kann dies
mit
der Funktion TOUPPER tun.
6.2) Pseudobefehle
------------------
6.2.1) SET und EQU
..................
SET und EQU erlauben die Definition typenloser Konstanten, d.h. sie
werden
keinem Segment zugeordnet und ihre Verwendung erzeugt in keinem Fall
eine
Warnung wegen Segmentverquickung. W„hrend EQU Konstanten definiert,
die
nicht wieder (mit EQU) ge„ndert werden k”nnen, erlaubt SET die
Definition
von Variablen, die sich w„hrend des Assemblerlaufes ver„ndern lassen.
Intern werden Konstanten und Variablen identisch gespeichert, der einzige
Unterschied 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
Befehl •bereinstimmt, d•rfte wohl reiner Zufall sein. Um nun aber keine
fehlertr„chtigen Handumkodierungen vornehmen zu mssen, enth„lt der
Assembler
eine Umsetzungstabelle f•r Zeichen, die jedem Quellcode ein Zielzeichen
zuordnet. Zur Modifikation dieser Tabelle (die initial 1:1 •bersetzt),
dient
der Befehl CHARSET. Der Befehl erwartet eine Bereichsangabe f•r die
zu
•bersetzenden Zeichen als ersten bzw. ersten/zweiten Parameter und
als
letzten Parameter den Bereich, in den die Zeichen umgemappt werden
sollen.
Zur Klarstel- lung zwei Beispiele:
CHARSET '„',128
bedeutet, daá das Zielsystem das „ mit der Zahl 128 kodiert.
das
Zielsystem keine Kleinbuchstaben untersttzt, k”nnen mit
CHARSET 'a','z','A'
Falls
alle Kleinbuchstaben auf die passenden Groábuchtaben automatisch
umgemappt
werden.
ACHTUNG! CHARSET beeinfluát nicht nur im Speicher abgelegte
Stringkonstanten, sondern auch als 'ASCII' formulierte Integerkonstanten. Dies
bedeutet, daá eine evtl. bereits modifizierte Umsetzungstabelle in den
obigen
Beispielen zu anderen Ergebnissen f•hrt!
6.2.3) CPU
..........
Speichert die nachfolgende Zahl als Bezeichnung f•r eine CPU. Kann wie
jeder andere Bezeichner in Ausdr•cken verwendet werden und ist bei der
bedingten Assemblierung verwendbar. Der Assembler pr•ft, ob ein
Maschinenbefehl auf der gew„hlten CPU verf•gbar ist und verweigert sie wenn nicht.
Defaultwert ist 68000.
6.2.4) SUPMODE
..............
Diese Variable kann nur ein- oder ausgeschaltet werden. Sie teilt dem
Assembler mit, ob der Supervisormode gerade eingeschaltet ist oder nicht.
Am
Anfang ist die Variable ausgeschaltet.
Beispiel :
SUPMODE ON
MOVE #0,SR ; nur im Supervisormode zul„ssig
SUPMODE OFF
MOVE #0,SR ; f•hrt zu einer Warnung des Assemblers
6.2.5) SEGMENT
..............
Der Atari unterscheidet verschiedene Adreábereiche, die nicht
miteinander
mischbar sind und jeweils auch verschiedene Befehle zur Ansprache
ben”tigen. Um auch diese verwalten zu k”nnen, stellt der Assembler mehrere
Programmz„hler zur Verf•gung, zwischen denen mit dem SEGMENT-Befehl hinund
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
folgende Segmente mit folgenden Namen verwaltet:
CODE: Programmcode
DATA: Datenbereich
BSS: Block storage segment, zu 0 initialisierte Daten, die nicht im
Programmcode auftauchen, sondern vom TOS angeh„ngt werden.
Labels, die in einem Segment eines bestimmten Typs definiert werden,
erhalten diesen Typ als Attribut. Damit hat der Assembler eine begrenzte
Prfm”glichkeit, ob mit den falschen Befehlen auf Symbole in einem Segment
zugegriffen wird. In solchen F„llen sollte der Assembler eine Warnung
ausgeben.
Achtung : Die Segmente werden nat•rlich auseinandergezogen und vom
Linker
richtig zusammengesetzt, daher darf man nat•rlich keine PC-relative
Adressierung •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
DS.W
DS.L
; reserviert 10 Bytes
1
; reserviert ein Wort
2,$FF
; reserviert 2 Langworte
; mit Inhalt $FF
Speicherreservierung ohne Inhaltsangabe ist in allen Segmenten erlaubt.
Der
Inhalt ist dann jeweils 0. Eine Inhaltsangabe ist nat•rlich nur im Code
und
im Datensegment erlaubt.
6.2.7) ALIGN
............
ALIGN mit einem dahinterstehenden Integerausdruck erlaubt es, den
Programmz„hler auf eine bestimmte Adresse auszurichten. Die Ausrichtung
erfolgt
dergestalt, daá der Programmz„hler so weit erh”ht wird, daá er ein
ganzzahliges vielfaches des Arguments wird :
align 2
macht den Programmz„hler gerade. Der Freiraum wird mit 0 gef•llt.
Stattdessen kann man auch EVEN ohne Wert benutzen.
6.2.8) MACRO
............
Dies ist der wohl wichtigste Befehl zur Makroprogrammierung.
Befehlsfolge
<Name>
Mit
der
MACRO [Parameterliste]
<Befehle>
ENDM
wird das Makro <Name>als die eingeschlossene Befehlsfolge definiert.
Diese
Definition alleine erzeugt noch keinen Code! Daf•r kann fortan die
Befehlsfolge einfach durch den Namen abgerufen werden, das ganze stellt also
eine
Schreiberleichterung dar. Um die ganze Sache etwas n•tzlicher zu
machen,
kann man bei der Makrodefinition eine Parameterliste mitgeben. Die
Parameternamen werden wie •blich durch Kommas getrennt und m•ssen - wie der
Makroname selber - den Konventionen f•r Symbolnamen gen•gen.
Beim Aufruf eines Makros werden die beim Aufruf angegebenen
Parameternamen •berall textuell im Befehlsblock eingesetzt und der sich so
ergebende
Assemblercode wird normal assembliert. Sollten beim Aufruf zu wenige
Parameter angegeben werden, werden sie als leere Strings •bergeben. Soll
mittendrin ein Parameter weggelassen werden, kann man zwei
aufeinanderfolgende
Kommas schreiben.
F•r die •bergebenen Parameter gelten besondere Regeln : Eine
zusammenh„ngende Kette von Zeichen ohne Komma gilt als ein Parameter, egal um
welche
Zeichen es sich handelt. Es k”nnen also auch spezielle
Adressierungsarten
wie (A0)+ bergeben werden. Wenn bewužt Strings bergeben werden
sollen,
m•ssen sie in Hochkommata eingeschlossen werden, der Parameter besteht
dann
aus dem String mit Hochkommata. Wird ein String in G„nsefžchen
eingeschlossen, besteht der Parameter nur aus dem String ohne G„nsefžchen.
So
ist es auch m”glich, Kommas und Leerzeichen in einem Parameter
unterzubringen.
Beispiele :
mac1
mac2
MACRO
MOVE
ENDM
mac1
MACRO
par2
ENDM
mac2
par1
D0,par1
A0
par2,par3
par3
MOVE,"D0,A0"
; entspricht "MOVE D0,A0"
; entspricht wiederum
; "MOVE D0,A0"
Es kann also praktisch alles durch Makroparameter ersetzt werden,
Befehle !
auch
In Makror•mpfen definierte Labels werden immer als lokal betrachtet,
ein
expliziter LOCAL-Befehl ist also nicht erforderlich. Sollen Label
global
bekannt sein, m•ssen sie mit einem Stern gekennzeichnet sein. Da auf
diese
Weise das Label mit jedem Makroaufruf neu definiert wird, darf es sich
nur
um Definitionen mit 'SET' handeln, damit keine Fehlermeldungen wie
'Label
schon definiert' kommen. Aus technischen Grnden ist es momentan n”tig,
ein
Makro vor der ersten Benutzung zu deklarieren. Wenn ein Makroparameter
in
G„nsefžchen eingeschlossen wird, wird er ebenfalls ersetzt, so daž
das
Aussehen des Parameters •berpr•ft werden kann.
Beispiel :
Test
MACRO Par
IF "Par" = "A"
...
Wenn als Parameter 'a' oder 'A' •bergeben wurde, ergibt der Vergleich
true.
Es wird aber nicht generell in Strings ersetzt, sondern nur, wenn der
gesamte String gleich einem Makroparameter ist. Der Parameter wird *immer*
in
Grožbuchstaben umgewandelt.
6.2.9) IRP
..........
Dies ist die eine vereinfachte Form von Makrodefinitionen f•r den Fall,
daá
eine Befehlsfolge einmal auf mehrere Operanden angewendet werden soll
und
danach nicht mehr gebraucht wird. IRP ben”tigt als ersten Parameter
ein
Symbol f•r den Operanden, und danach eine (fast) beliebige Menge von
Parametern, die nacheinander in den Befehlsblock eingesetzt werden. Um
eine
Menge von Registern auf den Stack zu schieben, kann man z.B. schreiben
IRP
op, D0,D1,D3
MOVE
op,-(SP)
ENDM
was in folgendem resultiert:
MOVE
D0,-(SP)
MOVE
D1,-(SP)
MOVE
D3,-(SP)
Benutzte Labels sind wieder f•r jeden Durchgang automatisch lokal.
Soll ein Label global sichtbar sein, muž es einen Stern hinter dem
Namen
haben. Dies geht nur bei Labels, die mit SET definiert werden, denn
andere
wrden eine Fehlermeldung erzeugen, daž das Label schon definiert ist.
6.2.10) REPT
............
Dies ist die einfachste Form der Makrobenutzung. Der im Rumpf
angegebene
Code wird einfach sooft assembliert, wie der Integerparameter von REPT
angibt. Dieser Befehl wird h„ufig in kleinen Schleifen anstelle einer
programmierten Schleife verwendet, um den Schleifenoverhead zu sparen.
Der Vollst„ndigkeit halber ein Beispiel:
REPT
3
ROR
#1,(A0)
ENDM
rotiert den Wert um 3 Stellen nach rechts.
Symbole sind wiederum f•r jede einzelne Repetition lokal.
6.2.11) Bedingte Assemblierung
..............................
Der Assembler unterst•tzt die bedingte Assemblierung mit Hilfe der
Befehle
IFC.. / ELSIFC / ENDC. Diese Befehle wirken zur Assemblierzeit, indem
entsprechend der Bedingung Teile •bersetzt oder •bersprungen werden. Diese
Befehle 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
ELSECZweig assembliert, falls er vorhanden ist.
IF-Anweisungen d•rfen beliebig verschachtelt werden, ein ELSEC
bezieht
sich immer auf das letzte vorangegangene, noch nicht abgeschlossene IFC.
Wenn in der Bedingung Symbole auftauchen, m•ssen diese unbedingt
vorher
definiert worden sein, damit im Pass 1 der richtige Block •bersetzt wird.
F•r den Test, ob ein Symbol definiert ist, wurde die Funktion DEF
eingef•hrt. Sie gibt TRUE (=1), wenn das angegebene Symbol definiert ist,
sonst
FALSE (=0).
Dies ist n•tzlich f•r Include Dateien :
IFC NOT DEF(thisfile) THEN; wenn nicht definiert
thisfile
EQU 1
; dann definieren
...
; und •bersetzen
ENDC
6.2.12) Lokale Label
....................
Die bedeutendste Erweiterung zu AS sind lokale Label. Damit k”nnen
innerhalb 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
LOCAL und END sichtbar. Ein * hinter einem Label (vor dem Doppelpunkt
falls
einer gesetzt wird) bedeutet, daž das Label global sein soll. Egal auf
welcher 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
sollen. Damit vermeidet man die Doppelbenutzung von Labels, die
unwissentlich
in einer Includedatei definiert sind.
Alle Label ohne Stern sind aužerhalb der ASSEMBLER ... END Struktur
nicht
bekannt, d.h. sie sind automatisch lokal.
Durch die Lokalisierung innerhalb von ASSEMBLER bis END ist dieser
Befehl
nicht n”tig, aber f•r reine Assemblerprojekte ist er wichtig.
6.3) Hochsprachenelemente
------------------------Der Assembler beherrscht auch einige der Oberon-Strukturen, wenn auch
wesentlich primitiver. Trotzdem kann man mit ihnen ein wenig Struktur in
ein
Assemblerprogramm bringen und auch Labeldefinitionen wie Loop o.„.
sparen.
6.3.1) IF cond THEN ... ELSIF ... ELSE ... END
..............................................
Die •bliche If-Abfrage darf nat•rlich nicht fehlen. Als Bedingungen
sind
aber lediglich die •blichen Condition Codes HI, LS, CC, HS, CS, LO, NE,
EQ,
VC, VS, PL, MI, GE, LT, GT und LE zugelassen.
Beispiel :
CMP D0,D1
IF EQ THEN
...
ELSIF LO THEN
...
ELSE
...
END
;
;
;
;
wenn D0 = D1
tu dies
wenn D1 < D0
tu dies
; sonst dies
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 LOOPSchleifen
mittendrin verlassen. Es wird ein Branch an das Ende der Struktur
eingef•gt. Wenn man eine Zahl in Klammern angibt, kann man gleich mehrere
Strukturen verlassen. Dabei einspricht EXIT einem EXIT(0).
Beispiel :
LOOP
REPEAT
TST D0
IF EQ THEN EXIT END
;
;
IF MI THEN EXIT(1) END;
;
UNTIL PL
END
verl„žt die
REPEAT-Schleife
verl„žt die
LOOP-Schleife
6.4) Diverses
------------6.4.1) INCLUDE
..............
Dieser Befehl f•gt die im Parameter angegebene Datei so im Text ein, als
ob
sie dort stehen w•rde. Dieser Befehl ist sinnvoll, um Quelldateien
aufzuspalten, die alleine nicht in den Speicher passen w•rden oder um
sich
"Toolboxen" zu erzeugen.
Aus Kompatibilit„tsgr•nden ist
G„nsef•áchen zu schreiben,
es
erlaubt,
den
Dateinamen
in
include stddef51.asm
und
include "stddef51.asm"
sind also „quivalent.
6.4.2) MESSAGE, WARNING, ERROR und FATAL
........................................
Der Assembler prft zwar die Quelltexte so streng wie m”glich und
liefert
diffenzierte Fehlermeldungen, je nach Anwendung kann es aber sinnvoll
sein,
unter bestimmten Bedingungen zus„tzliche Fehlermeldungen auszugeben,
mit
denen sich logische Fehler automatisch pr•fen lassen. Der Assembler
unter-
scheidet drei Typen von Fehlermeldungen,
dem
Programmierer zug„nglich sind:
die •ber drei
Befehle
auch
- WARNING : Fehler, die auf m”glicherweise falschen oder
ineffizienten
Code hinweisen. Die Assemblierung l„uft weiter, eine Codedatei wird
erzeugt.
- 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
Assemblers 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
Fehlermeldung abbrechen. Der String einer Fehlermeldung wird anstatt einer
Assemblermeldung in die Fehlerdatei geschrieben und mit Zeile und Spalte
versehen, 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
untersttzt werden, die keinen zus„tzlichen Code erfordern.
Beispiel :
CONST con = 10;
TYPE rec = RECORD
var1 : INTEGER;
var2 : ARRAY 10 OF CHAR;
END;
arr = ARRAY 10 OF LONGINT;
VAR a : rec;
b : POINTER TO rec;
c : arr;
PROCEDURE proc1;
...
PROCEDURE proc2*;
...
Dann sind folgende Zugriffe m”glich:
MOVE
#con,D0
; l„dt D0 mit 10
MOVE.L a,A0
; l„dt Adresse von a in A0
; (geht auch mit Prozeduren
; und Stringkonstanten)
MOVE
a.var1,D0
; geht weil a globale
; Variable ist
MOVE.B a.var2[5],D1
; dito
MOVE.L c[8],D2
; dito
BSR
proc
; innerhalb eines Moduls
JSR
proc2
; bei importierten und
; exportierten Prozeduren
Dagegen geht dies nicht:
MOVE
b.var1,D0
; b ist ein Zeiger und muž erst
; geladen werden
Dies kann so gel”st werden:
MOVE.L b,A0
; Inhalt von b = Zeiger auf rec
MOVE
rec.var1(A0),D0 ; typ.var ergibt Offset von var
MOVE.B rec.var2[5](A0),D0; genauso
MOVE.L arr[2](A1),D0
; geht genauso mit Arrays
Man kann also mit dem Typbezeichner die Offsets der Variablen innerhalb
des
Records bekommen. Dies sollte immer der direkten Angabe von Zahlen
vorgezogen werden, damit bei einer Žnderung der Datenstruktur nicht alle
Zahlen
ge„ndert werden m•ssen.
7) Der Linker
=============
Der Oberon-Linker (LINK.OBJ/TTP) dient dazu, vom Compiler erzeugte
Objektmodule zu einem lauff„higen Programm zusammenzubinden. Daf•r
ben”tigt
er nur die Objektmodule, die Symboldateien nicht.
7.1) Aufruf, Parameter
---------------------Der Linker sollte von einer Shell aus benutzt werden, die zumindest in
der
Lage ist, Environmentvariablen zu setzen, denn der Linker liest dort
seine
Optionen. Beim Aufruf kann man als Kommando einige Optionen sowie einen
Namen eines Objektmoduls •bergeben. Dieses Modul wird mit den von ihm
importierten Modulen zusammengelinkt und unter seinem Namen mit passender
Extension gespeichert. Die Syntax sieht also so aus:
link {<Option>} <Name>
Es wird nur der Name ohne Extension beachtet, ein eventueller Pfad wird
abgeschnitten. Dieser Name wird mit der Extension OBJ in den Suchpfaden
gesucht. 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.
Normalerweise 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
Gr”že.
Mit dieser Option kann man den Stack beliebig einstellen.
32K
-x|<ext>|: Damit kann die Extension eingestellt werden, die das
Programm
erhalten soll. Normalerweise ist das PRG, aber bei TOS-Programmen
kann
man TOS oder TTP angeben.
Ist von einem Modul eine Infodatei vorhanden und darin ist ein
Programmname
definiert, wird dieser beim Speichern des Programmes benutzt. Wenn ein
Pfad
angegeben ist, wird dort gespeichert, sonst in PRGPATH bzw. beim Modul.
Der
Name kann im Quelltext mit (*$N ...*) gesetzt werden, siehe Kap. ??.
7.2) Environmentvariablen
------------------------Der Linker wertet auch einige Environmentvariablen aus. Sie m•ssen
immer
grožgeschrieben sein und von einem '=' gefolgt sein. Gesetzt werden sie
in
der Shell und werden jedem Programm bergeben, daž von dieser Shell
aufgerufen 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
TOSProgrammen benutzt werden d•rfen. Diese Pfade werden vor denen in
OBJPATH durchsucht. Die Unterscheidung erfolgt anhand der Extension,
die
das zu erzeugende Programm erh„lt. F„ngt sie mit 'T' an, werden die
Module 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
GEMProgrammen benutzt werden d•rfen. Diese Pfade werden vor denen in
OBJPATH 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
definiert, 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
Symboltabelle erzeugt.
EXTSYM: Wieder Werte ON/OFF. Schaltet das erweiterte GST-Format der
Symboltabelle ein oder aus. Ist normalerweise eingeschaltet.
PRGEXT: Gibt die Extension an, die das gelinkte Programm erhalten
soll.
Beispiel : 'PRGEXT=TOS' erzeugt ein TOS-Programm (der Code muž
daf•r
natrlich geeignet sein). Standardm„žig wird die Extension PRG
benutzt.
STACKSIZE: Der Inhalt dieser Variablen muž eine Dezimalzahl sein,
die
Gr”že des Stacks angibt. Normalerweise ist dies 32K.
die
LINKALSO: Diese Variable darf eine Liste von Dateinamen, getrennt mit
Kommata, enthalten. Diese Objektmodule werden dann auch gelinkt, wenn
sie
nicht importiert werden. Damit ist es z.B. m”glich, w„hrend der
Testphase ein Debugmodul mitzulinken, daž sich in Exceptions einklinkt
oder
„hnliches. Ein Name sollte immer nur 8 Zeichen lang sein,
Extensions
sind nicht n”tig. Es sind nur maximal 5 Module m”glich. M•ssen es
mehr
sein, so muž man ein Leermodul definieren, daž diese Module
importiert,
und dieses kann man bei LINKALSO angeben.
LINK_ ...: Alle Variablen, die mit LINK_ anfangen, dienen zum
Umbenennen
von importierten Modulen. Wird z.B. LINK_IO=GEMIO definiert, wird
bei
jedem Import von IO stattdessen GEMIO gelinkt. Diese Module m•ssen
nat•rlich gleiche Schnittstellen haben.
8) Die Lader
============
Die Lader wurden zu einer Zeit entwickelt, als es noch keine Shell
f•r
Load-Time-Linking gab. Sie sind daher in der Lage, Objektmodule direkt
zu
linken und zu starten. Es gibt zwei Lader, einen f•r GEMApplikationen
(LOAD.PRG) und einen f•r TOS-Applikationen (LOAD.TTP). Inzwischen gibt
es
allerdings keinen Unterschied mehr. Man braucht nur jeweils die
richtige
Extension, damit beim Start die richtige Umgebung gew„hlt wird.
8.1) Aufruf, Parameter
---------------------Die Lader erhalten mindestens den Namen eines Moduls als Argument.
Dieses
Modul darf keine Extension haben, also nur der Name. Das Modul wird
zuerst
im Lader selbst gesucht, dann in den Suchpfaden, die in der
Environmentvariablen OBJPATH definiert sind. Ist sie nicht definiert, wird MODPATH
genommen. Wenn ein Modul nicht gefunden wird, wird mit einer Meldung
abgebrochen. 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
unter 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
weitergegeben. 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:
deutet
auf einen Versionskonflikt hin.
'Objectmodule defect'.
Dies
Wird ein Modul mit Extension •bergeben (z.B. Icon auf Loader gezogen),
so
wird das Modul normal gestartet mit Sys.ModuleCall FALSE. Nach
Beendigung
des Moduls erscheint dann die Meldung 'Procedure OBJ not found', falls
die
Extension OBJ war. Dies ist nicht weiter sch„dlich.
Die Lader haben ein angepažtes Modul f•r die Exceptionbehandlung
integriert. 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'
aufruft, 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
Bedeutung der Optionen ist in Kap. ?? erkl„rt.
9) Das Make-Utility
===================
Der Begriff Make d•rfte von C her bekannt sein. Hier ist es jedoch
nicht
n”tig, ein Makefile zu erzeugen. Make (MAKE.OBJ/TTP) liest die
importierten
Module aus dem Quelltext und •bersetzt alle Dateien, bei denen dies
n”tig
ist.
9.1) Aufruf, Parameter
---------------------Make kann ohne Parameter oder mit
Wird
Make ohne Parameter gestartet, so
•bersetzenden Modulen durchsucht. Wird ein
Module
•berpr•ft, die in den Suchpfaden
angegebenen
Moduls ben”tigt werden.
einem Modulnamen gestartet
werden.
werden alle Suchpfade nach zu
Modul genannt,
werden nur solche
stehen und f•r das Linken des
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
gesucht. Die Suchpfade f•r Sourcen, Objekt- und Symboldateien werden •ber
die
Environmentvariable 'MAKEPATH' definiert.
9.3) Hinweise
------------Wenn Module sich gegenseitig importieren, bleibt Make in einer
Endlosschleife h„ngen. Man erkennt dies daran, daž st„ndig dieselben
Dateinamen
ausgegeben werden. Mit Control-C kann man die Ausf•hrung abbrechen.
10) Der Scanner
===============
Der Scanner (SCAN.OBJ/TTP) dient dazu, von einer Position in einem
Programm die Stelle im richtigen Quelltext zu finden. Dies erfordert eine
erweiterte Symboltabelle am Programm. Diese erzeugt der Linker
normalerweise,
wenn nichts anderes verlangt wird.
10.1) Aufruf, Parameter
----------------------Scan erwartet zwei Parameter in der Kommandozeile,
getrennt sind:
die mit Leerzeichen
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
Optionen werden -e, -o und -s<pos>angegeben. Der Compiler •bersetzt das
bestimmte Modul, bis er an die Position gelangt, an der der Absturz
stattfand. 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,
und
terminiert.
macht Scan eine Meldung
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
gesucht.
11) Debugging
=============
Bis jetzt gibt es leider keinen Source Level Debugger f•r STJ-Oberon2.
Dies ist aber geplant und wird irgendwann kommen. Bis dahin muž man
sich
mit Low Level Debuggern herumplagen.
11.1) DB
-------Der Debugger DB von Atari eignet sich einigermažen zum Debuggen. Ich
m”chte
hier besonders auf den Befehl 'stack' hinweisen: Dieser Befehl
versucht
•ber den Stack die Aufrufkette von Subroutinen zur•ckzuverfolgen. Dies
geht
auch mit Oberon-Programmen, da diese genau wie C-Programme mit Register
A6
lokale Stacks aufbauen.
11.2) Bugaboo
------------Bugaboo (aus dem TurboAss-Paket) eignet sich ebenfalls zum Debuggen.
Er
kennt leider den Befehl 'stack' nicht, ist daf•r aber wesentlich
komfortabler. Leider arbeitet er nicht auf dem TT mit Grožbildschirm.
11.3) Tips
---------Zum Debuggen wird immer eine Symboltabelle ben”tigt.
Eine globale Variable kann man •ber den Namen ansprechen, lokale
Variable
einer Prozedur findet man bei Adressen ab (A6) abw„rts, deren Parameter
ab
8(A6) aufw„rts.
Die Namen der Symboltabelle sind nicht immer eindeutig. Wenn man also
ein
Symbol ansprechen will, muž man erst pr•fen, ob es das Gew•nschte ist.
Beispielsweise findet man die Prozedur 'Read' in File und in Paths.
Einen Befehl sollte man immer im Hinterkopf haben: Wenn n„mlich ein
Programm abgestrzt ist und man aus dem Debugger raus m”chte, sollte man
noch
die Exitprozedur aufrufen, damit alle Betriebsmittel freigegeben
werden.
Dazu muž man den PC auf das Symbol 'Exit' stellen und die Ausf•hrung
starten. Wenn der Exit nicht abstrzt, mžte eine Meldung ber die
Terminierung
des Programms kommen. Bei DB lautet der Befehl 'x pc .Exit', bei
Bugaboo
'let pc=.Exit'.
12) Utilities
=============
12.1) Der Browser
-----------------
Ein Browser ist ein Programm, daž aus der Symboldatei und der Source
eine
Definitionsdatei erzeugt. Die vorliegende Version ist noch in der
Entwicklung. Sie wertet lediglich die Symboldatei aus, so daž keine Kommentare
in
der Definitionosdatei sind.
Der Browser wurde von Dirk Theisen geschrieben.
12.2) Inline-Zeilen erzeugen
---------------------------F•r den Fall, daž jemand eine Datei als INLINE-Zeilen in eine Source
integrieren will (z.B. eine Resourcedatei), kann man dies mit Inline tun.
Inline fragt nach der zu konvertierenden Datei und speichert die erzeugte
Datei mit der Extension INL ab. Im Editor muž man dann noch den
Modulnamen
SYSTEM bzw. eine Abk•rzung davon mittels Suchen und Ersetzen vor
INLINE
setzen.
13) Speicherverwaltung
======================
Die Speicherverwaltung implementiert Funktionen zum Allozieren und
Freigeben dynamischen Speichers. Solcher Speicher ist grunds„tzlich nicht
initialisiert[6].
--------------[6]
in-
wie auch lokale Variable,
lediglich globale Variable werden zu 0
itialisiert
13.1) Benutzung in Programmen
----------------------------F•r die dynamische Speicherverwaltung stehen mehrere Funktionen zur
Verf•gung:
|NEW(<pointer>)|: Wenn als Argument ein Zeiger auf einen Record oder
ein
konstantes Array •bergeben wird, wird diese Struktur alloziert. Bei
Records werden 4 Bytes zus„tzlich alloziert, die den Typdeskriptor
auf-
nehmen.
Dieser steht immer _vor_ dem Record, d.h. der Zeiger zeigt
immer auf das erste Element des Records, wohingegen er bei anderen
Compilern auf den Deskriptor zeigt.
|NEW(<pointer>,<len>)|: Eine L„nge kann nur angegeben werden, wenn es
sich
bei dem Zeiger um einen Zeiger auf ein offenes Array handelt. Dabei
ist
len die Anzahl Indizes.
|SYSTEM.NEW(<pointer>,<len>)|: SYSTEM.NEW k•mmert sich nicht um den Typ
des
Zeigers. Es wird soviel Speicher alloziert, wie len in Bytes angibt.
So
allozierter Speicher wird niemals am Garbage Collect teilnehmen.
|SYSTEM.DISPOSE(<pointer>)|: Gibt den Speicher, auf den der •bergebene
Zeiger zeigt, wieder frei.
Der Garbage Collector wird mit Kernel.GC aufgerufen. Dies f•hrt
einen
kompletten Collect durch. Es gibt auch eine M”glichkeit, den Collect
in
kleine Teile zerhackt nebenher laufen zu lassen. Dies w•rde mit
Oberon.Collect unter Chatwin gehen. Dort sehe ich auch die einzige
sinnvolle
Anwendung. Im Moment kann ich von beidem nur abraten, da es noch nicht
ausgereift 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
Speicheranforderung genau der angeforderte Speicher alloziert wird (plus ein
Eintrag in einer Liste). Die Verwaltung der Liste hat aber so viel Zeit
ben”tigt, daž der Compiler merklich langsamer wurde. Effizienter wird das,
wenn
man den ben”tigten Speicher ein wenig aufrundet und in einem Array
unter-
bringt. Das kostet nat•rlich Speicher. Um diesen Overhead nicht zu
grož
werden zu lassen, habe ich Speicheranforderungen in 16 Klassen
unterteilt[7]. Gr”žere Objekte ab 256 Byte werden in einer Liste verwaltet.
Objekte zwischen 2 und 256 Byte werden in Arrays verwaltet, deren
Elementgr”že zwischen 16 und 256 Byte in 15 Stufen unterteilt ist.
Gegen•ber GEMDOS stellt sich die Speicherverwaltung anders dar. Dort
wird
immer mindestens 32K alloziert, so daž die Anzahl GEMDOS-Bl”cke nicht
allzu
grož wird und damit die Geschwindigkeit abnimmt. Es kann auch nicht
passieren, daž die Speicherverwaltung des GEMDOS keine Eintr„ge mehr hat.
--------------[7]
Mombergs Oberon verwendet nur 5 Klassen und hat damit mehr Overhead
14) Die Bibliotheken
====================
Die Bibliotheken erm”glichen eigentlich erst ein vern•nftiges
Programmieren
mit einer Programmiersprache. Hier soll eine šbersicht der vorhandenen
Module gegeben werden, n„here Informationen m•ssen den
Definitionsdateien
entnommen werden.
14.1) Betriebssystem
-------------------Alle Betriebssystemmodule implementieren die Aufrufe als Makros, d.h.
der
Code f•r den Trap wird beim Aufruf in den Code integriert. Es erfolgt
kein
Prozeduraufruf. Der Nachteil dieser Methode ist, daž alle Parameter in
der
Reihenfolge vertauscht sind. Der Oberon-Compiler legt den ersten
Parameter
auch als ersten auf den Stack, w„hrend C-Compiler den letzten Parameter
als
erstes auf den Stack legen.
14.1.1) BIOS
............
Die •blichen BIOS-Funktionen.
14.1.2) GEMDOS
..............
Die •blichen GEMDOS-Funktionen.
14.1.3) MiNT
............
Die neuen Funktionen unter MiNT sind eigentlich auch GEMDOS-Aufrufe.
Sie
sind aber hier separat verf•gbar. Sys.MiNT gibt an, ob MiNT
installiert
ist.
14.1.4) XBIOS
.............
Die •blichen XBIOS-Funktionen. Es fehlen Erweiterungen von TT und
Falcon,
•ber die ich keine Informationen habe.
14.2) Abstrakte Datenstrukturen
------------------------------14.2.1) BinTree
...............
BinTree implementiert einen bin„ren Baum.
BinTree wurde von H. M”ssenb”ck und Dirk Theisen geschrieben.
14.2.2) CDCL
............
CDCL steht f•r Circular Double Chained List. Es handelt sich also um
eine
doppelt verkettete Liste, deren erstes und letztes Element aufeinander
zeigen.
14.2.3) DCL
...........
DCL steht f•r Double Chained List.
doppelt
verkettete Liste.
Es handelt sich also
um
eine
14.2.4) FIFO
............
FIFO (First in first out) implementiert eine Liste, an deren Anfang
Elemente eingefgt und an deren Ende sie wieder entnommen werden k”nnen.
FIFO wurde von Dirk Theisen geschrieben.
14.2.5) LRU
...........
LRU (Least recently used) implementiert eine Priorit„tenliste
dem
Prinzip 'am l„ngsten nicht mehr benutzt zuerst'.
LRU wurde von Dirk Theisen geschrieben.
nach
14.2.6) Stack
.............
Stack implementiert eine Liste, an deren Anfang Elemente eingef•gt und
wieder 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,
Grundlage
f•r gepufferte Ausgabe dienen soll.
der als
14.3.2) CommandLine
...................
CommandLine implementiert die Auswertung eines per ARGV •bergebenen
Kommandos, 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,
Betriebssystems, •ber eine Alertbox.
insbesondere
des
14.3.7) Exceptions
..................
Exceptions f„ngt Softwarefehler wie Bus Error etc. ab und gibt eine
passende Meldung aus. Es gen•gt, Exceptions zu importieren oder mit
LINKALSO
hinzuzulinken.
14.3.8) Execute
...............
Execute ist immer dann zu verwenden, wenn man nicht genau weiž, in
welcher
Form (Modul oder Programm) etwas gestartet werden soll. Daher gibt es
ein
Execute im Lader, das Module startet, und ein kompatibles zum Linken,
das
Programme startet.
14.3.9) File
............
Hoffnungslos veraltetes Modul zur Dateibehandlung.
14.3.10) FileBuffer
...................
Ebenfalls veraltetes Modul
zwischengeschaltetem
Puffer.
zur
Dateibehandlung
mit
14.3.11) Filename
.................
Zusammensetzen und Aufteilen von Dateinamen.
14.3.12) IO
...........
IO implementiert Standardprozeduren zur Ein- und Ausgabe auf dem TOSBildschirm. 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,
CLIFenster von Chatwin umlenkt.
daž die Ausgabe in das
14.3.13) Kernel
...............
Kernel stellt haupts„chlich die
einige
Hilfsprozeduren zur Verf•gung.
Speicherverwaltung,
aber
auch
14.3.14) Key
............
War mal die Grundlage f•r die Zuweisung
Tastenkombinationen. Wird im Moment nicht benutzt.
von
Prozeduren
zu
14.3.15) MathCom
................
Grundlegende Prozeduren f•r mathematische Funktionen. Entstammt LPRModula.
14.3.16) MathLib0
.................
šbliche mathematische Funktionen. Entstammt LPR-Modula.
14.3.17) Memory
...............
Sehr schnelle Prozeduren zum Kopieren und F•llen von Speicher.
14.3.18) Modules
................
Modules ist fr das Nachladen von Modulen in den Ladern zust„ndig.
14.3.19) MVC
............
MVC steht f•r Model View Controller. Es implementiert Viewer, deren
Ausgabe
vom Inhalt eines Models abh„ngen. WinView baut darauf auf. Theoretisch
ist
es aber nicht an Fenster gebunden, man k”nnte auch Pseudofenster auf
einem
TOS-Bildschirm darauf aufbauen.
14.3.20) NumStr
...............
Umwandlung von Zahlen in Strings und umgekehrt.
14.3.21) Paths
..............
Suchpfadverwaltung.
14.3.22) Strings
................
Was man so braucht um mit Strings umzugehen.
14.3.23) Supervisor
...................
Ein- und Ausschalten des Supervisormodus.
14.3.24) Sys
............
Die Grundlage aller Programme. Enth„lt alle Standardfunktionen des
Compilers sowie die Programminitialisierung.
14.3.25) Task
.............
Enth„lt den Mechanismus zur sauberen Terminierung von Programmen oder
Programmteilen. Normalerweise uninteressant f•r Anwender.
14.3.26) VA
...........
VA enth„lt die Konstanten,
Venus)
ben”tigt werden.
die f•r das AV-Protokoll (Accessory <->
14.4) VDI-Module
---------------Das VDI implementiert alles zur Ausgabe auf beliebigen Ger„ten. Es ist
mir
nicht bekannt, ob es auch in TOS-Programmen benutzt werden darf.
14.4.1) VDI
...........
Die grundlegenden Strukturen und Variablen zur Arbeit mit dem VDI.
14.4.2) VDIAttributes
.....................
Einstellen von Attributen f•r die Ausgabe.
14.4.3) VDIControl
..................
Kontrollfunktionen des VDI. Es existiert
zum
Test, ob GDOS installiert ist.
eine
zus„tzliche
Funktion
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:
Men•s, Fenster und und und. Bis auf Form.Alert f•hren diese Prozeduren in
einem 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.
Programmen
verwendet werden.
Form.Alert darf
auch
in
TOS-
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
darzustellen und den Dialog mit dem Anwender zu f•hren.
eine
Dialogbox
14.6.2) FontSelect
..................
FontSelect bietet eine einfache M”glichkeit, mit einer Dialogbox den
Benutzer einen Font ausw„hlen zu lassen.
14.6.3) GemApp
..............
GemApp bildet die Grundlage zur Programmierung von GEM-Applikationen.
Es
muž unbedingt benutzt werden, wenn die erweiterten AES-Module
verwendet
werden.
14.6.4) GEMIO
.............
GEMIO ist das Pendant zu IO f•r TOS. Die Schnittstellen sind identisch,
so
daž man statt IO auch GEMIO linken kann.
14.6.5) Menus
.............
Menus automatisiert den Aufruf von Prozeduren •ber Men•punkte oder
Tastenkombinationen. Die Tastenkombinationen werden aus dem Eintrag des Men•s
gelesen und k”nnen dadurch von Benutzern individuell ge„ndert werden!
14.6.6) TermWin
...............
TermWin erweitert WinView derart, daž mit •blichen Schreibbefehlen
(WriteString...) Text in einem Fenster ausgegeben werden kann. Desweiteren
wird
ein Event STRING eingef•hrt.
14.6.7) WindowDialog
....................
WindowDialog verlegt einen Dialog in ein Fenster.
14.6.8) WinView
...............
WinView ist die Grundlage f•r Fensterapplikationen. Fast das gesamte
Handling von Fensters ist automatisiert. Im einfachsten Fall muž man nur
noch
eine Redrawprozedur implementieren.
15) Tutorial
============
Im nun folgenden Kapitel soll ein GEM-Programm entwickelt werden, daž
eine
Menleiste hat, ber einen Dialog in einem Fenster Eingaben erm”glicht
und
diese Eingaben graphisch in beliebig vielen Fenstern ausgeben kann.
Eine
neue Eingabe muž dann nat•rlich in allen Fenstern gezeichnet werden.
15.1) Die Resourcedatei
----------------------Die Resourcedatei wird mit einem Resource Construction Set erstellt.
Die
Resourcedatei fr unser Projekt heižt GEMDEMO.RSC. Wer noch nie eine
Resourcedatei erzeugt hat, sollte sich erstmal mit einem RCS
GEMDEMO.RSCangucken und mal etwas damit spielen. Aber bitte nicht ver„ndert
abspeichern
und mir dann eine Mail schicken, das Demo w•rde nicht funktionieren!
15.2) Der Rumpf
--------------[hbpt]
MODULE Tutor1;
IMPORT GemApp;
VAR
myApp : GemApp.Application;
BEGIN
NEW( myApp);
myApp.Init; myApp.Run; myApp.Exit
END Tutor1.
Abb. ?? zeigt den prinzipiellen Aufbau einer Applikation: Definition
einer Variablen vom Typ Application, deren Initialisierung und Aufruf
der
daran gebundenen Prozeduren Init, Run und Exit. Init initialisiert das
Programm. Dazu geh”rt z.B. die Anmeldung beim AES. Run implementiert
die
Event-Schleife, also warten auf Events vom AES und Aufruf von
HandleEvent,
das ebenfalls an Application gebunden ist. Exit meldet die Applikation
dann
wieder ab und sorgt auch f•r eine saubere Terminierung, z.B.
Schliežen
evtl. offen gebliebener Fenster etc. Sollte jemand dieses Programm
starten,
wird er in die Eventschleife gelangen. Diese kann mit ControlQverlassen
werden, diese Taste wird immer ausgewertet.
15.3) Resourcedatei laden
------------------------Als n„chstes m•ssen wir die Resourcedatei laden. Abb. ?? zeigt die
Erweiterungen.
[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
erstes die geerbte Prozedur Init aufrufen. Als n„chstes wird der
Mauszeiger
als Pfeil dargstellt, da er beim Programmstart immer auf 'Biene' steht.
Der
Aufruf von Rsrc.Load bewirkt das Laden und evtl. auch Suchen der
Resource-
datei. Wenn der Benutzer in der Fileselectbox 'Abbruch' anklickt,
gibt
Rsrc.Load FALSE zur•ck und die Applikation wird terminiert. app.Exit
wird
nicht mehr verlassen, deshalb geht das. Wenn man das Programm startet,
verh„lt es sich wie Tutor1, nur daž die Maus auf Pfeil umgeschaltet wird.
15.4) Die Men•zeile
------------------Nun wollen wir die Men•zeile anzeigen.
von
Init.
Abb. ?? zeigt die
Erweiterung
[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
empfiehlt es sich, eine Prozedur f•r den Men•punkt QUIT anzumelden, damit
man
das Programm auch wieder verlassen kann. Dann kann man mit menu.Show
die
Men•zeile darstellen.
Beim Start werden sie feststellen, daž sowohl beim Anklicken von
'Quit'
als auch bei Dr•cken von Control-Qdas Programm verlassen wird. Wie
funktioniert das? Ganz einfach: Menus hat mit GemApp.StoreEventHandler eine
Prozedur angemeldet, die Events verarbeitet. Diese wird immer aufgerufen,
wenn
ein Ereignis vom AES gemeldet wird, und filtert die Ereignisse heraus,
die
fr das Men ben”tigt werden.
15.5) Ein Fenster ”ffnen
-----------------------Beim Aufruf des Men•punktes 'Ausgabefenster' soll nun ein Fenster
ge”ffnet
werden. Der Einfachheit halber wird es nur eine weiže Fl„che
darstellen.
Abb. ?? zeigt die Žnderungen.
TYPE
Viewer
ViewDesc
= POINTER TO ViewDesc;
= RECORD(WinView.ViewDesc)
END;
MyModel
= POINTER TO ModelDesc;
ModelDesc = RECORD(MVC.ModelDesc)
END;
VAR
myModel : MyModel;
Station : INTEGER;
Workout : VC.workout;
PROCEDURE(v : Viewer) Redraw(x,y,w,h : INTEGER);
VAR x2, y2 : INTEGER;
BEGIN
x2 := x+w-1; y2 := y+h-1;
VC.VsClip( Station, TRUE, x, y, x2, y2);
VO.VBar( Station, x, y, x2, y2 );
END Redraw;
PROCEDURE OpenOutput;
VAR outWin : Viewer;
BEGIN
NEW( outWin); outWin.Init;
outWin.model := myModel;
outWin.SetTitle("Objektfenster");
outWin.SetFullSize( 0, 19, Workout.MaxX - 1,
Workout.MaxY - 20);
outWin.Open;
END OpenOutput;
PROCEDURE (app : Application) Init;
VAR Workin : VC.workin;
menu : Menus.Menu;
BEGIN
[...]
NEW( menu); menu.Init( Rsrc.GetAddr(MENU) );
menu.Set( FILE, QUIT, Exit );
menu.Set( DESK, INFO, ShowInfo );
menu.Set( WORK, OUTPUT2, OpenOutput );
menu.Show;
Station := 1;
Workin.Id := 1; Workin.LineType := 1;
Workin.LineColor := 1; Workin.MarkType := 1;
Workin.MarkColor := 1; Workin.Font := 1;
Workin.TextColor := 1; Workin.FillStyle := 0;
Workin.FillPat := 0; Workin.FillColor := 1;
Workin.KoorType := 2;
VC.VOpnvwk(Workin,Station,Workout);
VA.VswrMode(Station,VA.REPLACE);
VA.VsfPerimeter(Station,FALSE);
NEW( myModel); myModel.Init;
END Init;
[hbpt]
Zun„chst wird die Prozedur OpenOutput f•r den Men•punkt angemeldet.
Es
folgt die ™ffnung einer virtuellen Workstation, die zum Zeichnen des
Fensterinhaltes ben”tigt wird. Als letztes wird noch ein Model
initialisiert,
das sp„ter die Daten fr die Ausgabefenster aufnimmt. OpenOutput muž
ein
Fenster initialisieren, das Model, Titel und maximale Gr”že festlegen.
Dann
kann es ge”ffnet werden. outWin ist tats„chlich eine lokale Variable!
Wie
das gehen soll? Ganz einfach, die Verwaltung der Fenster •bernimmt
WinView!
Das einzige, was wir noch machen m•ssen, ist den Inhalt neuzeichnen.
Dies
•bernimmt die Prozedur Redraw, die an einen Typ Viewer gebunden werden
muž.
Diese wird von WinView immer automatisch aufgerufen, wenn das AES eine
Redraw-Message verschickt. Die Ereignisse, die Fenster betreffen, werden
wieder durch einen EventHandler bearbeitet, der bei GemApp angemeldet
wurde.
Deshalb funktionieren auch Mover, Closer, Fuller etc. ohne das wir
uns
darum gek•mmert haben!
15.6) Einen Dialog darstellen
----------------------------Nun wollen wir einen Dialog mit dem Benutzer in einem Fenster
Die
Žnderungen sind in Abb. ?? skizziert.
f•hren.
[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
Objektbaum mitgeteilt. Mit SetWork werden den Buttons im Dialog, die den
Status 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
OK
INPUT1
OUTPUT1
=
=
=
=
0;
4;
5;
6;
MENU
DESK
FILE
WORK
INFO
QUIT
INPUT2
OUTPUT2
=
=
=
=
=
=
=
=
1; (* menu *)
3; (* TITLE in tree MENU *)
4; (* TITLE in tree MENU *)
5; (* TITLE in tree MENU *)
8; (* STRING in tree MENU *)
17; (* STRING in tree MENU *)
19; (* STRING in tree MENU *)
20; (* STRING in tree MENU *)
INPUTBOX
CIRCLE
RECT
XPOS
YPOS
RADIUS
WIDTH
HEIGHT
DRAW
=
=
=
=
=
=
=
=
=
2;
2;
3;
4;
5;
6;
7;
8;
9;
TYPE
Viewer
ViewDesc
(*
(*
(*
(*
(*
(*
(*
(*
(*
(*
(*
(*
(*
form/dialog *)
BUTTON in tree BOX *)
BUTTON in tree BOX *)
BUTTON in tree BOX *)
form/dialog *)
BUTTON in tree INPUTBOX *)
BUTTON in tree INPUTBOX *)
FTEXT in tree INPUTBOX *)
FTEXT in tree INPUTBOX *)
FTEXT in tree INPUTBOX *)
FTEXT in tree INPUTBOX *)
FTEXT in tree INPUTBOX *)
BUTTON in tree INPUTBOX *)
= POINTER TO 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
RectDesc
= POINTER TO 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.
EnableRect 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
eingegebenen 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.
Fenster
kann nat•rlich einen anderen Ausschnitt darstellen.
Aber
jedes
15.8) Zusammenfassung
--------------------Dieses Kapitel sollte einige M”glichkeiten von Oberon und der
Module
zeigen. Das Ergebnis war ein 300 Zeilen langes Programm, daž
hoffentlich
einen guten Eindruck hinterlassen hat.
GEM-
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>
Addison-Wesley (1991), ISBN 0-201-54422-9.
M. Reiser, N. Wirth: <Programming in Oberon:
and
Modula>, Addison-Wesley (1992)
Steps beyond
Pascal
16.2) Danksagungen
-----------------Dank an Frank Storm, der mich darauf gebracht hat, statt einem Modulaeinen Oberon-Compiler zu schreiben und anfangs auch die E-Mail erledigt
hat.
Dank an den Chefbetatester Dirk Theisen f•r den Browser und sonstige
Unterst•tzung.
Dank an alle, die •ber Fehler berichten und neue Module implementieren.
Dank an Christian Strunk f•r seine TeX-Implementierung.
Dank an Roman Hodek f•r TeX2TXT, mit dem diese Anleitung in einen ganz
passablen Asciitext konvertiert werden konnte.
Ach ja,
dan-
dann sollte ich wohl auch noch Niklaus Wirth und seinem Team
ken, daž er Oberon erdacht hat und die Sourcen frei weitergibt.
Herunterladen