home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
mod201j.zip
/
modula2.exe
/
os2doc
/
mod-gr.inf
(
.txt
)
< prev
next >
Wrap
OS/2 Help File
|
1996-03-29
|
221KB
|
6,299 lines
ΓòÉΓòÉΓòÉ 1. Hinweise zu dieser Version ΓòÉΓòÉΓòÉ
Willkommen zu dieser Beta-Version 2.01J. Dieser Ъbersetzer ist Betaware. Diese
Software ist keine Shareware und auch keine Freeware!
Bitte lesen Sie die folgenden Sektionen BEVOR Sie den Ъbersetzer benutzen:
- Lizenz-Vereinbarung
- Kontakte zum Autor
- Was noch zu tun ist
ΓòÉΓòÉΓòÉ 1.1. Lizenz-Vereinbarung ΓòÉΓòÉΓòÉ
WENN SIE DIESES PROGRAMM KOPIEREN ODER NUTZEN,ERKLОREN SIE SICH MIT DEN
FOLGENDEN NUTZUNGSBEDINGUNGEN EINVERSTANDEN.
Der Autor БberlДсt Ihnen das Recht,"Canterbury-MODULA-2 Beta 2.01J" als ein
Beta-Tester zu nutzen. Dieses Paket enthДlt Programme, Quelltexte und
Dokumentation, im folgendem als "die Programme" bezeichnet. Die Programme sind
Demo- bzw. Beta-Test Versionen. Die Programme sind somit in Ihrem
Nutzungsumfang eingeschrДnkt. Die Vollversion kann stark von dieser
Demo-Version abweichen.
Die Programme sind urheberrechtlich geschБtzt. Weitergehende Rechte als die,wie
sie hier festgehalten sind, werden nicht Бbertragen. Wenn Sie mit den folgenden
Nutzungsbestimmungen ganz oder teilweise nicht einverstanden sind, erlischt die
Nutzungserlaubnis der Programme.
Die Nutzung wird unter folgenden Vorraussetzungen gewДhrt:
1. Sie kФnnen die Programme auf einer oder mehreren Maschinen nutzen.
2. Sie kФnnen fБr Backup-Zwecke Kopien der Programme anlegen.
3. Und Sie kФnnen Kopien der Original-Dateien an Dritte weitergeben,
vorrausgesetzt, dass eine Kopie dieser Lizenzvereinbaring ebenfalls
weitergegeben wird und der EmpfДnger ausdrБcklich auf die hier
genannten Bestimmungen hingewiesen wurde.
Jede Kopie oder Teilkopie der Programme muс den Original Copyright Vermerk
enthalten.
Auf keinen Fall dБrfen Sie:
1. Die Programme vermieten oder verleasen.
2. Die Programme decompilieren, reassemblieren oder auf sonstige Weise
rБckБbersetzen.
3. Die Programme fБr militДrische Zwecke nutzen.
Der Autor ist auf keinen Fall verantwortlich fБr:
1. Klagen Dritter gegen Sie wegen SchДden oder Verlusten
2. Datenverlust oder
3. Щkonomische SchДden, selbst wenn der Autor sich deren MФglichkeit
bewuсt ist.
Sollten Teile dieser Lizenzvereinbaring juristisch anfechtbar sein, so
beeinflussen sie nicht die Geltung der gesamten Vereinbarung.
Der Autor garantiert kein fehlerfreies Arbeiten der Programme.
WENN SIE DIESES PROGRAMM KOPIEREN ODER NUTZEN, ERKLОREN SIE SICH MIT DEN
NUTZUNGSBEDINGUNGEN EINVERSTANDEN.
DER AUTOR ЪBERNIMMT KEINERLEI HAFTUNGEN, WEDER AUSDRЪCKLICH NOCH IM
BESONDEREN FЪR DIE EIGNUNG DIESER PROGRAMME FЪR EINEN BESTIMMTEN ZWECK.
Sie kФnnen diese Lizenzvereinbarung zu jeder Zeit kБndigen. Der Autor kann
diese Lizenzvereinbarung aufheben, wenn Sie gegen die Bestimmungen, wie sie
hier festgehalten sind, verstoсen, oder aber, sobald die Vollversion dieses
Programmpaketes erscheint. In allen FДllen mБssen Sie alle Kopien der
Programme vernichten und sind nicht lДnger berechtigt, die Programme zu
nutzen.
Sie kФnnen die Rechte an dieser Lizenzvereinbarung nicht teilweise an
Dritte weitergeben. Eine Weitergabe ist nur in Verbindung mit dem gesamten
Programmpaket mФglich. In diesem Fall mБssen Sie alle Kopien der Programme
vernichten.
Diese Lizenzvereinbarung beruht auf dem Recht des Landes, in welchem Sie
das Programmpaket erwerben.
ΓòÉΓòÉΓòÉ 1.2. Kontakte zum Autor ΓòÉΓòÉΓòÉ
Bitte fБhlen Sie sich frei, Fehlerhinweise, Kommentare oder
VerbesserungsvorschlДge an den Autor Juergen Neuhoff zu senden. Am schnellsten
geht das via CompuServe E-Mail (dies ist auch die bevorzugte Art):
CompuServe 76721,303
Dieser Compiler wird demnДchst von folgender Firma vermarktet:
Mill Hill & Canterbury Group, Ltd.
P.O. BOX 1277
Peralta NM 87042
U.S.A.
CompuServe 73261,1622
Falls Sie diese Software aus einer CompuServe Forum-Bibliothek herunterluden,
kФnnen Sie auch Фffentliche Nachrichten zum Forum senden. Dadurch kФnnen auch
andere Beta-Tester aus Ihren Erfahrungen Nutzen ziehen.
ΓòÉΓòÉΓòÉ 1.3. Was noch zu tun ist ΓòÉΓòÉΓòÉ
Dieser Compiler ist noch eine frБhe Beta-Fassung. Deshalb gibt es noch viele
Dinge zu tun. KБnftige Versionen mФgen z.B. folgendes hinzubekommen:
- Volle symbolische Debugger-UnterstБtzung fБr IPMD oder SD386:
Dieser Compiler genereriert volle HLL3-kompatible Debug-Infos.
Diese sollten laut IBM sowohl von SD386 als auch von IPMD
unterstБtzt werden. Leider sind beide IBM Debugger fehlerhaft.
Diese Version unterstБtzt Source-Line-Level Debugging und fБr
SD386 (3.04) teilweise Symbole.
- Fehlerkorrekturen
- "Direct-to-SOM" Feature
- Modula-2 nach IDL Umwandlung
- Klassen-Bibliotheken
- IDE und/oder engere Integration in die WPS
Eine IDE wird gegenwДrtig entwickelt.
- Modula-Дhnliche Resourcen-Editoren
Ein visualler Interface Designer wird fБr M2 adaptiert.
- COMPLEX Datentyp
- BereichsБberprБfung wДhrend Laufzeit
- 32-16-Bit-Schnittstelle fБr fremde Bibliotheken
mit verschiedenen Namen und/oder Linker-Konventionen
- Assembler-Listing
═══ 2. EinfБhrung ═══
Modula-2 ist eine allgemeine Programmiersprache, welche von Pascal
weiterentwickelt wurde. Wie der Name 'Modula' es schon andeutet, ist das
Modul-Konzept ein bedeutendes Merkmal dieser Programmiersprache. Von Pascal ist
eine revidierte, systematischere Synatx Бbernommen worden. Dies schliesst
insbesondere Datenstrukturen wie zum Beispiel Reihungen, Verbunde, Varianten,
Mengen und Zeiger ein. Strukturierte Anweisungen schliessen u.a. die vertrauten
if-, case-, repeat-, while-, for-, und with-Anweisungen ein.
Dieser SprachБbersetzer ist eine Implementierung von Modula-2 fБr OS/2 2.x/3.0.
Er basiert auf den Beschreibungen des Buches 'Programmierung in Modula-2' von
N.Wirth, vierte Ausgabe. Diese Dokumentation ist nicht als eine EinfБhrung in
die Programmierung gedacht. Sie ist daher absichtlich knapp gehalten, weil sie
nur als eine Referenz dienen soll. Dieser Modula-2-Ъbersetzer ist fБr jene
Programmierer gedacht, welche effiziente Software schreiben mФchten, die unter
dem Betriebssystem OS/2 2.x/3.0 laufen soll.
ΓòÉΓòÉΓòÉ 2.1. Ein erstes Beispiel ΓòÉΓòÉΓòÉ
Dieser SprachБbersetzer ist eine OS/2 - Anwendung im Textmodus. Er wird von der
Kommandozeile in einem OS/2-Gesamtbildschirm oder einem OS/2-Textfenster
gestartet. Er kann weder unter DOS oder dem Presentation Manager laufen. Der
SprachБbersetzer wird durch Eintippen des Befehls 'MOD' aufgerufen.
Als Beispiel wollen wir ein einfaches Programm nehmen, welches nichts weiter
als die Anzeige einer Nachricht 'Hallo Welt' bewirkt. Der OS/2 2.x/3.0
System-Editor kann benutzt werden, um eine entsprechende Quelldatei in Modula-2
zu erstellen. Der Inhalt solch einer Quelldatei mag in etwa folgendermassen
aussehen:
MODULE HELLO;
IMPORT InOut;
BEGIN
InOut.WriteString( "Hallo Welt" );
InOut.WriteLn();
END HELLO.
Tippen Sie folgende Befehle ein, um dieses Programmbeispiel erstellen,
Бbersetzen, binden, und schliesslich ablaufen lassen zu kФnnen, und zwar von
einem OS/2 Gesamtbildschirm oder von einem Textfenster:
E HELLO.MOD <enter>
MOD HELLO -o -m -p <enter>
LINK386 @HELLO.RSP <enter>
HELLO <enter>
Die Ausgabe von dem Beispielprogramm sieht wie folgt aus:
Hallo Welt
Die notwendige Antwortdatei HELLO.RSP fБr den Binder wird automatisch vom
Modula-2 Ъbersetzer erstellt. Dies wird durch den '-m' -Schalter bewirkt. Der
Ъbersetzer erstellt Objekt-Dateien in einem Format, welches fБr das OS/2
2.x/3.0 Binder-Programm LINK386.EXE verwertbar ist. LINK386.EXE erzeugt
schliesslich die ausfБhrbare Programmdatei HELLO.EXE. Der Befehlsschalter '-p'
bewirkt eine ausfБhrliche Bildschirmprotokollierung aller zu Бbersetzenden
Programmtexte einschliesslich mФglicher Fehlermeldungen mit Aufforderungen zur
Antwort. Der Schalter '-o' veranlasst den Ъbersetzer, eine volle
Code-Optimierung durchzufБhren.
═══ 2.2. Merkmale der Ъbersetzer-Version 2.01 ═══
Dieser Ъbersetzer bietet die folgenden Hauptmerkmale:
- Ziel-Betriebssystem:
- 32-bit OS/2 2.x/3.0
- 16-bit OS/2 1.x
- 16-bit MS-Windows 3.x
- 16-bit DOS
Anmerkung: Die Modula-Bibliotheken sind zur Zeit nur
fБr 32-bit OS/2 2.x/3.0 verfБgbar. ZukБnftige Versionen werden
auch die Bibliothken fБr die anderen Zielsysteme enthalten.
- Ausgabedateien vom Ъbersetzer:
- 16- oder 32-bit Objekt-Dateien, verwendbar fБr
LINK.EXE oder LINK386.EXE.
- Antwortdatei(en) fБr den Binder
- Definitionsdateien fБr den Binder
- Integrierte 'Make' oder 'Build' -Einrichtung:
- 'Make' Бbersetzt auch geДnderte, abhДngige Module.
- 'Build' Бbersetzt auch alle abhДngige Module.
- Elementare Typen und Funktionen mit verschiedenen GrФssen:
- 1-, 2- und 4-byte 'cardinal'- und 'integer' -Typen
- 4- und 8-byte 'real' -Typen
- Mengentypen mit bis zu 256 Elementen:
- z.B. TYPE CharSet = SET OF CHAR;
- MДchtige Spracherweiterungen:
- Unterstreichungszeichen '_' erlaubt fБr Namen
(wie in OS/2 APIs)
- Bitweise Operatoren 'AND' 'OR' 'XOR' 'SHL' 'SHR' 'NOT'
- Neuer logischer Operator 'XOR'
- Objekt-Orientierung Дhnlich der Sprache Oberon
- System Object Model unter OS/2 unterstБtzt
- Initialisierte Variablen, ausgedrБckt als typisierte Konstanten
- Multidimensionale offene Reihungen
- Symbolischer INLINE Assemblierer
- NEAR oder FAR SchlБsselwФrter fБr
INTEL 80x86 Segmentierung
- Erweiterte Importe
- Entwicklung dynamischer Binder-Bibliotheken fБr OS/2 2.x/3.0
- Definitions-Module fБr externe .OBJ .DLL .LIB -Dateien
- OS/2 2.x/3.0 Schnittstelle fБr Control Program
- OS/2 2.x/3.0 Schnittstelle fБr Graphics Program
- OS/2 2.x/3.0 Schnittstelle fБr Presentation Manager
- OS/2 2.x/3.0 Schnittstelle fБr Workplace Shell
- OS/2 2.x/3.0 Schnittstelle fБr Tastatur
- OS/2 2.x/3.0 Schnittstelle fБr Bildschirm
- OS/2 2.x/3.0 Schnittstelle fБr Maus
ΓòÉΓòÉΓòÉ 3. Syntax ΓòÉΓòÉΓòÉ
Eine Sprache ist eine unbegrenzte Menge von SДtzen, wobei diese nach den Regeln
der Sprachsyntax geformt sein mБssen. In Modula-2 werden diese SДtze insgesamt
als Ъbersetzungseinheit bezeichnet. Jede Ъbersetzungseinheit besteht aus einem
Progamm- oder Definitions- Modul und wird in einer Quellendatei gespeichert.
Jede Einheit ist eine endliche Sequenz von Symbolen aus einem endlichen
Vokabular. Das Vokabular von Modula-2 besteht aus Namen, Zahlen, Zeichenketten,
Operatoren, Begrenzern und Kommentaren. Sie werden lexikalische Symbole genannt
und bestehen aus Zeichensequenzen.
Zur Beschreibung der Sprachsyntax wird ein Formalismus in Anlehnung an
Backus-Naur gebraucht. Die eckigen Klammern '[' und ']' geben eine optionalen
syntaktischen Eintrag an, und die geschweiften Klammern '{' und '}' geben deren
wiederholten Eintrag an (null oder mehr). Ein '|' Zeichen bedeutet eine Wahl
zwischen zwei EintrДgen. Syntaktische EintrДge werden von der Menge der
lexikalischen Modula-2 -Symbole gebildet. Sie werden als nicht-terminierende
Symbole bezeichnet und werden durch englische WФrter angegeben, um ihre
intuitative Bedeutung auszudrБcken. Die Symbole vom Vokabular der Sprache
selbst, die sogenannten terminierenden Symbole, werden durch in
AnfБhrungszeichen eingeschlossene Zeichenketten oder durch WФrter in
Grossbuchstaben, den sogenannten reservierten WФrtern, angegeben.
Nicht-terminierende Symbole werden aus terminierenden und nicht-terminierenden
Symbolen gebildet. Dabei werden Produktionen nach festen syntaktischen Regeln
benutzt. Produktionen werden durch das Gleichheitszeichen '=' angedeutet.
Beispiel 1:
Decl = VAR { VarDecl ";" }
Eine Deklaration (Decl) fДngt mit dem reservierten SchlБsselwort VAR an und
wird von einer (mФglicherwiese leeren) Liste von Variable-Deklarationen
(VarDecl), getrennt durch Semikolons, gefolgt.
Beispiel 2:
Stmt = RETURN [ Expr ] | EXIT
Eine Anweisung (Stmt) kann aus einem RETURN bestehen, welcher mФglicherweise
durch einen Ausdruck (Expr) gefolgt wird. Oder sie kann aus einem EXIT
bestehen.
ΓòÉΓòÉΓòÉ 4. Vokabular und dessen Darstellung ΓòÉΓòÉΓòÉ
Die Darstellung von Symbolen geschieht durch definierte Zeichen aus dem
ASCII-Zeichensatz. Symbole bestehen aus Namen, Zahlen, Zeichenketten,
Zeichen-Konstanten, Operatoren und Begrenzern, und Kommentaren. Leerzeichen
sowie ZeilenumbrБche dБrfen nicht innerhalb von Symbolen erscheinen ( ausser in
Kommentaren, und im Falle von Leerzeichen auch in Zeichenketten ). Sie werden
gewФhnlich ignoriert, es sei denn, sie werden zur Trennung zweier
aufeinanderfolgender Symbole gebraucht. Gross- und Klein-Buchstaben werden als
unterschiedlich betrachtet.
ΓòÉΓòÉΓòÉ 4.1. Namen ΓòÉΓòÉΓòÉ
ΓûÉ Ident = FirstLetter { "_" | Letter | Digit }
ΓûÉ FirstLetter = "_" | Letter
Namen (Identifiers) sind Folgen von Buchstaben und Ziffern. Das erste Zeichen
darf jedoch nicht aus einer Ziffer bestehen. Wenn die Spracherweiterungen
akitiviert sind, dann ist auch das Unterstreichungszeichen '_' fБr Namen
erlaubt. Dieses wird manchmal fБr Namen von OS/2 2.x/3.0 APIs benФtigt.
Ansonsten sollte sich der Programmierer davon zurБckhalten, freizБgig vom
Unterstreichungszeichen Gebrauch zu machen fБr seine eigenen Namen.
Beispiele beinhalten:
x scan Modula GetSymbol
Beispiele mit erlaubten Unterstreichnungszeichen:
FILE_READONLY OPEN_SHARE_DENYWRITE vector_graphics
ΓòÉΓòÉΓòÉ 4.2. Zahlen ΓòÉΓòÉΓòÉ
ΓûÉ Number = Integer | Real
ΓûÉ Integer = Digit { Digit } | OctalDigit { OctalDigit } "B" |
ΓûÉ Digit { HexDigit } "H"
ΓûÉ Real = Digit { Digit } "." { Digit } [ ScaleFactor ]
ΓûÉ ScaleFactor = "E" [ "+" | "-" ] Digit { Digit }
ΓûÉ HexDigit = Digit | "A" | "B" | "C" | "D" | "E" | "F"
ΓûÉ Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
ΓûÉ OctalDigit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7"
Zahlen sind vorzeichenlose ganze Zahlen (Integer) und Gleitkommawerte (Real).
Ganze Zahlen sind Folgen von Ziffern. Wird die Zahl von dem Buchstaben 'B'
gefolgt, dann handelt es sich um eine Oktalzahl; Wenn sie von dem Buchstaben
'H' gefolgt wird, handelt es sich um eine hexadezimale Zahl.
Der angenommene Typ einer ganzen Zahl wird aus den folgenden Wertebereichen
ermittelt:
SHORTINT 0 ............ 127
INTEGER 128 ......... 32 767
LONGINT 32 768 .. 2 147 483 647
SHORTCARD 0 ............ 255
CARDINAL 255 ......... 65 535
LONGCARD 65 536 .. 4 294 967 296
Das bedeutet, dass ein gegebener Wert 1 oder 2 Typen haben kann. Der Wert 128
zum Beispiel besteht sowohl aus dem Typ INTEGER als auch aus dem Typ SHORTCARD.
Das sieht komplizierter aus als es tatsДchlich ist, weil SHORTINT und INTEGER
und LONGINT untereinander kompatibel sind, und SHORTCARD und CARDINAL und
LONGCARD ebenfalls untereinander kompatibel sind.
Eine Gleitkommazahl besteht aus einer Folge von Dezimalziffern mit einem
Dezimalpunkt. Sie kann von einem dezimalen Skalierungsfaktor gefolgt werden.
Der Skalierungsfaktor wird durch den Buchstaben 'E' eingefБhrt und einem
mФglichen '+' oder '-' -Zeichen, gefolgt von den eigentlichen Ziffern des
Skalierungsfaktors. Der einfБhrende Buchstabe 'E' ist als Zehnerexponent zu
verstehen. Eine Gleitkommazahl wird intern immer als LONGREAL gespeichert. Der
dezimale Wertebereich und die Genauigkeit sind fБr bis zu 15 signifikante
Stellen und einer Zehnerpotenz im Bereich von -307 bis +308 garantiert. Sind
nur bis zu 6 signifikante Stellen und eine Zehnerpotenz im Bereich von -37 bis
+38 vorhanden, dann kann die Gleitkommazahl auch als SHORTREAL behandelt
werden.
Beispiele fБr ganze Zahlem:
1980 3764B 7BCH 0FFFFFFFFH
Beispiele fБr Gleitkommazahlen:
123456789012.345E-307 12345. 12.3
ΓòÉΓòÉΓòÉ 4.3. Zeichenketten ΓòÉΓòÉΓòÉ
ΓûÉ String = "'" { Character } "'" | """ { Character } """
Zeichenketten bestehen aus Folgen von Zeichen, welche in AnfБhrungszeichen
eingeschlossen sind. Die AnfБhrungszeichen kФnnen doppelt oder einfach sein.
Die Фffnenden und abschliessenden AnfБhrungszeichen mБssen sich jedoch
gleichen, und sie dБrfen nicht innerhalb der Zeichenkette erscheinen. Eine
Zeichenkette kann nicht auf der nДchsten Zeile fortgesetzt werden. Dieser
Ъbersetzer fБgt immer ein abschliessendes Null-Zeichen an den internen Speicher
fБr die Zeichenkette an, obwohl dies nicht explizit vorgeschrieben wird im
Wirth'schen Standard. Eine Zeichenkette namens 's' kann einer Reihung 'a',
bestehend aus Zeichen, zugewiesen werden, vorrausgesetzt, die LДnge von 's' ist
strikt kleiner als die Anzahl der Elemente von 'a'. Dadurch wird
sichergestellt, dass das interne abschliessende Null-Zeichen immer dem
resultierenden 'a' angehДngt werden kann. Der Zweck ist die Vereinfachung von
mФglichen Tests nach dem Ende einer Zeichenkette.
Beispiele fБr Zeichenketten:
"MODULA" "Don't worry" 'codeword "Barbarossa"'
ΓòÉΓòÉΓòÉ 4.4. Zeichen ΓòÉΓòÉΓòÉ
ΓûÉ CharConst = "'" Character "'" |
ΓûÉ OctalDigit { OctalDigit } "C" |
ΓûÉ Digit { HexDigit } "X"
Eine Zeichenkonstante stellt ein ASCII-Zeichen dar. Sie werden entweder durch
ein einzelnes Zeichen angegeben, welches in einfachen AnfБhrungszeichen
eingeschlossen wird, oder durch die Ordnungszahl des Zeichens in oktaler
Schreibweise, gefolgt durch den Buchstaben 'C'. Wenn die Spracherweiterungen
aktiviert sind, erlaubt dieser Ъbersetzer auch eine hexadizimale Schreibweise,
gefolgt vom Buchstaben 'X', fБr die Ordnungszahl des Zeichens. Das tatsДchliche
Aussehen und die Bedeutung der einzelnen Zeichen hДngen von den aktiven OS/2
2.x/3.0 Code-Seiten und Schrifttypen ab.
ΓòÉΓòÉΓòÉ 4.5. Operatoren und Begrenzer ΓòÉΓòÉΓòÉ
Zu den Operatoren und Begrenzern gehФren Sonderzeichen, Zeichenpaare und
reservierte WФrter. Die reservierten WФrter bestehen ausschliesslich aus
Grossbuchstaben und dБrfen nicht die Rolle von Namen Бbernehmen. Die Symbole
'#' and '<>' haben die gleiche Bedeutung, desgleichen '&' und 'AND', sowie '~'
und 'NOT'.
ΓòÉΓòÉΓòÉ 4.5.1. Sonderzeichen ΓòÉΓòÉΓòÉ
+ - * / & | ~
. , ; ^ .. : :=
= # < > <> <= >=
( ) [ ] { }
" '
═══ 4.5.2. Reservierte WФrter ═══
Die folgenden Namen werden als reservierte WФrter behandelt. Sie kФnnen nicht
fБr Benutzernamen verwendet werden.
AND DO IF OF SET
ARRAY ELSE IMPLEMENTATION OR THEN
BEGIN ELSIF IMPORT POINTER TO
BY END IN PROCEDURE TYPE
CASE EXIT LOOP QUALIFIED UNTIL
CONST EXPORT MOD RECORD VAR
DEFINITION FOR MODULE REPEAT WHILE
DIV FROM NOT RETURN WITH
Dieser Ъbersetzer betrachtet einige weitere Namen als erweiterte reservierte
WФrter fБr Modula-2 Spracherweiterungen.
═══ 4.5.3. Erweiterte reservierte WФrter ═══
Wenn die Spracherweiterungen aktiviert sind, dann werden die folgenden Namen
ebenfalls als reservierte WФrter behandelt. Sie kФnnen dann nicht fБr
Benutzernamen verwendet werden.
FAR
IS
NEAR
SHL
SHR
XOR
ΓòÉΓòÉΓòÉ 4.6. Kommentare ΓòÉΓòÉΓòÉ
Kommentare kФnnen Бberall im Programm zwischen zwei Symbolen eingefБgt werden.
Jede Zeichensequenz, welche in den Klammern '(*' und '*)' eingeschlossen ist,
bildet einen Kommentar. Kommentare kФnnen geschachtelt sein. Sie Дndern nicht
die Bedeutung des Programms. Kommentare kФnnen auch Ъbersetzer-Direktiven.
enthalten.
Kommentare werden vom Ъbersetzer Бbergangen. Sie dienen lediglich als
zusДtzliche Informationen fБr den menschlichen Betrachter. Der
INLINE-Assemblierer behandelt auch ein ';' als den Beginn eines Kommentars,
welcher bis zum Ende einer Zeile reicht.
═══ 5. Sichtbarkeitsbereich fБr Deklarationen ═══
Jeder Name, der im Programm vorkommt, muss durch eine Deklaration eingefБhrt
werden, es sei denn, es handelt sich um einen Standard-Namen. Letzterer wird
als vordeklariert betrachtet. Dieser Ъbersetzer hДlt die Vordeklarationen in
einem Pseudo-Definitions-Modul, welches SYSTEM genannt wird. Diese
Standard-Namen sind in allen Bereichen eines Programms gБltig. Sie sind
sozusagen durchlДssig.
Deklarationen dienen auch dazu, bestimmte permanente Eigenschaften eines
Objekts festzulegen, zum Beispiel, ob es sich um eine Konstante, einen Typ,
eine Variable, eine Prozedur oder einen Modul handelt. Der Name wird dann dazu
benutzt, um sich auf das entsprechende Objekt zu beziehen. Solch eine
Bezugnahme ist jedoch nur in den Programmbereichen mФglich, welche im
sogenannten Sichtbarkeitsbereich der Deklaration liegen. Kein Name darf
innerhalb eines gegebenen Sichtbarkeitsbereichs mehr als ein Objekt angeben.
Der Sichtbarkeitsbereich erstreckt sich textuell von der Stelle der Deklaration
bis zum Ende des Blocks der Prozedur oder des Moduls, zu welchem die
Deklaration gehФrt und zu welchem sie demzufolge lokal ist. Die
Sichtbarkeitsregel wird um folgende Punkte erweitert:
(1) Wenn ein Typ P als ein Zeigertyp definiert ist, z.B. P = POINTER
TO T, dann kann der Name T auch erst nach der Deklaration von P, aber
innerhalb des gleichen Sichtbarkeitsbereichs, deklariert werden.
(2) Feldnamen von einem Verbundtyp sind nur in Feldbezeichnern und in
with-Anweisungen, welche auf eine Variable dieses Verbundtyps Bezug
nehmen, erlaubt.
(3) Wenn ein Name, der im Modul M1 definiert ist, exportiert wird,
dann erweitert sich der Sichtbarkeitsbereich bis zum Ende des Blocks,
welcher M1 enthДlt. Wenn M1 eine Ъbersetzungseinheit darstellt,
erweitert sich der Sichtbarkeitsbereich auf alle Einheiten, die M1
importieren.
ΓòÉΓòÉΓòÉ 5.1. Qualifikation von Namen ΓòÉΓòÉΓòÉ
ΓûÉ Qualident = { Qualifier "." } Ident
ΓûÉ Qualifier = Ident
Ein Name kann qualifiziert sein. In diesem Falle wird ein Name vorangestellt,
welcher den Modul einer lokalen Modul-Deklaration bezeichnet, oder welcher eine
globale Ъbersetzungseinheit bezeichnet, die den Namen definiert und exportiert.
Das PrДfix und der Name sind durch einen Punkt getrennt. Standard-Namen haben
alle ihren Ursprung im SYSTEM Modul fБr diesen Ъbersetzer. Sie sind sozusagen
durchlДssig. Daher mБssen sie nicht qualifiziert werden.
ΓòÉΓòÉΓòÉ 5.2. Standard-Namen ΓòÉΓòÉΓòÉ
Einige der Standard-Namen fБr diesen Ъbersetzer mФgen nicht unbedingt bei
Ъbersetzern von anderen Herstellern verfБgbar sein. Sie sind mit einem Stern
markiert. Zu ihnen gehФren NEW, DISPOSE, LONG... und SHORT..., und sie werden
durch diesen Ъbersetzer wie Standard-Namen behandelt, weil die Elementar-Typen
verschieden GrФssen haben kФnnen und weil eine dynamische Speicherverwaltung
unterstБtzt werden soll.
ABS FLOAT LONGREAL *SHORTCARD
BITSET HALT *LONGTRUNC *SHORTFLOAT
BOOLEAN HIGH MAX *SHORTINT
CAP INC MIN *SHORTNIL
CARDINAL INCL *NEW *SHORTREAL
CHAR INTEGER NIL *SHORTTRUNC
CHR *LONG ODD SIZE
DEC *LONGCARD ORD TRUE
*DISPOSE *LONGFLOAT PROC TRUNC
EXCL LONGINT REAL VAL
FALSE *LONGNIL *SHORT
ΓòÉΓòÉΓòÉ 6. Deklarationen ΓòÉΓòÉΓòÉ
ΓûÉ Decl = CONST { ConstDecl ";" } | TYPE { TypeDecl ";" } |
ΓûÉ VAR { VarDecl ";" } | ProcedureDecl | ModuleDecl
Jedes Objekt, welches in einem Programm vorkommt, wie zum Beispiel Typen,
Variablen, oder Prozeduren, muss durch eine Deklaration eingefБhrt werden.
Durch eine Deklaration werden bestimmte permanente Eigenschaften eines Objekts
gekennzeichnet. Die folgenden Arten von Objekte kФnnen als Benutzernamen
deklariert werden:
- Konstanten
- Typen
- Variablen
- Prozeduren
- Module
ΓòÉΓòÉΓòÉ 6.1. Konstanten-Deklarationen ΓòÉΓòÉΓòÉ
ΓûÉ ConstDecl = ConstDef | ConstVarDecl "=" TypedConst
ΓûÉ ConstVarDecl = Ident ":" FormalType
ΓûÉ ConstDef = Ident "=" ConstExpr
ΓûÉ ConstExpr = Expr
Eine Konstanten-Deklaration bringt einen Namen mit einem konstanten Wert in
Verbindung. Ein konstanter Ausdruck ist ein Ausdruck, der schon beim textuellen
Einlesen ausgewertet wird und nicht erst wДhrend der ProgrammausfБhrung. Seine
Operanden sind Konstanten.
Beispiele fБr Konstanten-Deklarationen:
CONST
N = 100;
limit = 2*N - 1;
all = {0..WordSize-1};
bound = MAX(INTEGER) - N;
Dieser Ъbersetzer unterstБtzt auch die Deklarationen von initialsierten
Variablen durch den Gebrauch von sogenannten typisierten Konstanten. Diese
Besonderheit ist nur dann verfБgbar, wenn die Spracherweiterungen aktiviert
worden sind.
ΓòÉΓòÉΓòÉ 6.2. Typ-Deklarationen ΓòÉΓòÉΓòÉ
ΓûÉ TypeDecl = Ident = Type
ΓûÉ Type = SimpleType | ArrayType | RecordType | SetType |
ΓûÉ PointerType | ProcedureType
ΓûÉ SimpleType = Qualident | Enumeration | SubrangeType
Ein Datentyp bestimmt die Menge der Werte, die Variablen dieses Typs annehmen
dБrfen, sowie die dazugehФrigen Operatoren. Eine Typ-Deklaration dient dazu,
einen Namen mit dem Typ in Verbindung zu bringen. Solch eine Verbindung kann
mit unstrukturierten Typen bestehen, wie z.B.:
- Elementar-Typen
- AufzДhlungen
- Unterbereiche
- Zeigertypen
- Prozedur-Typen
Oder die Verbindung kann auch mit strukturierten Typen bestehen. In diesem Fall
beschreibt sie die Strukuren von Variablen diesen Typs, und demzufolge auch die
Operatoren, welche auf die Komponenten anwendbar sind. Es gibt drei verschieden
Arten von Strukturen:
- Verbunde
- Reihungen
- Mengen
Beispiele fБr Typ-Deklarationen:
TYPE
Color = (red, green, blue);
Index = [1..80];
Card = ARRAY Index OF CHAR;
Node = RECORD
key : CARDINAL;
left,right : TreePtr;
END;
Tint = SET OF Color;
TrrePtr = POINTER TO Node;
Function = PROCEDURE( CARDINAL ) : CARDINAL;
ΓòÉΓòÉΓòÉ 6.2.1. Elementare Typen ΓòÉΓòÉΓòÉ
Die folgenden elementaren Typen werden durch vordeklarierte Standardnamen
angegeben. Die Werte von den Elementar-Typen und ihre Anzahl von Bytes, die sie
im Speicher belegen, sind wie folgt:
SHORTINT -128 ... 127 1 byte
INTEGER -32 768 ... 32 767 2 bytes
LONGINT -2 147 483 648 ... 2 147 483 647 4 bytes
SHORTCARD 0 ... 255 1 byte
CARDINAL 0 ... 65 535 2 bytes
LONGCARD 0 ... 4 294 967 296 4 bytes
BOOLEAN FALSE und TRUE 1 byte
CHAR die Zeichen vom erweiterten 8-bit 1 byte
ASCII set (0X ... 0FFX).
SHORTREAL [+|-] 1.17E-38 ... 3.37E+38 4 bytes
LONGREAL [+|-] 2.23E-308 ... 1.67E+308 8 bytes
REAL standardmДssig wie LONGREAL, oder 8 bytes
wenn Schalter '-R8' gesetzt ist, oder
wenn Direktive (*$R8*) gesetzt ist.
wie SHORTREAL 4 bytes
wenn Schalter '-R4' gesetzt ist, oder
wenn Direktive (*$R4*) gesetzt ist.
═══ 6.2.2. AufzДhlungen ═══
ΓûÉ Enumeration = "(" IdentList ")"
ΓûÉ IdentList = Ident { "," Ident }
Eine AufzДhlung ist eine Liste von Namen, welche die mФglichen Werte angeben,
den ein Datentyp ausmacht. Diese Namen werden als Konstante im Programm
benutzt. Nur sie, und keine anderen Werte sonst, gehФren zu diesem Typ. Die
Werte sind geordnet, und die Ordnungsbeziehung wird durch ihre Reihenfolge in
der AufzДhlung definiert. Die Ordnungszahl des ersten Wertes ist 0. Eine
AufzДhlung mit nicht mehr als 256 Werten belegt nur einen Byte im Speicher,
sonst 2 Bytes.
Beispiele fБr AufzДhlungen:
(red, green, blue)
(club, diamond, heart, spade)
(Monday, Tueday, Wednesday, Thursday, Friday, Saturday, Sunday)
ΓòÉΓòÉΓòÉ 6.2.3. Unterbereichstypen ΓòÉΓòÉΓòÉ
ΓûÉ SubrangeType = [ BaseType ] "[" ConstExpr ".." ConstExpr "]"
ΓûÉ BaseType = Qualident
Ein Typ T kann als ein Unterbereich eines anderen, elementaren Typs oder
AufzДhlungstyps T1 (ausser Gleitkommas) definiert werden, indem der niedrigste
und hФchste Wert des Unterbereichs angegeben wird. Die erste Konstante gibt die
Untergrenze an, und sie darf nicht grФsser als die Obergrenze sein. Der Typ T1
dieser Bereichsgrenzen wird auch Basistyp von T genannt, und alle Operatoren,
die auf Operanden mit Typ T1 anwendbar sind, sind auch anwendbar auf Operanden
vom Typ T. Ein Wert, der einer Variablen mit einem Unterbereichstyp zugewiesen
werden soll, muss jedoch innerhalb des angegebenen Intervalls liegen. Der
Basistyp kann durch einen Namen angegeben werden, welcher dann vor den
Grenzwerten steht. Er kann in diesem Ъbersetzer sogar qualifiziert sein. Wenn
er weggelassen wird, und wenn die Untergrenze eine nicht negative Zahl ist,
dann ist der Baistyp ein Kardinaltyp (in diesem Ъbersetzer LONGCARD fБr 32-bit
Speichermodelle wie OS/2 2.x/3.0, oder CARDINAL fБr 16-bit Modelle); wenn er
eine negative Zahl ist, dann ist er ein Integer-Typ (in diesem Ъbersetzer
LONGINT fБr 32-bit Modelle wie OS/2 2.x/3.0, oder INTEGER fБr 16-bit Modelle).
Man sagt, dass ein Typ T1 kompatibel mit einem Typ T0 ist, wenn er entweder als
T1 = T0 oder als einen Unterbereich von T0 deklariert ist, oder wenn T0 ein
Unterbereich von T1 ist, oder wenn T0 und T1 beide Unterbereiche vom
identischen Basistyp sind.
Beispiele fБr Unterbereichstypen:
[ 0 .. N-1 ]
Color [red .. green]
[ 'A' .. 'Z' ]
[ Monday .. Friday ]
ΓòÉΓòÉΓòÉ 6.2.4. Reihungstypen ΓòÉΓòÉΓòÉ
ΓûÉ ArrayType = ARRAY IndexType { "," IndexType } OF Type
ΓûÉ IndexType = SimpleType
EinReihungstyp ist eine Struktur, welche aus einer festen Anzahl von Elementen
besteht, die alle gleichen Typs, nДmlich dem Komponententyp, sind. Die Elemente
der Reihung werden durch Indizes bezeichnet, d.h. durch Werte, die zum Indextyp
gehФren. Die Deklaration eines Reihungstyps gibt sowohl den Komponententyp als
auch den Indextyp an. Letzterer muss eine AufzДhlung, Unterbereichstyp, oder
einer der Elementar-Typen BOOLEAN oder CHAR sein.
Eine Deklaration der Form
ARRAY T1, T2, ... , Tn OF T
mit den Indextypen T1 ... Tn ist als eine AbkБrzung fБr die Deklaration
ARRAY T1 OF
ARRAY T2 OF
...
ARRAY Tn OF T
zu verstehen.
Beispiele fБr Reihungstypen:
ARRAY [0..N-1] OF CARDINAL
ARRAY [1..10], [1..20] OF [0..99]
ARRAY [-10..+10] OF BOOLEAN
ARRAY WeedDay OF Color
ARRAY Color OF WeekDay
ΓòÉΓòÉΓòÉ 6.2.5. Verbundtypen ΓòÉΓòÉΓòÉ
ΓûÉ RecordType = RECORD [ "(" RecordBase ")" ] FieldListSeq END
ΓûÉ RecordBase = Qualident
ΓûÉ FieldListSeq = FieldList { ";" FieldList }
ΓûÉ FieldList = [ IdentList ":" Type | Variants ]
ΓûÉ Variants = CASE [ Ident ":" ] Qualident
ΓûÉ OF VariantList ElseVariant END
ΓûÉ VariantList = Variant { "|" Variant }
ΓûÉ ElseVariant = ELSE FieldListSeq
ΓûÉ Variant = CaseLabelList ":" FieldListSeq
ΓûÉ CaseLabelList = CaseLabels { "," CaseLabels }
ΓûÉ CaseLabels = ConstExpr [ ".." ConstExpr ]
Ein Verbundtyp (record type) ist eine Struktur, die aus einer festen Anzahl von
Elementen mit mФglicherweise verschiedenen Datentypen besteht. Die Deklaration
eines Verbundtyps gibt fБr jedes Element, auch Feld oder Mitglied genannt,
seinen Typ an, ausserdem einen Namen, welcher das Feld angibt. Der
Sichtbarkeitsbereich dieser Felder liegt innerhalb der Verbunddefinition
selbst. Aber die Felder sind auch durch Feldbezeichner, welche sich auf
Elemente von Verbundvariablen beziehen, sichtbar, sowie innerhalb von
with-Anweisungen.
Ein Verbundtyp kann auch verschiedene variante Sektionen enthalten, von denen
jede den gleichen Speicher belegt. Der Wert eines Erkennungstyps gibt dabei an,
um welche Variante der Sektionen es sich dabei handelt. Es ist auch mФglich,
ein Erkennungsfeld zu benutzen, welches, sofern es mit einem Erkennungsnamen
und Erkennungstyp deklariert worden ist, den Erkennungswert wДhrend der
Programmlaufzeit speichert. Individuelle variante Strukturen werden durch
Fallmarken identifiziert. Diese Marken sind Konstanten fБr den Erkennungstyp,
und sie sind mФglicherweise durch ein Erkennungsfeld representiert.
Dieser Ъbersetzer bietet in Verbindung mit Verbundtypen auch Objekt-orientierte
Besonderheiten an, Дhnlich der neuen Sprache OBERON. NДheres hierrБber ist in
den folgenden Sektionen dieser Dokumentation zu finden:
- Objekt-orientierte Merkmale
- Erweiterungen von Verbundtypen
- Testen dynamischer Verbundtypen
- Typenschutz-Selektoren
- Regionaler Typenschutz
- Typ-gebundene Prozeduren
- System Object Model
Diese Objekt-orientierten Besonderheiten sind nur dann verfБgbar, wenn die
Spracherweiterungen aktiviert sind.
ΓòÉΓòÉΓòÉ 6.2.6. Mengentypen ΓòÉΓòÉΓòÉ
ΓûÉ SetType = SET OF SimpleType
ΓûÉ SimpleType = Qualident | Enumeration | SubrangeType
Ein Mengentyp (set type) wird durch ein SET OF T definiert. Er umfasst alle
Mengen von Werten gemДss ihrem Basistyp T. Der Basistyp muss ein Unterbereich
der ganzen Zahlen zwischen 0 und N-1 sein, oder er muss aus einem Unterbereich
einer AufzДhlung bestehen, mit hФchstens N Werten. Dabei ist N die maximale
Anzahl der Elemente. Dieser Ъbersetzer akzeptiert bis zu 256 Elemente. Deshalb
ist auch der Typ SET OF CHAR zulДssig.
Der vordeklarierte Typ BITSET = SET OF [0..15] ist in allen Programmteilen
gБltig, weil er zu den Standardnamen gehФrt und als solcher automatisch vom
Modul SYSTEM exportiert wird.
ΓòÉΓòÉΓòÉ 6.2.7. Zeigertypen ΓòÉΓòÉΓòÉ
ΓûÉ PointerType = [ NEAR | FAR ] POINTER TO Type
Variablen mit einem Zeigertyp (pointer type) P enthalten als Werte Zeiger auf
Variablen mit einem Typ T. Man sagt, dass der Zeigertyp P an T gebunden ist,
und dass T der Baistyp vom Zeiger ist. Wenn p eine Variable mit dem Typ P =
POINTER TO T ist, dann kann sein Wert durch den Aufruf einer Prozedur zur
Speicheranforderung erzeugt werden, wobei solch eine Prozedur typischerweise in
einem Modul zur Speicherverwaltung implementiert ist.
Der Aufruf der Standardprozedur NEW(p) wird zu einem ALLOCATE(p,SIZE(T))
Бbersetzt und sollte vorrangig immer dann benutzt werden, wenn es um die
Anforderung von dynamischen Speicher geht. Der Aufruf der Standardprozedur
DISPOSE(p) wird zu einem DEALLOCATE(p) Бbersetzt, und sollte vorrangig immer
dann benutzt werden, wenn ein Zeigerwert mit seinem zugeordneten Speicher
wieder frei werden soll. Der dahinterstehende Speicher steht danach fБr andere
Anforderungen zur VerfБgung.
Wenn die Spracherweiterungen aktiviert sind, kann die angenommene GrФsse fБr
eine Deklaration eines Zeigertyps durch die SchlБsselwФrter NEAR oder FAR
Бberschrieben werden. Dies ist besonders dann nБtzlich, wenn man separate
Speichersegmente ausserhalb vom Speichersegment DGROUP ansprechen mФchte. Die
voreingestelle GrФsse von Zeigertypen (NEAR oder FAR) hДngt vom Speichermodell
ab. Sie ist NEAR fБr das flache (lineare) Speichermodell von OS/2 2.x/3.0.
Ausser den o.g. Werten kann eine Zeigervariable auch den Wert NIL annehmen,
wodurch angedeutet werden soll, dass auf keine Variable gezeigt wird. Wenn die
Spracherweiterungen aktiviert sind, dann kФnnen auch LONGNIL fБr FAR Zeiger
bzw. SHORTNIL fБr NEAR Zeiger benutzt werden.
ΓòÉΓòÉΓòÉ 6.2.8. Prozedur-Typen ΓòÉΓòÉΓòÉ
ΓûÉ ProcedureType = [ NEAR | FAR ] PROCEDURE [ FormalTypeList ]
ΓûÉ FormalTypeList = "(" FTSectionList ")" [ ":" Qualident ]
ΓûÉ FTSectionList = [ FTSection { "," FTSection } ]
ΓûÉ FTSection = [ [ NEAR | FAR ] VAR ] FormalType
ΓûÉ FormalType = { ARRAY OF } Qualident
Variablen eines Prozedur-Typs T kФnnen einen Zeiger auf eine Prozedur P als
ihren Wert annehmen. Die Typen der formalen Parameter von P mБssen dieselben
sein wie jene aus der formalen Typliste von T. Das gleiche gilt fБr den
Ergebnistyp fБr den Fall einer Funktions-Prozedur. P darf weder lokal zu einer
anderen Prozedur deklariert werden, noch darf sie eine generische
Standard-Prozedur sein.
Wenn die Spracherweiterungen aktiviert sind, kФnnen die Attribute NEAR oder FAR
benutzt. FAR gibt zum Beispiel an, dass der Prozedur-Zeiger als Werte
Prozeduren, die in einem anderen Code-Segment deklariert sind, annehmen kann.
Im Falle von formalen Parametern deutet FAR VAR an, dass der Parameter als
Referenz zu einer Variablen aus einem anderen Datensegment (mФglicherweise
ausserhalb von DGROUP) aufzufassen ist. Dies ist besonders bei
Speicher-Modellen mit vielen Code- oder Daten-Segmenten nБtzlich.
ΓòÉΓòÉΓòÉ 6.3. Deklaration von Variablen ΓòÉΓòÉΓòÉ
ΓûÉ VarDecl = VarIdent { "," VarIdent } ":" Type
ΓûÉ VarIdent = Ident [ FarPointerConst ]
ΓûÉ FarPointerConst = "[" ConstExpr ":" ConstExpr "]"
Die Deklaration von Variablen (variable declaration) dient dazu, neue Variablen
einzufБhren und sie mit Namen in Verbindung zu bringen. Die Namen mБssen dabei
innerhalb des gegebenen Sichtbarkeitsbereichs eindeutig sein. Durch
Deklarationen werden auch feste Datentypen mit den Variablen in Verbindung
gebracht. Alle Variablen, deren Namen innerhalb einer Deklaration in der
gleichen Liste stehen, haben den selben Typ.
Beispiele fБr Deklarationen von Variablen (siehe Beispiele in der Sektion Бber
Typ-Deklarationen):
i,j,k : INTEGER;
x,y : REAL;
p,q : BOOLEAN;
s : BITSET;
FUNC : PROCEDURE( VAR INTEGER, LONGINT ) : BOOLEAN;
f : FUNC;
a : ARRAY Index OF CARDINAL;
w : ARRAY [0..7] OF RECORD
ch : CHAR;
count : CARDINAL;
END;
t : TreePtr;
Wenn die Spracherweiterungen aktiviert sind, dann kФnnen Variablen eines
Zeigertyps nach T0 und VAR-Parameter eines Verbundtyps T0 auch Werte annehmen,
deren Typ T1 eine Verbund-Erweiterung vom ursprБnglich deklarierten Typ T0
darstellen.
ΓòÉΓòÉΓòÉ 6.4. Prozedur-Deklarationen ΓòÉΓòÉΓòÉ
ΓûÉ ProcedureDecl = ProcedureHeading ";" Block Ident |
ΓûÉ ProcedureHeading ";" FORWARD
ΓûÉ ProcedureHeading = [ NEAR | FAR ] PROCEDURE
ΓûÉ [ Receiver ] Ident [ FormalParameters ]
ΓûÉ Receiver = "(" [ [ NEAR | FAR ] VAR ] Ident : Ident ")"
ΓûÉ Block = { Decl } [ BEGIN StmtSeq ] END
ΓûÉ Decl = CONST { ConstDecl ";" } | TYPE { TypeDecl ";" } |
ΓûÉ VAR { VarDecl ";" } | ProcedureDecl | ModuleDecl
Prozedur-Deklarationen bestehen aus einem Prozedur-Kopf und einem Block,
welcher auch Prozedur-KФrper genannt wird. Der Kopf gibt den Namen der Prozedur
an, ferner enthДlt er die formalen Parameter sowie, soweit vorhanden, den
Ergebnistyp. Der KФrper enthДlt Deklarationen und Anweisungen. Der Name der
Prozedur wird am Ende der Prozedur-Deklaration wiederholt. Wenn die
Spracherweiterungen eingeschaltet sind, dann darf auch ein optionaler EmpfДnger
(engl. Receiver) angegeben werden. Der EmpfДnger ist ein erster formaler
Parameter fБr ein Zielobjekt, auf dem die Prozedur angewendet werden soll. Er
wird nur fБr Typ-gebundene Prozeduren gebraucht. Und er Дhnelt sehr dem Konzept
fБr Klassen und Methoden aus der neuen Programmiersprache Oberon-2.
Es gibt zwei Arten von Prozeduren, nДmlich eigentliche Prozeduren und
Funktions-Prozeduren. Letztere werden durch einen Funktions-Bezeichner
innerhalb eines Ausdrucks aktiviert und produzieren ein Ergebnis, dass als ein
Operand in dem Ausdruck dient. Eigentliche Prozeduren werden durch einen
Prozedur-Aufruf aktiviert. Die Funktions-Prozedur ist durch Angabe eines
Resultattyps am Ende der Parameterliste der Deklaration gekennzeichnet. Ihr
KФrper muss mindestens eine RETURN-Anweisung enthalten, welche das Ergebnis der
Funktions-Prozedur liefert.
Der KФrper einer Prozedur kann auch als FORWARD deklariert werden. Dadurch wird
es fБr Prozeduren mФglich, sich gegenseitig rekursiv aufzurufen. Eine mit
FORWARD vordeklarierte Prozedur muss aber spДter im gleichen
Sichtbarkeitsbereich voll deklariert werden. Dabei muss der Prozedur-Kopf voll
wiederholt werden, gefolgt von einer vollstДndigen Deklaration des
Prozedur-Blocks.
Wenn die Spracherweiterungen aktiviert sind, dann kФnnen durch die WФrter FAR
oder NEAR angezeigt werden, ob die Prozeduren im gleichen oder in einem
separaten Code-Segment liegen. Dies ist fБr 16-bit APIs wie jene von MS-Windows
3.x von besonderer Bedeutung. Unter OS/2 2.x/3.0 selbst besteht keine
Notwendigkeit, das dort standardmДssig angenommene NEAR Attribut zu
Бberschreiben, weil ein 32-bit lineares 'Flat' Speicher-Modell benutzt wird.
Alle Konstanten, Variablen, Typen, Module und Prozeduren, die innerhalb des
Blocks, d.h. den Prozedur-KФrper, deklariert worden sind, sind lexikalisch als
lokal zur Prozedur zu betrachten. Die Werte von lokalen Variablen,
einschliesslich solcher aus lokalen Modulen, sind beim Eintritt der Prozedur
undefiniert. Denn die lokalen Variablen befinden sich auf dem Stapelspeicher
(stack). Jedesmal, wenn die Prozedur aufgerufen wird, wird ein neuer Rahmen auf
dem Stapelspeicher eingerichtet, um die lokalen Variablen aufzunehmen. Sie
verbleiben dort solange, bis der Prozeduraufruf abgeschlossen ist. Weil auch
Prozeduren als lokale Objekte deklariert werden kФnnen, dБrfen sie geschachtelt
sein. Jedes Objekt wird auf einer sogenannten Schachtelungsebene deklariert.
Wenn es zum Beispiel lokal zu einer Prozedur aus der Schachtelungsebene k
deklariert wird, befindet es sich selbst auf der Schachtelungsebene k+1.
Objekte, die in dem Modul, das eine Ъbersetzungseinheit darstellt, deklariert
sind, sind per Definition auf der Дussersten Schachtelungsebene 0 angesiedelt
und werden als statische Variablen betrachtet.
Neben den formalen Parametern und den lokalen Objekten sind auch die bisherigen
Objekte aus der Umgebung der Prozedur, d.h. aus dem Sichtbarkeitsbereich
auserhalb der Prozedur, fБr die Prozedur sichtbar, es sei denn, sie haben
gleiche Namen wie die lokalen Objekte.
Der Gebrauch eines Prozedur-Namens fБr einen Aufruf innerhalb der eigenen
Deklaration bewirkt eine rekursive Aktivierung der Prozedur, einschliesslich
der Einrichtung eines neuen Rahmens im Stapelspeicher fБr die lokalen
Variablen.
ΓòÉΓòÉΓòÉ 6.4.1. Formale Parameter ΓòÉΓòÉΓòÉ
ΓûÉ FormalParameters = "(" FPSectionList ")" [ ":" Qualident ]
ΓûÉ FPSectionList = [ FPSection { ";" FPSection } ]
ΓûÉ FPSection = [ [ NEAR | FAR ] VAR ] IdentList ":" FormalType
ΓûÉ FormalType = { ARRAY OF } Qualident
Formale Parameter sind Namen, welche in einem Prozedur-Aufruf die
entsprechenden aktuellen Parameter angeben. Der Zusammenhang zwischen den
formalen und aktuellen Parametern wird zum Zeitpunkt des Aufrufs einer Prozedur
hergestellt. Es gibt zwei Arten von Parametern, nДmlich Wert- und
Variable-Parameter. Die Art wird in der formalen Parameterliste angegeben.
Wert-Parameter stehen fБr lokale Variablen, welchen das ausgewertete Ergebnis
vom entsprechenden aktuellen Parameter als ihren Anfangswert zugewiesen
bekommen. Variable-Parameter haben ihre Entsprechung zu aktuellen Parametern,
die Variablen sind, und stehen fБr diese Variablen. Sie werden per Referenz
weitergereicht, und nicht durch einen Wert. Dabei werden ihre Adressen benutzt.
WДhrend Variable-Parameter durch das Symbol VAR angedeutet werden, werden
Wert-Parameter ohne diesem Symbol eingefБhrt.
Wenn die Spracherweiterungen aktiviert sind, kФnnen die Variable-Parameter als
NEAR oder FAR deklariert sein. Dies dient als einen Hinweis fБr die Prozedur,
um auf die entsprechenden aktuellen Variablen in einem NEAR Datensegment
(namens DGROUP fБr diesen Ъbersetzer) oder in einem separaten FAR Datensegment
zuzugreifen.
Formale Parameter sind lokal zu der Prozedur. Das heisst, dass ihr
Sichtbarkeitsbereich den Programmtext, welcher die Deklaration der Prozedur
ausmacht, umfasst.
Der Typ eines jeden formalen Parameters wird in der Parameterliste angegeben.
FБr Variable-Parameter muss er mit dem entsprechenden aktuellen Parametertyp
identisch sein, ausser im Falle eines Verbundtyps bei gleichzeitig aktivierten
Spracherweiterungen, wo er dann der Basistyp des entsprechenden aktuellen
Parametertyps sein muss. Hinsichtlich der Wert-Parameter gelten die Regeln der
Zuweisung.
Wenn der formale Parametertyp als ARRAY OF T festgelegt wird, dann spricht man
von einem Parameter einer offenen Reihung. Der entsprechende aktuelle Parameter
darf dann jede Reihung mit Elementtyp T sein. Wenn die Spracherweiterungen
aktiviert sind, kann der Parametertyp sogar aus einer multidimensionalen
offenen Reihung bestehen. Ein Parameter einer offenen Reihung kann nur
elementweise angesprochen werden, mit einem Indexbereich zwischen 0 und N-1,
wobei N die akuelle Anzahl der Elemente bedeutet. Die formale Reihung kann auch
als ganzes in einem aktuellen Parameter, dessen formaler Parameter selbst eine
offene Reihung ist, auftreten.
Eine Funktions-Prozedur ohne Parameter hat eine leere Parameterliste. Sie muss
durch einen Bezeichner fБr die Funktion mit einer ebenfalls leeren
Parameterliste, allerdings mit Klammern, aufgerufen werden. Wenn ein formaler
Parameter einen Prozedurtyp bezeichnet, dann muss der entsprechende aktuelle
Parameter eine auf der globalen Null-Ebene deklarierte Prozedur sein, oder er
muss eine Variable oder ein Parameter dieses Prozedurtyps sein. Er darf nicht
eine generische Standard-Prozedur sein.
Dieser Ъbersetzer akzeptiert auch strukturierte Ergebnistypen.
ΓòÉΓòÉΓòÉ 6.4.2. Standard-Prozeduren ΓòÉΓòÉΓòÉ
Standard-Prozeduren sind (fБr diesen Ъbersetzer im SYSTEM-Modul) vordefiniert.
Einige von ihnen sind lediglich generische Prozeduren, welche nicht explizit
deklariert werden kФnnen, und sie gelten fБr ganze Klassen von Operandtypen
oder sie haben verschiedene mФgliche Formen von Parameterlisten.
Die folgenden Standard-Funktionen sind fБr diesen Ъbersetzer verfБgbar:
Prozedur-Name Beschreibung
ABS( x ) absoluter Wert; Ergebnistyp = Argumenttyp
CAP( x ) wenn ch ein Kleinbuchstabe ist: der entsprechende
Grossbuchstabe. Sonst der gleiche Buchstabe.
CHR( x ) der Buchstabe mit Ordnungszahl x; CHR(x)=VAL(CHAR,x)
FLOAT( x ) x vom Typ SHORTINT, INTEGER, LONGINT, SHORTCARD,
CARDINAL, oder LONGCARD, dargestellt als ein Wert vom
Typ REAL
LONGFLOAT( x ) x vom Typ SHORTINT, INTEGER, LONGINT, SHORTCARD,
CARDINAL, oder LONGCARD, dargestellt als ein Wert vom
Typ LONGREAL
SHORTFLOAT( x ) x vom Typ SHORTINT, INTEGER, LONGINT, SHORTCARD,
CARDINAL, oder LONGCARD, dargestellt als ein Wert vom
Typ SHORTREAL
HIGH( a ) HФchster Indexwert einer Reihung a
MAX( T ) der Maximalwert vom Typ T, wobei T einen Elementartyp
(ausser Gleitkomma), eine AufzДhlung oder einen
Unterbereichstyp darstellt.
MIN( T ) der Minimalwert vom Typ T, wobei T einen Elementartyp
(ausser Gleitkomma), eine AufzДhlung oder einen
Unterbereichstyp darstellt.
ODD( x ) x MOD 2 <> 0
ORD( x ) Ordnungszahl (eines ganzzahligen (cardinal) Typs mit
gleicher GrФsse wie x) in der Menge von Werten,
welche durch Typ T von x definiert sind. T kann jede
AufzДhlung, CHAR, SHORTINT, INTEGER, LONGINT,
SHORTCARD, CARDINAL, oder LONGCARD sein.
SIZE( T ) Anzahl der Bytes fБr einen angegebenen Typ T.
SIZE( x ) Anzahl der durch eine Variable belegten Bytes fБr
seinen Typ.
TRUNC( x ) Ganzzahliger Anteil (des Typs INTEGER) der
Gleitkommazahl x (mit Typ REAL, SHORTREAL oder
LONGREAL).
LONGTRUNC( x ) Ganzzahliger Anteil (des Typs LONGINT) der
Gleitkommazahl x (mit Typ REAL, SHORTREAL oder
LONGREAL).
SHORTTRUNC( x ) Ganzzahliger Anteil (des Typs SHORTINT) der
Gleitkommazahl x (mit Typ REAL, SHORTREAL oder
LONGREAL).
LONG( x ) In der GrФsse erweiteter Wert von x, wobei x ein
Integer-, Cardinal- oder Real- Ausdruck ist, gemДss
den folgenden Regeln:
SHORTINT->INTEGER,
INTEGER->LONGINT,
LONGINT->LONGINT,
SHORTCARD->CARDINAL,
CARDINAL->LONGCARD,
LONGCARD->LONGCARD,
SHORTREAL->LONGREAL,
LONGREAL->LONGREAL,
REAL->LONGREAL
SHORT( x ) In der GrФsse gekБrzter Wert von x, wobei x ein
Integer-, Cardinal- oder Real- Ausdruck ist, gemДss
den folgenden Regeln:
LONGINT->INTEGER,
INTEGER->SHORTINT,
SHORTINT->SHORTINT,
LONGCARD->CARDINAL,
CARDINAL->SHORTCARD,
SHORTCARD->SHORTCARD,
LONGREAL->SHORTREAL,
SHORTREAL->SHORTREAL,
REAL->SHORTREAL
VAL( T, x ) Der Wert mit der Ordnungszahl x und dem Typ T. T ist
jede AufzДhlung, CHAR, SHORTINT, INTEGER, LONGINT,
SHORTCARD, CARDINAL, oder LONGCARD. Es gilt
VAL(T,ORD(x))=x, wenn x vom Typ T ist.
Die folgenden eigentlichen Standard-Prozeduren sind mit diesem Ъbersetzer
verfБgbar:
Prozedur-Name Beschreibung
DEC( x ) x := x - 1, wobei x als Variable den Typ SHORTINT,
INTEGER, LONGINT, SHORTCARD, CARDINAL, LONGCARD,
CHAR, AufzДhlung oder Unterbereich hat.
DEC( x, n ) x := x - 1, wobei x als Variable den Typ SHORTINT,
INTEGER, LONGINT, SHORTCARD, CARDINAL, LONGCARD,
CHAR, AufzДhlung oder Unterbereich hat. n muss ein
kardinaler Ausdruck sein.
EXCL( s, i ) s := s - { i }
HALT Terminiere ProgrammausfБhrung
INC( x ) x := x + 1, wobei x als Variable den Typ SHORTINT,
INTEGER, LONGINT, SHORTCARD, CARDINAL, LONGCARD,
CHAR, AufzДhlung oder Unterbereich hat.
INC( x, n ) x := x + 1, wobei x als Variable den Typ SHORTINT,
INTEGER, LONGINT, SHORTCARD, CARDINAL, LONGCARD,
CHAR, AufzДhlung oder Unterbereich hat. n muss ein
kardinaler Ausdruck sein.
INCL( s, i ) s := s - { i }
NEW( p ) ALLOCATE(p,SIZE(T)); Fordere dynamischen Speicher an
und weise seine Adresse einem Zeiger p zu.
DISPOSE( p ) DEALLOCATE(p,SIZE(T)); Gebe dynamischen Speicher
wieder frei und setze p auf NIL.
ΓòÉΓòÉΓòÉ 6.5. Module ΓòÉΓòÉΓòÉ
ΓûÉ ModuleDecl = MODULE Ident [ Priority ] { Import } [ Export ]
ΓûÉ Block Ident
ΓûÉ Priority = [ "[" ConstExpr "]" ]
ΓûÉ Import = [ FROM Ident ] IMPORT IdentList ";"
ΓûÉ Export = EXPORT [ QUALIFIED ] IdentList ";"
ΓûÉ IdentList = Ident { "," Ident }
Ein Modul ist eine Sammlung von Deklarationen fБr Konstanten, Typen, Variablen,
Modulen und Prozeduren, und eine Anweisungsfolge. Sie werden durch MODULE und
END eingeschlossen. Der Modulkopf enthДlt den Modulnamen und mФglicherweise
eine Anzahl von Importlisten und eine Exportliste. Eine Importliste bestimmt
alle Namen von Objekten, welche ausserhalb deklariert sind, aber innerhalb vom
Modul benutzt werden, und daher importiert werden mБssen. Die Exportliste
bestimmt alle Namen von Objekten, die innerhalb des Moduls deklariert worden
sind, aber ausserhalb gebraucht werden. Man kann also sagen, dass ein Modul
eine Mauer der Sichtbarkeit seiner lokalen Objekte darstellt, die nach aussen
hin streng vom Programmierer kontrolliert wird.
Objekte, die lokal zu einem Modul existieren, befinden sich auf der gleichen
Schachtelungsebene wie das Modul selbst. Sie kФnnen als lokal zu der Prozedur,
welche das Modul umschliesst, betrachtet werden, jedoch mit einer
restriktiveren Sichtbarkeit. Der Modulname wird am Ende der Deklaration
wiederholt.
ΓòÉΓòÉΓòÉ 6.5.1. Zweck lokaler Module ΓòÉΓòÉΓòÉ
Die Anweisungsfolge, welche den ModulkФrper ausmachen, wird ausgefБhrt, wenn
die Prozedur oder Ъbersetzungseinheit, zu welcher das Modul lokal ist,
aufgerufen wird. Sind mehrere Module deklariert, werden diese KФrper in der
Reihenfolge ihres Auftretens ausgefБhrt. Diese KФrper dienen dazu, lokale
Variablen zu initialisieren, und mБssen als Prefixe zum Anweisungsteil der sie
umschliessenden Prozedur oder Ъbersetzungseinheit betrachtet werden.
Erscheint ein Name in der Liste der Importe (oder des Exports), darf das
angegebene Objekt innerhalb (ausserhalb) des Moduls benutzt werden, so als ob
die Modulmauern nicht existierten. Wenn jedoch das Symbol EXPORT durch das
Symbol QUALIFIED gefolgt wird, dann mБssen die aufgelisteten Namen mit dem
PrДfix des Modulnamens versehen werden, um ausserhalb vom Modul benutzt werden
zu kФnnen. Solch ein qualifizierter Export trДgt zur Vermeidung von Konflikten
mit identischen Namen, welche von anderen Modulen exportiert werden und meist
andere Objekte angeben, bei.
Ein Modul kann mehrere Importlisten enthalten. Jede von ihnen wird durch eine
FROM-Klausel und einem Modulnamen eingeleitet. Die FROM-Klausel bewirkt eine
Ausschaltung der ansonsten notwendigen Qualifizierung der importierten Namen.
Diese Namen kФnnen nun im Modul so gebraucht werden, als ob sie in einer
normalen, nicht qualifizierenden Weise, exportiert worden wДren.
Wenn ein Verbundtyp exportiert wird, dann werden auch alle seine Felder
exportiert. Das gleiche gilt fБr die Namen von Konstanten im Falle einer
AufzДhlung.
═══ 6.5.2. Modul-PrioritДt ═══
Ein klassiches Problem der gleichzeitigen Abarbeitung mehrerer Aufgaben ist der
Austausch von Daten unter verschiedenen Prozessen, zum Beispiel im Rahmen einer
Kommunikation unter ihnen. GewФhnlich werden gemeinsame Variablen zum
Datenaustausch unter den Prozessen benutzt. Daraus ergibt sich die Problematik
einer harmonierenden Kooperation. Kein Prozess sollte auf gemeinsame Variablen
zugreifen, wДhrend ein anderer noch eine kritische Aktion mit ihnen durchfБhrt.
Ein vernБnftiger LФsungsansatz zu diesem Problem besteht darin, die gemeinsamen
Variablen in einem Modul, welches den wechselseitigen Ausschluss der Prozesse
garantiert, einzukapseln. Solch ein Modul ist auch als ein Monitor bekannt. Der
Zugriff auf seine lokalen Daten wird, weil sie verborgen sind, auf die
Anweisungen der Prozeduren vom Monitor begrenzt. Diese Prozeduren kФnnen
exportiert werden. Ein Modul wird durch die Angabe einer PrioritДt in seinem
Kopf zu einem Monitor erklДrt. Die PrioritДt ist ein ganzzahliger, kardinaler
Wert.
Unter OS/2 2.x/3.0 gibt es bis zu 32 verschiedene PrioritДten von 0 bis 31.
Jede PrioritДt hat einen entsprechenden OS/2 Mutex-Semaphor. Durch letzteren
werden alle Prozeduren innerhalb vom Monitor-Modul gegen gleichzeitige
Zugriffe von anderen OS/2-Threads geschБtzt. Dieser Ъbersetzer bildet Modula's
Prozesse auf OS/2-Threads, das heisst den grundlegenden und durch Zeitscheiben
gesteuerten AusfБhrungseinheiten, ab.
═══ 7. AusdrБcke ═══
ΓûÉ Expr = SimpleExpr [ Relation SimpleExpr ]
ΓûÉ SimpleExpr = [ "+" | "-" ] Term { AddOperator Term }
ΓûÉ Term = Factor { MulOperator Factor }
ΓûÉ Factor = CharConst | Number | String | Set |
ΓûÉ Designator [ ActualParams ] | "(" Expr ")" |
ΓûÉ Not Factor
ΓûÉ Set = Qualident "{" [ ElemList ] "}"
ΓûÉ ElemList = Elem { "," Elem }
ΓûÉ Elem = Expr { ".." Elem }
ΓûÉ ActualParams = "(" [ Expr { "," Expr } ] ")"
AusdrБcke (expressions) sind Konstrukte, die die Regeln der Abarbeitung
angeben, wobei Konstanten and laufende Werte von Variablen kombiniert werden
dБrfen, um durch die Anwendung von Operatoren und Funktions-Prozeduren andere
Werte zu erhalten. AusdrБcke bestehen aus Operanden and Operatoren. Klammern
dБrfen benutzt werden, um abweichende Assoziationen von Operatoren und
Operanden auszudrБcken.
Beispiele fБr AusdrБcke (vergleiche Beispiele aus der Sektion Бber
Variable-Deklarationen):
expression: denoted type:
1980 CARDINAL
k DIV 3 INTEGER
NOT p OR q BOOLEAN
(i+j) * (i-j) CARDINAL
s - {8,9,13} BITSET
a[i] + a[j] CARDINAL
a[i+j] * a[i-j] CARDINAL
(0<=k) & (k<100) BOOLEAN
t^.key = 0 BOOLEAN
{13..15} <= s BOOLEAN
i IN {0,5..8,15} BOOLEAN
ΓòÉΓòÉΓòÉ 7.1. Operanden ΓòÉΓòÉΓòÉ
ΓûÉ Designator = Qualident { Selector }
ΓûÉ Selector = "." Ident | "[" IndexList "]" | "^" | TypeGuard
ΓûÉ IndexList = Expr { "," Expr }
ΓûÉ TypeGuard = "(" Qualident ")"
Mit der Ausnahme literaler Konstanten, das heisst Zahlen, Zeichenketten,
Zeichen und Mengen, werden Operanden durch Bezeichner (designator) angegeben.
Ein Bezeichner besteht aus einem Namen, der sich auf die Konstante, Variable,
oder Prozedur bezieht. Solch ein Name kann auch durch Modulnamen qualifiziert
sein, und er kann, falls sich das bezeichnete Objekt auf ein Element einer
Struktur bezieht, durch Selektoren gefolgt werden.
Wenn die Struktur eine Reihung A ist, dann gibt der Bezeichner A[E] diejenige
Komponente an, dessen Index der augenblickliche Wert vom Ausdruck E ist. Der
Indextyp von A muss mit dem Typ von E zuweisungskompatibel sein. Ein Bezeichner
der Form A[E1,E2,...,En] steht als eine AbkБrzung fБr A[E1][E2]...[En].
Der Bezeichner P^ gibt die Variable, auf die durch den Zeiger P Bezug genommen
wird, an.
Wenn R eine strukturierte Variable eines Verbundtyps ist, dann gibt der
Bezeichner R.f das Feld f vom Verbund R an. Wenn die Spracherweiterungen
aktiviert sind und eine Prozedur m ist mit einem formalen EmpfДngertyp fБr den
Typ des Verbunds R deklariert, dann gibt R.m die Typ-gebundene Prozedur an.
Ebenfalls, wenn die Spracherweiterungen aktiviert sind, wird durch den
Typenschutz v(T0) die Variable v zu einem Ausdruck mit dem Typ T0. Das heisst,
dass die ProgrammausfБhrung (in diesem Ъbersetzer mit dem RБckgabewert 3)
abgebrochen wird, wenn der aktuelle Typ nicht T0 ist. Dieser Schutz is
anwendbar, wenn
(1) T eine Erweiterung des deklarierten Typs T0 von v ist, und
(2) v ein Variable-Parameter eines Verbundtyps oder v ein Verbundzeiger
ist.
Ist das bezeichnete Objekt eine Variable, dann bezieht der Bezeichner auf den
laufenden Wert der Variablen. Wenn das Objekt eine Funktions-Prozedur ohne
Parameterliste bezeichnet, dann bezieht sich der Bezeichner auf diese
Prozedur. Falls der Bezeichner von einer, mФglicherweise leeren,
Parameterliste gefolgt wird, dann bewirkt der Bezeichner eine Aktivierung der
Prozedur und steht fБr den RБckgabewert, der sich aus der AusfБhrung der
Prozedur ergibt. Die Typen dieser aktuellen Parameter mБssen den formalen
Parametern entsprechen, so wie sie in der Prozedur-Deklaration. beschrieben
sind.
Beispiele fБr Bezeichner (siehe Beispiele in der Sektion Бber
Variable-Deklarationen):
Designator: Denoted type:
k INTEGER
a[i] CARDINAL
w[3].ch CHAR
t^.key CARDINAL
t^.left^.right TreePtr
ΓòÉΓòÉΓòÉ 7.2. Operatoren ΓòÉΓòÉΓòÉ
ΓûÉ Relation = "=" | "<>" | "#" | "<" | "<=" | ">" | ">=" | IN | IS
ΓûÉ AddOperator = "+" | "-" | OR | XOR
ΓûÉ MulOperator = "*" | "/" | DIV | MOD | AND | "&" | SHL | SHR
ΓûÉ Not = NOT | "~"
Die Syntax von AusdrБcken unterscheidet zwischen vier Klassen von Operatoren
mit entsprechenden Vorrangregelungen. Die Operatoren '~' und NOT haben den
hФchsten Vorrang, gefolgt von Multiplikations-Operatoren, Additions-Operatoren
und den Relationen. Operatoren der gleichen Klasse haben eine Assozierung von
links nach rechts. Zum Beispiel steht x-y-z fБr (x-y)-z.
ΓòÉΓòÉΓòÉ 7.2.1. Arithmetische Operatoren ΓòÉΓòÉΓòÉ
Die folgenden Operatoren sind im Standard-Sprachumfang von Modula-2 definiert:
+ Addition oder UnДre IdentitДt
- Subtraktion oder unДre Vorzeichenumkehr
* Multiplikation
/ Gleitkomma-Division
DIV Ganzzahlige Division
MOD Modulus
Die arithmetischen Operatoren (ausser /) kФnnen auf Operanden der Typen
SHORTINT, INTEGER, LONGINT, SHORTCARD, CARDINAL, oder LONGCARD, oder deren
Unterbereiche angewandt werden. Beide Operanden mБssen entweder zu einem
Cardinal-Typ gehФren, oder sie mБssen beide zu einem der Integer-Typen
gehФren. Der Ergebnistyp ist immer LONGINT, INTEGER oder SHORTINT, wenn beide
Operanden zu einem Integer-Typ gehФren, und richten sich nach dem grФssten
Operandentyp. Sonst ist der Ergebnistyp LONGCARD, CARDINAL oder SHORTCARD,
wenn beide Operanden zu den Cardinal-Typen gehФren, und richten sich nach dem
grФssten Operand.
Die Operatoren '+', '-', und '*' finden auch fБr Gleitkomma-Operanden
Anwendung. In diesem Fall mБssem beide Operanden zu einem Real-Typ gehФren,
und das Ergebnis ist ein LONGREAL oder SHORTREAL, und richten sich nach dem
grФssten Operand. Der Divisions-Operator '/' wird nur fБr Gleitkomma-Operanden
gebraucht. Die Operatoren '+' und '-' sind auch fБr unДre Operanden gБltig,
und zwar jeweils nur fБr einen einzigen Operand. In solchen FДllen gibt '-'
die Vorzeichenumkehr an, wДhrend '+' einfach die IdentitДts-Operation
bedeutet, d.h. ohne besondere Berechnungen. Die Vorzeichenumkehr kann auf
Integer- oder Real-Operanden angewandt werden. Die Operatoren DIV und MOD sind
durch folgende Regeln definiert:
x DIV y ist gleich dem ganzzahligen Anteil des Quotienten x / y
x MOD y ist gleich dem Rest der Division x DIV y (fБr y > 0)
x = (x DIV y) * y + (x MOD y), 0 <= (x MOD y) < y
Wenn die Spracherweiterungen aktiviert sind, dann kФnnen die folgenden
bit-Operatoren fБr Cardinal- oder Integer-Operanden benutzt werden:
OR Bit-weises Oder
XOR Bit-weises exklusives Oder
AND Bit-weises Und
& Bit-weises Und, wie AND
SHL Bit-weises Schieben nach links
SHR Bit-weises Schieben nach rechts
NOT UnДre bit-weise Negierung
~ UnДre bit-weise Negierung
ΓòÉΓòÉΓòÉ 7.2.2. Logische Operatoren ΓòÉΓòÉΓòÉ
Die folgenden logischen Operatoren sind fБr den Standard-Sprachumfang von
Modula-2 verfБgbar. Sie sie fБr Bool'sche Operanden anwendbar und produzieren
wiederum ein Bool'sches Ergebnis.
OR logische Konjunktion
p OR q bedeutet "wenn p dann TRUE, sonst q"
AND logische Disjunktion
p AND q bedeutet "wenn p dann q, sonst FALSE"
& logische Disjunktion, wie AND
p & q bedeutet "wenn p dann q, sonst FALSE"
NOT uunДre logische Negation
Wenn die Spracherweiterungen aktiviert sind, dann steht auch der folgende
logische Operator fБr Bool'sche Operanden zur VerfБgung:
XOR logische exklusive Konjunktion
p XOR q bedeutet "wenn p dann NOT q, sonst q"
ΓòÉΓòÉΓòÉ 7.2.3. Mengen-Operatoren ΓòÉΓòÉΓòÉ
Die folgenden Operatoren finden bei Operanden fБr Mengentypen Anwendung und
produzieren als Ergebnis den gleichen Typ.
+ Mengen-Vereinigung
x IN (s1 + s2) bedeutet "(x IN s1) OR (x IN s2)"
- Mengen-Differenz
x IN (s1 - s2) bedeutet "(x IN s1) AND NOT (x IN s2)"
* Mengen-Durchschnitt
x IN (s1 * s2) bedeutet "(x IN s1) AND (x IN s2)"
/ symmetrische Mengen-Differenz
x IN (s1 / s2) bedeutet "(x IN s1) XOR (x IN s2)"
ΓòÉΓòÉΓòÉ 7.2.4. Relationen ΓòÉΓòÉΓòÉ
Relationen produzieren einen Bool'schen Ergebnistyp. Die Ordnungsrelationen
sind auf die Elementar-Typen SHORTINT, INTEGER, LONGINT, SHORTCARD, CARDINAL,
LONGCARD, BOOLEAN, CHAR, SHORTREAL, LONGREAL, REAL, und auf AufzДhlungen sowie
Unterbereichen anwendbar.
= gleich
# ungleich
<> ungleich, wie #
< kleiner als
<= kleiner oder gleich
Einschluss von Mengen
> grФsser als
>= grФsser oder gleich
Einschluss von Mengen
IN ist Element von einer Menge
IS Typentest
Die Relationen '=' und '#' sind auch auf Mengen und Zeiger anwendbar. '<=' und
'>=' auf Mengen angewandt, bedeuten deren (nicht echtes) Enthalten-Sein. Die
Relation IN prБft das Vorhanden-Sein eines Elements in einer Menge. In einem
Ausdruck der Art x IN s muss s vom Typ SET OF T sein, wobei T der Typ von x
oder mit ihm kompatibel sein muss.
Die Relation IS ist nur dann verfБgbar wenn die Spracherweiterungen aktiviert
sind. v IS T steht fБr 'v ist vom Typ T' und wird in einem Typentest benutzt.
Er ist anwendbar, wenn
(1) T ist eine Erweiterung des deklarierten Typs T0 von v ist, und
(2) v ein Variable-Parameter eines Verbundtyps oder v ein Verbundzeiger
ist.
Wenn zum Beispiel T eine Erweiterung von T0 ist, und v ein Bezeichner mit dem
deklariertem Typ T0 ist, dann prБft der Test 'v IS T', ob die aktuell
bezeichnete Variable (nicht nur vom Typ T0, sondern auch) vom Typ T ist. Der
Wert von 'NIL IS T' ist nicht definiert.
ΓòÉΓòÉΓòÉ 8. Anweisungen ΓòÉΓòÉΓòÉ
ΓûÉ Stmt = [ Assignment | ProcedureCall | IfStmt | CaseStmt |
ΓûÉ WhileStmt | RepeatStmt | LoopStmt | ForStmt |
ΓûÉ WithStmt | EXIT | ReturnStmt ]
Anweisungen (statements) geben die ProgrammausfБhrung an. Es gibt elementare
und strukturierte Anweisungen. Elementare Anweisungen setzen sich nicht aus
Teilen, die selbst wiederum Anweisungen enthalten, zusammen, wie dies bei den
strukturierten Anweisungen der Fall ist. Strukturierte Anweisungen werden
benutzt, um Sequenzen auszudrБcken, oder um konditionale, selektive, und
wiederholte AusfБhrungen zu bewirken.
Zu den elementaren Anweisungen gehФren die Zuweisung, der Prozedur-Aufruf, die
Return-Anweisung und die Exit-Anweisung. Eine strukturierte Anweisung kann aus
einer If-Anweisung, einer Case-Anweisung, einer While-Anweisung, einer
Repeat-Anweisung, einer Loop-Anweisung, einer For-Anweisung oder einer
With-Anweisung bestehen. Mit der Ausnahme von der With-Anweisung kontrollieren
sie den Fluss der ProgrammausfБhrung.
Eine Anweisung kann auch leer sein. Sie bezeichnet dann keine Aktion. Die
Leer-Anweisung ist miteingeschlossen, um die Zeichensetzungsregeln in
Anweisungsfolgen. abzuschwДchen.
ΓòÉΓòÉΓòÉ 8.1. Zuweisungen ΓòÉΓòÉΓòÉ
ΓûÉ Assignment = Designator ":=" Expr
Eine Zuweisung (assignment) ersetzt den augenblicklichen Wert einer Variablen
durch einen neuen Wert, der in einem Ausdruck beschrieben wird. Der
Zuweisungs-Operator wird als ':=' geschrieben und als 'ergibt gleich'
ausgesprochen. Der Bezeichner links vom Zuweisungs-Operator gibt eine Variable
an. Nach AusfБhrung einer Zuweisung enthДlt die Variable den neuen Wert, der
sich aus der Auswertung des Ausdrucks auf der rechten Seite ergeben hat. Der
alte Wert geht verloren. Er wird Бberschrieben.
Der Typ der Ergebnisvariablen muss mit dem Typ vom Ausdruck auf der rechten
Seite Zuweisungs-kompatibel sein. Operanden sind genau dann
Zuweisungs-kompatibel, wenn sie entweder beide kompatibel sind oder beide
Integer (SHORTINT, INTEGER, LONGINT) oder Cardinal (SHORTCARD, CARDINAL,
LONGCARD) oder entsprechende Unterbereiche fБr Integer oder Cardinal sind.
Falls jedoch eine Abschneidung der GrФsse aufgrund einer Zuweisung auftritt,
werden die Operanden nicht als Zuweisungs-kompatibel betrachtet. Cardinal- und
Integer-Operanden (und deren Unterbereiche) sind ebenfalls
Zuweisungs-kompatibel, obwohl sie nicht in AusdrБcken kompatibel sind.
Eine Zeichenkette der LДnge n1 kann einer Reihungsvariablen mit n2 > n1
Elementen vom Typ CHAR zugewiesen werden. In diesem Fall wird die Zeichenkette
um das Null-Zeichen 0C erweitert. Eine Zeichenkette der LДnge 1 ist mit dem Typ
CHAR kompatibel.
Beispiele fБr Zuweisungen:
i := k;
p := i = j;
j := log2( i+j );
s := { 2, 3, 5, 7, 11, 13 };
a[ i ] := (i + j) * (i - j);
t^.key := i;
w[ i+1 ].ch := "A";
Wenn die Spracherweiterungen aktiviert sind, dann darf ein Ausdruck mit einem
erweitetem Typ ebenfalls einer Zielvariablen zugewiesen werden.
ΓòÉΓòÉΓòÉ 8.2. Prozedur-Aufrufe ΓòÉΓòÉΓòÉ
ΓûÉ ProcedureCall = Designator [ ActualParams ]
ΓûÉ ActualParams = "(" [ Expr { "," Expr } ] ")"
Ein Prozedur-Aufruf (procedure call) dient der Aktivierung einer Prozedur. Der
Programmfluss wird zwecks weiterer AusfБhrung zur aktivierten Prozedur
umgeleitet. Und nach Abschluss der AusfБhrung wird mit der Anweisung, welche
dem Prozedur-Aufruf folgt, fortgefahren. Ein Prozedur-Aufruf kann auch eine
Liste von aktuellen Parametern enthalten. Diese werden an Stelle von den
entsprechenden formalen Parametern, welche in der Prozedur-Deklaration
definiert sind, benutzt. Die Positionen von den aktuellen und den formalen
Parametern stellen die entsprechenden Beziehungen her. Es gibt zwei Arten von
Parametern: Variable- und Wert-Parameter.
Bei einem Variable-Parameter kann der aktuelle Parameter nur aus einem
Bezeichner, welcher die Variable angibt, bestehen. Wenn er ein Element einer
strukturierten Variablen bezeichnet, werden alle Selektoren vor der
Substitution von Formal- nach Aktuell-Parameter ausgewertet. All dieses findet
vor der eigentlichen AusfБhrung der aufzurufenden Prozedur statt. Falls der
Parameter ein Wert-Parameter ist, muss der entsprechende aktuelle Parameter ein
Ausdruck sein. Dieser Ausdruck wird vor der eigentlichen Aktivierung der
Prozedur ausgewertet, und der sich ergebende Wert wird dem formalen Parameter
zugewiesen, so dass er nun wie eine lokale Variable auftritt.
Die Typen von entsprechenden aktuellen und formalen Parametern mБssen fБr
Variable-Parameter gleichwertig und fБr Wert-Parameter Zuweisungs-kompatibel
sein. Wenn die Spracherweiterungen aktiviert sind und wenn der formale
Parameter eine Variable eines Verbundtyps oder ein Wert-Parameter eines
Verbundzeigers ist, dann kann der aktuelle Parameter ein erweiteter Typ sein,
Дhnlich den Regeln fБr Zuweisungen.
Beispiele fБr Prozedur-Aufrufe:
Read( i );
Write( j*2+1, 6 );
INC( a[i] );
ΓòÉΓòÉΓòÉ 8.3. Anweisungsfolgen ΓòÉΓòÉΓòÉ
ΓûÉ StmtSeq = Stmt { ";" Stmt }
Eine Computer-Verarbeitung ist eine Folge von Aktionen, die einen
Anfangszustand in einen Endzustand umwandeln. Vom Endzustand wird die erhoffte
Bedingung fБrs Ergebnis erwartet. In Modula-2 stellt die Anweisung die
grundlegende AusfБhrungseinheit dar. Man kann also die AusfБhrung als eine
Folge von Aktionen in Form von Anweisungen (statement sequence) ausdrБcken.
Stmt1; Stmt2; Stmt3; ... Stmti; ... Stmtn;
Das Semikolon dient als Trennungszeichen zwischen zwei Anweisungen. Es deutet
an, dass die Aktion einer Anweisung von der Aktion der textuell folgenden
Anweisung gefolgt wird. Nur Anweisungen, welche den AusfБhrungsfluss bestimmen,
wie zum Beispiel eine Return-Anweisung oder eine Exit-Anweisung oder aber
Schleifen-Konstrukte, kФnnen bewirken, dass die ProgrammausfБhrung woanders
fortgesetzt wird.
ΓòÉΓòÉΓòÉ 8.4. If-Anweisungen ΓòÉΓòÉΓòÉ
ΓûÉ IfStmt = IF BoolExpr THEN StmtSeq
ΓûÉ { ELSIF BoolExpr THEN StmtSeq }
ΓûÉ [ ELSE StmtSeq ] END
ΓûÉ BoolExpr = Expr
If-Anweisungen bewirken die bedingte AusfБhrung von geschБtzten Anweisungen.
Der Bool'sche Ausdruck, der einer Anweisungsfolge vorrausgeht, dient als ein
Schutzmechanismus. Diese AusdrБcke werden in der Reihenfolge ihres Auftretens
solange ausgewertet, bis einer TRUE ergibt, und eine darauffolgende AusfБhrung
der zugehФrigen Anweisungsfolge bewirkt. Wenn keiner der Bool'schen AusdrБcke
TRUE ergibt, dann wird, fall vorhanden, die Anweisungsfolge, die dem Symbol
ELSE folgt, zur AusfБhrung gebracht.
Beispiele:
IF (ch >= "A") & (ch <= "Z") THEN
ReadIdentifier
ELSIF (ch >= '0') & (ch <= '9') THEN
ReadNumber
ELSIF ch = '"' THEN
ReadString( '"' );
ELSIF ch = "'" THEN
ReadString( "'" );
ELSE
SpecialCharacter
END;
ΓòÉΓòÉΓòÉ 8.5. Case-Anweisungen ΓòÉΓòÉΓòÉ
ΓûÉ CaseStmt = CASE Expr OF Case { "|" Case } [ ELSE StmtSeq ] END
ΓûÉ Case = CaseLabelList ":" StmtSeq
ΓûÉ CaseLabelList = CaseLabels { "," CaseLabels }
ΓûÉ CaseLabels = ConstExpr [ ".." ConstExpr ]
Case-Anweisungen bestimmen die Selektion und AusfБhrung einer Anweisungsfolge
gemДss dem Wert eines Ausdrucks. Zuerst wird dieser Case-Ausdruck berechnet.
Dann wird diejenige Anweisungsfolge ausgefБhrt, deren Liste von Fallmarken den
berechneten Wert enthДlt. Der Typ vom Case-Ausdruck darf nur ein Elementar-Typ
(ausser Gleitkommas), eine AufzДhlung, oder ein Unterbereich sein. Alle
Fallmarken mБssen mit diesem Typ streng kompatibel sein. Fallmarken sind
Konstanten, von denen kein Wert mehrfach vorkommen darf. Wenn der Wert vom
Ausdruck in keinem der FДlle als Fallmarke vorkommt, dann wird, falls
vorhanden, die Anweisungsfolge, die dem Symbol ELSE folgt, zur AusfБhrung
gebracht.
Beispiele:
CASE ch OF
"A".."Z" : ReadIdentifier;
| "0".."9" : ReadNumber;
| "'" , '"' : ReadString( ch );
ELSE SpecialCharacter;
END;
ΓòÉΓòÉΓòÉ 8.6. While-Anweisungen ΓòÉΓòÉΓòÉ
ΓûÉ WhileStmt = WHILE BoolExpr DO StmtSeq END
ΓûÉ BoolExpr = Expr
While-Anweisungen bewirken eine Wiederholung. Wenn der Bool'sche Ausdruck TRUE
ergibt, wird die Anweisungsfolge ausgefБhrt. Die Auswertung des Ausdrucks und
die AusfБhrung der Anweisungsfolge werden wiederholt, solange der Bool'sche
Wert TRUE ergibt.
Beispiele:
WHILE j > 0 DO
j := j DIV 2;
i := i + 1
END;
WHILE i # j DO
IF i > j THEN
i := i - j;
ELSE
j := j - i;
END;
END;
WHILE (t # NIL) & (t^.key # i) DO
t := t^.left
END;
ΓòÉΓòÉΓòÉ 8.7. Repeat-Anweisungen ΓòÉΓòÉΓòÉ
ΓûÉ RepeatStmt = REPEAT StmtSeq UNTIL BoolExpr
ΓûÉ BoolExpr = Expr
Repeat-Anweisungen bewirken eine wiederholte AusfБhrung einer Anweisungsfolge,
in zwar in AbhДngigkeit vom Wert eines Bool'schen Ausdrucks. Der Ausdruck wird
nach jeder AusfБhrung der Anweisungsfolge erneut ausgewertet, und die
Wiederholung wird beendet, sobald der Ausdruck den Wert TRUE ergibt. Die
Anweisungsfolge wird mindestens einmal ausgefБhrt.
Beispiele:
REPEAT
k := i MOD j;
i := j;
j := k;
UNTIL j = 0;
ΓòÉΓòÉΓòÉ 8.8. For-Anweisungen ΓòÉΓòÉΓòÉ
ΓûÉ ForStmt = FOR ControlVar ":=" Expr TO Expr [ BY ConstExpr ]
ΓûÉ DO StmtSeq END
ΓûÉ ControlVar = Ident
ΓûÉ ConstExpr = Expr
Eine For-Anweisung bewirkt eine bestimmte Anzahl von wiederholten AusfБhrungen
einer Anweisungsfolge, wobei ein laufend inkrementierter oder dekrementierter
Wert einer Integer- oder Cardinal-Variablen zugewiesen wird. Diese Variable
nennt man die Kontrollvariable einer For-Anweisung. Die Kontrollvariable darf
nicht die Komponente einer strukturierten Variablen sein, auch darf sie weder
importiert noch ein Parameter sein, es sei denn, dass die Spracherweiterungen
aktiviert sind.
Die Anweisung
FOR v := low TO high BY step DO
statements
END;
ist gleichbedeutend mit
v := low;
temp := high;
IF step > 0 THEN
WHILE v <= temp DO
statements;
v := v + step;
END;
ELSE
WHILE v >= temp DO
statements;
v := v + step;
END;
END;
'low' muss mit 'v' Zuweisungs-kompatibel sein, 'high' muss mit 'v' kompatibel
(das heisst vergleichbar) sein, und 'step' muss ein konstanter Ausdruck
ungleich Null sein, und zwar fБr einen Integer- oder Cardinal-Typ. Falls 'step'
nicht angegeben ist, dann wird 1 als sein Wert angenommen.
Beispiele:
FOR i := 1 TO 80 DO
j := j + a[ i ];
END;
FOR i := 80 TO 2 BY -1 DO
a[ i ] := a[ i-1 ];
END;
ΓòÉΓòÉΓòÉ 8.9. Loop/Exit-Anweisungen ΓòÉΓòÉΓòÉ
ΓûÉ Stmt = LoopStmt | EXIT
ΓûÉ LoopStmt = LOOP StmtSeq END
Eine Loop-Anweisung bewirkt die wiederholte AusfБhrung einer Anweisungsfolge.
Sie wird durch die AusfБhrung einer EXIT-Anweisung innerhalb der Folge beendet.
Eine Exit-Anweisung wird durch das Symbol EXIT angegeben. Sie bewirkt die
Terminierung der sie umschliessenden Loop-Anweisung und die Fortsetzung mit
derjenigen Anweisung, die der Loop-Anweisung folgt. Exit-Anweisungen stehen im
Zusammenhang mit der Loop-Anweisung, von welcher sie umgeben sind, trotz ihrer
syntaktischen UnabhДngigkeit. Dieser Ъbersetzer gibt jedoch eine Warnung aus,
wenn ein EXIT ohne umschliessende Loop-Anweisung gefunden wird.
Loop-Exit-Anweisungen sind nБtzlich, um Wiederholungen mit verschiedenen
Austrittspunkten programmieren zu kФnnen, oder um eine Austrittsbedingung in
der Mitte einer wiederholten Anweisungsfolge auszudrБcken.
Beispiel:
LOOP
ReadInt( i );
IF i < 0 THEN
EXIT;
END;
WriteInt( i );
END;
ΓòÉΓòÉΓòÉ 8.10. With-Anweisungen ΓòÉΓòÉΓòÉ
ΓûÉ WithStmt = WITH RecDesignator DO StmtSeq END
ΓûÉ RecDesignator = Designator | Guard
ΓûÉ Guard = Qualident ":" Qualident
Die With-Anweisung besteht aus einer Verbundvariablen und einer
Anweisungsfolge. In diesen Anweisungen kann die Qualifikation von Feldnamen
weggelassen werden, sofern sie sich auf die Variable, welche in der
With-Klausel angegeben ist, bezieht. Gibt der Bezeichner eine Komponente einer
strukturierten Variablen an, wird der Selektor vor der Anweisungsfolge genau
einmal ausgewertet. Die With-Anweisung erФffnet einen neuen
Sichtbarkeitsbereich.
Beispiel (vergleiche Beispiele aus der Sektion Бber Variable-Deklarationen):
WITH t^ DO
key := 0;
left := NIL;
right := NIL
END;
Wenn die Spracherweiterungen aktiviert sind, dann kann eine With-Anweisung in
AbhДngigkeit vom Ergebnis eines Typentests eine Anweisungsfolge ausfБhren und
wendet dabei fБr jedes Auftreten dieser Verbundvariable innerhalb der
Anweisungsfolge einen Typenschutz an.
Wenn 'v' ein Variable-Parameter eines Verbundtyps oder ein Verbundzeiger ist,
mit dem dazugehФrigen statischen Typ T0', dann hat die Anweisung
WITH v : T1 DO ... END
die folgende Bedeutung: Wenn 'T1' der dynamische Typ von 'v' ist, dann wird die
Anweisungsfolge ausgefБhrt, wobei 'v' so betrachtet wird, als wДre der
dazugehФrige Typ 'T1'; sonst wird die ProgrammausfБhrung gestoppt (mit einem
RБckgabewert von 3 bei diesem Ъbersetzer)
Beispiel:
TYPE
(* basic employee structure *)
Employee = POINTER TO EmployeeDesc;
EmployeeDesc = RECORD
Name : ARRAY [0..30] OF CHAR;
Salary : REAL;
END;
(* extended employee record for secretaries *)
Secretary = POINTER TO SecretaryDesc;
SecretaryDesc = RECORD( Employee )
Bonus : REAL;
END;
VAR
EmployeeVar : Employee;
(* .............................. *)
WITH EmployeeVar : Secretary DO
Employee^.Salary := 1234.00;
Employee^.Bonus := 77.00;
END;
Der regionale Typenschutz erФffnet nicht einen neuen Sichtbarkeitsbereich, aber
ein lokaler Typenschutz in der With-Klausel sehr wohl.
Das gleiche Beispiel mit einem lokalen Typenschutz:
WITH EmployeeVar( Secretary )^ DO
Salary := 1234.00;
Bonus := 77.00;
END;
ΓòÉΓòÉΓòÉ 8.11. Return-Anweisungen ΓòÉΓòÉΓòÉ
ΓûÉ ReturnStmt = RETURN [ Expr ]
Eine Return-Anweisung bewirkt die Terminierung einer Prozedur. Sie wird durch
das Symbol RETURN, gefolgt von einem mФglichem Ausdruck, angegeben, wenn die
Prozedur eine Funktion ist. Der Typ von diesem Ausdruck muss mit dem
Ergebnistyp, welcher im Prozedurkopf erkДrt worden ist, Zuweisungs-kompatibel
sein.
Funktions-Prozeduren erforden die Anwesenheit mindestens einer
Return-Anweisung, welche den Ergebniswert beinhaltet. In eigentlichen
Prozeduren kann die Return-Anweisung fehlen und wird dann am Ende vom
Prozedur-KФrper angenommen. Jede explizite Return-Anweisung erscheint also als
ein zusДtzlicher Terminierungspunkt.
═══ 9. Typen-VertrДglichkeiten ═══
Innerhalb dieser Dokumentation werden Begriffe zur Beschreibung der
KompatibilitДt von Typen auf verschiedenen Ebenen benutzt. Diese Sektion gibt
eine Ъbersicht Бber die vollstДndigen Definitionen fБr die folgenden Begriffe
und KompatibilitДts-Regeln:
- Identische Typen
- Gleichwertige Typen
- Typenerweiterungen
- Zuweisungs-KompatibilitДt
- Ausdrucks-KompatibilitДt
- Erweiterte Ausdrucks-KompatibilitДt
- Strenge Ausdrucks-KompatibilitДt
- Reihungs-KompatibilitДt
- Ъbereinstimmung formaler Parameterlisten
- Typtransfer-Funktionen
Die Regeln sind gegenБber Standard-Modula-2 etwas erweitert. Dies ist wegen den
verschiedenen GrФssen der Elementartypen und wegen den Spracherweiterungen
notwendig. Dennoch ist fБr Programme, die sich mit den Typen gemДss den
Beschreibungen in Wirth's 'Programmierung in Modula-2, 4te Ausgabe' begnБgen,
eine AbwДrtsvertrДglichkeit gegeben. Der Wirth'sche Standard erwДhnt die
elementaren Typen INTEGER, LONGINT und CARDINAL, nicht aber SHORTINT,
SHORTCARD, oder LONGCARD, in seinem o.g. Buch. Und selbst der LONGINT-Typ wird
dort nur kurz erwДhnt, ohne nДher auf die Auswirkungen hinsichtlich seiner
VertrДglichkeitsregeln einzugehen.
Dieser Ъbersetzer versucht sich so eng wie mФglich an den Wirth'schen Standard
zu halten, bietet aber auch SHORT- oder LONG-Versionen fБr Integers, Cardinals,
und fБr die Standardfunktionen TRUNC und FLOAT.
ΓòÉΓòÉΓòÉ 9.1. Identische Typen ΓòÉΓòÉΓòÉ
Zwei Variablen 'a' und 'b' mit den Typen 'Ta' und 'Tb' haben identische Typen,
wenn
1. 'Ta' und 'Tb' beide durch denselben Typnamen angegeben werden, oder
2. 'Ta' in einer Typ-Deklaration 'Ta=Tb' mit 'Tb' gleichgesetzt wird,
oder
3. 'a' und 'b' in der gleichen Namensliste einer Deklaration fБr eine
Variable, fБr ein Feld eines Verbunds, oder fБr einen formalen
Parameter (ausser offenen Reihungen) erscheinen.
ΓòÉΓòÉΓòÉ 9.2. Gleichwertige Typen ΓòÉΓòÉΓòÉ
Zwei Typen 'Ta' und 'Tb' sind gleichwertig, wenn
1. 'Ta' und 'Tb' typenidentisch sind, oder wenn
2. 'Ta' und 'Tb' offene Reihungen mit gleichwertigen Elementstypen sind,
oder wenn
3. 'Ta' und 'Tb' Prozedur-Typen beschreiben, deren formale
Parameterlisten Бbereinstimmen.
ΓòÉΓòÉΓòÉ 9.3. Typenerweiterung von eimem Basityp ΓòÉΓòÉΓòÉ
Diese Regel gilt nur dann, wenn die Spracherweiterungen aktiviert sind.
FБr eine Typ-Deklaration 'Tb=RECORD(Ta)...END' ist 'Tb' eine direkte
Erweiterung von 'Ta', und 'Ta' ist ein direkter Basistyp von 'Tb'.
Ein Typ 'Tb' ist eine Erweiterung von Typ 'Ta', das heisst, 'Ta' ist ein
Basistyp von 'Tb', wenn
1. 'Ta' und 'Tb' typenidentisch sind, oder
2. 'Tb' eine direkte Erweiterung einer Erweiterung von 'Ta' ist.
Wenn 'Pa = POINTER TO Ta' ist, und 'Pb = POINTER TO Tb' ist, ist 'Pb' eine
Erweiterung von 'Pa' ('Pa' ist ein Basistyp von 'Pb'), wenn 'Tb' eine
Erweiterung von 'Ta' ist.
═══ 9.4. Zuweisungs-KompatibilitДt ═══
Ein Ausdruck 'e' mit Typ 'Te' ist Zuweisungs-kompatibel mit einer Variablen 'v'
vom Typ 'Tv', wenn eine der folgenden Bedingungen zutrifft:
1. 'Te' und 'Tv' sind typenidentisch.
2. 'Te' und 'Tv' sind Cardinal- oder Integer-Typen und
TSIZE(Tv)>=TSIZE(Te).
3. 'Te' und 'Tv' sind Real-Typen und TSIZE(Tv)>=TSIZE(Te).
4. 'Te' und 'Tv' sind Verbundtypen und 'Te' ist eine Erweiterung von
'Tv' und der dynamische Typ von 'v' ist 'Tv'.
5. 'Te' und 'Tv' sind Zeigertypen und 'Te' ist eine Erweiterung von
'Tv'.
6. 'Tv' ist ein Zeigertyp und 'e' ist NIL.
7. 'Tv' ist eine CHAR- Reihung mit n Elementen, und 'e' ist eine
Zeichenkette-Konstante mit m Zeichen und m < n.
8. 'Tv' ist ein Prozedur-Typ und 'e' ist der Name einer Prozedur deren
formale Parameter mit jenen von 'Tv' Бbereinstimmen.
9. 'Tv' oder 'Te' ist einer der SYSTEM-Typen BYTE, WORD, DWORD oder
LONGWORD, FWORD, QWORD, TBYTE und 'TSIZE(Tv)=TSIZE(Te)'.
10. 'Tv' ist der SYSTEM-Typ SHORTADDRESS (oder NEAR ADDRESS fБr die
Speicher-Modelle Tiny, Small, Medium, oder Flat32) und 'Te' ist ein
Cardinal-, Integer-, oder NEAR Zeiger-Typ und
'TSIZE(Tv)>=TSIZE(Te)'.
11. 'Tv' ist ein Cardinal-, Integer-, oder NEAR Zeiger-Typ und 'Te' ist
der SYSTEM-Typ SHORTADDRESS (oder NEAR ADDRESS fБr die
Speicher-Modelle Tiny, Small, Medium, oder Flat32) und
'TSIZE(Tv)>=TSIZE(Te)'.
12. Entweder 'Tv' oder 'Ta' ist der SYSTEM-Typ LONGADDRESS (oder FAR
ADDRESS fБr die Speicher-Modelle Compact oder Large) und der andere
'Ta' oder 'Tv' ist irgendein FAR Zeigertyp.
═══ 9.5. Ausdrucks-KompatibilitДt ═══
FБr einen gegebenen Operator sind die Typen seiner Operanden Ausdrucks-
kompatibel, wenn sie den Bedingugen der folgenden Tabelle, die auch die
Ergebnistypen zeigt, entspricht. Es wird angenommen, dass der Zeigertyp 'P1'
eine Erweiterung vom Typ 'P0' ist. Wenn die Spracherweiterungen aktiviert sind,
dann sind auch einige zusДtzliche Ausdrucks-KompatibilitДten verfБgbar.
Die SYSTEM-Typen SHORTADDRESS, ADDRESS und LONGADDRESS werden wie Cardinals
behandelt. Und wenn der Relations-Operator weder '=' noch '#' noch '<>' ist,
und wenn der ADDRESS-Typ ein FAR ADDRESS (bzw. LONGADDRESS) ist, dann wird nur
der Offset-Teil fБr die Berechnung herangezogen. Wenn es FAR ADDRESS (bzw.
LONGADDRESS) Operanden in einem relationalen Ausdruck gibt, dann sind nur die
'=' oder '#' oder '<>' erlaubt. Wenn es ADDRESS- Operanden in einem
nicht-relationalen Ausdruck gibt, dann ist der Ergebnistyp der Typ vom
Address-Operand.
ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
ΓöéOperator ΓöéOperand1 ΓöéOperand2 ΓöéErgebnistyp Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé+ - * DIV ΓöéSHORTINT ΓöéSHORTINT Γöékleinster Integer Γöé
ΓöéMOD ΓöéINTEGER ΓöéINTEGER Γöéder beide Γöé
Γöé ΓöéLONGINT ΓöéLONGINT ΓöéOperandtypen Γöé
Γöé ΓöéUnterbereich ΓöéUnterbereich Γöéeinschliesst Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé+ - ΓöéSHORTINT Γöé Γöéidentischer Γöé
Γöé ΓöéINTEGER Γöé ΓöéInteger-Typ Γöé
Γöé ΓöéLONGINT Γöé Γöé Γöé
Γöé ΓöéUnterbereich Γöé Γöé Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé+ - * ΓöéSHORTREAL REALΓöéSHORTREAL REALΓöékleinster Real der Γöé
Γöé ΓöéLONGREAL ΓöéLONGREAL Γöébeide Operandtypen Γöé
Γöé Γöé Γöé Γöéeinschliesst Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé+ - ΓöéSHORTREAL REALΓöé Γöéidentischer Real-TypΓöé
Γöé ΓöéLONGREAL Γöé Γöé Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé/ ΓöéSHORTREAL REALΓöéSHORTREAL REALΓöékleinster Real der Γöé
Γöé ΓöéLONGREAL ΓöéLONGREAL Γöébeide Operandtypen Γöé
Γöé Γöé Γöé Γöéeinschliesst Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé+ - * / ΓöéMengentyp Γöéidentischer Γöéidentischer Γöé
Γöé Γöé ΓöéMengentyp ΓöéMengentyp Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéOR AND & ΓöéBOOLEAN ΓöéBOOLEAN ΓöéBOOLEAN Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéNOT ~ ΓöéBOOLEAN Γöé ΓöéBOOLEAN Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé= <> < <= ΓöéSHORTINT ΓöéSHORTINT ΓöéBOOLEAN Γöé
Γöé> >= # ΓöéINTEGER ΓöéINTEGER Γöé Γöé
Γöé ΓöéLONGINT ΓöéLONGINT Γöé Γöé
Γöé Γöéint-UnterbereiΓöéUnterbereich Γöé Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé= <> < <= ΓöéSHORTCARD ΓöéSHORTCARD ΓöéBOOLEAN Γöé
Γöé> >= # ΓöéCARDINAL ΓöéCARDINAL Γöé Γöé
Γöé ΓöéLONGCARD ΓöéLONGCARD Γöé Γöé
Γöé ΓöéUnterbereich ΓöéUnterbereich Γöé Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé= <> < <= ΓöéSHORTREAL REALΓöéSHORTREAL REALΓöéBOOLEAN Γöé
Γöé> >= # ΓöéLONGREAL ΓöéLONGREAL Γöé Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé= <> < <= ΓöéCHAR ΓöéCHAR ΓöéBOOLEAN Γöé
Γöé> >= # ΓöéUnterbereich ΓöéUnterbereich Γöé Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé= <> < <= ΓöéBOOLEAN ΓöéBOOLEAN ΓöéBOOLEAN Γöé
Γöé> >= # Γöé Γöé Γöé Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé= <> <= >=ΓöéMengentyp Γöéidentischer ΓöéBOOLEAN Γöé
Γöé# Γöé ΓöéMengentyp Γöé Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé= <> # ΓöéZeigertyp P0 ΓöéZeigertyp P0 ΓöéBOOLEAN Γöé
Γöé Γöéoder P1 Γöéoder P1 Γöé Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
│= <> < <= │AuszДhlung │identische │BOOLEAN │
│> >= # │ │AufzДhlung │ │
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéIN ΓöéSHORTCARD ΓöéSET OF erster ΓöéBOOLEAN Γöé
Γöé ΓöéSHORTINT CHAR ΓöéTyp Γöé Γöé
Γöé ΓöéBOOLEAN Γöé Γöé Γöé
│ │AufzДhlung │ │ │
Γöé ΓöéUnterbereich Γöé Γöé Γöé
ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
═══ 9.6. Erweiterte Ausdrucks-KompatibilitДt ═══
Dieser Ъbersetzer fБr Modula-2 hat zusДtzliche Ausdrucks-KompatibilitДten
implementiert. Sie sind nur verfБgbar, wenn die Spracherweiterungen aktiviert
sind, und sie schliessen weitere logische, relationale, und auch Bit-weise
Operatoren ein. Typ T1 muss eine Erweiterung von Typ T0 sein fБr die Relation
'T0 IS T1'.
Die folgende Tabelle zeigt die zusДtzlichen KompatibilitДten:
ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
ΓöéOperator ΓöéOperand1 ΓöéOperand2 ΓöéErgebnistyp Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéXOR ΓöéBOOLEAN ΓöéBOOLEAN ΓöéBOOLEAN Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéOR XOR ANDΓöéSHORTINT ΓöéSHORTINT Γöékleinster Integer Γöé
ΓöéSHL SHR & ΓöéINTEGER ΓöéINTEGER Γöéder beide Γöé
Γöé ΓöéLONGINT ΓöéLONGINT ΓöéOperandtypen Γöé
Γöé ΓöéUnterbereich ΓöéUnterbereich Γöéeinschliesst. Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéOR XOR ANDΓöéSHORTCARD ΓöéSHORTCARD Γöékleinster Cardinal Γöé
ΓöéSHL SHR & ΓöéCARDINAL ΓöéCARDINAL Γöéder beide Γöé
Γöé ΓöéLONGCARD ΓöéLONGCARD ΓöéOperandtypen Γöé
Γöé ΓöéUnterbereich ΓöéUnterbereich Γöéeinschliesst. Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéNOT ~ ΓöéSHORTINT Γöé Γöéidentischer Integer Γöé
Γöé ΓöéINTEGER Γöé Γöé Γöé
Γöé ΓöéLONGINT Γöé Γöé Γöé
Γöé ΓöéUnterbereich Γöé Γöé Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéNOT ~ ΓöéSHORTCARD Γöé Γöéidentischer CardinalΓöé
Γöé ΓöéCARDINAL Γöé Γöé Γöé
Γöé ΓöéLONGCARD Γöé Γöé Γöé
Γöé ΓöéUnterbereich Γöé Γöé Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé= <> # ΓöéProzedur-Typ Γöéidentischer Γöéidentischer Γöé
Γöé ΓöéT ΓöéProzedur-Typ ΓöéProzedur-Typ T Γöé
Γöé Γöé ΓöéT Γöé Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéIS ΓöéTyp T0 Γöéerweiteter ΓöéBOOLEAN Γöé
Γöé Γöé ΓöéTyp T1 Γöé Γöé
ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
═══ 9.7. Strenge Ausdrucks-KompatibilitДt ═══
Zwei Operanden sind streng kompatibel zueinander, wenn sie Ausdrucks-kompatibel
sind, und wenn ihre Typen gleicher GrФsse sind. Strenge
Asudrucks-KompatibilitДt ist fБr Operanden in den folgenden ZusammenhДngen
erforderlich:
ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
ΓöéKontext ΓöéOperand1 ΓöéOperand2 Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéCase-Anweisung ΓöéFallmarke ΓöéCase-Ausdruck Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéProzedur-AufrufΓöéaktueller Parameter Γöéformaler Γöé
Γöé Γöé ΓöéVAR-Parameter Γöé
ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
═══ 9.8. Reihungs-KompatibilitДt ═══
Ein aktueller Parameter 'a' mit Typ 'Ta' ist Reihungs-kompatibel mit einem
formalen Parameter 'f' mit Typ 'Tf', wenn
1. 'Tf' und 'Ta' typenidentisch sind, oder wenn
2. 'Tf' eine offene Reihung ist, und 'Ta' irgendeine Reihung ist, und
deren Element-Typen Reihungs-kompatibel sind, oder wenn
3. 'Tf' ein 'ARRAY OF CHAR' und 'a' eine Zeichenkette ist.
═══ 9.9. Ъbereinstimmung formaler Parameterlisten ═══
Zwei formale Parameterlisten stimmen Бberein, wenn
1. sie die gleiche Anzahl von Parametern haben
2. und sie entweder identische oder keine Ergebnistypen fБr Funktionen
haben, und
3. die Parameter an den entsprechenden Positionen gleichwertige Typen
haben, und
4. die Parameter an den entsprechenden Positionen beide entweder Wert-
oder VAR-Parameter sind.
ΓòÉΓòÉΓòÉ 9.10. Typtransfer-Funktionen ΓòÉΓòÉΓòÉ
Neben den Objekten, die vom Pseudo-Modul SYSTEM exportiert werden, gibt es noch
eine weitere system-abhДngige Eigenschaft. Es handelt sich um die MФglichkeit,
einen Typnamen 'T' als den Namen eines Typtransfers zu benutzen, um den Typ des
Operands mit dem neuen Typ 'T' zu Бberschreiben. Solche Funktionen sind
natБrlich stark implementierungs-abhДngig, weil keine expliziten Instruktionen
zur Konvertierung daran beteiligt sind. Sie reinterpretieren einfach einen
Operanden als einen Wert mit einem anderen Typ. Der Programmierer sollte
beachten, dass Typtransfers nicht immer fБr andere Ъbersetzer Бbertragbar sind.
Obwohl Modula-2 eine typenstrenge Sprache ist, gibt es einige Бbertragbare
Erleichterungen fБr die PrБfungen von Typen, und zwar durch standardisierte
Funktionen fБr Typtransfers, z.B. VAL(T,x), CHR(x) oder ORD(x), desgleichen
standardisierte Funktionen zur Оnderung der TypgrФssen, z.B. SHORT(x) oder
LONG(x).
Beispiele fБr Typtransfers :
VAR i : SHORTINT;
VAR ch : CHAR;
VAR b : BOOLEAN;
VAR v : SHORTREAL;
VAR c : LONGCARD;
....
BEGIN
(* BOOLEAN b interpreted as SHORTINT *)
i := SHORTINT( b );
(* BOOLEAN b interpreted as CHAR *)
ch := CHAR( b );
(* LONGCARD c interpreted as SHORTREAL *)
v := SHORTREAL( c );
END ....
ΓòÉΓòÉΓòÉ 10. SYSTEM-Modul ΓòÉΓòÉΓòÉ
Das Modul SYSTEM enthДlt gewisse Konstanten, Typen, Functions-Prozeduren, und
eigentliche Prozeduren. Diese sind notwendig, um besondere maschinennahe
Operationen fБr einen bestimmtem Computer und/oder einem bestimmten
Betriebssystem zu implementieren. U.a. gehФren dazu MФglichkeiten, auf GerДte,
die vom Computer kontrolliert werden, zuzugreifen, oder aber auch
Erleichterungen der strengen, durch die Sprache erzwungenen, Regeln zur
TypenvertrДglichkeit.
Es wird sehr empfohlen, den Gebrauch des Moduls SYSTEM nur auf maschinennahe
Module zu beschrДnken. Solche Module sind dann natБrlich nicht portable und
unsicher. Sie sind aber leicht an dem Namen SYSTEM, welcher in der Importliste
erscheint, zu erkennen.
Hinweis: Da die Objekte, die von SYSTEM importiert werden, speziellen Regeln
gehorchen, muss dieses Modul dem Ъbersetzer bekannt sein. Es wird daher ein
Pseudo-Modul genannt, fБr das man kein gesondertes Definitions-Modul schreiben
muss.
Dieser Ъbersetzer hat auch alle Standard-Namen im Modul SYSTEM implementiert,
von wo aus sie automatisch zu allen anderen Modulen exportiert werden.
ΓòÉΓòÉΓòÉ 10.1. SYSTEM-Konstanten ΓòÉΓòÉΓòÉ
Die folgenden Konstanten geben das aktive Speicher-Modell, das Ziel-
Betriebssystem und die Ziel- Prozessoren an. Sie werden nur qualifiziert
exportiert. Ihre Werte werden wДhrend des Starts des Ъbersetzers automatisch
gesetzt. Sie kФnnen jedoch durch entsprechende Schalter von der Befehlszeile
beeinflusst werden. Die folgende Tabelle zeigt die mФglichen Konstanten und
ihre Werte:
SYSTEM.TinyModel TRUE bei 16-bit-Ъbersetzung fБr Tiny- Speicher-Modell
sonst FALSE
SYSTEM.SmallModel TRUE bei 16-bit-Ъbersetzung fБr Small- Speicher-Modell
sonst FALSE
SYSTEM.MediumModel TRUE bei 16-bit-Ъbersetzung fБr Medium- Speicher-Modell
sonst FALSE
SYSTEM.CompactModel TRUE bei 16-bit-Ъbersetzung fБr Compact-
Speicher-Modell
sonst FALSE
SYSTEM.LargeModel TRUE bei 16-bit-Ъbersetzung fБr Large- Speicher-Modell
sonst FALSE
SYSTEM.Flat32Model TRUE bei 32-bit-Ъbersetzung fБr Flat- Speicher-Modell
sonst FALSE
SYSTEM.DOS TRUE bei Ъbersetzung fБr DOS,
sonst FALSE
SYSTEM.WIN TRUE bei Ъbersetzung fБr MS-Windows 3.x,
sonst FALSE
SYSTEM.OS2 TRUE bei Ъbersetzung fБr OS/2,
sonst FALSE
SYSTEM.Processor 8086 bei Ъbersetzung fБr 8086/8088 CPU,
80286 bei Ъbersetzung fБr 80286 CPU,
80386 bei Ъbersetzung fБr 80386 CPU,
80486 bei Ъbersetzung fБr 80486 CPU,
80586 bei Ъbersetzung fБr 80586 (PENTIUM) oder hФhere CPU
SYSTEM.NumericProcessor TRUE wenn Ъbersetzung auch fБr 80x87 numerischen
Koprozessor,
FALSE wenn kein numerischer Koprozessor angegeben.
Hinweis:OS/2 2.x/3.0 benutzt eine Software-Emulation, wenn kein
numerischer Koprozessor im Computer-System installiert ist.
ΓòÉΓòÉΓòÉ 10.2. SYSTEM-Typen ΓòÉΓòÉΓòÉ
Die Sprache Modula-2 erzwingt gewФhnlich eine strenge TypenprБfung wДhrend der
Ъbersetzung. Diese kann jedoch durch den Gebrauch der SYSTEM-Typen BYTE, WORD,
DWORD, FWORD, QWORD oder TBYTE erleichtert werden. FБr sie sind keine
Operationen ausser der Zuweisung definiert. Wenn jedoch ein formaler Parameter
einer Prozedur einen der o.g. Typen enthДlt, dann darf der entsprechende
aktuelle Typ jeden Typ, der den gleichen Speicherplatz fБr eine gegebene
Implementation belegt, beinhalten. Wenn der formale Parameter ein 'ARRAY OF T'
ist, wobei 'T' einer der o.g. Typen ist, dann darf der entsprechende aktuelle
Parameter 'A' jeden Typ beinhalten, solange SIZE(A)=TSIZE(T)*n gilt. Das
heisst, dass die SpeichergrФsse genau ein Vielfaches der GrФsse vom Typ 'T'
betragen muss. Die folgende Tabelle zeigt die TypgrФssen fБr o.g. Typen:
Typ GrФsse
SYSTEM.BYTE 1
SYSTEM.WORD 2
SYSTEM.DWORD 4
SYSTEM.LONGWORD wie SYSTEM.DWORD
SYSTEM.FWORD 6
SYSTEM.QWORD 8
Die folgenden Zeigertypen sind Ausdrucks-kompatibel und Zuweisungs-kompatibel
mit allen Zeigertypen mit gleichem (mФglicherweise implizitem) NEAR- oder
FAR-Attribut und gleicher TypgrФsse. Wenn sie einen (mФglicherweise
impliziten) NEAR Zeiger angeben, dann sind sie auch mit Cardinal- und
Integer-Typen Zuweisungs-kompatibel. Sie sind wie folgt definiert:
SYSTEM.SHORTADDRESS NEAR POINTER TO BYTE
SYSTEM.ADDRESS Bei einer Ъbersetzung fБr Compact oder Large
Speicher-Modelle:
FAR POINTER TO BYTE
sonst:
NEAR POINTER TO BYTE
SYSTEM.LONGADDRESS FAR POINTER TO BYTE
SYSTEM.PROCESS SYSTEM.ADDRESS
ΓòÉΓòÉΓòÉ 10.3. SYSTEM-Funktions-Prozeduren ΓòÉΓòÉΓòÉ
Die Funktions-Prozeduren vom Modul SYSTEM bieten elementare Laufzeitdienste und
maschinennahe Operationen an. Einige von ihnen sind generisch und werden
wДhrend der Ъbersetzung wie Makros expandiert. Andere sind als echte Prozeduren
im Modul SYSTEM.MOD implementiert. In diesem Ъberstzer haben auch alle
Standard-Funktionen ihren Ursprung im SYSTEM-Modul.
Die folgenden Funktions-Prozeduren sind verfБgbar und gehФren nicht zu den
Standard-Objekten. Sie werden in den folgenden Sektionen beschrieben.
- generisch LEN( a, n )
- generisch LEN( a )
- generisch TSIZE( T )
- generisch DSIZE( a, n )
- generisch DSIZE( a )
- generisch ADR( x )
- generisch LONGADR( x )
- generisch SHORTADR( x )
- generisch OFS( x )
- generisch SEG( x )
- generisch currentFile( )
- generisch currentLine( )
- PROCEDURE GetExitProc( ) : PROC
Die folgenden Laufzeit-Funktionen sind im SYSTEM-Modul implementiert:
- PROCEDURE TestBit
( Set:ADDRESS; BitPos:SHORTCARD ):BOOLEAN;
- PROCEDURE LongMul
( i,j:LONGCARD ):LONGCARD;
- PROCEDURE LongIMul
( i,j:LONGINT ):LONGINT;
- PROCEDURE LongDiv
( i,j:LONGCARD ):LONGCARD;
- PROCEDURE LongIDiv
( i,j:LONGINT ):LONGINT;
- PROCEDURE LongMod
( i,j:LONGCARD ):LONGCARD;
- PROCEDURE LongIMod
( i,j:LONGINT ):LONGINT;
- PROCEDURE LongShl
( i,j:LONGCARD ):LONGCARD;
- PROCEDURE LongShr
( i,j:LONGCARD ):LONGCARD;
- PROCEDURE LongSar
( i,j:LONGINT ):LONGINT;
- PROCEDURE somResolve
( Object : LONGWORD; MethodToken : LONGWORD ) : LONGWORD;
- PROCEDURE somFindSMethodOk
( classObject : LONGWORD; idMethod : LONGWORD ) : LONGWORD;
- PROCEDURE somGetClass
( Object : LONGWORD ) : LONGWORD;
ΓòÉΓòÉΓòÉ 10.3.1. SYSTEM-Funktion LEN ΓòÉΓòÉΓòÉ
Die Funktion LEN(a,n) gibt fБr einen Reihungs- Operanden 'a' in der Dimension
'n' die Anzahl der Elemente als eine Cardinal-Zahl zurБck. Die Funktion LEN(a)
ist gleichbedeutend mit LEN(a,0). Das folgende Beispiel veranschaulicht ihre
Verwendung:
..........
FROM SYSTEM IMPORT LEN;
..........
CONST
Len0 = 15;
Len1 = 20;
Len2 = 25;
..........
VAR
A : ARRAY [1..Len0], [1..Len1], [1..Len2] OF INTEGER;
i : CARDINAL;
j : CARDINAL;
k : CARDINAL;
..........
BEGIN
i := LEN( A ); (* i := 15 *)
j := LEN( A, 1 ); (* j := 20 *)
k := LEN( A, 2 ); (* k := 25 *)
END
..........
ΓòÉΓòÉΓòÉ 10.3.2. SYSTEM-Funktion TSIZE ΓòÉΓòÉΓòÉ
Die Funktion TSIZE(T) gibt fБr einen gebenen Typ 'T' seine Byte-GrФsse als eine
Cardinal- oder Integer-Zahl zurБck. Diese Funktion wird gewФhnlich wДhrend der
Anforderung von dynamischen Speicher gebraucht.
Das folgende Beispiel verdeutlicht die Verwendung:
IMPORT Storage;
IMPORT SYSTEM;
...........
TYPE
A : ARRAY [0..10] OF LONGINT;
...........
VAR
pa : POINTER TO A;
...........
BEGIN
(* Allocate 11 * TSIZE( LONGINT ) = 11 * 4 = 44 bytes *)
Storage.ALLOCATE( pa, SYSTEM.TSIZE( A ) );
...........
END
...........
ΓòÉΓòÉΓòÉ 10.3.3. SYSTEM-Funktion DSIZE ΓòÉΓòÉΓòÉ
Die Funktion DSIZE(a,n) gibt fБr einen Reihungs- Operanden 'a' in der Dimension
'n' die Operand-GrФsse als eine Cardinal-Zahl zurБck. Die Funktion DSIZE(a) ist
gleichbedeutend mit DSIZE(a,0). Das folgende Beispiel verdeutlicht den
Gebrauch:
..........
FROM SYSTEM IMPORT DSIZE;
..........
CONST
Len0 = 15;
Len1 = 20;
Len2 = 25;
..........
VAR
A : ARRAY [1..Len0], [1..Len1], [1..Len2] OF INTEGER;
i : CARDINAL;
j : CARDINAL;
k : CARDINAL;
..........
BEGIN
i := DSIZE( A ); (* i := 15*20*25*TSIZE(INTEGER) *)
j := DSIZE( A, 1 ); (* j := 20*25*TSIZE(INTEGER) *)
k := DSIZE( A, 2 ); (* k := 25*TSIZE(INTEGER) *)
END
..........
ΓòÉΓòÉΓòÉ 10.3.4. SYSTEM-Funktion ADR ΓòÉΓòÉΓòÉ
Die Funktion ADR(x) gibt die Adresse eines Operanden 'x' zurБck. Der
Ergebnistyp ist ADDRESS. Die Funktion ADR(x) verhДlt sich wie SHORTADR(x), wenn
fБr eines der nicht-segmentierten kleinen Daten- Modelle Tiny, Small, Medium
oder Flat32 Бbersetzt wird. Sonst verhДlt sie sich wie ein LONGADR(x), wenn fБr
eines der segmentierten Daten- Modelle Compact oder Large Бbersetzt wird.
ΓòÉΓòÉΓòÉ 10.3.5. SYSTEM-Funktion LONGADR ΓòÉΓòÉΓòÉ
Die Funktion LONGADR(x) gibt die FAR Adresse eines Operanden 'x' zurБck. Der
Ergebnistyp ist der segmentierte FAR Zeiger LONGADDRESS, welcher mit jedem FAR
Zeiger- oder Cardinal- Ausdruck kompatibel ist, und welcher mit jedem FAR
Zeiger Zuweisungs-kompatibel ist.
ΓòÉΓòÉΓòÉ 10.3.6. SYSTEM-Funktion SHORTADR ΓòÉΓòÉΓòÉ
Die Function SHORTADR(x) gibt die NEAR Adresse eines Operanden 'x' zurБck. Der
Ergebnistyp ist der nicht-segmentierte NEAR Zeiger SHORTADDRESS, welcher mit
jedem NEAR Zeiger- oder Cardinal- Ausdruck kompatibel ist, und welcher mit
jedem NEAR Zeiger-, Cardinal- oder Integer-Operand Zuweisungs-kompatibel ist.
ΓòÉΓòÉΓòÉ 10.3.7. SYSTEM-Funktion OFS ΓòÉΓòÉΓòÉ
Die Funktion OFS(x) gibt den Offset-Anteil der Adresse von einem Operand 'x'
zurБck. Wenn die Adresse von x eine FAR Adresse ist, dann wird der
Segment-Anteil von ihr entfernt. Der Ergebnistyp ist LONGCARD fБr 32-bit
Speicher-Modelle und CARDINAL fБr 16-bit Speicher-Modelle.
ΓòÉΓòÉΓòÉ 10.3.8. SYSTEM-Funktion SEG ΓòÉΓòÉΓòÉ
Die Funktion SEG(x) gibt den Segment-Anteil von der Adresse eines Operanden 'x'
zurБck. Der Offset-Anteil wird von der Adresse entfernt. Der Ergebnistyp ist
CARDINAL.
ΓòÉΓòÉΓòÉ 10.3.9. SYSTEM-Funktion currentFile ΓòÉΓòÉΓòÉ
Die Funktion currentFile() gibt eine Null-terminierte Zeichenkette fБr den
Dateinamen vom akuell zu Бbersetzenden Modul zurБck. Diese Funktion wird
hauptsДchlich zur Fehlersuche oder fБr Fehlerroutinen gebraucht.
ΓòÉΓòÉΓòÉ 10.3.10. SYSTEM function currentLine ΓòÉΓòÉΓòÉ
Die Funktion currentLine() gibt eine Null-terminierte Zeichenkette fБr die
Zeilennummer vom aktuell zu Бbersetzenden Modul zurБck. Diese Funktion wird
hauptsДchlich zur Fehlersuche oder fБr Fehlerroutinen gebraucht.
ΓòÉΓòÉΓòÉ 10.3.11. SYSTEM-Funktion GetExitProc ΓòÉΓòÉΓòÉ
Die Prozedur
PROCEDURE GetExitProc() : PROC;
ist im Modul SYSTEM deklariert. Sie gibt die zuletzt gesetzte Prozedur aus
einer Kette von Beendigungs-Prozeduren zurБck. Weitere Informationen darБber,
wie man eine eigene Modul-spezifische Beendigungs-Prozedur implementieren kann,
sind in dieser Dokumentation in der Sektion SetExitProc nДher beschrieben.
ΓòÉΓòÉΓòÉ 10.4. SYSTEM-Prozeduren ΓòÉΓòÉΓòÉ
Die eigentlichen Prozeduren aus dem Modul SYSTEM stellen elementare
Laufzeitdienste und maschinennahe Operationen zur VerfБgung. Einige von ihnen
sind generisch und werden wДhrend der Ъbersetzung wie Makros expandiert. Andere
sind als echte Prozeduren im Modul SYSTEM.MOD implementiert. In diesem
Ъbersetzer haben auch alle Standard-Prozedureen ihren Urprung im SYSTEM-Modul.
Die folgenden Prozeduren, welche nicht zum Standard gehФren, sind verfБgbar und
werden in den folgenden Sektionen nДher beschrieben:
- INLINE
( ... )
- PROCEDURE IOTRANSFER
( VAR p1,p2:ADDRESS; va:CARDINAL );
- PROCEDURE LISTEN
( );
- PROCEDURE NEWPROCESS
( p:PROC; a:ADDRESS; n:CARDINAL; VAR p1:ADDRESS );
- PROCEDURE TRANSFER
( VAR p1,p2:ADDRESS );
- PROCEDURE ExitProgram
( ExitCode:SHORTCARD );
- generisch NEW( p )
- generisch DISPOSE( p )
- PROCEDURE SetExitProc
( UserProc : PROC );
Die folgenden Laufzeit-Prozeduren sind im SYSTEM-Modul implementiert:
- PROCEDURE OrBytes
( Dest,Source1,Source2:ADDRESS; Size:LONGCARD );
- PROCEDURE XorBytes
( Dest,Source1,Source2:ADDRESS; Size:LONGCARD );
- PROCEDURE AndBytes
( Dest,Source1,Source2:ADDRESS; Size:LONGCARD );
- PROCEDURE MemSet
( Dest:ADDRESS; Val:WORD; Size:LONGCARD );
- PROCEDURE MemCmp
( Dest,Source: ADDRESS; Size:LONGCARD );
- PROCEDURE MemCpy
( Dest,Source: ADDRESS; Size:LONGCARD );
- PROCEDURE SetBitRange
( Dest:ADDRESS; FromBit:SHORTCARD; ToBit:SHORTCARD );
- PROCEDURE DelBitRange
( Dest:ADDRESS; FromBit:SHORTCARD; ToBit:SHORTCARD );
- PROCEDURE TestBit
( Set:ADDRESS; BitPos:SHORTCARD ):BOOLEAN;
- PROCEDURE Push
( Param:ADDRESS; Size:LONGCARD );
- PROCEDURE PushString
( Str:ADDRESS; StrSize:LONGCARD; Size:LONGCARD );
- PROCEDURE LocalCopy
( VAR Source:ADDRESS; Size:LONGCARD );
- PROCEDURE LocalFree
( VAR Source:ADDRESS );
- PROCEDURE StartUp
( );
- PROCEDURE TypeGuard
( Wanted : TypeDescADDRESS; Actual : TypeDescADDRESS );
- PROCEDURE EnterPriority
( Level : SHORTCARD );
- PROCEDURE ExitPriority
( );
- PROCEDURE LinkVMT
( TypeInfo : TypeDescADDRESS; VMT : TypeDescADDRESS );
- PROCEDURE CopyVMT
( Dest, Origin : TypeDescADDRESS; Size : LONGCARD );
- PROCEDURE InitVMT
( Dest : TypeDescADDRESS; Size : LONGCARD );
- PROCEDURE InitSOM
( );
ΓòÉΓòÉΓòÉ 10.4.1. Standard-Prozedur NEW ΓòÉΓòÉΓòÉ
Die Standard-Prozedur NEW hat fБr diesen Ъbersetzer ihren Ursprung im
SYSTEM-Modul. Der Prozedur-Aufruf
NEW( p )
wird wДhrend der Ъbersetzung zum Prozedur-Aufruf
ALLOCATE( p, TSIZE( p^ ) )
expandiert. Er bewirkt die Anforderung von dynamischen Speicher aus dem
globalen Stapelspeicher (Heap) und weist dessen Adresse der Zeigervariablen 'p'
zu. Die GrФsse vom angeforderten Speicher entspricht der GrФsse vom Typ, auf
den durch 'p' gezeigt wird.
Wenn die Spracherweiterungen aktiviert sind, und wenn 'p' ein Zeiger zu einem
Verbundtyp ist, dann wird ein Prozedur-Aufruf
NEW( p )
in folgende Anweisungsfolge Бbersetzt:
ALLOCATE
( p,
TSIZE( <type descriptor address> ) +
TSIZE( <record type> )
);
t := p;
IF t # NIL THEN
IF <extended type> THEN
t^ := ADR( <type desciptor> );
ELSE
t^ := NIL;
END;
p := ADDRESS( t ) + TSIZE( <type descriptor address> );
END;
Bevor ein Speicherblock fБr einen Verbund reserviert wird, mБssen einige Bytes
fБr einen Zeiger zu einem internen Typbeschreiber angefordert werden. Dies
geschieht automatisch. Diese zusДtzliche Information wird z.B. fБr dynamische
Typen-Tests fБr Verbunde, ferner fБr Typenschutz- Selektoren, oder fБr einen
regionalen Typenschutz gebraucht.
Die Standard-Prozedur NEW kann auch zur Erzeugung von Instanzen vom OS/2 System
Object Model gebraucht werden. Wenn 'p' als solch einen SOM-Zeiger deklariert
worden ist, wird der Prozedur-Aufruf
NEW( p )
in eine Anweisungsfolge Бbersetzt, in welcher mittels statischer
MethodenauflФsung die OS/2-Prozedur 'somNew' gefunden wird, die wiederum per
Prozedurzeiger zwecks Erzeugung einer neuen Instanz der gewБnschten
Objektklasse aufgerufen wird.
Dieser Ъbersetzer fБhrt fБr die Code-Generierung verschiedene Optimierungen
durch. Zu diesem Zweck wird eine interne BuchfБhrung Бber den Inhalt aller
Zeiger benutzt. Insbesondere nimmt der Ъbersetzer an, dass jeder Zeiger, dessen
Wert durch ein NEW(p) entstanden ist, nur auf Objekte innerhalb des
Stapelspeichers (heap) zeigen kann, nicht aber auf andere Variablen. So kann
der Code-Optimierer Zeiger-Werte von ausserhalb des Stapelspeichers (heap)
weiterhin in CPU-Register halten.
ΓòÉΓòÉΓòÉ 10.4.2. Standard-Prozedur DISPOSE ΓòÉΓòÉΓòÉ
Die Standard-Prozedur DISPOSE hat fБr diesen Ъbersetzer ihren Ursprung im
SYSTEM-Modul. Der Prozedur-Aufruf
DISPOSE( p )
wird wДhrend der Ъbersetzung zum Prozedur-Aufruf
DEALLOCATE( p, TSIZE( p^ ) )
expandiert. Dies bedeutet, dass ein zuvor angeforderter dynamischer
Speicherblock wieder freigesetzt wird und 'p' mit NIL gelФscht wird. Die GrФsse
des freigesetzten Speichers entspricht der GrФsse vom Typ, auf den 'p' zeigen
kann.
Wenn die Spracherweiterungen aktiviert sind, und wenn 'p' ein Zeiger zum einem
Verbund ist, dann wird ein Prozedur-Aufruf
DISPOSE( p )
in die folgende Anweisungsfolge Бbersetzt:
p := ADDRESS( p ) - TSIZE( <type descriptor address> );
DEALLOCATE
( p,
TSIZE( record type ) +
TSIZE( <type descriptor address> )
);
Das bedeutet, dass 'p' erst um die GrФsse der Adresse von einem intern
gefБhrten Typbeschreiber dekrementiert wird. Erst danach wird der Speicher
freigesetzt. Denn jeder zugeordnete Speicherblock fБr Verbunde enthДlt in den
ersten Bytes vor dem Verbundspeicher einen Zeiger zu einem Typbeschreiber, und
diese Bytes mБssen auch freigesetzt werden.
Die Standard-Prozedur DISPOSE kann auch zur Freisetzung von Instanzen vom OS/2
System Object Model gebraucht werden. Wenn 'p' als solch einen SOM-Zeiger
deklariert worden ist, dann wird der Prozedur-Aufruf
DISPOSE( p )
in eine Anweisungsfolge Бbersetzt, in welcher mittels statischer
MethodenauflФsung die OS/2 Prozedur 'somFree' gefunden wird, die wiederum per
Prozedurzeiger zwecks Freisetzung des SOM-Objektes aufgerufen wird.
ΓòÉΓòÉΓòÉ 10.4.3. SYSTEM-Prozedur ExitProgram ΓòÉΓòÉΓòÉ
Die Prozedur
PROCEDURE ExitProgram( ExitCode : SHORTCARD );
ist im Module SYSTEM deklariert. Sie akzeptiert einen Wert-Parameter. Diese
Prozedur wird automatisch am Ende eines Haupt- Programm-Moduls aufgerufen. Der
Standard- Prozedur-Aufruf
HALT();
wird fБr diesen Ъbersetzer in ein
SYSTEM.ExitProgram( 0 );
umgewandelt. ExitProgram bekommt einen Wert-Parameter fБr den RБckgabe-Code.
Unter OS/2 2.x/3.0 wird solch ein RБckgabe-Code an den Aufrufer zurБckgegeben,
z.B. nach dem API-Funktions-Aufruf DosExecProgram(...) in einem der
VAR-Parameter.
Wenn die Spracherweiterungen aktiviert sind, dann wird jeder verfehlte
Typentest mit einem SYSTEM.ExitProgram(3) verabschiedet.
ΓòÉΓòÉΓòÉ 10.4.4. SYSTEM-Prozedur SetExitProc ΓòÉΓòÉΓòÉ
Die Prozedur
PROCEDURE SetExitProc( UserProc : PROC );
ist im Modul SYSTEM deklariert. Sie akzeptiert einen Wertparameter namens
'UserProc'. Prozedur SetExitProc wird normalerweise gebraucht, um eine neue
Prozedur oder eine wiederherzustellende Prozedur an die Spitze einer Kette von
Beendiguns-Prozeduren zu setzen. Letztere werden beim Programmabschluss
nacheinander aufgerufen.
Das folgende Beispiel zeigt, wie man eine Modul-spezifische
Beendigungs-Prozedur implementiert:
IMPLEMENTATION MODULE <module-id>;
...
VAR
PreviousExitProc : PROC;
...
PROCEDURE <exit-id>();
BEGIN
<module specific exit code>
SYSTEM.SetExitProc( PreviousExitProc );
END <exit-id>;
...
BEGIN
<module initialization>
PreviousExitProc := SYSTEM.GetExitProc();
SYSTEM.SetExitProc( <exit-id> );
END <module-id>.
ΓòÉΓòÉΓòÉ 10.5. Koroutinen ΓòÉΓòÉΓòÉ
Das Standard-Werk 'Programmierung in Modula-2' von N.Wirth (4.Ausgabe)
beschreibt eine Schnittstelle unter Modula-2 fБr die Implementation von
quasi-gleichzeitigen Prozessen auf einem konventionellen Computer mit nur einem
Hauptprozessor. Das Wort Prozess wird hier im Sinne einer Koroutine gebraucht.
Koroutinen sind Prozesse, die alle von einem einzigen Prozessor ausgefБhrt
werden. Eine Koroutine kann aber auch durch eine GerДteunterbrechung verursacht
werden.
Dieser Ъbersetzer bietet keine spezielle Implementierung fБr Koroutinen an,
ausser einem primitiven kooperativen Multitasking innerhalb eines
OS/2-Prozesses. Bei einer Ъbersetzung fБr OS/2 2.x/3.0 sollte besser das Modul
'Processes' benutzt werden. Dort werden Koroutinen als OS/2 2.x/3.0
AusfБhrungseinheiten (threads) implementiert. Routinen fБr OS/2-Unterbrechungen
(exception handlers) kФnnen durch den Gebrauch der OS/2 2.x/3.0 Exception
Managment API 'DOSEXCEPTIONS' einfach installiert werden.
Trotzdem bietet das Modul SYSTEM eine Schnittstelle fБr die Implementierung
eines eigenen Koroutinen-Systems an, unter Verwendung der folgenden
Deklarationen:
PROCEDURE NEWPROCESS
( p:PROC; a:ADDRESS; n:CARDINAL; VAR p1:ADDRESS );
PROCEDURE TRANSFER
( VAR p1,p2:ADDRESS );
PROCEDURE IOTRANSFER
( VAR p1,p2:ADDRESS; va:CARDINAL );
PROCEDURE LISTEN
( );
NEWPROCESS dient dazu, einen neuen Prozess (Koroutine) zu erzeugen, wobei seine
Parameter die folgende Bedeutung haben:
P gibt die Prozedur an, welche den Prozess ausmacht
A ist die Basisadresse vom Arbeitsspeicher fБr den Prozess
n ist die GrФsse des Arbeitsspeichers.
p1 als ein Ergebnisparameter gibt die Adresse eines neu erzeugten
Prozess-Beschreibers an.
Ein neuer Prozess mit 'P' als Programm und 'A' als Arbeitsspeicher der GrФsse
'n' wird an 'p1' zugewiesen. Der Prozess wird nur eingerichtet, aber noch
nicht aktiviert. 'P' muss eine auf der globalen Null-Ebene deklarierte
Prozedur sein.
Die KontrollБbergabe zwischen zwei Prozessen geschieht durch die folgende
Prozedur:
PROCEDURE TRANSFER( VAR p1,p2:ADDRESS )
Dieser Aufruf suspendiert den augenblicklichen Prozess, welcher an 'p1'
zugewiesen wird, und nimmt wieder die weitere AusfБhrung des Prozesses,
welcher durch 'p2' bezeichnet wird, auf. Offensichtlich muss 'p2' einem
Prozess durch einen frБheren Aufruf von NEWPROCESS oder TRANSFER zugewiesen
worden sein. Beide Prozeduren mБssen vom Modul SYSTEM importiert werden. Ein
Programm muss abbrechen, wann immer die Kontrolle das Ende der Prozedur,
welche den KФrper eines Prozesses ausmacht, erreicht. Wegen dieser Forderung
erzeugt dieser Ъbersetzer automatisch ein HALT() am Ende von Prozeduren, die
TRANSFER(...) -Anweisungen enthalten. Weil die Zuweisung nach 'p1' erst nach
der Identifizierung des neuen Prozesses 'p2' erfolgen soll, dБrfen die
aktuellen Parameter identisch sein.
Die Prozedur IOTRANSFER Дhnelt dem TRANSFER, ausser dass als einen weiteren
Parameter eine Nummer 'va' fБr einen Unterbrechungsvektor akzeptiert wird.
Diese wird ebenfalls in den Prozessbeschreiber, auf den 'p1' zeigt,
gespeichert. Nach der AusfБhrung eines IOTRANSFERs veranlasst jede neue
CPU-Unterbrechung, die Routine an der Stelle, welche im Prozessbeschreiber
'p1' festgehalten ist, die Kontrolle wieder aufzunehmen.
Die parameterlose Prozedur LISTEN dient dazu, die augenblickliche PrioritДt
vom Modul runterzusetzen, so dass anstehende Unterbrechungen (IOTRANSFERs) zur
AusБbung kommen.
ΓòÉΓòÉΓòÉ 10.6. SYSTEM INLINE-Assemblierer ΓòÉΓòÉΓòÉ
Modula-2 ist hauptsДchlich eine Hochsprache. Maschinennahe UnterstБtzung ist
gewФhnlich nicht direkt programmierbar, es sei denn, dass die MФglichkeiten vom
Pseudo-Modul SYSTEM benutzt werden. Manchmal ist es notwendig, maschinennahe
Funktionen auf der Ebenen der CPU-Instruktionen zu implementieren. WДhrend
andere Ъbersetzer solche Aufgaben einem externen Assemblierer Бberlassen, hat
dieser Ъbersetzer eine andere LФsung zur VerfБgung gestellt. Die Anweisung
SYSTEM.INLINE(...) aktiviert einen eingebetteten und vollstДndig symbolischen
Assemblierer fБr die INTEL 80x86 und 80x87 Prozessorfamilien. Eine vollstДndige
Assembler-Beschreibung wБrde den Rahmen dieser Referenz-Dokumentation fБr den
Ъbersetzer sprengen. Die INLINE-Anweisung akzeptiert eine unbestimmte Anzahl
von akutellen Parametern, welche als Instruktionen und Direktiven fБr den
Assemblierer behandelt werden. NДhere Informationen Бber die Programmierung in
der Maschinensprache ist z.B. in der folgenden Literatur zu finden:
- 'The 80386/387 Architecture' by Stephen P. Morse,
1987, John Wiley & Sons, New York
- '386 DX Microprocessor Programmer's Reference Manual'
1990, Intel Corporation, Literature Sales
Eine vollstДndige Sprach-Grammatik fБr den INLINE-Assemblierer ist in einer der
folgenden Sektionen dieser Dokumentation mit eingeschlossen.
Eine INLINE-Anweisung muss alle Register ausser eAX bewahren bzw.
wiederherstellen.
═══ 10.6.1. Parameter-Ъbergabe-Konventionen ═══
Dieser Ъbersetzer Бbergibt die Prozedur-Parameter grundsДtzlich auf dem
CPU-Stack. Unter 32-Bit OS/2 ist diese Art der Parameter-Ъbergabe fast
identisch mit IBM's "_System"-Konvention.
Ein Prozedur-Kopf kann entweder als eine C-artige oder als eine Pascal-artige
Einheit deklariert werden. Dies geschieht, indem man die Direktiven (*$CDECL+*)
oder (*$CDECL-*) gebraucht. Standard-mДssig werden Pascal-artige Prozeduren
angenommen. Falls eine Prozedur Pascal-artig ist, werden die Parameter von
links nach rechts Бbergeben, und die aufgerufene Prozedur muss den CPU-Stack
vor dem RБcksprung bereinigen. Falls eine Prozedur C-artig ist, werden die
Parameter in umgekehrter Reihenfolge, das heisst von rechts nach links,
Бbergeben. Und es ist dann die Aufgabe des Aufrufers, den CPU-Stack unmittelbar
nach Beendigung der aufgerufenen Prozedur zu bereinigen.
Modula-2 erwartet ausserdem zusДtzliche HIGH-Parameter auf dem CPU-Stack fБr
alle offenen Reihungsparameter. Diese werden vom Ъbersetzer fБr den
Programmierer unsichtbar auf dem CPU-Stack abgelegt, und dies, bevor die
regulДren Parameter auf dem CPU-Stack kommen. Die aufgerufene Pascal-artige
Prozedur sollte nur den Bereich fБr die regulДren Parameter vom CPU-Stack
beseitigen. Alle zusДtzlichen HIGH-Werte sind vom Aufrufer aus dem CPU-Stack zu
entfernen.
Die folgende INLINE-Assemblierungsfolge zeigt einen typischen Prozedur-Aufruf
fБr das 32-Bit flache Speichermodell:
SYSTEM.INLINE
(
;----------------------------------------------
; Beispiel Aufruf einer Pascal-artigen Prozedur
;----------------------------------------------
PUSH <HIGH Дussere Dimension fБr n-ten offenen Reihungsparameter>
:
PUSH <HIGH innere Dimension fБr n-ten offenen Reihungsparameter>
:
PUSH <HIGH Дussere Dimension fБr 1-ten offenen Reihungsparameter>
:
PUSH <HIGH innere Dimension fБr 1-ten offenen Reihungsparameter>
:
PUSH <1. parameter>
PUSH <2. parameter>
:
PUSH <letzter Parameter>
CALL <Ziel-Prozedur>
ADD ESP, <totale GrФsse aller HIGH-Parameter, sofern vorhanden>
:
);
Von C-artigen Prozeduren wird nicht erwarted, dass sie HIGH-Werte fБr offene
Reihungen benutzen. Deshalb sieht das gleiche Beispiel, diesmal in C-Stil,
etwas anders aus:
SYSTEM.INLINE
(
;-------------------------------------------
; Beispiel Prozedur einer C-artigen Prozedur
;-------------------------------------------
PUSH <letzter Parameter>
:
PUSH <2. Parameter>
PUSH <1. Parameter>
CALL <Ziel-Prozedur>
ADD ESP, <totale GrФsse aller regulДren Parameter>
:
);
Sobald eine aufgerufene Prozedur die Kontrolle erhДlt, hat sie eine eine
ENTER-Instruktion ausgefБhrt. Letztere sichert die Zeiger aller Stack-Rahmen
auf dem CPU-Stack und reserviert einen neuen Stack-Rahmen fБr lokale Variablen.
Sowohl die lokalen Variablen als auch die Parameter werden Бber Basis-Zeiger
adressiert, wie im folgenden Beispiel:
SYSTEM.INLINE
(
;-----------------------------------------
; Beispiel Adressierung Prozedur-Parameter
;-----------------------------------------
MOV EAX, <parameter-id>[ EBP ]
:
;-------------------------------------
; Beispiel Adressieung lokale Variable
;-------------------------------------
MOV <local-var-id>[ EBP ], EAX
:
);
Wenn eine Pascal-artige Prozedur ursprБnglich mit aktivierten
Spracherweiterungen deklariert worden ist, dann Бnbergibt der Ъbersetzer fБr
jeden Verbund-VAR-Parameter ein Doppelwort auf dem CPU-Stack. Dies ist
notwendig wegen dynamischer Typ-Informationen. Diese Informationen werden dem
CPU-Stack noch vor den HIGH-Parametern und den regulДren Parametern Бbergeben.
Die dynamischen Typ-Informationen werden nur bei Benutzung von
Objekt-orientierten Sprach-Konstrukten wie z.B. der IS-Relation benФtigt. Die
augenblickliche Modula-2 Ъbersetzer-Version bietet keine UnterstБtzung fБr
OOP-Erweiterungen auf der Ebene der INLINE-Assemblierung an. Die
RET-Instruktion der aufzurufenden Prozedur hat den CPU-Stack nur von den
regulДren Parametern zu bereinigen. Der Бberige Stack-Speicher (d.h.
HIGH-Parameter und Typ-Informationen) muss vom Aufrufer bereinigt werden.
Daraus folgt, dass, solange die aufgerufene Prozedur nicht die zusДtzliche
internen Parameter benutzt, diese Prozedur voll in INLINE-Assembler oder sogar
in einer anderen Programmiersprache implementiert werden kann.
Falls eine aufgerufene Prozedur einen strukturierten Wert zurБckgibt, dann muss
der Aufrufer einen unsichtbaren Adressparameter fБr die Struktur auf dem
CPU-Stack Бbergeben. Dadurch weiss die aufzurufende Prozedur wohin sie ihren
RБckgabewert schreiben kann. Dieser versteckte Parameter wird wie ein regulДrer
erster VAR-Parameter behandelt.
═══ 10.6.2. RБckgabe-Register ═══
Jede Funktions-Prozedur muss seinen RБckgabewert in CPU-Register laden. Die
folgenden Register werden in AbhДngigkeit von der jeweiligen Typ-GrФsse des
formalen RБckgabe-Parameters benutzt:
AL 1-Byte RБckgabe-Typ
AX 2-Bytes RБckgabe-Typ
EAX 4-Bytes RБckgabe-Typ (32-Bit Code)
DX:AX 4-Bytes RБckgabe-Typ (16-Bit Code)
ST(0) REAL,SHORTREAL,LONGREAL RБckgabe-Typ
ΓòÉΓòÉΓòÉ 11. Prozesse ΓòÉΓòÉΓòÉ
Weil Modula-2 ursprБnglich auch fБr die Programmierung von Betriebssystemen
entworfen worden war, bietet es zum Ausdruck gleichzeitig ablaufender
AktivitДten das Konzept der Koroutinen an. Dieser Ъbersetzer hat einen anderen
Weg eingeschlagen, um gleichzeitig ablaufende Prozesse unter OS/2 2.x/3.0 zu
realisieren. Um nicht das Rad von neuem zu erfinden, nutzt dieser Ъbersetzer
die bereits verfБgbaren zeitscheibengesteuerten Mehrfach-Anwendungen von OS/2
2.x/3.0 (preemptive multitasking), und nutzt daher ausschliesslich die
Mechanismen aus dem API 'DOSPROCESSES'. Dieser API stellt die Besonderheiten
quasi-nebenlДufiger Anwendugen (multitasking) zur VerfБgung. Sie werden von
eimem Modul namens 'Processes' benutzt. Modul 'Processes' hДlt sich eng an die
VorschlДge aus dem Anhang von Wirth's Buch 'Programmierung in Modula-2' in der
vierten Ausgabe. Die Prozesse von Modula-2 werden auf Verarbeitungseinheiten
(threads) von OS/2 abgebildet. Deshalb kann ein Programm durch den Gebrauch des
Moduls 'Processes', welcher ausschliesslich die Verarbeitungseinheiten
(threads) von OS/2 benutzt, auf einfache Art mehrere nebenlДufige Anwendungen
(preemtive tasks) innerhalb eines OS/2-Prozesses ablaufen lassen.
Modul 'Processes' stellt die folgende Schnittstelle zur VerfБgung:
DEFINITION MODULE Processes;
TYPE SIGNAL;
PROCEDURE StartProcess( P : PROC; n : CARDINAL );
(*
start a concurrent process with program P
and workspace of size n.
PROC is a standard type defined as PROC = PROCEDURE().
*)
PROCEDURE SEND( VAR s : SIGNAL );
(*
one process waiting for s is resumed
*)
PROCEDURE WAIT( VAR s : SIGNAL );
(*
wait for some other process to send s
*)
PROCEDURE Awaited( s : SIGNAL ) : BOOLEAN;
(*
Awaited( s ) = "at least one process is waiting for s"
*)
PROCEDURE Init( VAR s : SIGNAL );
(*
compulsory initialization
*)
END Processes.
═══ 12. Ъbersetzungseinheiten ═══
ΓûÉ CompilationUnit = DefModule | [ IMPLEMENTATION ] ProgramModule
ΓûÉ
ΓûÉ ProgramModule = MODULE Ident Priority ";" { Import } Block Ident "."
ΓûÉ Priority = [ "[" ConstExpr "]" ]
ΓûÉ Import = [ FROM Ident ] IMPORT IdentList ";"
ΓûÉ IdentList = Ident { "," Ident }
ΓûÉ
ΓûÉ DefModule = DEFINITION MODULE Ident ";" { Import } { Def } END Ident "."
ΓûÉ Def = CONST { ConstDef ";" } | TYPE { TypeDef ";" } |
ΓûÉ VAR { VarDecl ";" } | ProcedureHeading ";"
ΓûÉ ConstDef = Ident "=" ConstExpr
ΓûÉ TypeDef = TypeDecl | Ident
Eine Quellen-Textdatei wird von diesem Ъbersetzer als eine Einheit akzeptiert
und wird daher Ъbersetzungseinheit (compilation unit) genannt. Es gibt drei
Arten von Ъbersetzungseinheiten:
- Haupt-Module
- Definitions-Module
- Implementations-Module
Ein Haupt-Modul besteht aus einem Hauptprogramm und setzt sich aus aus einem
Pogramm-Modul zusammen. Insbesondere enthДlt es keine Exportliste. Importierte
Objekte werden in anderen, separat Бbersetzbare Programmteile, definiert. Diese
bestehen jeweils aus zwei Einheiten, welche Definitions- und
Implementations-Module genannt werden.
Ein Definitions-Modul gibt die Namen und Eigenschaften derjenigen Objekte, die
von anderen Klienten benФtigt werden mФgen, an. Die Klienten sind andere
Module, welche die Objekte importieren. Diese Objekte werden automatisch
qualifiziert exportiert. Zu ihnen gehФren die Konstanten, Typen, Variablen
sowie die Spezifikationen von Prozedur-KФpfen. Das entsprechende
Implementations-Modul enthДlt weitere lokale Objekte und Anweisungen, welche
nicht fБr Klienten bekannt sein mБssen. Es enthДlt auch die vollstДndigen
Prozedur-Deklarationen, und mФglicherweise die Deklarationen weiterer Objekte,
die nicht exportiert werden. Definitions- und Implemenatations-Module
existieren paarweise. FБr diesen Ъbersetzer kann ein Implementations-Modul aber
dann weggelassen werden, wenn das Definitions-Modul sich auf eine Schnittstelle
ausserhalb von Modula-2 bezieht. Dazu gehФren z.B. Definitions-Module, welche
APIs fБr Betriebssysteme beschreiben, oder welche nur die Definitionen von
Konstanten und Typen, nicht aber von Laufzeitobjekten wie Variablen oder
Prozeduren, enthalten. Sowohl Definitions- als auch Implementations-Module
kФnnen Importlisten enthalten. Und alle Objekte, die im Definitions-Modul
definiert werden, sind im entsprechenden Implementations-Modul automatisch
verfБgbar, ohne explizitem Import.
Das Definitions-Modul stell offensichtlich die Schnittstelle zwischem dem
Implementations-Modul einerseits und den Klienten andererseits dar. Das
Definitions-Modul sollte nur die Deklarationen solcher Objekte beinhalten, die
von Klienten benФtigt werden mФgen, und keine anderen. In diesem Ъbersetzer
kann ein Definitions-Modul auch eine API vom Betriebssystem darstellen. In
solchen FДllen werden die Implementations- Module in anderen Computersprachen
gewФhnlich von Drittanbiertern in Form vorБbersetzter Module angeboten. Die
Definitions-Module von diesem Ъbersetzer kФnnen sich auf fremde .OBJ, .LIB oder
.DLL -Dateien, welche die Ausgabe anderer SprachБbersetzer, statische und
dynamische Bindebibliotheken enthalten, beziehen.
Definitions-Module implizieren qualifizierten Export. Typendefinitionen kФnnen
aus vollstДndig spezifizierten, transparenten, Typen bestehen, oder sie kФnnen
auch nur den Typnamen enthalten. Im letzteren Fall muss die vollstДndige
Spezifikation dann im entsprechenden Implementations-Modul erscheinen, und sein
Export ist undurchsichtig (opaque). Der Typ ist den importierenden Modulen nur
mit seinem Namen bekannt, aber seine Бbrigen Eigenschaften bleiben verborgen.
Deshalb mБssen alle Prozeduren, welche mit Operanden diesen Typs arbeiten, im
gleichem Implementations-Modul deklariert sein, wo auch die Бberigen
Eigenschaften vom Datentyp deklariert worden sind. Undurchsichtiger (opaque)
Export ist in diesem Ъbersetzer auf Zeiger und elementare Typen (ausser
Gleitkommas) beschrДnkt. Zuweisungen und Gleichheitstests sind auf alle
undurchsichtige (opaque) Typen anwendbar.
Оhnlich wie bei den lokalen Modulen, dient auch der KФrper eines
Implementations-Moduls der Initialisierung von lokalen Objekten. Vor seiner
AusfБhrung werden erst alle importierten Module in der gelisteten Reihenfolge
ihres Auftretens initialisiert, sofern noch nicht geschehen. Omportieren sich
Module gegenseitig, ist die Reihenfolge der Initialisierung nicht festgelegt,
═══ 13. Ъbersetzer-Bedienung ═══
Dieser Ъbersetzer wird von der OS/2 2.x/3.0 Kommandozeile aufgerufen. Dazu ist
die folgende Syntax fБr die Kommandozeile notwendig:
MOD Quellendatei {Schalter}
Das Kommando wird mit einem 'MOD' oder 'MOD.EXE' begonnen, und muss von dem
Namen der Modula-2-Quelldatei und mФglichen Schaltern gefolgt werden. Eine
Quelldatei enthДlt eine komplette Ъbersetzungseinheit. Der Name der Quelldatei
muss mit '.MOD' fБr Programm-Module oder mit '.DEF' fБr Definitions-Module
erweitert sein. Fehlt die Angabe einer Namenserweiterung, wird '.MOD'
angenommen. Die Namen der Module kФnnen bis zu 255 Zeichen lang sein und
unterscheiden zwischen Gross- und Kleinschreibung. Dieser Ъbersetzer nimmt bis
8 erste Zeichen vom Modulnamen als Grossbuchstaben fБr den entsprechenden
Dateinamen an und erweitert den Dateinamen mit der o.g. Erweiterung. Diese
8.3-Konvention fБr Dateinamen ist mit dem FAT-Dateisystem vertrДglich. Sie ist
auch fБr das neue installierbare Dateisystem HPFS von OS/2 2.x/3.0 verwendbar.
HPFS unterstБtzt lange Dateinamen und unterscheidet dabei zwischen Gross- und
Keinschreibung. Dieser Modula-2-Ъbersetzer erkennt jedoch nur die Dateien,
deren Namen bis zu 8 Zeichen lang sind, und macht dabei keinen Unterschied
zwischen ihrer Gross- und Kleinschreibung. Der Name der anszugebenden
Objektdatei ist der gleiche wie der von der Eingabe-Quelldatei, jedoch in
Grossbuchstaben, und mit der Namenserweiterung '.OBJ' anstelle von '.MOD' oder
'.DEF'.
Hinweise: Definitions-Dateien fБr den Binder unter OS/2 2.x/3.0 oder MS-Windows
3.x benutzen ebenso wie Modula-2 die Namenserweiterung '.DEF'. Um daher
Verwechslungen zu vermeiden, sollten die Defintiions-Dateien fБr den Binder und
die Definitions-Dateien fБr Modula-2 in getrennten Unterverzeichnissen gehalten
werden.
Wenn die Make- oder Build- Schalter auf der Kommandozeile fБr eine Ъbersetzung
angegeben worden sind, dann produziert der Ъbersetzer fБr Modula-2 eine
komplette Antwortsdatei fБr den Binder (mit der Namenserweiterung '.RSP') und
mФglicherweise auch eine Definitionsdatei fБr den Binder (mit der
Namenserweiterung '.LDF'), zusДtzlich zu den Objektdateien (Namenserweiterungen
'.OBJ'). Diese Ausgabedateien sind fБr die OS/2 2.x/3.0 Binderprogramme
LINK386.EXE oder LINK.EXE, welche schliesslich die ausfБhrbare Datei
(Namenserweiterung '.EXE') erzeugen, verwendbar.
Das folgende Beispiel zeigt, wie man fБr das lineare Flat- Speicher-Modell das
32-bit Hauptprogramm aus der Datei 'TEST.MOD' Бbersetzt und zu der ausfБhrbaren
Datei 'TEST.EXE' bindet:
MOD TEST.MOD -m -o -mf
LINK386 @TEST.RSP
Das Beispiel produziert eine Datei namens TEST.EXE, die fertig fБr die
ProgrammausfБhrung ist.
Damit der Ъbersetzer richtig arbeiten kann, muss er einige Variablen aus der
Umgebung vom Betriebssystem konsultieren, um z.B. die Laufwerksbuchstaben und
Namen von Unterverzeichnissen fБr die Quell- und Objekt-Dateien zu kennen. Die
Schalter auf der Kommandozeile informieren den Ъbersetzer fБr Modula-2
darrБber, wie er seine Ъbersetzung ausfБhren soll.
Die notwendigen Angaben in der Umgebung vom Betriebssystem sowie die Schalter
auf der Kommandozeile werden in den folgenden Sektionen dieser Dokumentation
nДher beschrieben.
ΓòÉΓòÉΓòÉ 13.1. Kommandozeilen-Schalter ΓòÉΓòÉΓòÉ
Einige der Merkmale dieses Ъbersetzers fБr Modula-2 werden durch Schalter auf
der Kommandozeile kontrolliert. Sie dienen als globale Direktiven fБr die
Ъbersetzung. Einige von ihnen kФnnen auch durch spezielle Kommentare innerhalb
der Quelldateien angegeben werden. Sie werden dann als lokale Direktiven
behandelt und wirken wДhrend der Ъbersetzung nur innerhalb des Moduls, in dem
sie angegeben sind. Schalter von der Kommandozeile hingegen wirken global fБr
alle Module. Die Schalter der Kommandozeile mБssen hinter dem Namen der
Quelldatei stehen und von Leerzeichen untereinander getrennt sein. Jeder
Schalter wird durch einen Bindestrich '-' eingefБhrt und werden unmittelbar
durch die Zeichenkette, welche den Schalter ausmacht, gefolgt. FБr die
Zeichenkette eines Schalters wird keine Unterscheidung zwischen Gross- und
Kleinschreibung gemacht, z.B. stellen -B und -b den gleichen Schalter dar.
Die folgenden Schalter fБr die Kommandozeile sind fБr diesen Ъbersetzer
verfБgbar:
-M Make fБr Binder: Ъbersetze auch abhДngige,
geДnderte Module
-B Build fБr Binder: Ъbersetze alle abhДngigen
Module
-P Ъbersetzung mit Quelldateianzeige und
Fehlerunterbrechungen
-XL Erweiterte Modula-2-Sprache
-XI Undokumentierte CPU-Instruktionen
-XF Vereinfachte Funktionsbezeichner
-8086 Produziere 8086-Code
-x86 Produziere Code fБr 286, 386, 486 oder 586
-F Numerischer Koprozessor
-E=Verzeichnis Zielverzeichnis fБr ausfБhrbare Datei
-SS=stacksize GrФsse des Stapelspeichers (stack size) fБr
ausfБhrbare Datei in K-Bytes
-C=Anzahl Abbruch nach <Anzahl> semantischen Fehlern
-R4 oder -R8 4-Byte oder 8-Byte-Real
-D Debugger-UnterstБtzung
-L Zeilennummern in die Objektdateien
-Mx Speicher-Modell
(Tiny,Small,Medium,Compact,Large,Flat32)
-OB Optimierung von AusdrБcken
-OI Optimierung fБr Zeiger und Indizes
-OG Globale Datenflussanalyse
-O Allumfassende Optimierung: -OG -OB -OI
-DOS Ziel-Betriebssystem DOS
-OS2 Ziel-Betriebssystem OS/2 1.3 oder 2.x/3.0
-WIN Ziel-Betriebssystem MS-Windows 3.x
-SSFAR Nehme FAR Stapelspeicher-Segment (stack
segment) an
-A -A1 -A2 -A4 Feldausrichtung
-V Nehme flБchtige globale Variablen an
-PM:Typ OS/2-Anwendungstyp PM, VIO, oder NOVIO
-$=Sonderzeichen Redefiniere das einfБhrende Zeichen fБr
Ъbersetzer-Direktiven
-CDECL C-artige Prozeduren
-H2 oder -H4 2-Byte oder 4-Byte-HIGH
-FSAVE Sichere alle FPU-Register zu Beginn einer
Prozedur
Die folgenden Schalter sind fБr das OS/2 2.x/3.0 Betriebssystem
voreingestellt:
-386 -OS2 -MF -E=.\ -SS=8 -C=15 -R8 -A -PM:VIO -H4
ΓòÉΓòÉΓòÉ 13.1.1. Speicher-Modelle ΓòÉΓòÉΓòÉ
Dieser Ъbersetzer unterstБtzt bis zu sechs verschiedene Speicher-Modelle. Ein
Speichermodell gibt den Ъbersetzer an, wo und wie die Daten- und Code-Segmente
fБr die schliessliche ausfБhrbare Datei anzuordnen oder zu kombinieren sind.
Diese Information wird wegen der segmentierten Mechanismen fБr Speicherzugriffe
bei den Intel 80x86-Prozessoren gebraucht. Einer moderner Computer bietet
gewФhnlich viele Megabytes an direktem Zugriffsspeicher (DRAM) an, mit denen
seine Programme laufen kФnnen. Aber wenn der 80x86-Prozessor im 16-Bit-Modus
lДuft, dann sind alle CPU-Register nur 16 Bits gross, sodass sie nur einen
Bereich von 64 KB abdecken wБrden. Dies bedeutet, dass der RAM-Speicher nur in
kleinen Portionen mit jeweils nicht mehr als 64 KB ansprechbar ist. Diese Art
von Speicherzugriff nennt man auch segmentierten Speicherzugriff. Jeder
16-Bit-Zeiger kann nur innerhalb eines Segments zeigen, welches nicht grФsser
als 64 KB sein darf. Segment-Deskriptoren werden wДhrend der Laufzeit benФtigt,
damit das System die Startadressen aktueller Code- oder Daten-Segmente
innerhalb des physischen Speichers kennt. 16-Bit grosse Segment-Register zeigen
auf solche Deskriptoren. Eine vollstДndige lineare Speicheradresse besteht
daher aus zwei Komponenten:
16-Bit-Segment : 16-oder-32-Bit-Offset
Ein Zeiger, welcher sowohl die Segment- als auch die Offset-Komponente enthДlt,
wird ein FAR Zeiger genannt. Ein Zeiger, der nur den Offset-Anteil einer
Speicheradresse enthДlt, ist ein NEAR Zeiger. Ein NEAR Zeiger zeigt auf eine
Adresse innerhalbs eines Standard-Speicher-Segments, dessen Deskriptor-Zeiger
in einen der beiden Segment-Register DS oder CS (Daten- oder Code-Segment)
gespeichert ist. Bei einer 32-Bit-Ъbersetzung fБr Programme ist der
Offset-Anteil 32 Bits gross und deckt einen Adressbereich von bis zu 4
Giga-Bytes ab. FБr die absehbare Zukunft ist dies fБr moderne Programme mehr
als genug. Deshalb brauchen Programme fБr den 32-Bit-Modus nur einen linearen
Adressraum fБr den Speicherzugriff (Speicher-Modell Flat). Alle notwendigen
Segment-Register werden in diesem Speicher-Modell auf die gleiche physikalische
Baisiadresse eingestellt. Ein hДufiges Problem bei 16-Bit-Programmen ist
insbesondere die Aufteilung und Kombinierung der Speichersegmente unter den
Modulen und Daten. Je nach Auswahl des Speicher-Modells sind folgende AnsДtze
fБr diesen Ъbersetzer von Modula-2 implementiert worden:
Model Name Align Combine Class Group Remarks
S _TEXT WORD PUBLIC 'CODE' -
_DATA WORD PUBLIC 'DATA' DGROUP
_BSS WORD PUBLIC 'BSS' DGROUP
STACK PARA STACK 'STACK' DGROUP (1)
M x_TEXT WORD PUBLIC 'CODE' - (3)
_DATA WORD PUBLIC 'DATA' DGROUP
_BSS WORD PUBLIC 'BSS' DGROUP
STACK PARA STACK 'STACK' DGROUP (1)
C _TEXT WORD PUBLIC 'CODE' -
x_DATA WORD private 'FAR_DATA' -
x_BSS WORD private 'FAR_BSS' -
STACK PARA STACK 'STACK' DGROUP (1)
L x_TEXT WORD PUBLIC 'CODE' - (3)
x_DATA WORD private 'FAR_DATA' -
x_BSS WORD private 'FAR_BSS' -
STACK PARA STACK 'STACK' DGROUP (1)
F _TEXT DWORD PUBLIC 'CODE' - (2)
_DATA DWORD PUBLIC 'DATA' DGROUP (2)
_BSS DWORD PUBLIC 'BSS' DGROUP (2)
STACK DWORD STACK 'STACK' DGROUP (1) (2)
Bemerkungen:
(1) STACK wird nur fБr das Haupt-Modul definiert.
(2) 32-Bit-Segment
(3) x_TEXT:
ein logisches Code-Segment pro Modul x.
x_BSS:
Ein logisches, nicht initialisiertes, Daten-Segment pro Modul x.
x_DATA:
Ein logisches, initialisiertes, Daten-Segment pro Modul x.
FБr eine Ъbersetzung kann das gewБnschte Speicher-Modell durch folgende
Schalter auf der Kommandozeile ausgewДhlt werden, mit folgenden totalen
GrФssen fБr die Code- und Daten-Segmente:
ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
│Schalter │Code-GrФsse │Daten-GrФsse │Modus │
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé-MS Γöékleiner 64 KB Γöékleiner 64 KB Γöé16-Bit-Code Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
│-MM │grФsser 64 KB │kleiner 64 KB │16-bit code │
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
│-MC │kleiner 64 KB │grФsser 64 KB │16-Bit-Code │
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
│-ML │grФsser 64 KB │grФsser 64 KB │16-Bit-Code │
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé-MF Γöé0..4 GB Γöé0..4 GB Γöé32-Bit-Code Γöé
ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
ΓòÉΓòÉΓòÉ 13.1.2. Ziel-Betriebssystem ΓòÉΓòÉΓòÉ
Diese Implementierung von Modula-2 akzeptiert die folgenden Schalterangaben
fБrs Ziel-Betriebssystem:
Ъbersetzer-
Schalter Beschreibung
-OS2 Produziere 80x86 Objekt-Code fБr IBM OS/2 2.x/3.0 oder 1.3
-WIN Produziere 80x86 Objekt-Code fБr MS Windows 3.x
-DOS Produziere 80x86 Real-Modus Objekt-Code fБr DOS
Diese Ъbersetzer-Version 2.01 wird gegenwДrtig jedoch nur mit Standard-Modulen
und APIs fБr OS/2 2.x/3.0 ausgeliefert. ZukБnftige Versionen werden auch
vollstДndige Standard-Bibliotheken fБr DOS und MS-Windows beinhalten.
ΓòÉΓòÉΓòÉ 13.1.3. Ziel-Prozessoren ΓòÉΓòÉΓòÉ
Dieser Ъbersetzer fБr Modula-2 produziert Objekt-Code fБr die Intel
80x86-Prozessor-Familie. Ein Schalter fБr einen Koprozessor muss immer dann
angegeben werden, wenn der INLINE- Assemblierer Instruktionen fБr den
numerischen 80x87 Koprozessor akzeptieren soll. Der Code-Generator fБr die
Haupt-CPU nimmt immer an, dass ein numerischer Koprozessor oder eine
entsprechende Software-Emulation existiert, unabhДngig davon, ob ein Schalter
fБr den Koprozessor aktiviert ist oder nicht. Unter OS/2 2.x/3.0 wird eine
Emulation fБr den Koprozessor mit dem Betriebssystem selbst bereitgestellt. Die
gegenwДrtige Version des Ъbersetzers bietet daher keinen eigenen Emulator fБr
den Koprozessor an. Unter OS/2 2.x/3.0 wird als Haupt-CPU 80386 amgenommen fБr
das lineare 32-Bit Flat Speicher-Modell.
Zusammenfassung der mФglichen Schalter fБr die Ziel-Prozessoren:
-8086
-80286 oder -286
-80386 oder -386
-80486 oder -486
-80586 oder -586
-F
ΓòÉΓòÉΓòÉ 13.1.4. Make und Build ΓòÉΓòÉΓòÉ
Ein Modula-Programm besteht typischerweise aus vielen Modulen, welche
untereinander in einer hierarchischen Ordnung in Beziehung stehen. Das Modul
auf der Hauptebene besteht gewФhnlich aus einem Hauptprogramm oder einem
Implementations-Modul einer dynamischen Binder-Bibliothek. Es kann Module aus
untergeordneten Ebenen importieren. Die Module auf den niedrigeren Ebenen
kФnnen ihrerseits wieder andere Module aus noch niedrigeren Ebenen importieren,
usw. Wenn ein Modul auf einer niedrigen Ebene geДndert worden ist und deshalb
neu Бbersetzt werden soll, dann sind alle Module, die das geДnderte Modul
importieren, ebenfalls von der Оnderung betroffen. Insbesondere, wenn die
Оnderung im Definitions-Modul geschehen ist, mБssen alle daraus importierende
Module ebenfalls neu Бbersetzt werden.
Dieser Prozess der NeuБbersetzung der abhДngigen importierenden Module wird
'Make' oder 'Build' genannt. Eine Make-Funktion bedeutet, dass nur die
geДnderten abhДngigen Module neuБbersetzt werden sollen, wДhrend ein 'Build'
eine NeuБbersetzung aller abhДngigen Module bewirkt (ob geДndert oder nicht).
Andere Ъbersetzer mБssen hierfБr oft die Dienste eines separaten Make-Programms
benutzen, welches eine Beschreibungs-Datei mit Angaben aller
Modul-AbhДngigkeiten braucht, um eine Neu-Ъbersetzung der Module zu bewirken.
Dieser Ъbersetzer fБr Modula-2 hat jedoch bereits eine Make- oder
Build-Funktion integriert. Diese Funktion wird einfach durch einen der
folgenden Schalter auf der Kommandozeile aktiviert:
-M NeuБbersetzung auch der geДnderten abhДngigen Module
-B NeuБbersetzung aller abhДngigen Module
Wenn einer der o.g. Schalter auf der Kommandozeile angegeben wird, dann
produziert der Ъbersetzer auch eine komplette Antwortsdatei und eine
Definitionsdatei, welche direkt vom 32-Bit LINK386.EXE oder vom 16-Bit
LINK.EXE Programm benutzt werden, um die ausfБhrbare Programmdatei erzeugen zu
kФnnen.
═══ 13.1.5. Erweiterungen fБr Sprache und CPU ═══
Dieser Ъbersetzer fБr Modula-2 bietet eine erweiterte Grammatik der Sprache an,
falls der folgende Schalter auf der Kommandozeile angegeben wird:
-XL
Die Intel 80x86-CPU-Familie bietet einige undokumentierte Code-Intruktionen an.
Ihr Gebrauch verkleinert den Maschinen-Code und macht das Programm etwas
schneller. Der Code-Generator dieses Ъbersetzers kann von diesen Instruktionen
Gebrauch machen, wenn folgender Schalter fБr die erweiterten CPU-Instruktionen
aktiviert ist:
-XI
Die undokumentierten Instruktionen sollten mit jeder INTEL 80386 (oder hФher)
CPU funktionieren, aber sie sind nicht notwendigerweise in CPUs von anderen
Herstellern verfБgbar, selbst wenn die anderen CPUs ansonsten kompatibel sind.
Es wДre oftmals wБnschenswert, wenn man die RБckgabewerte von
Funktionsbezeichnern ignorieren kФnnte. Dies gilt besonders fБr die APIs von
OS/2. Diese Forderung geht nicht konform mit der strengeren Sprachdefinition
von Modula-2. Dieser Ъbersetzer akzeptiert jedoch den weniger strengen
Funktionsbezeichner, wenn der Schalter
-XF
auf der Kommandozeile angegeben wird. Er ermФglicht es dem Programmierer, auch
die Namen von Funktionsprozeduren wie normale Prozeduraufrufe zu gebrauchen,
wodurch der RБckgabewert einfach ignoriert wird.
ΓòÉΓòÉΓòÉ 13.1.6. Stapelspeicher-Segment ΓòÉΓòÉΓòÉ
Es gibt zwei Schalter fБr die Kommandozeile, die den Stapelspeicher (stack
segment) wДhrend der Laufzeit beeinflussen:
-SSFAR
-SS=StapelspeichergrФsse
Der '-SSFAR'-Schalter teilt dem Ъbersetzer mit, dass das Segment fБr den
Stapelspeicher nicht innerhalb des standardmДssigen Datensegments DGROUP liegen
soll. Dieser Schalter wird hauptsДchlich fБr 16-Bit Speicher-Modelle gebraucht,
und zwar bei den dynamischen Binder-Bibliotheken, dessen Funktionen von anderen
Programmen, die einen eigenen CPU-Stapelspeicher fБr lokale Variablen und
aktuelle Parameter benutzen, aufgerufen werden. Dieser Schalter wird nicht fБr
das 32-Bit Flat Speicher-Modell z.B. bei den dynamischen Binder-Bibliothken
benФtigt, weil das lineare Adressierungsschema sich nicht um die Segmentierung
kБmmert.
Der Schalter 'SS=StapelspeichergrФsse' teilt dem Ъbersetzer mit, dass er die
angegebene StapelspeichergrФsse in Kilo-Bytes an die Antwortsdatei fБr den
Binder weiterreichen soll. Unter den 16-Bit Speicher-Modellen darf der
Wertebereich der StapelspeichergrФsse nicht 64 Kilo-Bytes Бberschreiten. Dies
hДngt mit der 16-Bit-Segmentierung des Speichers zusammen. FБr 32-Bit-Programme
darf der Wert bis zu 65536 Kilo-Bytes gross sein. Die angenommene GrФsse fБr
den Stapelspeicher betrДgt 8 Kilo-Bytes.
Beispiele fБr die Kommandozeile:
REM
REM build an optimized 16-bit small memory model
REM dynamic link library
REM
MOD MYLIB.MOD -OS2 -MS -O -SSFAR -B
LINK @MYLIB.RSP
REM
REM make an optimized 32-bit flat memory model program
REM with a stacksize of 128 KBytes
REM
MOD MYPROG.MOD -OS2 -MF -O -SS=128 -M
LINK386 @MYPROG.RSP
═══ 13.1.7. Debugger-UnterstБtzung ═══
Die gegenwДrtige Ъbersetzer-Version 2.01 bietet keinen Debugger an. Erst fБr
zukБnftige Versionen ist ein eigener Debugger vorgesehen. Dennoch kФnnen einige
elementare Debugger-Informationen in die zu erzeugenden Objekt-Dateien
geschrieben werden. Der Binder setzt diese Informationen dann in die endgБltige
ausfБhrbare Programmdatei. Die folgenden Debugger- Schalter werden unterstБtzt:
-L
-D
Der '-L'- Schalter teilt dem Ъbersetzer mit, dass die Zeilennummern der
ursprБnglichen Quelldateien in die zu erzeugenden Objekt-Dateien geschrieben
werden sollen. Von dort aus werden sie vom Binderprogramm in die MAP-Datei und
in die ausfБhrbare Programmdatei weitergereicht. Wenn fБr das 32-Bit OS/2
Zielsystem Бbersetzt wird, dann ist das interne Format der Zeilennummern fБr
HLL-kompatible Debuggers, z.B. IBM's SD386 aus DevCon Vol. 6 oder hФher
(Development Tools, Disc 1), lesbar. Ansonsten werden die Zeilennummern in
einem Format erzeugt, welcher fБr CodeView-kompatible Debuggers geeignet sein
sollte.
Der '-D'- Schalter veranlasst den Code-Generator vom Ъbersetzer, den Code
derart zu produzieren, dass alle in CPU-Register gehaltene Speicherwerte nach
jeder Modula-2-Quellzeile in die entsprechenden Variablen abgelegt werden.
Dadurch wird sichergestellt, dass der RAM-Speicher nach der Abarbeitung jeder
Quellzeile immer auf den neuesten Stand bleibt. Dies is dann nБtzlich, wenn man
mit einem Debugger Quellzeile fБr Quellzeile durchgeht und dabei den Inhalt von
Variablen inspizieren oder anzeigen lassen mФchte. Zu diesem Zweck deaktiviert
der '-D'- Schalter die '-OB'- und '-OI'- Optimierungs- Schalter.
Der '-D' Schalter veranlasst den Ъbersetzer auch, HLL-komatible symbolische
Debug-Infos zu erzeugen. Diese werden in die OBJ-Dateiausgabe geschrieben. Der
Linker schreibt diese Informationen schliesslich in die ausfБhrbare EXE-Datei.
Beispiel zur Programmerzeugung und Debugger-Aufruf:
MOD MYPROG.MOD -B -O -L
LINK386 @MYPROG.RSP
SD386 MYPROG.EXE
ΓòÉΓòÉΓòÉ 13.1.8. Optimierungen ΓòÉΓòÉΓòÉ
Modula-2 ist eine Programmier-Hochsprache und ist im hohen Masse unabhДngig von
der Hardware. Aus diesem Grunde Бbersetzt dieser Compiler die Quell-Anweisungen
nicht sofort in den Maschinen-Code. Er erzeugt vielmehr einen Zwischen-Code fБr
die Anweisugen. Erst dieser Zwischen-Code wird dann in den Maschinen-Code des
gewБnschten Ziel-Prozessors transformiert. Um nun die besonderen Eigenschaften
der CPU zu nutzen, mit dem Ziel von kБrzeren und schnelleren Programmen, kФnnen
zuvor einige Optimierungen durchgefБhrt werden. Dieser Ъbersetzer bietet fБr
die Optimierungen die folgenden Schalter an:
-OG
-OB
-OI
-O
Der '-OG'- Schalter veranlasst den Ъbersetzer, eine globale Datenflussanalyse
Бber die Grenzen elementarer BlФcke hinweg durchzufБhren. Eine Anweisungsfolge
von einem Prozedur- oder Modul- KФrper wird immer in elementare BlФcke
unterteilt. Diese kommen durch Anweisungen zustande, die den Programmfluss
Дndern, z.B. IF-THEN-ELSE oder Schleifen. Die aus der globalen
Datenflussanalyse gewonnenen Informationen dienen als Grundlage fБr eine
weitere Analyse lebendiger Variablen. Durch letztere wird herrausgefunden, wie
lange jede Variable nach ihrer Zuweisung oder Initialisierung von den
nachfolgenden Anweisungen gebraucht wird. Diese Information Бber lebende
Variablen wird wiederum fБr die Zuordnung von Adressen der temporДren Variablen
auf dem Laufzeit-Stapelspeicher und auch fБr Schleifenoptimierungen gebraucht.
TemporДre Variablen entstehen wДhrend der ProgrammausfБhrung, um dort
Zwischenergebnisse komplexer Ausdrucke zu speichern. Das Ziel besteht natБrlich
darin, mФglichst wenig Stapelspeicher fБr die temporДren Variablen zu benutzen.
Besser ist es, freie CPU-Register geschickter auszunutzen. Das Ziel der
Schleifen-Optimierung besteht darin, Variablen, die innerhalb von Schleifen
angesprochen werden, ebenfalls in CPU-Register zu halten, weil auf solche
Variablen in der Regel viel hДufiger zugegriffen wird.
Die globale Datenflussanalyse dient auch als Grundlage fБr eine Analyse
verfБgbarer Register. Letztere versucht herrauszufinden, wie lange ein
Register-Byte sogar Бber elementare BlФcke hinweg seinen Wert dort behalten
kann, ohne die beabsichtigte Semantik des Programms zu verletzen. Diese Analyse
trДgt dazu bei, dass wДhrend der Programmlaufzeit CPU-Register nicht zu oft aus
dem RAM-Speicher nachgeladen werden mБssen.
Der '-OB'- Schalter veranlasst den Ъbersetzer, eine Optimierung der AusdrБcke
durchzufБhren. Wenn in einem Quell-Programm eine komplexer Ausdruck hДufig
vorkommt, ist es oftmals mФglich, solch einen Ausdruck wДhrend der
ProgrammausfБhrung nur einmal auszuwerten und das Ergebnis in einer temporДren
Variablen zwischenzuspeichern. Solch ein gemeinsamer Ausdruck kann dann
jedesmal, wenn er vorkommt, benutzt werden. Er muss nicht immer wieder von
neuem ausgewertet werden. Gemeinsame AusdrБcke werden von diesem Ъbersetzer
innerhalb von elementaren BlФcken und in einem gewissen Umfang sogar global,
d.h. Бber elementare BlФcke hinweg, erkannt.
Der '-OB'- Schalter teilt dem Ъbersetzer auch mit, dass er den o.g.
Zwischen-Code vereinfachen soll. Muliplikationen und Divisionen kФnnen zum
Beispiel oftmals durch schnellere Schift-Instruktionen ersetzt werden.
Der '-OI'- Schalter veranlasst den Ъbersetzer, fБr indizierte und
Zeiger-derefenzierte AusdrБcke einen effizienteren Maschinen-Code zu erzeugen.
Ein Operand fБr die Intel 80x86-CPU kann nicht nur aus einem Offset-Wert fБr
eine Speicheradresse bestehen, sondern zusДtzlich aus Index- und/oder
Basis-Register, und einem Skalierungsfaktor. Das Ziel der Optimierung ist es
also, mФglichst viele Zeiger oder Indizes wДhrend der Laufzeit in Basis- oder
Index-Register der entsprechenden Operanden zu halten.
Der '-O'- Schalter veranlasst den Ъbersetzer, alle o.g. Optimierungen
durchzufБhren. Er ist lediglich eine Kurzform fБr die Notation '-OG -OB -OI'.
ΓòÉΓòÉΓòÉ 13.1.9. Feldausrichtungen ΓòÉΓòÉΓòÉ
Dieser Ъbersetzer bietet verschiedene Arten von Feldausrichtungen an. Ein
Verbundfeld kann auf eine Byte-, Wort- oder Doppelwort-Grenze ausgerichttet
werden. Durch gute Feldausrichtungen kann die Zeit fБr den Speicherzugriff auf
ein Feld reduziert werden. Wenn zum Beipiel in einem 32-Bit-Programm auf ein
Verbundfeld mit DoppelwortgrФsse zugegriffen werden soll, wБrde hierfБr bei
Nichtausrichtung auf Doppelwortgrenze mehr als ein Schritt benФtigt werden.
Ausrichtungen werden durch diesen Ъbersetzer durch das EinfБgen von anonymen
FБllbytes erreicht.
Die folgenden Ausrichtungs- Schalter werden vom Ъbersetzer erkannt:
-A Standard-Ausrichtung
-A1 Byte-Ausrichtung
-A2 Wort-Ausrichtung
-A4 Doppelwort-Ausrichtung
Der '-A1'- Schalter gibt dem Ъbersetzer an, jedes Verbundfeld auf eine
Byte-Grenze auszurichten. Das bedeutet, dass nirgendwo FБllbytes eingefБgt
werden.
Der '-A2'- Schalter gibt dem Ъbersetzer an, jedes Verbundfeld, welches grФsser
als 1 Byte ist, oder welches einen Verbundtyp hat, auf eine 2-Bytes-Wort-Grenze
auszurichten. Dies geschieht durch EinfБgen von FБllbytes vor den
auszurichtenden Feldern.
Der '-A4'- Schalter gibt dem Ъbersetzer an, jedes Verbundfeld, dessen TypgrФsse
grФsser als 1 Byte ist oder dessen Typ aus einem Verbund besteht, auf eine
4-Bytes-Doppelwort-Grenze auszurichten. Dies geschieht durch EinfБgen von
FБllbytes vor den auszurichtenden Feldern.
Falls auf der Kommandozeile kein Ausrichtungs- oder der '-A'- Schalter
angegeben ist, wird fБr die Verbundfelder eine standard-mДssige Ausrichtung
gemДss folgendem Schema durchgefБhrt:
Wenn das Feld einen Verbundtyp hat, richte es auf die NEAR ZeigergrФsse (2
Bytes fБr 16-Bit- Speichermodelle, 4 Bytes fБr 32-Bit- Speicher-Modelle) aus.
Sonst, wenn die FeldgrФsse 1 Byte ist, fБhre Byte-Ausrichtung durch.
Sonst, wenn die FeldgrФsse 2 Bytes ist, fБhre Wort-Ausrichtung durch.
Sonst fБhre Wort-Ausrichtung bei den 16-Bit- Speicher-Modellen und
Doppelwort-Ausrichtung bei den 32-Bit Speicher-Modellen durch.
Wenn der Typ eines Verbundfelds aus einer (mФglicherweise multidimensionalen)
Reihung besteht, dann wird fБr o.g. Ausrichtungen der Typ der Elemente der
Reihung herangezogen.
ΓòÉΓòÉΓòÉ 13.1.10. OS/2-Anwendungstypen ΓòÉΓòÉΓòÉ
Unter OS/2 gibt es drei verschiedene Anwendungstypen:
-PM:NOVIO Anwendung im Textmodus fБr Gesamtbildschirm
-PM:VIO Anwendung im Textmodus auch fБr Fenster unter dem
Presentation Manager
-PM:PM Anwendung fБr den Presentation Manager
Eine Anwendung im Textmodus fБr den Gesamtbildschirm ist nicht mit dem OS/2
Presentation Manager vertrДglich. Sie muss daher in einer separaten Sitzung
mit einem vollen Text-Bildschirm ablaufen (text-mode screen session). Diese
Art von Anwendungen darf aber dafБr auch maschinennahe Methoden fБr die
Bildschirmausgabe oder den Maus- und Tastatur-Eingaben benutzen.
Eine Fenster-vertrДgliche Anwendung im Text-Modus darf nur eine bestimmte
Teilmenge aus dem OS/2 API fБr Bildschirm, Tastatur und Maus benutzen. Solch
eine Anwendung im Text-Modus kann entweder in einer separaten
Bildschirmsitzung laufen, mit einem vollen Bildschirm, oder aber in einem
Textfenster auf dem Presentation Manager Desktop. Alle Standard-Bibliotheken
von Modula-2 fБr diesen Ъbersetzer sind als Fenster-vertrДgliche Anwendungen
im Text-Modus konzipiert. Der Ъbersetzer selbst ist ebenfalls
fenstervertrДglich.
Eine Anwendung fБr den OS/2 Presentation Manager lДuft unter einer grafischen
OberflДche unter Benutzung von Fenstern. Sie kann nicht als separate
Bildschirmsitzung im Text-Modus laufen. Der Presentation Manager bietet eine
CUA-konforme Schnittstelle fБr den Benutzer. Er ist fБr Programme gedacht,
welche Fenster und grafische Objekte benutzen, einschliesslich einer vollen
MausunterstБtzung.
Nur einer der o.g. Schalter kann auf der Kommandozeile angegeben werden. Falls
solch eine Angabe fehlt, wird der Fenster-vertrДgliche Anwendungstyp '-PM:VIO'
angenommen.
ΓòÉΓòÉΓòÉ 13.1.11. C-artige Prozeduren ΓòÉΓòÉΓòÉ
Die folgenden Schalter zeigen dem Ъbersetzer an, dass er eine C-artige
Reihenfolge der ParameterБbergabe (von rechts nach links) oder einen C-artigen
Beendigungs-Code fБr eine Prozedur benutzen soll. C-artig bedeutet hier, dass
die Konventionen der Programmiersprache C benutzt werden sollen. Normalerweise
wird auch fБr Modula-2 eine Konvention gemДss der Pascal-Sprache benutzt.
-CPARAM C-artige Reihenfolge der ParameterБbergabe
-CRET C-artige Prozedur-Beendigung. Aufrufer, nicht
Prozedur, rДumt den Stapelspeicher auf.
-CDECL -CPARAM und -CRET kombiniert.
Diese Angaben werden benФtigt, um eine VertrДglichkeit mit Funktionen, welche
in der C-Sprache geschrieben worden sind, herzustellen.
Hinweis: Diese Angaben sind fБr alle zu Бbersetzende Module aktiv. Da
Modula-2-Prozeduren gewФhnlich der Pascal-Konvention fБr die
ParameterБbergaben und dem Beendigungs-Code folgen, sollten C-artige
Konventionen nur die Ausnahme bilden. Die Pascal-Konvention erzeugt kБrzeren
und auch sichereren Maschinen-Code. Es wird daher empfohlen, nicht o.g.
Schalter von der Kommandozeile zu gebrauchen, sondern lieber Фrtliche
Ъbersetzer- Direktiven vor den jeweiligen Prozedur-Deklarationen innerhalb der
Quelltexte einzufБgen.
ΓòÉΓòÉΓòÉ 13.1.12. Sonstige Schalter ΓòÉΓòÉΓòÉ
Die folgenden sonstigen Schalter werden von diesem Ъbersetzer erkannt:
-P Ъbersetzung mit Quelltext-Protokollierung
und Fehlerunterbrechungen
-W0 Warnungen Level 0
-W1 Warnungen Level 1
-E=Verzeichnis Unterverzeichnis fБr ausfБhrbare Datei
-C=Anzahl Abbruch nach <Anzahl> Fehlern
-R4 REAL = SHORTREAL
-R8 REAL = LONGREAL
-H2 HIGH gibt 2-Byte CARDINAL zurБck
-H4 HIGH gibt 4-Byte LONGCARD zurБck
-V Nehme an, dass globale Variablen flБchtig
sind
-FSAVE Sichere alle FPU-Register zu Beginn einer
Prozedur.
-$=Sonderzeichen Definiere ein neues EinfБhrungszeichen fБr
Ъbersetzer-Direktiven
Der '-P'- Schalter veranlasst wДhrend der Ъbersetzung die Protokollierung der
Quelldateien auf dem Bildschirm. Ausserdem wird bei jeder Fehlermeldung die
Ъbersetzung unterbrochen, bis der Benutzer eine Taste drБckt. Wenn dieser
Schalter nicht angegeben wird, zeigt der Ъbersetzer nur die Fehlermeldungen
an, ohne weitere Aufforderungen an den Benutzer.
Die '-W0' oder '-W1' Schalter setzen den Level fБr Warnmeldungen wДhrend der
Ъbersetzung. Wenn der Level fБr Warnungen 1 ist, dann zeigt der Ъbersetzer
Warnungen an. Wenn der Level fБr Warnungen 0 ist, dann werden keine Warnungen
angezeigt. RegulДre Fehlermeldungen werden immer angezeigt.
Der '-E=Verzeichnis'- Schalter bestimmt das Unterverzeichnis, in welches die
Antwortdatei fБr den Binder, die Definitions-Dateien fБr den Binder, sowie die
schliessliche ausfБhrbare Datei selbst geschrieben werden sollen. Falls diese
Angabe fehlt, wird als Unterverzeichnis das aktuell eingestellte Verzeichnis
(-E=.\) angenommen.
Beispiel fБr Kommandozeile:
REM
REM make an optimized executable program for
REM the directory C:\MOD32\OS2BIN
REM
MOD MYPROG.MOD -M -O -E=C:\MOD32\OS2BIN
LINK386 @C:\MOD32\OS2BIN\MYPROG.RSP
Die '-R4'- oder '-R8'- Schalter teilen dem Ъbersetzer mit, welche TypengrФsse
fБr REAL zu benutzen ist. Ein REAL-Typ kann entweder ein 4-Bytes SHORTREAL
oder ein 8-Bytes LONGREAL sein. Die Grundannahme ist REAL=LONGREAL. Dieser
Schalter ist eingefБhrt worden, um eine VertrДglichkeit mit anderen
Ъbersetzern von Modula-2 zu gewДhrleisten.
Die '-H2'- oder '-H4'- Schalter teilen dem Ъbersetzer mit, welche TypgrФsse
von der Standard-Prozedur HIGH erwartet wird. StandardmДssig wird LONGCARD fБr
das 32-Bit 'flat' Speichermodell und CARDINAL fБr eines der 16-Bit
Speichermodelle zurБckgegeben.
Der '-V'- Schalter teilt dem Ъbersetzer mit, dass alle nicht auf dem
Stapelspeicher befindliche (das heisst nicht lokale) Variablen als flБchtig zu
betrachten sind. FlБchtige (volatile) Variablen werden nur fБr die Dauer einer
Maschinen-Instruktion in einem CPU-Register gehalten, wenn Бberhaupt. Auf eine
flБchtige Variable kann gleichzeitig von mehreren asynchronen Prozessen
zugegriffen werden. Deshalb kФnnen sie nicht Бber mehrere
Maschinen-Instruktionen hinweg in Register gehalten werden. Ein Beispiel fБr
flБchtige Variablen ist das eines angeschlossenen GerДtes mit einer
Hauptspeicherabbildung (memory mapped device).
Der Schalter '-FSAVE' teilt dem Ъbersetzer mit, dass zu Beginn einer Prozedur
Code fБr die Sicherung aller FPU-Register zu erzeugen ist. Und er veranlasst
den Ъbersetzer auch, vor dem Verlassen einer Prozedur Code zur
Wiederherstellung der FPU-Register zu erzeugen. Dieser Schalter ist fБr
Pascal-artiges Verhalten vorgesehen: Die aufgerufene Prozedur hat fБr die
Sicherung und Wiederherstellung der FPU-Register zu sorgen. Ohne diesem
Schalter wБrde der Ъbersetzer ein C-artiges Verhalten annehmen, d.h. die
FPU-Register werden vor dem Aufruf einer Prozedur vom Aufrufer gesichert.
Der Schalter '-$=Sonderzeichen' teilt dem Ъbersetzer mit, dass er ein anderes
Sonderzeichen fБr den Start von in Kommentaren eingelagerten
Ъbersetzer-Direktiven benutzen soll. Das voreingestellte EinfБhrungszeichen
fБr Ъbersetzer-Direktiven ist das Dollar-Zeichen '$'. Ъbersetzer-Direktiven
dienen als lokale Ъbersetzer-Schalter, welche nur fБr die Dauer der
Ъbersetzung eines Moduls gБltig sind. Sie sind in besonderen
Quelldatei-Kommentaren eingebettet und beginnen mit diesem Sonderzeichen.
Beispiel:
REM
REM compile with a redefined compiler directive
REM introducing character
REM
MOD MYPROG.MOD -O -$=?
Wenn die Quelldatei MYPROG.MOD vom obigen Beispiel Ъbersetzer-Direktiven,
enthДlt, dann werden sie nur mit dem neuen EinfБhrungszeichen '?' erkannt.
Beispiel:
MODULE MyProg;
(*$R8 no more recognized as compiler directive R8 *)
(*?A4 now recognized as compiler directive A4 *)
.........
END MyProg.
Durch die Definition eines neuen EinfБhrungszeichen fБr in Kommentare
eingebetteten Ъbersetzer-Direktiven werden mФgliche Konflikte mit anderen
Modula-2-Ъbersetzern, welche eine Дhnliche Direktiven-Syntax benutzen,
vermieden.
═══ 13.2. Ъbersetzer-Direktiven ═══
Viele der Schalter von der Kommandozeile sind auch lokal innerhalb der
Quell-Module verfБgbar. Sie sind in spezielle Kommentare eingebettet und dienen
als lokale Ъbersetzer-Direktiven, das heisst Anweisungen, wie die Ъbersetzung
durchzufБhren ist. Die folgende Liste summiert die hДufig gebrauchten
Ъbersetzer-Direktiven, die von diesem Ъbersetzer erkannt werden:
(*$XL+*) oder (*$XL-*) aktiviere oder deaktiviere die Spracherweiterungen
(*$XI+*) oder (*$XI-*) aktiviere oder deaktiviere den Gebrauch von
undokumentierten CPU-Instruktionen
(*$XF+*) oder (*$XF-*) aktiviere oder deaktiviere weniger strenge
Funktionsbezeichner
(*$8086*)
(*$80286*) oder (*$286*)
(*$80386*) oder (*$386*)
(*$80486*) oder (*$486*)
(*$80586*) oder (*$586*) Ъbersetze fБr spezifizierte Ziel-CPU
(*$F+*) oder (*$F-*) Nehme die Existenz eines numerischen Koprozessors fБr
den INLINE-Assemblierer an
(*$R4*) oder (*$R8*) Nehme REAL=SHORTREAL oder REAL=LONGREAL an
(*$D+*) oder (*$D-*) Aktiviere oder deaktiviere Debugger- UnterstБtzung
(*$L+*) oder (*$L-*) Aktiviere oder deaktiviere das Weiterreichen von
Quell- Zeilennummern an die Ausgabe-Objektdateien.
(*$OB+*) oder (*$OB-*) Aktiviere oder deaktiviere die Optimierung von
AusdrБcken
(*$OG+*) oder (*$OG-*) Aktiviere oder deaktiviere die globale Datenfluss-
Optimierung fБr Register-Zuordnungen und Schleifen-Optimierungen
(*$OI+*) oder (*$OI-*) Aktiviere oder deaktiviere die Zeiger- und Index-
Optimierung fБr die Benutzung der CPU Basis/Index-Register.
(*$O+*) oder (*$O-*) Aktiviere oder deaktiviere alle Ъbersetzer-
Optimierungen
(*$DLL*) Diese Direktive wird nur am Beginn eines Definitions-Moduls
erkannt. Das entsprechende Implementations-Modul soll eine dynamische
Binder-Bibliothek werden.
(*$PREFIX*) Diese Direktive wird nur am Beginn eines Definitions-Moduls
erkannt. Wenn das entsprechende Implementations-Modul eine dynamische
Binder-Bibliothek werden soll, werden alle Фffentliche Symbole mit
dem Modul-Namen qualifiziert. Sonst nimmt OS/2 unqualifizierte
Symbole fБr eine DLL an.
(*$SSFAR*) Diese Direktive wird nur am Beginn eines Definitions-Moduls
erkannt. Es wird ein FAR (dass heisst ein separates)
Stapelspeicher-Segment wird fБr die Ъbersetzung des Moduls
angenommen.
(*$A*)
(*$A1*)
(*$A2*)
(*$A4*) Verbundfeld- Ausrichtung (A = Standard-Ausrichtung, An =
Ausrichtung auf n-Grenze)
(*$V+*) oder (*$V-*) Aktiviere oder deaktiviere die Annahme, dass globale
Variablen flБchtig sind.
(*$CPARAM+*) oder (*$CPARAM-*) C-artige oder Pascal-artige
ParameterБbergabe-Reihenfolge fБr Prozeduren.
(*$CRET+*) oder (*$CRET-*) C-artiger oder Pascal-artiger Beendigungs-Code
einer Prozedur.
(*$CDECL+*) oder (*$CDECL-*) C-artige oder Pascal-artige Prozeduren.
Beinhaltet (*$CPARAMё*) und (*$CRETё*).
(*$SOM+*) oder (*$SOM-*) Nachfolgend deklarierte Verbund-Typen werden als
OS/2 SOM -Klassen oder als normale Modula-2-Verbunde betrachtet.
(*$API16+*) oder (*$API16-*) Diese Direktive wird nur in einem
Definitions-Modul einer alten 16-Bit-API fБr OS/2 akzeptiert. Wenn
die Direktive aktiviert ist, werden alle folgenden APIs (d.h.
ProzedurkФpfe im Definitions-Modul) wie 16-Bit-APIs behandelt. Obwohl
die ProzedurkФpfe wie fБrs flache 32-Bit-Speichermodell deklariert
werden, wird der Programmablauf bei jedem Aufruf o.g. Prozeduren
zuerst in einem 16-Bit-Modus umgeschaltet. Dies geschieht dadurch,
dass die die AusfБhrungskontrolle zunДchst in die Prozedur
'SYSTEM.Thunk' gelangt, von welcher sie in die gewБnschte
16-Bit-Bibliothek weitergeleitet wird. Diese Umsetzung von 0:32- zur
16:16- Adressierung ist fБr das flache 32-Bit OS/2 leider manchmal
notwendig, weil noch immer einige 16-Bit-APIs nicht in entsprechende
32-Bit-APIs umgesetzt worden sind. Ansonsten besteht keine
Notwendigkeit, diese Direktive zu gebrauchen.
(*$H2*) or (*$H4*) Standard-Prozedur HIGH gibt einen CARDINAL- oder
LONGCARD- Wert zurБck.
(*$W1*) oder (*$W0*) Aktiviere oder deaktiviere Warnmeldungen wДhrend der
Ъbersetzung.
Jede im Kommentar eingebettete Ъbersetzer-Direktive muss mit einem
Sonderzeichen, welches gewФhnlich ein Dollarzeichen '$' ist, beginnen. Ein
anderes Sonderzeichen kann durch die Angabe des Schalters '-$=Sonderzeichen'
auf der Kommandozeile definiert werden. Dadurch kФnnen Konflikte mit anderen
Ъbersetzern von Modula-2 vermieden werden. Andere Ъbersetzer kФnnen nДmlich
eine Дhnliche Synatx fБr Direktiven innerhalb der Kommentare benutzen.
═══ 13.3. Bedingte Ъbersetzung ═══
Dieser Ъbersetzer erlaubt auch die bedingte Ъbersetzung, indem man folgende in
Kommentaren eingebettete Direktiven benutzt:
(*$IF BoolExpr *) oder
(*$IF NOT BoolExpr *) oder
(*$IFDEF Ident *) oder
(*$IFNDEF Ident *)
........
(*$ELSE *)
........
(*$ENDIF *)
Dabei ist 'Ident' irgendein existierender Name. Und 'BoolExpr' ist irgendein
existierender Name einer Bool'schen Konstante.
Beispiel:
PROCEDURE CAP( ch:CHAR ):CHAR;
CONST
UseCountryCode = SYSTEM.OS2 AND SYSTEM.Flat32Model;
VAR
(*$IF UseCountryCode *)
CountryCode : COUNTRYCODE;
rc : APIRET;
(*$ENDIF *)
BEGIN
(*$IF UseCountryCode *)
(* 32-bit OS/2 uses own case mapping *)
CountryCode.Country := 0;
CountryCode.CodePage := 0;
rc := DosMapCase( 1, CountryCode, ch );
(*$ELSE*)
(* use Modula's case mapping *)
CASE ch OF
| 'Д': ch := 'О';
| 'Ф': ch := 'Щ';
| 'Б': ch := 'Ъ';
| 'a'..'z': ch := CHR( ORD(ch) - (ORD('a') - ORD('A')) );
END;
(*$ENDIF*)
RETURN ch;
END CAP;
ΓòÉΓòÉΓòÉ 13.4. Binder-Direktiven ΓòÉΓòÉΓòÉ
Dieser Ъbersetzer stell auch eine spezielle Direktive fБr das Binder-Programm
zur VerfБgung. Sie wird als eine besondere Direktive in einem Kommentar
angegeben und nur innerhalb eines Programm-Moduls erkannt. Sie wird mit dem
SchlБsselwort $LINK eingefБhrt und von einer beliebigen Anzahl von Definitionen
fБrs Binder-Programm gefolgt. Letztere werden direkt an die Antwort-Datei fБr
das Binder-Programm weitergereicht. Sie ergДnzen oder ersetzen andere
standard-mДssig erzeugte Binder-Anweisungen.
Beispiel:
(*$LINK
LIBRARY ANIMAL
INITINSTANCE
DESCRIPTION
'Animal class DLL, compiled with Modula-2.'
PROTMODE
DATA
MULTIPLE NONSHARED LOADONCALL
*)
Falls eine Binder-Direktive eine IMPORTS- oder EXPORTS- Liste enthДlt, wird
keine standard-mДssige Import- oder Export- Liste mehr aus dem Definitionsmodul
erzeugt. Deswegen muss eine IMPORTS- oder EXPORTS- Direktive immer eine
komplette Liste aller Фffentlichen Symbole angeben. Eine Teilliste reicht nicht
aus. Das Binder-Programm (fБr gewФhnlich LINK386.EXE oder LINK.EXE) muss in der
Lage sein, alle Angaben aus der Binder-Direktive zu verstehen. Normalerweise
ist der Gebrauch von expliziten Binder-Direktiven БberflБssig fБr Programme
oder dynamische Binder-Bibliotheken. Die Direktive $LINK ist hauptsДchlich
wegen den vom Standard abweichenden Spezifikationen bei den OS/2
SOM-Bibliotheken eingefБhrt worden.
Diese Ъbersetzer-Dokumentation enthДlt keine genaue Beschreibung aller
mФglichen Binder-Anweisungen. Letztere sind den HandbБchern von den
Binder-Programmen LINK386 oder LINK zu entnehmen.
═══ 13.5. Ъbersetzer-Umgebung ═══
Jedes Programm lДuft in einem Prozess, welcher seine eigene Umgebung hat. Die
Prozess-Umgebung besteht aus einer Folge von Null-terminierten Zeichenketten.
Jede Zeichenkette hat die Form <Name>=<Inhalt>. Eine Zeichenkette aus der
Umgebung beginnt immer mit einem Namen, welcher die Umgebungsvariable genannt
wird. Er wird von einem Gleichheitszeichen '=' und einer Zeichenkette gefolgt.
Umgebungsvariablen speichern fБr die Programme gewФhnlich die Informationen
Бber die Umgebung im Betriebssystem. Dazu gehФren zum Beispiel Angaben, in
welchen Unterverzeichnissen auf der Festplatte nach bestimmten Daten oder
Programmen gesucht werden soll.
Dieser Ъbersetzer fБr Modula-2 konsultiert die folgenden Umgebungsvariablen:
MOD_SRC Verzeichnisse fБr Modula-2 Quelldateien (.MOD oder .DEF)
MOD_TMP Verzeichnis fБr temporДre Dateien (.TMP oder .WRK)
MOD_LIB Verzeichnis fБr Bibliotheks-Dateien (.LIB oder .DLL)
MOD_OBJ_SMALL
MOD_OBJ_MEDIUM
MOD_OBJ_COMPACT
MOD_OBJ_LARGE
MOD_OBJ_FLAT32 Verzeichnisse fБr Objekt-Dateien (.OBJ) fБr die
entsprechenden Speicher-Modelle.
DPATH Standard-Verzeichnis fБr Objekt-Dateien (.OBJ)
APPEND Standard-Verzeichnis fБr Objekt-Dateien (.OBJ)
LIB Standard-Verzeichnis fБr Bibliotheks-Dateien (.LIB oder .DLL)
Wenn die MOD_LIB Umgebungsvariable nicht existiert, dann wird die LIB
Umgebungsvariable genommen.
Wenn die _MOD_OBJ_... Umgebungsvariable fБr das entsprechende Speicher-Modell
nicht existiert, dann wird die DPATH Umgebungsvariable genommen. Wenn auch die
DPATH Umgebungsvariable nicht existiert, dann wird die APPEND
Umgebungsvariable genommen. Der Ъbersetzer mag mehrere Pfade nach
Objekt-Dateien absuchen, um zu prБfen, ob abhДngige Module neu Бbersetzt
werden mБssen. Aber tatsДchlich neu Бbersetzte Module werden nur im ersten
angegebenen Pfad abgespeichert.
Falls gar keine Umgebungsvariable fБr die Verzeichnisse der Objekt-Dateien
existiert, wird das aktuell eingestellte Verzeichnis '.\' fБr Objekt-Dateien
benutzt. Das gleiche gilt fБr Bibiliotheks-Dateien.
Die Programme LINK.EXE oder LINK386.EXE brauchen keine spezielle
Umgebungsvariablen, wenn die entsprechende Antwortdatei fБr den Binder benutzt
wird. Eine Antwortdatei wird durch die Make- oder Build- Funktion erzeugt. Nur
die TMP-Variable muss angegeben worden sein, weil diese das Verzeichnis fБr
temporДre Dateien, welche auch vom Binder erzeugt werden, benennt.
ΓòÉΓòÉΓòÉ 13.6. Erstellung dynamischer Binder-Bibliotheken ΓòÉΓòÉΓòÉ
Eine dynamische Binder-Bibliothek enthДlt ausfБhrbaren Code fБr gemeinsam
benutzte Prozeduren, Дhnlich den bisherigen Bibliotheken. Der Code aus den
dynamischen Bibliotheken wird jedoch nicht in die ausfБhrbare (.EXE) Datei
Бbernommen. Stattdessen wird die Bibliothek selbst wДhrend der Laufzeit
zusammen mit der ausfБhrbaren Datei in den Speicher geladen
Dynamische Bibliothken dienen prinzipiell dem gleichen Zweck wie
Standard-Bibiotheken, aber sie haben folgende Vorteile:
- Anwendungen werden schneller gebunden. Mit dem dynamischen Binden
wird der ausfБhrbare Code einer dynamischen Binder-Bibliothek nicht
in die ausfБhrbare Datei einer Anwendung eingebaut. Nur eine
Import-Definition wird dort eingebracht.
- Anwendungen belegen weniger Platz auf der Festplatte. Mit dem
dynamischen Binden ist es mФglich geworden, dass verschiedene
Programme auf die gleiche dynamische Prozedur, die nur einmal geladen
wird, zugreifen kФnnen. Ohne dynamisches Binden mБsste solch eine
Prozedur in jede .EXE-Datei kopiert werden, und wБrde dann mehrfach
existieren.
- Bibliotheken und Anwendungen sind unabhДngig. Dynamische
Binder-Bibliotheken kФnnen viele Male geДndert werden, ohne dass die
Anwendungen, welche sie benutzen, neu gebunden werden mБssen. Dies
ist besonders fБr Drittanbieter von Bibliotheken von Vorteil. Im
Falle von Оnderungen braucht nur eine neue Kopie der Bibliothek auf
der Festplatte installiert zu werden. Und wДhrend der Laufzeit kФnnen
die unverДndert gebliebenen Anwendungen automatisch auf die neuen
Bibliotheks-Prozeduren zugreifen.
- Code- und Daten-Segmente kФnnen gemeinsam benutzt werden. Ohne
dynamisches Binden wДre so etwas gar nicht mФglich, weil dann jede
ausfБhrbare Datei ihre eigenen Kopien dieser Segmente benutzen wБrde.
Durch die gemeinsame Benutzung von Segmenten dank dem dynamischen
Binden kann der Arbeitsspeicher effizienter bennutzt werden.
Unter OS/2 2.x/3.0 kann man auch gemeinsam benutzte Variablen als Teil der
Schnittstelle einer dynamischen Binder-Bibliothek deklarieren. Wie bei den
Фffentlichen Prozeduren werden auch diese gemeinsamen Variablen nur einmal
angelegt, aber stehen dann fБr alle Anwendugen, welche die dynamische
Binder-Bibliothek benutzen, zur VerfБgung.
Dieser Ъbersetzer unterstБtzt die Erstellung dynamischer Binder-Bibliotheken.
Ein Definitions-Modul dient dazu, die Фffentliche Schnittstelle der
dynamischen Binder-Bibliothek zu beschreiben, wДhrend das dazugehФrige
Implementations-Modul alle privaten Daten und Prozeduren deklariert. Aus der
Sicht eines Programmierers gibt es kaum einen Unterschied zwischen einem
normalen Modul und einer dynamischen Binder-Bibliothek. Um aus dem Code,
welcher von diesem Ъbersetzer aus einem Implementations-Modul erzeugt wird,
eine dynamische Binder-Bibliothek zu machen, muss folgende Ъbersetzer-
Direktive ganz am Anfang vom Definitions-Modul angegeben werden.
(*$DLL*)
Falls fБr ein segmentiertes 16-Bit- Speicher-Modell Бbersetzt wird, dann muss
das Stapelspeicher-Segment fБr die dynamische Binder-Bibliothek als FAR
behandelt werden, denn es ist der Stapelspeicher vom Aufrufer, und nicht vom
Implementations-Modul, welcher wДhrend der Laufzeit benutzt wird. Die folgende
Ъbersetzer- Direktive, welche ganz am Anfang eines Definitions-Moduls
anzugeben ist, informiert den Ъbersetzer darrБber, dass das
Stapelspeicher-Segment von ausserhalb stammt, also FAR ist:
(*$SSFAR*)
Das folgende Beispiel illustriert die Erstellung einer dynamischen
Binder-Bibliothek unter OS/2 2.x/3.0 aus dem Standard-Modul 'Terminal'. Die
Quelldateien fБr die Definitions- und Implementations-Module mФgen
folgendermassen aussehen:
(*$DLL Terminal to be implemented as dynamic link library *)
DEFINITION MODULE Terminal;
PROCEDURE Read( VAR ch: CHAR );
PROCEDURE BusyRead( VAR ch: CHAR );
PROCEDURE ReadAgain();
PROCEDURE ScanCode():SHORTCARD;
PROCEDURE SetEcho( Flag: BOOLEAN );
PROCEDURE GetEcho( VAR Flag: BOOLEAN );
PROCEDURE Write( ch: CHAR );
PROCEDURE WriteLn();
PROCEDURE WriteString( s: ARRAY OF CHAR );
END Terminal.
IMPLEMENTATION MODULE Terminal;
(* private code and data declarations ... *)
END Terminal.
Die Schritte fБr die Erstellung sind dann fast die gleichen wie diejenigen
einer normalen ausfБhrbaren Datei. Insbesondere wird dabei die Make- Funktion
benutzt.
REM
REM Make the dynamic link library
REM TERMINAL.DLL
REM
MOD TERMINAL.MOD -m -o
LINK386 @TERMINAL.RSP
In der Tat gibt zwischen den internen Formaten fБr ausfБhrbare Dateien und fБr
dynamische Binder-Bibliotheken kaum einen Unterschied. Nur die Erweiterungen
der Dateinamen unterscheiden sich wie folgt:
.DLL fБr dynamische Binder-Bibliotheken
.EXE fБr ausfБhrbare Dateien
ΓòÉΓòÉΓòÉ 14. Spracherweiterungen ΓòÉΓòÉΓòÉ
Modula-2 ist eine mДchtige Hochsprache fБr die Programmierung. Die
Sprachgrammatik basiert auf den VorschlДgen des Buches 'Programmierung in
Modula-2', vierte Ausgabe, von N.Wirth. Dennoch ist auch Modula-2 nicht
perfekt. Moderne Software-Projekte erfordern Werkzeuge fБr die
Objekt-orientierte Programmierung und teilweise auch fБr die Kooperation mit
Modulen, welche in anderen Programmiersprachen, wie z.B. C, geschrieben worden
sind. Eine Programmiersprache muss auch Zugang zu den APIs vom Betriebssystem
bieten. Aus o.g. GrБnden bietet dieser Ъbersetzer einige Erweiterungen
gegenБber dem Modula-Standard an. Die Erweiterungen kФnnen entweder auf der
Kommandozeile mit dem globalen Schalter
-XL
oder innerhalb von Kommantaren mit der lokalen Ъbersetzer- Direktive
(*$XL+*)
aktiviert werden. Es werden dann folgende neue Merkmale angeboten:
- Erweiterte Namen
- Neue reservierte Worte
- Object-orientierte Merkmale
- Erweiterung von Verbunden
- Testen dynamischer Verbundtypen
- Typenschutz-Selektoren
- Regionaler Typenschutz
- Typ-gebundene Prozeduren
- System Object Model
- Bitweise Operatoren
- Neue logische Operatoren
- Typisierte Konstanten
- Multidimensionale offene Reihungsparameter
- Segmentierung
- Erweiterte Importe
Durch den Gebrauch eines der o.g. Merkmale wird ein Programm natБrlich weniger
portierbar fБr andere Ъbersetzer von Modula-2. Aber diese Erweiterungen kФnnen
die Erstellung von Software fБr viele Projekte wesentlich vereinfachen. Die
folgenden Sektionen in dieser Dokumentation enthalten nДhere Informationen Бber
jede der o.g. Spracherweiterungen.
ΓòÉΓòÉΓòÉ 14.1. Erweiterte Namen ΓòÉΓòÉΓòÉ
Die Namen fБr Modula-2 bestehen aus Buchstaben und Ziffern. Bei den Buchstaben
wird zwischen Gross- und Kleinschreibung unterschieden. Jeder Name muss mit
einem Buchstaben beginnen. FБr die meisten Anwendungsprogramme ist diese
Namensregelung ausreichend. Nut bei gemischtsprachiger Programmierung oder bei
Benutzung von APIs vom Betriebssystem sind die ProgrammierbedБrfnisse
hinsichtlich der Zusammensetzung der Namen nicht immer befriedigt. Die APIs von
OS/2 2.x/3.0 und Module in der C-Sprache erlauben in ihren Zeichenketten fБr
Namen auch das Unterstreichungszeichen '_'. Deshalb akzeptiert auch dieser
Ъbersetzer zusДtzlich zu den normalen Buchstaben und Ziffern das
Unterstreichungszeichen fБr die Namensbildung. Dies ist aber nur dann
gestattet, wenn fБr die Spracherweiterungen entweder der entsprechende Schalter
auf der Kommandozeile oder in einem Kommentar die entsprechende Ъbersetzer-
Direktive aktiviert worden ist.
ΓòÉΓòÉΓòÉ 14.2. Neue reservierte Worte ΓòÉΓòÉΓòÉ
Einige der erweiterten Merkmale der Sprache wie zum Beispiel die
Objekt-orientierte Programmierung oder die neuen bitweisen und logischen
Operatoren machen es erforderlich, folgende neue Worte als reserviert
einzufБhren:
FAR
IS
NEAR
SHL
SHR
XOR
Die o.g. Namen werden aber nur dann als neue SchlБsselworte betrachtet, wenn
die Spracherweiterungen entweder auf der Kommandozeile durch einen Schalter
oder in einem Kommentar durch eine Direktive entsprechend aktiviert worden
sind. Diese Worte sind dann nicht mehr fБr Benutzernamen verfБgbar.
ΓòÉΓòÉΓòÉ 14.3. Objekt-orientierte Merkmale ΓòÉΓòÉΓòÉ
Dieser Ъbersetzer fБr Modula-2 ist mit Objekt-orientierten Sprachkonstrukten
erweitert worden. Sie lehnen sich eng an die neue Oberon-Sprache an. Oberon ist
in den spДten 1980ern als eine Nachfolgesprache fБr Modula-2 entwickelt worden,
und zwar durch Niklaus Wirth an der ETH ZБrich. Die Oberon-Sprache ist
ausfБhrlich in folgenden BБchern beschrieben worden:
- 'Programming in Oberon', by Martin Reiser, 1992, Addison Wesley, New
York.
- 'Object-Oriented Programming in Oberon-2', by Hanspeter MФssenbeck,
1993, Springer-Verlag, New York.
Schon fast seit den UrsprБngen der Programmierung ist die Entwicklung von
Software durch eine Prozedur-orientierte Art des Denkens betont gewesen.
Programme wurden in Prozeduren aufgeteilt. Prozeduren transformierten
Eingabedaten zu Ausgabedaten.
Der Objekt-orientierte Ansatz rБckt anstelle der Prozeduren die Daten mehr in
den Vordergrund. Die Daten und die Operationen, welche auf sie anwendbar sind,
machen sogenannte Objekte aus. Diese kФnnen gewisse Anfragen abarbeiten und
geben als Ergebnis Daten zurБck.
Der wesentliche Punkt ist nun hierbei der, dass man sich nicht um den Typ des
Objekts, an welchen eine Anfrage geschickt wird, zu kБmmern hat. Jeder
Objekttyp besitzt seine eigenen Hantierer, welche Methoden genannt werden. Und
mit diesen werden alle Anfragen abgearbeitet.
Objekt-orientierte Sprachen bieten gewФhnlich folgende Merkmale:
- verborgene Informationen
- Datenabstraktion
- Vererbung
- Dynamisches Binden
Das Verbergen von Informationen bedeutet, dass die Implementation komplexer
Daten in Objekte eingekapselt ist und dass Klienten nur eine abstrakte Sicht
dieser Daten zugДngig ist. Klienten kФnnen die eingekapselten Daten nicht
direkt ansprechen, sondern sie mБssen hierfБr Prozeduren, welche Bestandteil
der jeweiligen Objekte sind, benutzen. So werden die Klienten nicht mit den
Details der Implementation behelligt, und sie sind auch nicht von spДteren
Оnderungen in der Implementation des Objekts betroffen. Das Verbergen von
Informationen ist auch schon bei nicht Objekt-orientierten Programmiersprachen
seit vielen Jahren verfБgbar gewesen. Modula-2 zum Beispiel erreicht dieses
durch Module mit exportierten Prozeduren zur Handhabung der verborgenen Daten.
Zur Objekt-orientierten Programmierung gehФrt jedoch mehr.
Die Datenabstraktion ist der nДchste Schritt, der Бber das Verbergen von
Informationen hinausgeht. Die o.g. Objekte existieren nur einmal, aber
manchmal werden mehrere Kopien von ihnen benФtigt. So wie der Programmierer
eine beliebige Anzahl von Variablen gleichen Typs deklarieren kann, macht es
Objekt-orientierte Programmierung mФglich, mehrfache Objekte eines gemeinsamen
abstrakten Datentyps, einschliesslich ihren speziellen Operationen, zu
deklarieren. Ein abstrakter Datentyp ist somit eine Einheit aus Daten und
ihren anwendbaren Operationen. Mehrfache Variablen solch eines Typs kФnnen
deklariert werden. Unter Modula-2 wird dies hauptsДchlich mit Variablen eines
Verbundtyps erreicht. Dieser Verbund kann auch Felder mit Prozedur-Typen fБr
die Bearbeitungsfunktionen und Operationen enthalten. Bearbeitungsfunktionen
kФnnen natБrlich auch innerhalb eines gleichen Moduls zusammen mit den
Verbundtypen separat deklariert werden.
Die Vererbung ist ein neuartiges Konzept. Man findet sie nicht in
konventionellen Programmiersprachen. Sie beinhaltet, dass ein bereits
existierender abstrakter Datentyp, das heisst ein Verbundtyp, zu einem neuen
Typ erweitert werden kann. Dieser neue Typ ererbt alle Daten und Operationen
vom bisherigen Typ, und er kann zusДtzliche Daten und Operationen bekommen
oder ererbte Operationen modifizieren. Dadurch wird es mФglich, einen Typ als
ein halbfertiges Produkt zu entwerfen und ihn in eine Bibliothek abzulegen.
SpДter kann er zu verschiedenen Endprodukten erweitert werden. Von besonderer
Beduetung ist bei der Vererbung die Tatsache, dass der erweiterte Typ mit dem
Original kompatibel bleibt. Alle Prozeduren, die mit dem originalen Typ
arbeiten, laufen auch fБr Objekte mit dem neuen Typ. Dadurch wird die
Wiederverwendbarkeit bereits existierender Algorithmen erheblich gefФrdert.
Das vierte Merkmal von Objekt-orientierten Programmiersprachen ist das
dynamische Binden von Nachrichten oder Anfragen an Prozeduren. Prozeduren
werden erst wДhrend der Laufzeit an den dynamischen Typ von Objekten gebunden.
Dynamisches Binden ist auch schon seit langer Zeit in Form von
Prozedur-Variablen bekannt. Die Aktivierung einer Prozedur-Variablen
veranlasst die AusfБhrung derjenigen Prozedur, die wДhrend der Laufzeit in ihr
steht. Das Arbeiten mit Prozedur-Variablen ist jedoch mБhselig und
fehlertrДchtig. Das Konzept der dynamischen Bindung in den Objekt-orientierten
Sprachen stellt eine elegantere und sichere LФsung dar.
Die folgende Tabelle Бbersetzt die wichtigsten Begriffe von
Objekt-orientierten Sprachen in eine konventionelle Terminologie. Diese
Begriffe representieren nicht unbedingt radikal neue Konzepte, aber sie haben
ihre entsprechenden Begriffe in der konventionellen Programmierung.
OOP-Begriff Konventioneller Begriff
Klasse Erweiterbarer Verbundtyp, welcher einen abstrakten
Datentyp mit Feldern von Prozedurtypen definiert.
Objekt Variable, welche zu einer Instanz von einem
(mФglicherweise erweiterten ) Verbundtyp zeigt.
Nachricht Ein Aufruf einer Prozedur, welche mit der Klasse in
Verbindung steht
Methode Prozedur einer Klasse, entweder im selben Modul
deklariert, oder dynamisch an einem Verbundfeld mit
einem kompatiblen Prozedur-Typ gebunden, oder
Typ-gebunden zur Klasse.
Um es zusammenzufassen: Objekt-orientierte Programmierung bedeutet eine
Programmierung mit abstrakten Datentypen (Klassen), unter Zuhilfenahme der
Vererbung und dem dynamischen Binden. Dieser Ъbersetzer fБr Modula-2 bietet
folgende MФglichkeiten fБr die Objekt-Orientierung an:
- Erweiterung von Verbundtypen
- Testen dynamischer Verbundtypen
- Typenschutz-Selektoren
- Regionaler Typenschutz
Objekt-Orientierung wird durch den Gebrauch o.g. MФglichkeiten und durch den
Gebrauch von Variablen mit Prozedurtypen fБr das dynamische Binden von
Methoden an Verbunde erreicht. Objekt-Orientierung kann auch in noch
elegantere Weise durch Typ-gebundene Prozeduren in Verbindung mit oben
aufgelisteten Merkmalen erreicht werden. AusfБhrliche Beipiele sind in dieser
Dokumentation in den Abschnitten Бber den Typentests und Бber den
Typ-gebundenen Prozeduren beschrieben.
ΓòÉΓòÉΓòÉ 14.3.1. Erweiterung von Verbundtypen ΓòÉΓòÉΓòÉ
Die MФglichkeit der Erweiterung von Verbundtypen ist eines der Aspekte der
Objekt-orientierten Programmierung (OOP) und der Grund dafБr, dass OOP sich in
vielen Situationen gegenБber der konventionellen Programmierung als Бberlegen
erweist.
In diesem Ъbersetzer fБr Modula-2 kann ein Verbundtyp zu einem neuen Typ,
welcher neue Felder enthДlt, erweitert werden, wДhrend die KompatibilitДt mit
dem ursprБnglichen Typ bewahrt bleibt. In den Deklarationen
TYPE
T0 = RECORD ... END;
T1 = RECORD( T0 ) ... END;
ist T1 eine (direkte) Erweiterung von T0, und T0 ist der (direkte) Basistyp von
T1. Oder, um es in OOP-Begriffen auszudrБcken: T0 ist die Basisklasse oder
Superklasse von T1, wДhrend die Erweiterung als eine Unterklasse von T0
betrachtet werden kann.
Die Angabe des Namens des Basistyps in Klammern hinter dem Symbol RECORD deutet
an, dass der neue Typ eine Erweiterung vom Basistyp ist und somit zusДtzlich zu
seinen eigenen Feldern auch alle Felder vom Basistyp enthalten soll, so als ob
diese hier explizit deklariert worden wДren. Man sagt, dass der erweiterte Typ
die Felder vom Basistyp erbt. Deshalb spricht man im Zusammenhang einer
Typerweiterung auch von Vererbung. Die Erweiterung eines Typs funktioniert auch
fБr entsprechende Zeigertypen.
Beispiele:
TYPE
P0 = POINTER TO T0;
P1 = POINTER TO T1; (* P1 extends P0 *)
T0 = RECORD ... END;
T1 = RECORD( T0 ) ... END; (* T1 extends T0 *)
ΓòÉΓòÉΓòÉ 14.3.2. Testen dynamischer Verbundtypen ΓòÉΓòÉΓòÉ
Ein gДngiges Problem in der Objekt-orientierten Programmierung ist das der
MethodenauflФsung. Nachrichten oder Anfragen kФnnen zu jeder Variablen, welche
zu einem dynamisch reservierten Verbund zeigt, (d.h. Objekt-Variablen)
verschickt werden. Das Objekt muss nun die richtige Prozedur zur Handhabung der
Anfragen oder Nachrichten herausfinden. HierfБr muss der dynamische Typ des
Objekts bekannt sein. Da eine Objekt- Variable auch auf Verbunde seiner
Basistypen zeigen kann, wird vor dem eigentlichen Aufruf einer Prozedur zur
Handhabung einer Nachricht ein dynamischer Typentest benФtigt. Nur so kann zum
richtigen Typ die entsprechende Prozedur gefunden werden. Solch ein Test muss
also den dynamischen Typ fБr einen Verbund- Zeiger, welcher in einer Variablen
steht, feststellen. Der neue relationale Operator 'IS' fБhrt genau diesen
Typentest durch:
v IS T
ist nur dann erfБllt, wenn der aktuelle (oder dynamische) Typ von 'v' eine
Erweiterung von 'T' ist; das heisst, er muss zu 'T' oder zu einer Erweiterung
von 'T' gleich sein. 'T' muss eine Erweiterung vom deklarierten (oder
statischen) Typ einer Variablen 'v' sein; Und die Variable 'v' ist ein Verbund-
Zeiger oder ein formaler VAR-Parameter eines Verbundtyps.
Das folgende Beispiel zeigt ein Objekt-orientiertes GrundgerБst fБr eine
einfache Grafikverarbeitung:
TYPE (* Message types for graphic objects *)
Msg = RECORD
END;
DrawMsg = RECORD( Msg )
END;
ClearMsg = RECORD( Msg )
END;
MarkMsg = RECORD( Msg )
END;
MoveMsg = RECORD( Msg )
dX,dY : INTEGER;
END;
...
TYPE (* common graphics figure type *)
Figure = POINTER TO FigureRec;
TYPE (* Handler procedure for graphics figure *)
Handler = PROCEDURE( Self : Figure; VAR Message : Msg );
TYPE (* common graphics figure structure *)
FigureRec = RECORD
Handle : Handler;
selected : BOOLEAN;
END;
...
TYPE (* Rectangle = extended Figure *)
Rectangle = POINTER TO RectangleRec;
RectangleRec = RECORD( FigureRec )
x,y,w,h : INTEGER;
END;
...
TYPE (* TextBox = extended Rectangle *)
TextBox = POINTER TO TextBoxRec;
TextBoxRec = RECORD( RectangleRec )
text : ARRAY [0..31] OF CHAR;
END;
...
(* Message handler for Rectangle *)
PROCEDURE HandleRectangle( Self : Figure; Message : Msg );
BEGIN
WITH Self : Rectangle DO
(* 'Self' treated as if it were of type 'Rectangle' *)
IF Message IS DrawMsg THEN
WITH Message : DrawMsg DO
(* draw a rectangle *)
...
END;
ELSIF Message IS ClearMsg THEN
WITH Message : ClearMsg DO
(* clear a rectangle *)
...
END;
ELSIF Message IS MarkMsg THEN
WITH Message : MarkMsg DO
(* mark a rectangle *)
Self^.selected := TRUE;
...
END;
ELSIF Message IS MoveMsg THEN
WITH Message : MoveMsg DO
(* move a rectangle *)
Self^.x := Self^.x + Message.dX;
Self^.y := Self^.y + Message.dY;
...
END;
ELSE
(* Message not understood, typically no action *)
END;
END;
END HandleRectangle;
...
(* Message handler for TextBox *)
PROCEDURE HandleTextBox( Self : Figure; Message : Msg );
BEGIN
WITH Self : TextBox DO
...
END;
END HandleRectangle;
...
VAR
MyFigure : Figure;
MyRectangle : Rectangle;
MyTextBox : TextBox;
...
BEGIN
(* Create new Rectangle object *)
NEW( MyRectangle );
MyFigure = MyRectangle;
...
(* dynamic binding of a Rectangle specific handler *)
MyFigure^.Handle := HandleRectangle;
...
IF MyFigure IS Figure THEN (* TRUE *)
(* perform Figure specific operations *)
...
END;
...
IF MyFigure IS Rectangle THEN (* TRUE *)
...
(* perform Rectangle specific operations,
e.g. drawing and marking
*)
MyFigure^.Handle( MyFigure, DrawMsg );
MyFigure^.Handle( MyFigure, MarkMsg );
...
END;
...
IF MyFigure IS TextBox THEN (* FALSE *)
...
(* this would perform TextBox specific operations,
if Figure were of type TextBox
*)
...
END;
...
END ...
ΓòÉΓòÉΓòÉ 14.3.3. Typenschutz-Selektoren ΓòÉΓòÉΓòÉ
ΓûÉ Designator = Qualident { Selector }
ΓûÉ Selector = TypeGuard
ΓûÉ TypeGuard = "(" Qualident ")"
Jedes Objekt (im Sinne von OOP) ist fБr diesen Ъbersetzer eine Variable, welche
auf eine Instanz (Auftreten) eines (mФglicherweise erweiterten) Verbundtyps
zeigt. Wegen den Regeln der Zuweisung fБr erweiterte Verbunde muss sich ein
Objekt- Operand nicht immer auf den ursprБnglichen Verbundtyp beziehen. Es kann
auch auf eine der erweiterten Typen zeigen. Aus diesem Grund ist ein neuer
Selektor eingefБhrt worden, nДmlich der sogenannte Typenschutz.
Der Typenschutz 'V(T0)' stellt sicher, dass die Variable 'v' mindestens den
dynamischen Typ 'T0' (oder einen der Erweiterungen) besitzt. Die
ProgrammausfБhrung wird abgebrochen, wenn 'v' nicht den geforderten Typ
enthДlt. Der Typenschutz ist anwendbar, wenn
(1) T0 eine Erweiterung vom deklarierten Typ 'T' von 'v' ist, und
(2) 'v' ein formaler VAR-Parameter eines Verbundtyps oder 'v' ein
Verbundzeiger ist.
Durch die Angabe eines Typenschutz-Selektors erreicht der Programmierer, dass
der Operand so behandelt wird, als ob er von Anfang an mit dem erweiterten Typ
deklariert worden wДre, ohne auf einen Laufzeittest fБr den korrekten Gebrauch
des Verbundtyps zu verzichten.
Beispiel:
TYPE
(* common graphics base type *)
Figure = POINTER TO FigureRec;
FigureRec = RECORD
selected : BOOLEAN;
END;
...
(* extended Figure *)
Rectangle = POINTER TO RectangleRec;
RectangleRec = RECORD( FigureRec )
x,y,w,h : INTEGER;
END;
...
(* extended Rectangle *)
TextBox = POINTER TO TextBoxRec;
TextBoxRec = RECORD( RectangleRec )
text : ARRAY [0..31] OF CHAR;
END;
...
VAR
MyFigure : Figure;
...
BEGIN
...
IF MyFigure IS TextBox THEN
(* MyFigure has extended type
POINTER TO TextBoxRec during run time
*)
MyFigure( TextBox )^.text := "default string";
END;
...
END
...
ΓòÉΓòÉΓòÉ 14.3.4. Regionaler Typenschutz ΓòÉΓòÉΓòÉ
ΓûÉ WithStmt = WITH Guard DO StmtSeq END
ΓûÉ Guard = Qualident ":" Qualident
Es kommt hДufig vor, dass in einer Anweisungsfolge der gleiche Typenschutz
mehrfach auftritt. Deshalb wДre ein Typenschutz mit einem erweiterten
textuellen Sichtbarkeitsbereich wБnschenswert. Dieser wБrde die Klarheit
verbessern und den Verwaltungsaufwand verringern. Die erweiterte Form der
With-Anweisung bietet genau den geforderten regionalen Typenschutz. Im
Gegensatz zur normalen Modula-2- With-Anweisung macht diese erweiterte Form
nicht automatisch in einem neuen lokalen Sichtbarkeitsbereich die Verbundfelder
verfБgbar. Verbundfelder mБssen selbst innerhalb dieser erweiterten
With-Anweisung immer noch mit einem Verbund- Bezeichner qualifiziert werden.
Beispiel:
TYPE
(* common graphics base type *)
Figure = POINTER TO FigureRec;
FigureRec = RECORD
selected : BOOLEAN;
END;
...
(* extended Figure *)
Rectangle = POINTER TO RectangleRec;
RectangleRec = RECORD( FigureRec )
x,y,w,h : INTEGER;
END;
...
(* extended Rectangle *)
TextBox = POINTER TO TextBoxRec;
TextBoxRec = RECORD( RectangleRec )
text : ARRAY [0..31] OF CHAR;
END;
...
VAR
MyFigure : Figure;
...
BEGIN
...
IF MyFigure IS Rectangle THEN
WITH MyFigure : Rectangle DO
(* Designator 'MyFigure' treated as if it were of type
POINTER TO RectangleRec inside this scope
*)
MyFigure^.x := 1;
MyFigure^.y := 2;
MyFigure^.w := 10;
MyFigure^.h := 15;
END;
END;
...
END
...
ΓòÉΓòÉΓòÉ 14.3.5. Typ-gebundene Prozeduren ΓòÉΓòÉΓòÉ
ΓûÉ ProcedureHeading = [ NEAR | FAR ] PROCEDURE
ΓûÉ [ Receiver ] Ident [ FormalParameters ]
ΓûÉ Receiver = "(" [ [ NEAR | FAR ] VAR ] Ident : Ident ")"
Dieser Ъbersetzer fБr Modula-2 unterstБtzt das Konzept der Typ-gebundenen
Prozeduren. Es ist nur dann verfБgbar, wenn die Spracherweiterungen akitviert
sind. Typ-gebundene Prozeduren wurden erstmalig mit der neuen Sprache Oberon-2
eingefБhrt. Oberon-2 ist der Objekt-orientierte Nachfolger von Modula-2. Dies
ist auch der Grund dafБr, dass dieser Ъbersetzer fБr Modula-2 viele
Objekt-orientierte Merkmale von Oberon-2 Бbernommen hat, und zwar in Form einer
Spracherweiterung fБr Modula-2.
Global deklarierte Prozeduren kФnnen an einem Verbundtyp, welcher im selben
Modul deklariert ist, gekoppelt sein. Man sagt, dass diese Prozeduren dann an
den Verbundtyp gebunden sind. Somit kann der Verbundtyp dann als eine Klasse
aufgefasst werden, wobei seine Typ-gebundene Prozeduren als seine Methoden
dienen. Die Methoden sind fБr die Zugriffe und VerДnderungen auf die
(mФglicherweise mehrfach auftretende) Instanz einer Klasse verantwortlich.
Die Bindung wird durch den Typ vom EmpfДnger angegeben. Der EmpfДnger steht in
dem Kopf einer Prozedur-Deklaration. Der EmpfДnger darf entweder als ein
VAR-Parameter eines Verbundtyps T oder als einen Wert-Parameter mit einem
Zeigertyp zum Verbundtyp T angegeben werden. Die Prozedur ist dann an den Typ T
gebunden und wird innerhalb von T als lokal betrachtet.
Die Bindung einer Prozedur P zu einem Typ T0 beinhaltet auch die Bindung zu
einem Typ T1, sofern letzterer eine Erweiterung von T0 ist. Eine Prozedur P'
(mit gleichem Namen wie P) darf aber auch explizit an T1 gebunden werden,
wodurch die Bindung von P Бberschrieben wird. P' wird dann als eine
Redefinition von P fБr T1 aufgefasst. Die formalen Parameter von P und P'
mБssen Бbereinstimmen. Sowohl P' als auch T1 mБssen im gleichen Modul
deklariert werden. Dies gilt auch fБr die ursprБnglichen P und T. Wenn T1
exportiert wird, dann darf auch P' exportiert werden. Im Gegensatz zu Oberon-2
akzeptiert dieser Ъbersetzer fБr Modula-2 auch die Deklarationen von privaten
Typ-gebundenen Prozeduren, selbst wenn sie vererbte Methoden, die aus anderen
Definitions-Modulen exportiert werden, Бberschreiben. Eine Typ-gebundene
private Methode kann nur in einem Implementations-Modul oder in einem
Programm-Modul angegeben werden, wДhrend sein Typ selbst im entsprechenden
Definitions-Modul deklariert sein kann.
Falls ein Bezeichner v auf einen Verbund zeigt und P eine Typ-gebundene
Prozedur ist, dann gibt v^.P diejenige Prozedur an, die an den dynamischen Typ
von v gebunden ist. Sie kann dabei eine andere Prozedur sein als diejenige,
welche an den statischen Typ von v gebunden ist. Die Variable v wird gemДss den
Regeln zur Ъbergabe von Parametern einer Prozedure-Deklaration. weitergereicht.
Es kann auch eine Eltern-Prozedur bezeichnet werden. Wenn r als EmpfДnger mit
einem VAR-Parameter und einem Verbundtyp T deklariert worden ist, gibt r.P^ die
redefinierte, und an den Basistyp von T gebundenene, Prozedur P an. Ebenso
gilt, falls p als ein EmpfДnger mit einem VAL-Parameter und einem formalen
Zeigertyp P auf dem Verbundtyp T deklariert worden ist, dass p^.P^ diejenige
redefinierte Prozedur P bezeichnet, welche an den Basistyp von T gebunden ist.
Die Bezeichnung einer Eltern-Prozedur ergibt immer eine statische Bezugnahme
zur Prozedur, ohne sich um etwaige dynamische Bindungen zu kБnmern.
Bei einer vorwДrts deklararierten Typ-gebundenen Prozedur mittels FORWARD muss
der als EmpfДnger angegebene Parameter mit der aktuellen Prozedur-Deklaration
typenmДssig identisch sein. Das gleiche gilt auch fБr alle in einem
Definitions-Modul angegebenen ProzedurkФpfe mit Typ-Bindung, da sie erst im
Implementations-Modul voll deklariert werden. Die formalen Parameter mБssen fБr
beide Deklarationen Бbereinstimmen.
Beispiel:
TYPE
TREE = POINTER TO NODE;
NODE = RECORD
key : INTEGER;
left : TREE;
right : TREE;
END;
TYPE
CENTERTREE = POINTER TO CENTERNODE;
CENTERNODE = RECORD( NODE )
width : INTEGER;
subnode : TREE;
END;
(* declaring method Insert for TREE *)
PROCEDURE( self : TREE ) Insert( node : TREE );
VAR p, father : TREE;
BEGIN
p := self;
REPEAT
father := p;
IF node^.key = p^.key THEN
RETURN
ELSIF node^.key < p^.key THEN
p := p^.left
ELSE
p := p^.right;
END;
UNTIL p = NIL;
IF node^.key < father^.key THEN
father^.left := node;
ELSE
father^.right := node;
END;
node^.left := NIL;
node^.right := NIL;
END Insert;
(* overriding method Insert for extended CENTERTREE *)
PROCEDURE( self : CENTERTREE ) Insert( node : TREE );
BEGIN
WriteInt( node( CENTERTREE )^.width );
(* now calling parent method bound to TREE *)
self^.Insert^( node );
END Insert:
ΓòÉΓòÉΓòÉ 14.4. System Object Model ΓòÉΓòÉΓòÉ
OS/2 besitzt ein besonderes System-Object-Model (SOM). Es stellt eine
Objekt-orientierte Schnittstelle zur Erzeugung, Darstellung und Оnderung von
Software-Objekten dar. Die Software-Objekte werden in binДre
Klassen-Bibliotheken zusammengefasst. Im Gegensatz zu den Modellen fБr Objekte,
wie man sie in den formalen Objekt-orientierten Sprachen wie z.B. C++ oder
Oberon-2 findet, ist der Ansatz fБr SOM sprachneutral. Das bedeutet, dass
Benutzer und Entwerfer eines Objektes ihre Programmierung nicht in der gleichen
Sprache durchfБhren mБssen. Diese UnabhДngigkeit der Entwurfs- und Benutzer-
Sprachen erstreckt sich sogar auf das Konzept der Unterklassen (oder, um es in
Modula-2 oder Oberon-2 auszudrБcken: erweiterte Verbunde ). Der Benutzer einer
SOM-Klasse kann eine neue Unterklasse entwerfen. Diese kann, muss aber nicht,
in der gleichen Sprache wie die der Бbergeordneten Klasse formuliert werden.
Prinzipiell ist es von Vorteil, SOM zu gebrauchen. Denn SOM gestattet auch
Оnderungen von Einzelheiten aus der Implementierung und teilweise sogar von der
Schnittstelle einer Klasse. Dabei ensteht kein Bruch mit der binДren
Schnittstelle der Klasse, und es ist auch keine Neu-Ъbersetzung von
Klient-Programmen erforderlich. Man kann also festhalten, dass, wenn Оnderungen
einer SOM-Klasse keine Оnderungen in Klient-Programmen erfordern, das fБr jene
Klient-Programme keine Neu-Ъbersetzung notwendig wird. Dies ist bei vielen
Objekt-orientierten Sprachen nicht der Fall. Und deshalb ist es auch von
besonderem Vorteil, wenn man SOM benutzt. SOM-Klassen kФnnen folgende
strukturelle Оnderungen erfahren, ohne die binДre RБckwДrts-VertrДglichkeit
aufzugeben:
- HinzufБgen von neuen Methoden
- Оndern der GrФsse eines Objektes durch HinzufБgen oder Entfernen von
Instanz-Variablen
- HinzufБgen von neuen Klassen oberhalb der eigenen Klasse in der
Hierarchie der Vererbungen
- Versetzen von Methoden auf eine hФhere Stufe innerhalb der Hierarchie der
Klasse
Kurzgefasst: Typische Arten von VerДnderungen kФnnen an der Implementierung
vorgenommen werden. Diese mФgen sich erst wДhrend der Software-Entwicklung
ergeben.
SOM soll wegen der folgenden drei GrБnde sprachunabhДngig sein:
1. Alle SOM-Interaktionen bestehen aus standard-mДssigen Prozedur-Aufrufen.
Auf Systemen mit standardisierten Binder-Konventionen fБr
Prozedur-Aufrufe unterstБtzen die SOM-Interaktionen entsprechende
Standards. Deshalb kФnnen die meisten Programmiersprachen, welche externe
Prozedur-Aufrufe kennen, vollen Gebrauch von SOM machen. Unter Modula-2
fБr OS/2 bedeutet dies nichts anderes als der Aufruf von externen
Prozeduren, welche in den Definitions-Modulen fБr dynamische
Binder-Bibliotheken deklariert sein mБssen. Die dynamischen
Binder-Bibliotheken fБr OS/2 kФnnen Фffentliche SOM-Klassen enthalten.
2. Die Form der Programmier-Schnittstelle, oder kurz API, mag von Sprache zu
Sprache unterschiedlich sein. Dies wird durch sogenannte SOM-Bindungen
erreicht. Die Art und Weise, in der Programmierer Methoden aufrufen,
Objekte erzeugen, und so weiter, kann mit Leichtigkeit in die
semantischen Regeln aus einem grossen Bereich verschiedenster
kommerzieller Objekt-orientierter Programmier-Sprachen umgesetzt werden.
Dies gilt zum Beispiel fБr die Sprache C++. Selbst prozedurale Sprachen
wie zum Beispiel C oder Modula-2 bleiben nicht aussen vor. Die
SOM-Bindungen bestehen aus einer Menge von Makros und Prozedur-Aufrufen,
die die Implementierung und Benutzung von SOM-Klassen vereinfachen, denn
die jeweilige Schnittstelle ist auf die spezielle Programmiersprache
anpassbar.
3. SOM unterstБtzt verschiedene Mechanismen zur Methoden-AuflФsung, welche
in die jeweilige Semantik aus einer grossen Auswahl von
Objekt-orientierten Sprachen umgesetzt werden kФnnen. Deshalb kФnnen
SOM-Klassen Бber die Grenzen verschiedener Objekt-Modelle hinweg
gemeinsam benutzt werden. Aus diesem Grund gibt es drei verschiedene
zugreifbare Verfahren zur Methoden-AuflФsung.
Die Mechanismen zur Methoden-AuflФsung unter SOM sind wie folgt:
Offset-AuflФsung Diese entspricht in etwa dem Konzept der virtuellen Funktion
von C++, oder auch dem Konzept der Typ-gebundenen Prozeduren aus Oberon-2
oder aus dieser erweiterten Modula-2-Sprache. Die Offset-AuflФsung
beinhaltet im wesentlichen ein statisches Schema von Objekt-Typen. Das
polymorphe Verhalten basiert streng auf die Klassen-Vererbung. Die
Offset-AuflФsung bietet die schnellste Leistung bei einer
SOM-Methoden-AuflФsung. Methoden, die durch die Offset-AuflФsung
zugДnglich werden, kФnnen als statische Methoden betrachtet werden, weil
sie als einen festen Bestandteil einer Objekt-Schnittstelle gelten.
Namens-AuflФsung Diese entspricht in etwa den Verfahren aus Objective-C und
Smalltalk. Die Namens-AuflФsung unterstБtzt typenlose Zugriffe auf
Objekte. Man spricht auch manchmal davon, dass solche Objekte lediglich
einen dynamischen Typ besitzen. Der polymorphe Charakter basiert auf den
akuellen Protokollen, denen die Objekte gehorchen. Die Namens-AuflФsung
bietet die MФglichkeit, Code zur Manipulation von Objekten, welche zur
Zeit der Ъbersetzung weder den Typ noch das Aussehen vom Objekt kennen,
zu schreiben.
AuflФsung durch Abfertigungs-Funktionen Die Abfertigungs-Funktion (engl.
dispatch function) ist ein besonderes Merkmal von SOM. Sie erlaubt eine
auf besondere Regeln basierende Methoden-AuflФsung. Dies ist sonst nur in
der DomДne der empfangenden Objekte gebrДuchlich. Sprachen, die eine
besondere Eingangs- oder Ausgangs- Sequenz erfordern, oder lokale Objekte
aus verteilten Objekt-DomДnen, sind gute Kandidaten fБr den Gebrauch von
Abfertigungs-Funktionen zur Methoden-AuflФsung. Diese Technik bietet das
hФchste Mass an Kapselung fБr die Implementierung eines Objektes,
allerdings auf Kosten der System-Leistung.
Die ursprБngliche Planungsphilosophie von SOM sieht den Gebrauch eines
speziellen SOM-Ъbersetzers vor. Dieser SOM-Ъbersetzer liest eine
sprach-neutrale Klassenbeschreibung ein und erzeugt als Ausgabe
sprachspezifische SOM-Bindungen. Dieser Ъbersetzer fБr Modula-2 bietet einen
direkteren Ansatz. Dadurch ist kein spezieller sprach-neutraler SOM-Ъbersetzer
mehr erforderlich. Existierende oder neue SOM-Klassen werden einfach als
vertraute Definitions-Module fБr Modula-2 formuliert. Und neue SOM-Klassen
kФnnen in einem Implementations-Modul fБr Modula-2 eingefБhrt werden.
NatБrlich bietet dieser direkte Ansatz keine automatische Erzeugung von
Sprach-Bindungen fБr andere Sprachen an. Aber die mit Modula-2 erzeugten
binДren Bibliotheken mit neuen SOM-Klassen sind voll kompatibel mit dem OS/2
System Object Model. Und falls der Implementierer die sprach-neutrale Form der
Beschreibung einer SOM-Klasse anbieten mФchte, kann er immer noch den OS/2
SOM-Ъbersetzer nebst dazugehФrigen HandbБchern erwerben, und die
sprach-unabhДngige Form einer Beschreibungsdatei, d.h. 'interface description
file' (IDL-file), fБr den SOM-Ъbersetzer erstellen. Der SOM-Ъbersetzer wБrde
wiederum die Bindungen fБr die anderen Sprachen erzeugen kФnnen.
Es gibt nur eine vordefinierte Basis-Klasse von all den SOM-Klassen. Alle
Бbrigen SOM-Klassen werden also letztlich von dieser Basis-Klasse hergeleitet.
Diese Basis-Klasse heisst 'SOMObject'. Sie bietet grundlegende Methoden an,
deren FДhigkeiten fБr jede SOM-Klasse nБtzlich sind. SOM bietet auch das
Konzept der Metaklassen an. Eine Metaklasse ist eine Klasse, dessen Instanzen
sДmtlich wiederum aus Klassen bestehen (auch unter den Bezeichnungen
Klassen-Objekte oder Klassen-Deskriptoren bekannt). Die Metaklasse bietet
Fabrizierungs-Methoden fБr eine regulДre Klasse, wДhrend eine regulДre Klasse
Instanz-Methoden bereithДlt. Fabrizierungs-Methoden beinhalten Methoden zur
Erzeugung oder Konstruktion von Instanzen fБr regulДre Klassen. Die
Basis-Klasse fБr alle Metaklassen von SOM heisst 'SOMClass'. Sie ist selbst
wiederum von 'SOMObject' hergeleitet. Eine neue SOM-Klasse wird gewФhnlich mit
einer entsprechenden Metaklasse zu einem einzigen Modul gebБndelt.
ΓòÉΓòÉΓòÉ 14.4.1. SOM-Klassen-Definition ΓòÉΓòÉΓòÉ
Jede unter OS/2 vorhandene SOM-Klasse wird schliesslich als eine binДre Datei
in einer dynamischen Binder-Bibliothek gespeichert. Falls ein Programmierer auf
solch eine Bibliothek zugreifen mФchte, wird er eine sprach-spezifische
Schnittstelle zur Programmierung von Anwendungen, genannt die API (engl. fБr
application programming interface) gebrauchen. Solch eine API besteht aus einer
Klassenbeschreibung, die geeignet ist, um in den Prozess einer Ъbersetzung
eingefБgt zu werden. Zum Beispiel verwendet die C-Sprache zu diesem Zweck
spezielle Kopf-Dateien (engl. header files). Dieser Ъbersetzer fБr Modula-2
gebraucht Definitions-Module, welche die dynamischen Binder-Bibliotheken mit
ihren SOM-Klassen beschreiben. Das Fehlen entsprechender Implementations-Module
verursacht nicht unbedingt eine Fehlermeldung durch diesen Ъbersetzer. Der
Ъbersetzer versucht vielmehr, eine dynamische Binder-Bibliothek oder eine
Import-Bibliothek gleichen Namens zu finden, welche mit einem anderen
SprachБbersetzer erzeugt worden ist. Das Definitions-Modul bezieht sich dann
auf diese Bibliothek. Oder um es in Begriffen von OS/2 SOM auszudrБcken: Das
Definitions-Modul, welches die Objekt-orientierte Beschreibung einer Klasse
enthДlt, stellt die erforderliche Sprach-Bindung fБr Modula-2 dar.
Die Фffentliche Schnittstelle einer SOM-Klasse kann fБr diesen Ъbersetzer in
einem Definitions-Modul fБr Modula-2 ausgedrБckt werden. Das Definitions-Modul
beschreibt die neue Klasse in Begriffen, welche sich an eine
Sprachen-erweiterte Objekt-orientierte Syntax anlehnen. Dabei werden erweiterte
Verbundtypen und Typ-gebundene Prozeduren benutzt. Das folgende Beispiel
demonstriert alle Merkmale der Beschreibung einer Schnittstelle von einer neuen
SOM-Klasse:
(*$DLL soll eine dynamische Binderbibliothek werden *)
(*$XL+ Modula-2 Sprach-Erweiterung : '_' zulДssig fБr Symbole *)
(*$CDECL+ C-artige Prozeduren *)
(*$A Standard-Ausrichtung fБr Verbundfelder *)
DEFINITION MODULE Dog;
(************************************************************************
Щffentliche Schnittstelle fБr eine SOM-Klasse namens 'Dog'.
*************************************************************************)
IMPORT SOM; (* nФtig fБr generelle SOM-Merkmale *)
(************************************************************************
ZusДtzliche IMPORT-, TYPE-, und CONST-Deklarationen zur UnterstБtzung
von 'Dog'
*************************************************************************)
IMPORT ANIMAL; (* Dieses Modul enthДlt die Schnittstelle der Elternklasse *)
IMPORT OS2DEF;
TYPE PSZ = OS2DEF.PSZ;
(*************************************************************************
SOM-Klasse API fБr 'Dog', einschl. Typ-gebundener Prozeduren
**************************************************************************)
(* Diese Typen werden fast immer fБr eine SOM-Klasse gebraucht *)
TYPE PSOMClass = SOM.PSOMClass;
TYPE INTEGER4 = SOM.INTEGER4;
TYPE somMToken = SOM.somMToken;
TYPE somDToken = SOM.somDToken;
TYPE somMethodProc = SOM.somMethodProc;
TYPE PDog = POINTER TO Dog;
TYPE PM_Dog = POINTER TO M_Dog;
(* Haupt- und Unter-Version fБr die neue SOM-Klasse 'Dog' *)
CONST
Dog_MajorVersion = 0;
Dog_MinorVersion = 0;
(* Jede SOM-Klasse hat eine Фffentliche Struktur namens <class>ClassData,
dessen Felder aus Kennungen zur MethodenauflФsung bestehen.
Dieses Beispiel besteht aus 4 Kennungen fБr die 4 Methoden
der SOM-Klasse 'Dog'.
*)
TYPE
DogClassDataStructure = RECORD
classObject : PSOMClass;
setBreed : somMToken;
setColor : somMToken;
getBreed : somMToken;
getColor : somMToken;
END;
VAR
DogClassData : DogClassDataStructure;
(* Klasse 'Dog' wird als eine Erweiterung vom Verbundtyp 'Animal'
ausgedrБckt. Letztere vererbt alle Verbundfelder und Typ-gebundene
Prozeduren. Die Direktive '$SOM+' teilt dem Ъbersetzer mit,
dass der neue Verbundtyp 'Dog' als eine erweiterte SOM-Klasse
und nicht als ein erweiterter Modula-2-Verbund zu behandeln ist.
*)
TYPE
(*$SOM+ *)
Dog = RECORD( ANIMAL.Animal ) END;
(*$SOM- *)
(* Jede SOM-Klasse muss eine Prozedur namens <class>NewClass enthalten *)
PROCEDURE DogNewClass
(
majorVersion : INTEGER4;
minorVersion : INTEGER4
) : PSOMClass;
(* Eine SOM-Klasse mag Typ-gebundene Prozeduren (auch als Methoden bekannt)
enthalten. FБr jede der folgenden Typ-gebundenen Prozeduren
muss in der vorherigen Verbund-Variable namens <class>ClassData
ein entsprechendes Kennungsfeld angegeben worden sein.
*)
PROCEDURE( Self : PDog ) setBreed
(
myBreed : OS2DEF.PSZ
);
PROCEDURE( Self : PDog ) setColor
(
myColor : OS2DEF.PSZ
);
PROCEDURE( Self : PDog ) getBreed() : OS2DEF.PSZ;
PROCEDURE( Self : PDog ) getColor() : OS2DEF.PSZ;
(*************************************************************************
SOM-Klassen-API fБr M_Dog, einschliesslich Typ-gebundene Prozeduren.
Dies ist die Metaklasse.
Die Metaklasse ist optional, und sollte, sofern vorhanden, nur fБr
Fabrizierungs-Methoden wie z.B. Konstruktoren oder Destruktoren
benutzt werden. Die Syntax der Metaklasse ist ansonsten Дhnlich
der einer regulДren Klasse aufgebaut.
**************************************************************************)
CONST
M_Dog_MajorVersion = 0;
M_Dog_MinorVersion = 0;
TYPE
M_DogClassDataStructure = RECORD
classObject : PSOMClass;
newDog : somMToken;
END;
VAR
M_DogClassData : M_DogClassDataStructure;
TYPE
(*$SOM+ *)
M_Dog = RECORD( ANIMAL.M_Animal ) END;
(*$SOM- *)
PROCEDURE M_DogNewClass
(
majorVersion : INTEGER4;
minorVersion : INTEGER4
) : PSOMClass;
PROCEDURE( Self : PM_Dog ) newDog
(
sound : OS2DEF.PSZ;
breed : OS2DEF.PSZ;
color : OS2DEF.PSZ
) : PDog;
END Dog.
ΓòÉΓòÉΓòÉ 14.4.2. SOM-Klassen-Verwendung ΓòÉΓòÉΓòÉ
Ein Anwendungsprogrammierer kann von einer vordefinierten SOM-Klasse vollen
Gebrauch machen. Die Definition einer SOM-Klasse wird fБr ein Programm in
Modula-2 durch eine IMPORT-Anweisung verfБgbar gemacht. Meistens wird das
Programm eine oder mehrere Instanzen von der SOM-Klasse erzeugen. In diesem
Ъbersetzer kann dies einfach durch den Gebrauch der Standard-Prozedur NEW
erreicht werden. Letztere mБndet in einen internen Aufruf der SOM-Prozedur
'somNew'. Nahezu alle Objekt-orientierte Konstrukte dieses Ъbersetzers kФnnen
auch auf Instanzen von SOM-Klassen angewandt werden. Dies schliesst dynamische
Typen-Tests, designierte Typenschutz-Selektoren, regionale Typenschutze, und
Aufrufe Typ-gebundener Prozeduren ein. Das Arbeiten mit Instanzen von
SOM-Klassen ist somit genauso einfach wie mit regulДren erweiterten Verbunden.
Lediglich die Datenfelder einer SOM-Klasse kФnnen nicht direkt angesprochen
werden. Auf sie kann man nur indirekt zugreifen. Dies geschieht in der Regel
nur innerhalb der Typ-gebundenen Prozeduren, d.h. den Фffentlichen Methoden,
einer Implementation. Aus diesem Grund werden in der Definition eines Verbundes
die Feld-Komponenten nie als Verbundfelder angegeben.
Dieser Ъbersetzer wandelt folgende Sprachkonstrukte in entsprechende interne
Aufrufe von SOM-Prozeduren um, sofern sie auf SOM-Klassen angewandt werden:
Dynamische Typen-Tests Der dynamische Typ eines SOM-Objektes kann durch die
IS-Relation getestet werden. Der Ъbersetzer produziert Code zum Aufruf
der SOM-internen Funktions-Prozedur 'somIsA'. Die Methode 'somIsA' wird
von der Grundklasse 'SOMObject' geerbt.
Typenschutz Jeder designierte Typenschutz-Selektor und jeder regionale
Typenschutz wird fБr SOM-Objekte durch diesen Ъbersetzer in einen Aufruf
der SOM-Prozedur 'somIsA' umgewandelt. Sein RБckgabe-Wert vom Typ BOOLEAN
wird zur Laufzeit getestet. Und 'SYSTEM.ExitProgram' wird im Falle einer
Typenschutz-Verletzung zwecks vorzeitiger Programm-Terminierung
aufgerufen.
Aufruf von Typ-gebundenen Prozeduren Der Aufruf einer Prozedur, welche an eine
SOM-Klasse gebunden ist, beinhaltet den internen Aufruf der
Laufzeit-Prozedur 'SYSTEM.somResolve'. Letztere ruft wiederum die
SOM-Prozedur 'somResolve' auf.
Aufruf einer Eltern-Methode Der Aufruf einer Eltern-Methode bewirkt den
direkten Sprung zu einer Prozedur, welche an den Basistyp des
augenblicklichen erweiterten Verbundes gebunden ist. Die Prozedur von
diesem Basis-Verbundtyp trДgt den selben Namen. Dieser Ъbersetzer
Бbersetzt solch einen Aufruf in eine statische Methoden-AuflФsung. Dazu
wird 'SYSTEM.somFindSMethodOk' benutzt. Letztere ruft wiederum die
SOM-Prozedur 'somFindSMethodOk' auf.
Erzeugung eines SOM-Objektes mit NEW Ein Prozedur-Aufruf NEW( p ) wird durch
diesen Ъbersetzer in eine Code-Sequenz, welche u.a. die SOM-Prozedur
'somNew' aufruft, umgewandelt.
LФschen eines SOM-Objektes mit DISPOSE Ein Prozedur-Aufruf DISPOSE( p ) wird
durch diesen Ъbersetzer in eine Code-Sequenz, welche u.a. die
SOM-Prozedur 'somFree' aufruft, umgewandelt.
ΓòÉΓòÉΓòÉ 14.4.3. SOM-Klassen-Implementierung ΓòÉΓòÉΓòÉ
Dieser Ъbersetzer fБr Modula-2 unterstБtzt die Erstellung neuer SOM-Klassen,
welche von bereits existierenden Klassen abzuleiten sind. Die Фffentliche
Schnittstelle der neuen SOM-Klasse muss in einem Definitions-Modul angegeben
werden, wДhrend die Klasse selbst mit all den neuen oder Бberschriebenen
Methoden in einem Implementations-Modul geschrieben werden muss. Die Details
der Implementierung sind fБr andere Klienten-Programme nicht sichtbar. Der
durch Ъbersetzung erzeugte Maschinen-Code von den Methoden der Klasse wird
gewФhnlich in einer dynamischen Binder-Bibliothek gespeichert. Deshalb muss,
falls eine neue SOM-Klasse in Modula-2 implementiert werden soll, das
Definitions-Modul zu Beginn eine in einem Kommentar einzubettende $DLL+ -
Direktive fБr den SprachБbersetzer enthalten.
Die folgenden Sektionen sollen die Implementierung einer SOM-Klasse
illustrieren. Die Implementierung einer neuen SOM-Klasse ist etwas
komplizierter als die Implementierung einer neuen und lediglich erweiterteten
Klasse nur fБr Modula-2 (d.h. nach der Art von OBERON-2). Letztere erfordert
nur die Deklaration von all den Typ-gebundenen Prozeduren, welche als
entsprechende ProzedurkФpfe im Definitions-Modul angegeben wurden. SOM unter
OS/2 benutzt ein komplizierteres Verfahren zur Methoden-AuflФsung, bevor der
Zugriff auf eine Фffentliche Typ-gebundene Prozedur einer SOM-Klasse mФglich
wird. Die letztlich erzeugte dynamische Binder-Bibliothek offeriert eine
Фffentliche Verbund-Variable, die die Felder mit den Kennungen fБr alle
Methoden der SOM-Klasse enthДlt. WДhrend der Laufzeit kann eine solche Kennung
zu dem gewБnschten Zeiger auf die Prozedur umgewandelt werden. Letztere kann
dann als Typ-gebundene Prozedur aufgerufen werden. Das Auffinden einer Methode
auf dieser Art ist auch als Offset-AuflФsung bekannt, weil SOM die Фffentlichen
Kennungen der Methoden aus der dynamischen Binder-Bibliothek als eine Art von
Index auf eine SOM-interne virtuelle Methoden-Tabelle behandelt. Letztere wird
ausserhalb der zu Modula-2 gehФrenden Laufzeitbibliotheken unterhalten. Ausser
der eben genannten Offset-AuflФsung bietet SOM auch die sogenannte
Namens-AuflФsung sowie die AuflФsung durch Abfertigungs-Funktionen an, um den
Zugriff auf eine Methode zu bekommen. Dies ist deshalb notwendig, weil einige
Programmiersprachen nicht fДhig sind, die grundlegende Offset-AuflФsung zu
verwenden. Schliesslich soll SOM ja Sprachen-neutral sein. Aus o.g. GrБnden ist
also die Implementierung einer SOM-Klasse in Modula-2 (und fБr jede andere
Objekt-orientierte Sprache) im Gegensatz zur Implementierung einer Klasse aus
der jeweiligen Sprache etwas komplizierter durchzufБhren, aber nicht unmФglich.
Das Implementations-Modul sollte folgende Komponenten enthalten:
(1) SOM-spezifische, in Kommentare einzubettende,
Ъbersetzer-Direktiven.
(2) GДngige IMPORT-Anweisungen, und individuelle Deklarationen fБr
Konstanten, Typen, und Variablen.
(3) Implementierungs-Kopf mit gДngigen Deklarationen fБr Konstanten,
Typen, und Variablen.
(4) Prozedur-RБmpfe zur Anwendung und Abfertigung (engl. apply and
redispatch stubs) fБr all die neuen Methoden.
(5) FORWARD-Deklarationen von allen privaten (oder privat
Бberschriebenen) Methoden.
(6) Prozeduren fБr die Erzeugung der neuen SOM-Klasse.
(7) Methoden-Prozeduren fБr die neue SOM-Klasse.
(8) Modul-Initialisierung.
Wenn eine explizite Metaklasse existiert, sollte sie im gleichen Modul
implementiert werden, indem man auch fБr sie die in (3) bis (7) genannten
Komponenten angibt. Eine Metaklasse stellt Klassen-Methoden wie zum Beispiel
Instanz-erzeugende Prozeduren oder Konstruktor-Methoden zur VerfБgung. Falls
keine explizite Metaklasse existiert, dann wird diejenige aus der
Eltern-Klasse benutzt.
Die folgenden Sektionen aus dieser Dokumentation beinhalten eine genauere
Beschreibung aller Komponenten fБr die Implementierung. Die Programm-Beispiele
enthalten Platzhalter, welche durch '<' und '>' begrenzt sind, wie etwa
<class> oder <identifier>. Sie mБssen beim Schreiben eines
Implementations-Moduls durch die tatsДchlichen Namens-Symbole ersetzt werden.
Der Platzhalter <class> ist immer durch den aktuellen Namen der neuen
SOM-Klasse zu ersetzen.
═══ 14.4.3.1. SOM-Klassen-Implementierung (Ъbersetzer-Direktiven) ═══
Ein Implementations-Modul fБr eine neue SOM-Klasse sollte immer mit einigen in
Kommentaren eingebetteten Direktiven fБr den Ъbersetzer beginnen, und zwar wie
folgt:
IMPLEMENTATION MODULE <module-identifier>;
(*$XL+ Modula-2 Spracherweiterung: '_' im Symbol, OOP-FДhigkeit *)
(*$CDECL+ C-artige Prozeduren *)
(*$A Standard-Ausrichtung fБr Verbundfelder *)
(*$LINK
LIBRARY <module-identifier>
INITINSTANCE
PROTMODE
DATA
MULTIPLE NONSHARED LOADONCALL
*)
Der $LINK - Schalter teilt dem Ъbersetzer fБr Modula-2 mit, dass die
schliessliche SOM-Klasse eine dynamische Binder-Bibliothek werden soll, die
aber im Gegensatz zu Standard-Konventionen wДhrend der Laufzeit fБr jede
Anwendung ein neues Datensegment erzeugen soll.
ΓòÉΓòÉΓòÉ 14.4.3.2. SOM-Klassen-Implementierung (IMPORTs und Deklarationen) ΓòÉΓòÉΓòÉ
Das Implementations-Modul beginnt mit einer Reihe von gДngigen
IMPORT-Anweisungen, welche immer fБr eine neue SOM-Klasse gebraucht werden. Es
folgen weitere Programmzeilen fБr Modula-2, welche dem fБr die Zielsprache
weiterzureichenden Block vom SOM-Ъbersetzer entsprechen. Sie enthalten weitere
individuelle IMPORTs und Deklarationen fБr Konstanten, Typen, und Variablen.
(*************************************************************************
GДngige IMPORTs fБr die Implementierung einer SOM-Klasse.
**************************************************************************)
IMPORT SOM; (* grundlegendes SOM-Modul, wird immer gebraucht *)
IMPORT <parent-module>; (* Modul mit Eltern-Klasse, wird immer gebraucht *)
IMPORT Conversions; (* Datenkonvertierungen *)
FROM SOMMISC IMPORT somDebug; (* Debugger-UnterstБtzung *)
FROM SOMMISC IMPORT somWriteString; (* Debugger-UnterstБtzung *)
FROM SOMMISC IMPORT somWriteLn; (* Debugger-UnterstБtzung *)
FROM SYSTEM IMPORT currentFile; (* Debugger-UnterstБtzung *)
FROM SYSTEM IMPORT currentLine; (* Debugger-UnterstБtzung *)
FROM SYSTEM IMPORT ADR;
(*************************************************************************
Dies ist Modula's GegenstБck zum sprachneutralen SOM-erzeugten
Zeilenblock, der sonst fБr die Zielsprache vor der SOM-Klasse
weiterzureichen wДre.
Er besteht aus weiteren individuellen IMPORTs fБr die Implementation.
**************************************************************************)
IMPORT ..... ;
(*************************************************************************
Dies ist Modula's GegenstБck zum sprachneutralen SOM-erzeugten
Zeilenblock, der sonst fБr die Zielsprache hinter der SOM-Klasse
weiterzureichen wДre.
Er besteht aus privaten Typen, Konstanten, Variablen,
und/oder Prozeduren fБr die Implementierung der Klasse.
**************************************************************************)
CONST
.....
TYPE
.....
VAR
.....
ΓòÉΓòÉΓòÉ 14.4.3.3. SOM-Klassen-Implementierung (Implementatierungs-Kopf) ΓòÉΓòÉΓòÉ
Der Implementatierungs-Kopf fБr eine neue SOM-Klasse wird gewФhnlich durch den
SOM-Ъbersetzer aus einer Sprachen-neutralen Form der Definition der Klasse
erzeugt. FБr diesen Ъbersetzer fБr Modula-2 muss er jedoch manuell angegeben
werden, weil die augenblicklichen SOM-Versionen noch keine Sprachen-Bindungen
fБr Modula-2 generieren kФnnen. Der grundlegende Aufbau vom
Implementatierungs-Kopf ist immer der gleiche, unabhДngig von der neuen Klasse.
Er kann nur hinsichtlich der Anzahl der Instanz-Felder oder der Anzahl der
Methoden variieren.
(*************************************************************************
Implementatierungs-Kopf fБr die neue SOM-Klasse.
(Konstanten, Typen, und Variablen)
**************************************************************************)
CONST
<class>_MaxNoMethods = <number>; (* Anzahl der neuen Methoden *)
<class>Debug = FALSE; (* an/aus Testanweisungen in Methoden *)
(*
* Deklaration der C-spezifischen Datenstruktur fБr die Klasse;
* Plaziere sie hier oder in das Definitionsmodul.
*)
TYPE
<class>CClassDataStructure = RECORD
parentMtab : SOM.somMethodTabs;
instanceDataToken : SOM.somDToken;
END;
VAR
<class>CClassData : <class>CClassDataStructure;
(*
* TemporДre Datenstruktur fБr die Klasse, wird nur zur
* Erzeugung der Klasse gebraucht
*)
VAR
<class>tempClassData : SOM.somClassDataStructure;
(*
* Interne Datenfelder fБr die Instanz
*)
TYPE
<class>Data = RECORD
<1st field> : <1st type>;
..........................
<nth field> : <nth type>;
END;
P<class>Data = POINTER TO <class>Data;
(*
* Funktion <class>GetData, gibt Zugriff zu den Instanz-Daten, falls da
*)
PROCEDURE <class>GetData( Self : P<class> ) : P<class>Data;
BEGIN
RETURN SOM.somDataResolve( Self, <class>CClassData.instanceDataToken );
END <class>GetData;
(*
* SOM-spezifische Kennungen fБr all
* die neuen und auch den Бberschriebenen Methoden
*)
VAR
somId_<method-1> : SOM.somId;
................................
somId_<method-n> : SOM.somId;
ΓòÉΓòÉΓòÉ 14.4.3.4. SOM-Klassen-Implementierung (Anwendung/Abfertigung) ΓòÉΓòÉΓòÉ
Der Implementierungs-Kopf muss auch fБr jede neue Methode Prozedur-StБmpfe zur
Anwendung und Abfertigung (engl. apply stub and redispatch stub) angeben. Diese
sind zusДtzlich zu den jeweiligen Methoden-Prozeduren erforderlich, weil SOM
mehrere Techniken zur MethodenauflФsung wДhrend der Laufzeit unterstБtzen muss.
Denn ein Anwendungsprogramm mag nicht immer die normale Offset-AuflФsung
beherrschen.
Jede Methode kann eine unbestimmte Anzahl formaler Parameter, welche gewФhnlich
als Doppelworte (DWORD) auf dem Stapelspeicher geschrieben werden, enthalten.
Der Anwendungsstumpf hat zu diesem Zweck einen formalen Parameter, welcher auf
die offene Parameterliste fБr die Methode zeigt. Er wird gewФhnlich als eine
offene Reihung von Doppelworten ausgedrБckt, also ARRAY OF DWORD. Jedes
Doppelwort entspricht einem aktuellen numerischen Wertparameter. FБr Strukturen
und Reihungen werden gewФhnlich nur Referenzen, d.h. deren Adressen,
weitergereicht. Jede Adresse entspricht dann einem DWORD. Ein LONGREAL besteht
aus 2 Doppelworten. Man kann als Wertparameter auch lange Strukturen und
nicht-offene Reihungen fБr die Zielmethode vorsehen. Sie sind jedoch dann nicht
immer ein genaues Vielfaches von Doppelworten. Daher sollten sie die Ausnahme
bilden. Wenn nФtig, kann man fБr den Anwendungsstumpf die Parameter-Liste der
Zielmethode auch als ARRAY OF BYTE ausdrБcken, der zu allen erdenklichen
Parametern beliebiger GrФsse kompatibel ist.
Der Anwendungsstumpf muss aus der offenen Parameterliste die einzelnen
Parameter fБr die aufzurufende Zielmethode extrahieren und weiterreichen.
Danach wird die Zielmethode, welche zum 'Self'-Objekt gehФrt, aufgerufen.
Die Prozedur-StБmpfe zur Anwendung und Abfertigung sind fБr eine Prozedur ohne
RБckgabewert wie folgt zu implementieren:
(*
* Anwendungs-Stunpf fБr eine neue Methoden-Prozedur ohne RБckgabe
*)
PROCEDURE somAP_<method>
(
somSelf : P<class>;
id : SOM.somId;
desc : SOM.somId;
VAR args : ARRAY OF SOM.DWORD
);
VAR
<param-0> : <basic-type>;
....................
<param-n> : <basic-type>;
BEGIN
<param-0> := args[0];
.................
<param-n> := args[n];
somSelf^.<method>( <param-0>, ... <param-n> );
END somAP_<method>;
(*
* Abfertigungs-Stumpf fБr eine neue Methoden-Prozedur ohne RБckgabe
*)
PROCEDURE somRD_<method>
(
somSelf : P<class>;
<param-0> : <basic-type>;
.......................
<param-n> : <basic-type>
);
VAR
retBuffer : SOM.somToken;
retValue : SOM.somToken;
args : SOM.ADDRESS;
dispatched : BOOLEAN;
BEGIN
retValue := ADR( retBuffer );
args := ADR( somSelf ) + SIZE( somSelf );
dispatched := somSelf^.somDispatch( retValue, somId_<method>, args^ );
END somRD_<method>;
Wenn die Methode eine Funktions-Prozedur mit RБckgabewert ist, dann sehen die
Anwendungs- und Abfertigungs-StБmpfe etwas anders aus:
(*
* Anwendungs-Stumpf fБr eine neue Funktions-Methode
*)
PROCEDURE somAP_<method>
(
somSelf : P<class>;
id : SOM.somId;
desc : SOM.somId;
VAR args : ARRAY OF SOM.DWORD
) : <returning-type>;
VAR
<param-0> : <basic-type>;
....................
<param-n> : <basic-type>;
BEGIN
<param-0> := args[0];
.................
<param-n> := args[n];
RETURN somSelf^.<method>( <param-0>, ... <param-n> );
END somAP_<method>;
(*
* Abfertigungs-Stumpf fБr eine neue Funktions-Methode
*)
PROCEDURE somRD_<method>
(
somSelf : P<class>;
<param-0> : <basic-type>;
.......................
<param-n> : <basic-type>
) : <returning-type>;
VAR
retBuffer : <returning-type>;
retValue : SOM.somToken;
args : SOM.ADDRESS;
dispatched : BOOLEAN;
BEGIN
retValue := ADR( retBuffer );
args := ADR( somSelf ) + SIZE( somSelf );
dispatched := somSelf^.somDispatch( retValue, somId_<method>, args^ );
RETURN retBuffer;
END somRD_<method>;
ΓòÉΓòÉΓòÉ 14.4.3.5. SOM-Klassen-Implementierung (FORWARD-Deklarationen) ΓòÉΓòÉΓòÉ
WДhrend der Erzeugung einer Klasse werden einige vorweggenommene statische
Bezugnahmen auf private (oder privat Бberschriebene) Methoden gemacht. FБr
letztere existieren keine KФpfe im Definitions-Modul der neuen SOM-Klasse. FБr
jede dieser Methoden muss deshalb eine vorweggenommene Deklaration geschrieben
werden. Solch eine Deklaration enthДlt nur den Prozedurkopf, gefolgt vom
SchlБsselwort FORWARD.
(*
* Beispiel einer vorweggenommenen Deklaration
* einer echten privaten Methoden-Prozedur
*)
PROCEDURE( Self : P<class> ) <private-method-id>
( <parameters> );
FORWARD;
(*
* Beispiel einer vorweggenommenen Deklaration
* einer privaten Funktions-Methode
*)
PROCEDURE( Self : P<class> ) <private-method-id>
( <parameters> ) : <returning-type>;
FORWARD;
ΓòÉΓòÉΓòÉ 14.4.3.6. SOM-Klassen-Implementierung (Klassen-Erzeugung) ΓòÉΓòÉΓòÉ
Das OS/2-System fБr SOM muss fБr jede Klasse, welche wДhrend der
Informations-Verarbeitung irgendwann ins Dasein kommen mag,
Laufzeitinformationen bereit halten. Eine SOM-Klasse kann sogar Бber Prozesse
hinaus erhalten bleiben. Aber jede SOM-Klasse muss vor ihrem ersten Gebrauch
erst einmal erzeugt werden. Die Instanzen einer SOM-Klasse kФnnen erst nach der
Erzeugung der Klasse selbst erzeugt werden. Die Erzeugung einer Klasse
geschieht durch den Aufruf spezieller SOM-Prozeduren aus den dynamischen
Binder-Bibliotheken. Das grundlegende Aussehen der Prozeduren zur Erzeugung von
Klassen gleicht sich immer. SOM unterhДlt erzeugte Klassen mittels interner
Klassen-Deskriptoren. Solch ein interner Klassen-Deskriptor wird von SOM als
eine Instanz der Metaklasse betrachtet und wird daher Klassen-Objekt genannt.
Ein Zeiger auf letzteren wird nach Beendigung der Klassen-Erzeugung verfБgbar
gemacht.
(*************************************************************************
Erzeugungs-Prozeduren fБr eine SOM-Klasse.
Nur die Prozedur <class>NewClass() ist Фffentlich
verfБgbar fБr Klienten-Programme.
**************************************************************************)
(*
* Klassen-Initialisierung
*)
PROCEDURE <class>somInitializeClass;
VAR
m : <class>; (* nФtig fБr statisch angesprochene Methoden *)
c : SOM.PSOMClass;
md : SOM.somId;
BEGIN
c := <class>tempClassData.classObject;
md := SOM.somIdFromString( "----" );
(* FБge zur neuen SOM-Klasse die neuen Methoden einschliesslich
den Anwendungs- und Abfertigungs- StБmpfen hinzu.
*)
<class>ClassData.<method-1> := c^.somAddStaticMethod
( somId_<method-1>, md, m.<method-1>, somRD_<method-1>, somAP_<method-1> );
......................................................................
<class>ClassData.<method-n> := c^.somAddStaticMethod
( somId_<method-n>, md, m.<method-n>, somRD_<method-n>, somAP_<method-n> );
(* Ъberschreibe eventuell geerbte Methoden *)
c^.somOverrideSMethod( somId_<override-method-1>, m.<override-method-1> );
.....................................................................
c^.somOverrideSMethod( somId_<override-method-n>, m.<override-method-n> );
END <class>somInitializeClass;
(*
* Prozedur zur Erzeugung der Klasse
*)
PROCEDURE <class>somCreateClass
(
pClsObj : SOM.PSOMClass;
mClsObj : SOM.PSOMClass
);
VAR
classObject : SOM.PSOMClass;
BEGIN
classObject := mClsObj^.somNew();
<class>tempClassData.classObject := classObject;
classObject^.somInitClass
(
"<class>",
pClsObj,
SIZE( <class>Data ),
<class>_MaxNoMethods,
<class>_MajorVersion,
<class>_MinorVersion
);
<class>CClassData.instanceDataToken := classObject^.somGetInstanceToken();
<class>somInitializeClass();
<class>CClassData.parentMtab := classObject^.somGetPClsMtab();
classObject^.somSetClassData( SYSTEM.ADR( <class>ClassData ) );
classObject^.somClassReady();
(* mache nun das neu erzeugte Klassen-Objekt sichtbar *)
<class>ClassData.classObject := classObject;
END <class>somCreateClass;
(*
* Фffentliche NewClass-Prozedur
*)
PROCEDURE <class>NewClass
(
majorVersion : SOM.INTEGER4;
minorVersion : SOM.INTEGER4
) : SOM.PSOMClass;
VAR
pClsObj : SOM.PSOMClass;
mClsObj : SOM.PSOMClass;
line : LONGCARD;
b : BOOLEAN;
BEGIN
(* ЪberprБfe die Versions-Nummern *)
IF ((majorVersion <> 0) AND (majorVersion <> <class>_MajorVersion)) OR
((minorVersion <> 0) AND (minorVersion > <class>_MinorVersion)) THEN
somWriteString( "<class>NewClass: Error, bad version numbers." );
somWriteLn();
b := Conversions.StrToLongCard( currentLine(), line );
SOM.SOMError( SOM.SOMERROR_BadVersion, currentFile(), line );
END;
(* Keine weiteren AktivitДten, wenn Klassen-Objekt schon existiert *)
IF <class>ClassData.classObject <> NIL THEN
RETURN <class>ClassData.classObject;
END;
(* Stelle sicher, dass die Umgebung initialisiert ist *)
IF SOM.SOMClassMgrObject = NIL THEN
SOM.SOMClassMgrObject := SOM.somEnvironmentNew();
IF SOM.SOMClassMgrObject = NIL THEN
b := Conversions.StrToLongCard( currentLine(), line );
SOM.SOMError( SOM.SOMERROR_CouldNotStartup, currentFile(), line );
END;
(* SOMClassMgrObject initialisiert... *)
END;
(* Erhalte das Eltern-Klassen-Objekt *)
pClsObj := <parent-module>.<parent-class>NewClass( 0, 0 ); (* static *)
pClsObj := SOM.SOMClassMgrObject^.somFindClass
( SOM.somIdFromString( "<parent-class>" ), 0, 0 );
IF pClsObj = NIL THEN
b := Conversions.StrToLongCard( currentLine(), line );
SOM.SOMError( SOM.SOMERROR_NoParentClass, currentFile(), line );
END;
(* Erhalte das Metaklassen-Objekt *)
(* Falls explizite Metaklasse, erhalte sie von dort ... *)
mClsObj := <metaclass>NewClass( 0, 0 ); (* statisch*)
mClsObj := SOM.SOMClassMgrObject^.somFindClass
( SOM.somIdFromString( "<metaclass>" ), 0, 0 );
(* ... sonst benutze die Metaklasse von der Elternklasse:
mClsObj := pClsObj^.mtab^.classObject;
*)
IF mClsObj = NIL THEN
b := Conversions.StrToLongCard( currentLine(), line );
SOM.SOMError( SOM.SOMERROR_NoMetaClass, currentFile(), line );
END;
SOM.somConstructClass
( <class>somCreateClass, pClsObj, mClsObj, SYSTEM.ADR( <class>tempClassData ) );
RETURN <class>ClassData.classObject;
END <class>NewClass;
ΓòÉΓòÉΓòÉ 14.4.3.7. SOM-Klassen-Implementierung (Methoden-Prozeduren) ΓòÉΓòÉΓòÉ
Der letzte Bestandteil der Implementierung einer neuen SOM-Klasse besteht aus
den Deklarationen fБr all die neuen und Бberschriebenen Methoden. Jede Methode
muss als eine vollstДndige Typ-gebundene Prozedur deklariert werden. Die
folgenden Beispiele zeigen den grundlegenden Aufbau zur Implementierung von
echten Methoden und von Funktions-Methoden:
(*
* Beispiel einer echten Methoden-Prozedur, Typ-gebunden an neue SOM-Klasse
*)
PROCEDURE( Self : P<class> ) <method-id> ( <parameters> );
VAR
somThis : P<class>Data;
BEGIN
somThis := <class>GetData( Self );
IF <class>Debug THEN
somDebug( "<class>", "<method-id>", currentFile(), currentLine() );
END;
.........
END <method-id>;
(*
* Beispiel einer Funktions-Methode, Typ-gebunden an neue SOM-Klasse
*)
PROCEDURE( Self : P<class> ) <method-id> ( <parameters> ) : <return-type>;
VAR
somThis : P<class>Data;
BEGIN
somThis := <class>GetData( Self );
IF <class>Debug THEN
somDebug( "<class>", "<method-id>", currentFile(), currentLine() );
END;
.........
RETURN <expression>;
END <method-id>;
ΓòÉΓòÉΓòÉ 14.4.3.8. SOM-Klassen-Implementierung (Modul-Initialisierung) ΓòÉΓòÉΓòÉ
Eine SOM-Klasse wird gewФhnlich in einem Modul implementiert. Das Modul kann
durch SprachБbersetzung und Linkerlauf in eine dynamische Binderbibliohek
umgewandelt werden. Solch eine Bibliothek muss eine Initialisierungsroutine
enthalten. Sie wird pro Prozess einmal aufgerufen mit je einem
Prozess-bezogenen Datensegment. Diese Routine sieht wie folgt aus:
(*
* Beispiel einer Modul-Initialisierung fБr eine neue SOM-Klasse
*)
BEGIN (* Eintrittspunkt vom Klassen-Modul *)
(* initialisiere SOM's Umgebung, falls letztere noch nicht aktiviert ist *)
IF SOM.SOMClassMgrObject = NIL THEN
SOM.SOMClassMgrObject := SOM.somEnvironmentNew();
END;
(* initialisiere einige Felder aus Klassen-unterstБtzenden Verbunden *)
<class>CClassData.parentMtab := NIL;
<class>ClassData.classObject := NIL;
(* Finde die Identifizierungskennungen fБr alle neue oder Бberschriebene
* Methoden
*)
somId_<method_0> := SOM.somIdFromString( "<method_0>" );
............................................................
somId_<method_n> := SOM.somIdFromString( "<method_n>" );
(* falls eine explizite Metaklasse im gleichen Modul deklariert worden ist,
* dann initialisiere einige Felder fБr Metaklasse-unterstБtzende
* Verbunde
*)
M_<class>CClassData.parentMtab := NIL;
M_<class>ClassData.classObject := NIL;
(* falls eine explizite Metaklasse im gleichen Modul deklariert worden ist,
* dann finde die Identifizierungskennungen fБr alle neue oder
* Бberschriebene Methoden, die zur Metaklasse gehФren.
*)
somId_<method_0> := SOM.somIdFromString( "<method_0>" );
............................................................
somId_<method_n> := SOM.somIdFromString( "<method_n>" );
END <Modul-Identifizierer>.
ΓòÉΓòÉΓòÉ 14.5. Bitweise Operatoren ΓòÉΓòÉΓòÉ
Dieser Ъbersetzer fБr Modula-2 bietet erweiterte bitweise arithmetische
Operatoren an. Sie sind fБr Cardinal- oder Integer- Operanden anwendbar und
werden Bit fБr Bit bearbeitet. Bitweise Operatoren sind nur dann verfБgbar,
wenn entweder der Schalter auf der Kommandozeile oder die entsprechende
Ъbersetzer- Direktive fБr die Spracherweiterungen aktiviert worden ist. Sie
vereinfachen z.B. den Zugriff auf Bitfelder von den Schnittstellen der APIs von
Betriebssystemen wie OS/2 2.x/3.0. Und sie vereinfachen auch die Portierung von
maschinennahen Code, welcher in anderen Programmiersprachen geschrieben worden
ist. Die meisten der bitweisen Operatoren kФnnten auch durch den Gebrauch von
Mengen-Operatoren fБr Variablen mit Mengentypen implementiert werden. Der
Gebrauch von Variablen mit Mengentypen und den dazugehФrigen Mengen-Operatoren
ist immer dann fБr die Implementierung von bitweisen Operationen zu empfehlen,
wenn die MФglichkeit der Portierung des Quellencodes im Vordergrund steht. Die
Benutzung der neuen bitweisen Operatoren sollte auf maschinennahe Module
beschrДnkt bleiben. Die folgende Tabelle gibt eine Ъbersicht Бber die neuen
arithmetischen bitweisen Operatoren:
OR Bitweises Oder
XOR Bitweises exklusives Oder
AND Bitweises Und
& Bitweises Und, wie AND
SHL Bitweises Schiften nach links
SHR Bitweises Schiften nach Rechts
NOT UnДre bitweise Negation
~ UnДre bitweise Negation
ΓòÉΓòÉΓòÉ 14.6. Neue logische Operatoren ΓòÉΓòÉΓòÉ
Modula-2 bietet eine gewisse Menge von logischen Operatoren fБr Bool'sche
AusdrБcke an. Es gibt jedoch keine direkte Implementation fБr das logische
exklusive 'OR'. Ein exklusives 'OR' ergibt nur dann TRUE, wenn entweder der
erste oder zweite Bool'sche Ausdruck TRUE ergibt, aber nicht beide
gleichzeitig. Beispiel:
IF (Contition1 AND NOT Condition2) OR
(NOT Condition1 AND Condition2) THEN
(* execute if either, but not both conditions are met *)
END
Wenn entweder der Schalter auf der Kommandozeile oder die entsprechende
Ъbersetzer- Direktive fБr die Spracherweiterungen aktiviert ist, dann kann das
o.g. Beispiel mit dem neuen Operator 'XOR' wie folgt vereinfacht werden:
IF Condition1 XOR Condition2 THEN
(* execute if either, but not both conditions are met *)
END
ΓòÉΓòÉΓòÉ 14.7. Typisierte Konstanten ΓòÉΓòÉΓòÉ
ΓûÉ ConstDecl = ConstDef | ConstVarDecl "=" TypedConst
ΓûÉ ConstVarDecl = Ident ":" FormalType
ΓûÉ TypedConst = ConstExpr | PointerConst | ArrayConst | RecordConst
ΓûÉ PointerConst = POINTER TO Qualident |
ΓûÉ PROCEDURE Qualident |
ΓûÉ "^" Qualident
ΓûÉ RecordConst = "(" FieldConstList ")"
ΓûÉ FieldConstList = FieldConst { ";" FieldConst }
ΓûÉ FieldConst = [ FieldId ":" TypedConst ]
ΓûÉ FieldId = Ident
ΓûÉ ArrayConst = "[" TypedConstList "]"
ΓûÉ TypedConstList = TypedConst { "," TypedConst }
Die ursprБngliche Sprachdefinition von Modula-2 bietet keine MФglichkeit zur
Darstellung von initialisierten Variablen an. Deshalb ist man auf Module mit
Anweisungsfolgen zur Zuweisung von Startwerten an Variablen angewiesen. Obwohl
Module automatisch zu Programmbeginn ausgefБhrt werden, sind sie in gewisser
Hinsicht wegen der Zuweisungen verschwenderisch.
Dieser Ъbersetzer bietet daher einen weiteren Weg an, um Variablen
initialisieren zu kФnnen. Wenn entweder der Schalter auf der Kommandozeile oder
die entsprechende Ъbersetzer- Direktive fБr die Spracherweiterungen aktiviert
worden ist, dann kФnnen Variablen gleich mit Startwerten deklariert werden,
ohne explizite Zuweisungen zu benutzen. Derart initialisierte Variablen nennt
man typisierte Konstanten. Typisierte Konstanten sind nicht auf elementare
Typen beschrДnkt. Sie kФnnen auch fБr strukturierte Typen wie zum Beispiel
Reihungen oder Verbunde benutzt werden. Typisierte Konstanten werden wie
Deklarationen von normalen Variablen eingefБhrt. Sie enthalten jedoch
zusДtzliche Angaben Бber ihre Startwerte. Das Binder-Programm plaziert alle
typisierten Konstanten in ein spezielles initialisiertes Segment, welches auch
intern erzeugte Zeichenketten und andere Konstanten aufnimmt. Wenn die
Datensegmente durch das Betriebssystem zur spДteren ProgrammausfБhrung in den
Arbeitsspeicher geladen werden, dann werden auch alle initialen Werte mit ihnen
geladen. Typisierte Konstanten sind insbesondere fБr lange initialisierte
Tabellen von Nutzen. Konstante Variable-Deklarationen mit typisierten
Konstanten sind nur innerhalb einer 'CONST' -Sektion zulДssig. Der konstante
Wert muss mit dem Typ der entsprechenden konstanten Variable-Deklaration
Zuweisungs- kompatibel sein.
Eine typisierte Konstante fБr einen Reihungstyp besteht aus einer Liste von
typisierten Konstanten fБr die Elemente der Reihung. Die Elemente dieser Liste
werden durch Kommas voneinander getrennt. Und die Liste selbst muss in eckige
Klammern eingeschlossen sein. Falls die Anzahl der typisierten Konstanten aus
der Liste kleiner ist als die Anzahl der deklarierten Elemente der Reihung,
dann werden die Бbrigen Elemente automatisch mit binДren Nullen initialisiert.
Wenn die deklarierte Variable eine Zeichenreihung als Typ hat, kann auch eine
Zeichenkette als entsprechende typisierte Konstante angegeben werden.
Eine typisierte Konstante fБr einen Verbundtyp besteht aus einer Liste von
Feldkonstanten. Die Feldkonstanten werden durch Semikolons ';' voneinander
getrennt. Jede Feldkonstante wird durch den Feldnamen eingefБhrt, und muss
durch einen Doppelpunkt ':' und der typisierten Konstante gefolgt werden. Die
Liste der Feldkonstanten selbst muss durch die runde Klammerung '(' und ')'
eingeschlossen sein. Die Reihenfolge der Feldkonstanten muss die gleiche sein
wie die in dem entsprechenden Verbundtyp. Jedes Feld ohne entsprechende
Feldkonstante wird mit binДren Nullen initialisiert (es sei denn, sie ist durch
Case-Varianten mit dort angegebenen Feldkonstanten Бberlagert).
Eine Zeigerkonstante (pointer constant) kann fБr Datenzeiger oder fБr Prozedur-
Variablen angegeben werden. Sie werden endgБltig durch den Binder korrigiert,
weil sie die Adressen von Variablen oder Prozeduren reprДsentieren sollen. Ein
Datenzeiger wird durch die Folge 'POINTER TO' eingefБhrt, wДhrend vor einer
Prozedur-Konstante das SchlБsselwort 'PROCEDURE' stehen muss. Es kann auch eine
alternative Kurzform zur Darstellung fБr Zeigerkonstanten benutzt werden, indem
man nur das zeichen '^' voranstellt. In diesem Fall konsultiert der Ъbersetzer
den Typ der deklarierten Variablen, um die korrekte Wahl zwischen Daten- und
Prozedur-Zeiger vornehmen zu kФnnen. Die Zeigerkonstante wird immer durch einen
(mФglicherweise qualifizierten) Namen fБr die Variable oder Prozedur, deren
Adresse als Konstante dienen soll, abgeschlossen.
Beispiele:
TYPE
ArrayType = ARRAY [0..10] OF CHAR;
RecType = RECORD
Str : ArrayType;
Len : INTEGER;
Handler : PROC;
Next : POINTER TO RecType;
END;
...
PROCEDURE MyProc();
BEGIN
...
END MyProc;
...
VAR
YourRecVar : RecType;
...
CONST
MyRecVar : RecType =
(
Str : "MyString";
Len : 8;
Handler : ^MyProc;
Next : ^YourRecVar;
);
...
Die konstante Variable-Deklaration darf auch eine eindimensionale offene
Reihung als ihren Typ angeben. In diesem Fall wird die Anzahl der Elemente
durch die Anzahl der typisierten Konstanten festgelegt. Beispiel:
CONST
(* zero terminated initialized text string variables *)
Msg1 : ARRAY OF CHAR = "This is message 1";
Msg2 : ARRAY OF CHAR = "This is another text string";
(* initialized integer array variable with 6 elements *)
Token : ARRAY OF INTEGER = [ 1, 2, 3, 4, 5, 6 ];
ΓòÉΓòÉΓòÉ 14.8. Multidimensionale offene Reihungsparameter ΓòÉΓòÉΓòÉ
ΓûÉ FormalType = { ARRAY OF } Qualident
Der Standardsprachumfang von Modula-2 bietet offene Reihungen fБr formale
Parameter in Prozedur-Deklarationen oder in Prozedur-Typen an. In diesem
Ъbersetzer sind auch multidimensionale offene Reihungen erlaubt, wenn entweder
der Schalter auf der Kommandozeile oder die entsprechende Ъbersetzer- Direktive
fБr die Spracherweiterungen aktiviert ist. Der entsprechende aktuelle Parameter
muss eine Zuweisungs-kompatible Reihung sein mit der gleichen Anzahl von
Dimensionen. Die Obergrenzen (HIGHs) aller Dimensionen werden automatisch vor
den eigentlichen aktuellen Parametern auf den Stapelspeicher abgelegt. Jede
DimensionsgrФsse kann durch AusdrБcke wie HIGH(x) oder SYSTEM.LEN(x) ermittelt
werden. Beispiel:
PROCEDURE MyProc( x : ARRAY OF ARRAY OF ARRAY OF INTEGER );
VAR
High0 : LONGCARD;
High1 : LONGCARD;
High2 : LONGCARD;
Len0 : LONGCARD;
Len1 : LONGCARD;
Len2 : LONGCARD;
BEGIN
High0 := HIGH( x ); (* HIGH outer dimension *)
High1 := HIGH( x[0] ); (* HIGH middle dimension *)
High2 := HIGH( x[0][0] ); (* HIGH inner dimension *)
Len0 := SYSTEM.LEN( x, 0 ); (* outer dimension length *)
Len1 := SYSTEM.LEN( x, 1 ); (* middle dimension length *)
Len2 := SYSTEM.LEN( x, 2 ); (* inner dimension length *)
...
END MyProc;
...
ΓòÉΓòÉΓòÉ 14.9. Segmentierung ΓòÉΓòÉΓòÉ
Wie schon vorher in der Dokumentation in der Sektion Бber Speicher-Modelle
erklДrt, bietet die Intel 80x86 CPU-Familie nur einen segmentierten
Speicherzugriff an. In den 16-Bit- Speicher-Modellen bedeutet es, dass ein
Zeiger nur einen Bereich von 64 KB adressieren kann. Um auf verschiedene
Segmente zuzugreifen, benutzt man man 16 Bits grosse Selektoren. Das
Betriebssystem fБhrt spezielle Deskriptoren fБr die Segmente. Dort werden
Informationen Бber SegmentgrФssen und ihren linearen Startadressen gespeichert.
Es sind daher zwei verschiedene Arten von Zeigertypen verfБgbar. Ein NEAR
Zeiger enthДlt den Offset relativ zum Beginn des Segments. Als dazugehФriger
Segment-Selektor wird fБr Daten der Wert aus dem Segment-Register DS und fБr
Code der Wert aus dem Segment-Register CS angenommen. Ein FAR Zeiger enthДlt
zusДtzlich zum Offset immer einen expliziten Segment-Selektor.
Segment-Selektoren sind 16 Bits grosse Indizes auf entsprechende
Segment-Deskriptoren.
In AbhДngigkeit vom gewДhlten Speicher-Modell ist fБr eine Ъbersetzung der
Zeiger standardmДssig eine FAR oder NEAR Einheit. Wenn aber entweder der
Schalter auf der Kommandozeile oder die entsprechende Ъbersetzer- Direktive fБr
die Spracherweiterungen aktiviert ist, dann kФnnen die SchlБsselworte 'FAR'
oder 'NEAR' benutzt werden, um die Zeigerart zu modifizieren. Diese neuen
SchlБsselworte sind in folgenden ZusammenhДngen verfБgbar:
ΓûÉ ProcedureHeading = [ NEAR | FAR ] PROCEDURE
ΓûÉ [ Receiver ] Ident [ FormalParameters ]
ΓûÉ Receiver = "(" [ [ NEAR | FAR ] VAR ] Ident : Ident ")"
ΓûÉ FormalParameters = "(" FPSectionList ")" [ ":" Qualident ]
ΓûÉ FPSectionList = [ FPSection { ";" FPSection } ]
ΓûÉ FPSection = [ [ NEAR | FAR ] VAR ] IdentList ":" FormalType
ΓûÉ PointerType = [ NEAR | FAR ] POINTER TO Type
ΓûÉ ProcedureType = [ NEAR | FAR ] PROCEDURE [ FormalTypeList ]
ΓûÉ FormalTypeList = "(" FTSectionList ")" [ ":" Qualident ]
ΓûÉ FTSectionList = [ FTSection { "," FTSection } ]
ΓûÉ FTSection = [ [ NEAR | FAR ] VAR ] FormalType
Eine Prozedur oder ein Prozedur-Typ kann als FAR oder NEAR deklariert werden.
Eine FAR Prozedur wird segmentiert aufgerufen und beendet. Dazu erzeugt der
Code-Generator segmentierte Instruktionen fБr Calls oder Returns. Eine NEAR
Prozedur wird von Code, der im gleichen Segment steht, aufgerufen und
unsegmentiert beendigt. Der Code-Generator produziert fБr die Call- und
Return-Instruktionen nur Offset-Werte fБr die Code-Adressen.
Ein Zeigertyp kann auch als FAR oder NEAR deklariert werden, indem er die
Standard-Attribute Бberschreibt. Das Standard-Attribut ist NEAR fБr die
Speicher-Modelle Tiny, Small, Compact, oder Flat32, sonst wird FAR angenommen.
Ein FAR Zeiger besteht aus den Angaben
16-Bit Segment : 16-oder-32-Bit Offset,
wДhrend ein NEAR Zeiger nur aus dem
16-oder-32-Bit Offset
besteht.
Ein formaler VAR-Parameter darf durch eines der beiden SchlБsselworte 'FAR'
oder 'NEAR' eingeleitet werden. Dadurch werden die Standard-Attribute
Бberschrieben. Als Standard-Attribut wird fБr die Speicher-Modelle Compact oder
Large FAR angenommen, sonst NEAR. Ein FAR VAR-Parameter zeigt auf eine
Variable, die durch Referenz Б bergeben worden ist, und die in einem anderen
Datensegment stehen kann. Ein NEAR VAR-Parameter, der ebenfalls durch Referenz
Бbergeben wird, zeigt immer auf eine Variable, die im Standard-Datensegment
steht.
ΓòÉΓòÉΓòÉ 14.10. Erweiterte Importe ΓòÉΓòÉΓòÉ
ΓûÉ Import = FROM Ident IMPORT IdentList ";" |
ΓûÉ IMPORT [ FROM ] Ident { "," [ FROM ] Ident }
Standard-Modula bietet keine MФglichkeit, aus einem anderen Definitionsmodul
alle Namen unqualifiziert zu importieren, es sei denn, man spezifiziert alle
gewБnschten Namen in einer expliziten Liste. Beispiel:
FROM WINFRAME IMPORT
WinCreateStdWindow,
WinFlashWindow,
:
BEGIN
(* unqualifizierte Bezugnahme auf importiertes WinCreateStdWindow *)
WinCreateStdWindow( ... );
(* qualifizierte Bezugnahme ebenso mФglich *)
WINFRAME.WinCreateStdWindow( ... );
END ...;
Wenn man es mit einer grossen Anzahl von Objekten zu tun hat, die alle
unqualifiziert importiert werden sollen, muss man in mБhsamer Kleinarbeit alle
Namen in langen Importlisten angeben. Dies ist oftmals der Fall, wenn man fБr
den OS/2 Presentation Manager oder der Workplace Shell Programme schreibt. Aus
diesem Grund bietet dieser SprachБbersetzer eine besondere Erweiterung fБr die
Import-Anweisung, nДmlich den unqualifizierten Import eines ganzen
Definitionsmoduls. Diese Erweiterung veranlasst den SprachБbersetzer, wДhrend
der Einlesephase nicht nur im aktuellen Modul nach Namen zu suchen, sondern
auch im importierten Definitionsmodul. Der Sichtbarkeitsbereich erstreckt sich
somit auch auf alle unqualifiziert importierten Definitionsmodule. Selbst wenn
zwei unqualifiziert importierte Module ein Objekt gleichen Namens exportieren,
wird das erste vom zweiten Бberschattet. Um das o.g. Beispiel wieder
aufzugreifen, diesmal mit der neuen Import-Konstruktion:
IMPORT FROM WINFRAME;
:
BEGIN
(* unqualifizierte Bezugnahme auf importiertes WinCreateStdWindow *)
WinCreateStdWindow( ... );
(* qualifizierte Bezugnahme ebenfalls immer noch mФglich *)
WINFRAME.WinCreateStdWindow( ... );
END ...;
ΓòÉΓòÉΓòÉ 15. Sprachgrammatik ΓòÉΓòÉΓòÉ
Die Sprachen fБr Modula-2 und fБr den INLINE-Assemblierer werden nach einer
bestimmten Menge von Grammatikregeln geformt. Zur Beschreibung der Syntax wird
eine erweiterte Notation nach Backus-Naur benutzt.
Die Modula-2-Grammatik unterstБtzt nicht nur Wirth's Standard-Syntax, sondern
auch einige mДchtige Spracherweiterungen.
Die INLINE-Assemblierer-Grammatik ist mit dem Ziel einer einfachen Benutzung
entworfen worden. Einige der reservierten Worte wie z.B. die Namen von
32-Bit-Registern sind nur fБr 32-Bit-Programme verfБgbar.
ΓòÉΓòÉΓòÉ 15.1. Modula-2-Grammatik ΓòÉΓòÉΓòÉ
CompilationUnit = DefModule | [ IMPLEMENTATION ] ProgramModule
ProgramModule = MODULE Ident Priority ";" { Import } Block Ident "."
Priority = [ "[" ConstExpr "]" ]
Import = FROM Ident IMPORT IdentList ";" |
IMPORT [ FROM ] Ident { "," [ FROM ] Ident }
IdentList = Ident { "," Ident }
DefModule = DEFINITION MODULE Ident ";" { Import } { Def } END Ident "."
Def = CONST { ConstDef ";" } | TYPE { TypeDef ";" } |
VAR { VarDecl ";" } | ProcedureHeading ";"
ConstDef = Ident "=" ConstExpr
TypeDef = TypeDecl | Ident
ProcedureHeading = [ NEAR | FAR ] PROCEDURE
[ Receiver ] Ident [ FormalParameters ]
Receiver = "(" [ [ NEAR | FAR ] VAR ] Ident : Ident ")"
FormalParameters = "(" FPSectionList ")" [ ":" Qualident ]
FPSectionList = [ FPSection { ";" FPSection } ]
FPSection = [ [ NEAR | FAR ] VAR ] IdentList ":" FormalType
FormalType = { ARRAY OF } Qualident
Qualident = { Qualifier "." } Ident
Qualifier = Ident
Block = { Decl } [ BEGIN StmtSeq ] END
Decl = CONST { ConstDecl ";" } | TYPE { TypeDecl ";" } |
VAR { VarDecl ";" } | ProcedureDecl | ModuleDecl
ConstDecl = ConstDef | ConstVarDecl "=" TypedConst
ConstVarDecl = Ident ":" FormalType
TypeDecl = Ident = Type
VarDecl = VarIdent { "," VarIdent } ":" Type
VarIdent = Ident [ FarPointerConst ]
FarPointerConst = "[" ConstExpr ":" ConstExpr "]"
ProcedureDecl = ProcedureHeading ";" Block Ident |
ProcedureHeading ";" FORWARD
ModuleDecl = MODULE Ident [ Priority ] { Import } [ Export ]
Block Ident
Export = EXPORT [ QUALIFIED ] IdentList ";"
TypedConst = ConstExpr | PointerConst | ArrayConst | RecordConst
PointerConst = POINTER TO Qualident |
PROCEDURE Qualident |
"^" Qualident
RecordConst = "(" FieldConstList ")"
FieldConstList = FieldConst { ";" FieldConst }
FieldConst = [ FieldId ":" TypedConst ]
FieldId = Ident
ArrayConst = "[" TypedConstList "]"
TypedConstList = TypedConst { "," TypedConst }
Type = SimpleType | ArrayType | RecordType | SetType |
PointerType | ProcedureType
SimpleType = Qualident | Enumeration | SubrangeType
Enumeration = "(" IdentList ")"
SubrangeType = [ BaseType ] "[" ConstExpr ".." ConstExpr "]"
BaseType = Qualident
ArrayType = ARRAY IndexType { "," IndexType } OF Type
IndexType = SimpleType
RecordType = RECORD [ "(" RecordBase ")" ] FieldListSeq END
RecordBase = Qualident
FieldListSeq = FieldList { ";" FieldList }
FieldList = [ IdentList ":" Type | Variants ]
Variants = CASE [ Ident ":" ] Qualident
OF VariantList ElseVariant END
VariantList = Variant { "|" Variant }
ElseVariant = ELSE FieldListSeq
Variant = CaseLabelList ":" FieldListSeq
SetType = SET OF SimpleType
PointerType = [ NEAR | FAR ] POINTER TO Type
ProcedureType = [ NEAR | FAR ] PROCEDURE [ FormalTypeList ]
FormalTypeList = "(" FTSectionList ")" [ ":" Qualident ]
FTSectionList = [ FTSection { "," FTSection } ]
FTSection = [ [ NEAR | FAR ] VAR ] FormalType
StmtSeq = Stmt { ";" Stmt }
Stmt = [ Assignment | ProcedureCall | IfStmt | CaseStmt |
WhileStmt | RepeatStmt | LoopStmt | ForStmt |
WithStmt | EXIT | ReturnStmt ]
Assignment = Designator ":=" Expr
ProcedureCall = Designator [ ActualParams ]
ActualParams = "(" [ Expr { "," Expr } ] ")"
IfStmt = IF BoolExpr THEN StmtSeq
{ ELSIF BoolExpr THEN StmtSeq }
[ ELSE StmtSeq ] END
BoolExpr = Expr
CaseStmt = CASE Expr OF Case { "|" Case } [ ELSE StmtSeq ] END
Case = CaseLabelList ":" StmtSeq
CaseLabelList = CaseLabels { "," CaseLabels }
CaseLabels = ConstExpr [ ".." ConstExpr ]
WhileStmt = WHILE BoolExpr DO StmtSeq END
RepeatStmt = REPEAT StmtSeq UNTIL BoolExpr
LoopStmt = LOOP StmtSeq END
ForStmt = FOR ControlVar ":=" Expr TO Expr [ BY ConstExpr ]
DO StmtSeq END
ControlVar = Ident
WithStmt = WITH RecDesignator DO StmtSeq END
RecDesignator = Designator | Guard
Guard = Qualident ":" Qualident
ReturnStmt = RETURN [ Expr ]
ConstExpr = Expr
Expr = SimpleExpr [ Relation SimpleExpr ]
SimpleExpr = [ "+" | "-" ] Term { AddOperator Term }
Term = Factor { MulOperator Factor }
Factor = CharConst | Number | String | Set |
Designator [ ActualParams ] | "(" Expr ")" |
Not Factor
Set = Qualident "{" [ ElemList ] "}"
ElemList = Elem { "," Elem }
Elem = Expr { ".." Elem }
Relation = "=" | "<>" | "#" | "<" | "<=" | ">" | ">=" | IN | IS
AddOperator = "+" | "-" | OR | XOR
MulOperator = "*" | "/" | DIV | MOD | AND | "&" | SHL | SHR
Not = NOT | "~"
Designator = Qualident { Selector }
Selector = "." Ident | "[" IndexList "]" | "^" | TypeGuard
IndexList = Expr { "," Expr }
TypeGuard = "(" Qualident ")"
CharConst = "'" Character "'" | Digit { HexDigit } "X" |
OctalDigit { OctalDigit } "C"
String = "'" { Character } "'" | """ { Character } """
Number = Integer | Real
Integer = Digit { Digit } | OctalDigit { OctalDigit } "B" |
Digit { HexDigit } "H"
Real = Digit { Digit } "." { Digit } [ ScaleFactor ]
ScaleFactor = "E" [ "+" | "-" ] Digit { Digit }
HexDigit = Digit | "A" | "B" | "C" | "D" | "E" | "F"
Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
OctalDigit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7"
Ident = FirstLetter { "_" | Letter | Digit }
FirstLetter = "_" | Letter
ΓòÉΓòÉΓòÉ 15.2. INLINE-Assemblierer-Grammatik ΓòÉΓòÉΓòÉ
Jeder Name aus den Eingabedaten einer Quelldatei wird einem der Symbole
'Ident', 'ConstId', 'Qualifier' oder 'Keyword' zugeordnet. Von einem strengen
lexikalischen Standpunkt aus betrachtet scheinen sie keine
Unterscheidungsmerkmale zu haben. Die lexikalische PrБfung in diesem
INLINE-Assemblierer ist jedoch dahingehend erweitert worden, dass durch
zusДtztliche semantische (kontext-sensitive) PrБfungen festgestellt werden
kann, zu welchen der o.g. Symbole ein Name gehФren soll. Die lexikalischen
Regeln fБr Zahlen und Zeichenkonstanten sind mit denen von Modula-2 identisch.
Inline = "(" InlineList ")"
InlineList = CodeList { InstrList }
InstrList = CSEG eol CodeList | DSEG eol DataList |
SSEG eol DataList | ISEG eol InitList
CodeList = Code { eol Code }
Code = CodeInstr | CondCode
DataList = Data { eol Data }
Data = DataInstr | CondData
InitList = Init
Init = InitInstr | CondInit
CondCode = IF CondExpr [ THEN | eol ] CodeList [ ELSE CodeList ] ENDIF
CondData = IF CondExpr [ THEN | eol ] DataList [ ELSE DataList ] ENDIF
CondInit = IF CondExpr [ THEN | eol ] InitList [ ELSE InitList ] ENDIF
CondExpr = ImmedExpr
CodeInstr = [ Label ] [ CodeStmt ]
CodeStmt = InstrId [ Operand [ Operand [ Operand ] ] ] |
CodeDirective CodeConstLst
Label = AnyId ":"
InstrId = [ RepPrefix ] AnyId | AND | OR | XOR | NOT | DIV | SHL | SHR
RepPrefix = REP | REPE | REPZ | REPNE | REPNZ
AnyId = Ident | ConstId
Operand = UserReg | SegReg | MemDesignator | ImmedExpr | SegExpr |
OfsExpr | FloatStack | ControlReg | DebugReg | TestReg
UserReg = AX | BX | CX | DX | SI | DI | BP | SP |
AL | AH | BL | BH | CL | CH | DL | DH | Reg32
Reg32 = EAX | EBX | ECX | EDX | ESI | EDI | EBP | ESP
SegReg = CS | DS | ES | SS | FS | GS
FloatStack = ST [ "(" ImmedExpr ")" ]
ControlReg = CR0 | CR2 | CR3
DebugReg = DR0 | DR1 | DR2 | DR3 | DR6 | DR7
TestReg = TR6 | TR7
MemDesignator = [ Attr ] Mem
Mem = MemId [ DispExpr | "[" IndexExpr "]" ] | "[" MemExpr "]"
DispExpr = Unary DispTerm { Unary DispTerm }
DispTerm = ImmedTerm
IndexExpr = IndexStart { Unary DispTerm | RegTerm }
IndexStart = [ "-" ] DispTerm | RegTerm
RegTerm = BX | BP | SI | DI | reg32 [ "*" ScaleFactor ]
ScaleFactor = ImmedFactor
MemExpr = MemStart { Unary DispTerm | "+" RegTerm }
MemStart = [ "-" ] DispTerm | RegTerm | MemId
MemId = Designator
Attr = FAR | NEAR | SHORT |
SegReg ":" | SizeAttr | SizeAttr SegReg ":"
SizeAttr = SizeId [ PTR ] | LOW | HIGH
SizeId = BYTE | WORD | DWORD | FWORD | QWORD | TBYTE
SegExpr = SEG MemId
OfsExpr = OFFSET MemId
Designator = Qualident { "." MemberId }
Qualident = { QualifierList "." } UserId
QualifiedConst = { QualifierList "." } ConstId
QualifierList = Qualifier { "." Qualifier }
UserId = Ident | Keyword
MemberId = AnyId | Keyword
CodeDirective = DataDirective
CodeConstLst = CodeConst { "," CodeConst }
CodeConst = ImmedExpr | SegExpr | OfsExpr | FarPointerConst |
Designator | DupSize DUP "(" CodeConstLst ")"
FarPointerConst = "[" ImmedExpr ":" ImmedExpr "]"
DataInstr = [ DataName DataDirective DataAttrLst ]
DataName = [ AnyId ]
DataDirective = DB | DW | DD | DF | DQ | DT
DataAttrLst = DataAttr { ",' DataAttr }
DataAttr = "?" | DupSize DUP "(" DataAttrLst ")"
DupSize = ImmedExpr
InitInstr = [ InitName InitDecl ]
InitName = [ AnyId ]
InitDecl = CodeDirective CodeConstLst
ImmedExpr = SimpleImmedExpr { Relation SimpleImmedExpr }
SimpleImmedExpr = [ Unary ] ImmedTerm { AddOperator ImmedTerm }
ImmedTerm = ImmedFactor { MulOperator ImmedFactor }
ImmedFactor = QualifiedConst | Number | String | CharConst |
"(" ImmedExpr ")" | NOT ImmedFactor |
TYPE VarId | SIZE VarId | LENGTH VarId
VarId = Designator
AddOperator = "+" | "-" | OR | XOR
MulOperator = "*" | "/" | DIV | MOD | "&" | AND | SHL | SHR
Unary = "+" | "-"