205 10 14MB
German Pages 219 [224] Year 1976
de Gruyter Lehrbuch van der Meulen Kühling Programmieren in ALGOL68 II
Sietse G. van der Meulen Peter Kiihling
Programmieren in ALGOL68 II. Sprachdefinition, Transput und spezielle Anwendungen
w DE
G
Walter de Gruyter Berlin New York 1977
Sietse G. van der Meulen, Dozent und wiss. Mitarbeiter am Fachbereich Informatik der Universität Utrecht/Nederland, Mitglied der IFIP-Working Group on ALGOL (W.G. 2.1) Peter
Kühling,
Wiss. Assistent der Informatik-Forschungsgruppe Softwaretechnik an der Technischen Universität Berlin Mit zahlreichen Abbildungen im Text
CIP-Kurztitelaufnahme der Deutschen Bibliothek Meulen, Sietse G. van der Programmieren in ALGOL68 [achtundsechzig]/Sietse G. van der Meulen; Peter Kühling. - Berlin, New York: de Gruyter. NE: Kühling, Peter: 2. Sprachdefinition, Transput und spezielle Anwendungen. - 1. Aufl. - 1977. (De-Gruyter-Lehrbuch) ISBN 3 11 004978 3
© Copyright 1976 by Walter de Gruyter & Co., vormals G. J. Göschen'sche Verlagshandlung, J. Guttentag, Verlagsbuchhandlung, Georg Reimer, Karl J. Trübner, Veit & Comp., 1000 Berlin 30. Alle Rechte, insbesondere das Recht der Vervielfältigung und Verbreitung sowie der Übersetzung, vorbehalten. Kein Teil des Werkes darf in irgendeiner Form (durch Photokopie, Mikrofilm oder ein anderes Verfahren) ohne schriftliche Genehmigung des Verlages reproduziert oder unter Verwendung elektronischer Systeme verarbeitet, vervielfältigt oder verbreitet werden. Printed in Germany. Satz: IBM-Composer, Walter de Gruyter, Berlin. Druck: Karl Gerike, Berlin. Bindearbeiten: Dieter Mikolai, Berlin.
Vorwort
Der vorliegende zweite Band ist eine Weiterführung des ersten. Während der erste Band das Interesse an ALGOL68 wecken und gleichzeitig zum Verständnis der Algorithmik beitragen sollte, will der zweite Band die erworbenen Kenntnisse über ALGOL68 vertiefen bzw. erweitern. Dies geschieht in drei Teilen: In Teil III wird die zur Definition von ALGOL68 benutzte Zweistufen-Grammatik erläutert; es wird beschrieben, wie ALGOL68 im Revised Report [2] definiert wurde. Hierdurch soll der Leser in die Lage versetzt werden, anhand des Revised Report die letzten Details von ALGOL68 sich selbst anzueignen. In Teil IV wird der Transput (Ein-Ausgabe) vom Standpunkt des Benutzers aus eingehend behandelt. Auf das beim Transput verwendete Modell der Programmumgebung wird besonderer Wert gelegt. In Teil V werden zwei library-preludes zur Beschreibung und Manipulation von Vektoren und Matrizen sowie von Bildern angegeben. Dadurch soll insbesondere demonstriert werden, wie man die 'Standard'-Sprache ALGOL68 in eine, der speziellen Anwendung entsprechende Fachsprache überführen kann. Der angegebene Index bezieht sich nicht nur auf diesen zweiten, sondern auch auf den ersten Band. Im Anhang findet man ein Syntax-Diagramm, das wir mit freundlicher Genehmigung der Autoren aus dem ALGOL-Bulletin, Nr. 37 übernommen haben. Unser besonderer Dank gilt Herrn W. Griffioen, der die angegebene libraryprelude GRAPHIC auf der Rechenanlage des Rechenzentrums der Universität Utrecht implementierte. Er formulierte auch das Anwendungsbeispiel und ließ es mit Hilfe eines Plotters zeichnen. Für die wertvolle Unterstützung bei der Beschreibung des Transput sind wir Herrn K. Kleine sehr dankbar, ebenso Herrn W. Koch für seine kritischen Bemerkungen und Verbesserungsvorschläge. Dem Verlag danken wir erneut für seine Geduld sowie die gute und unkomplizierte Zusammenarbeit. Berlin, im September 1976
S. G. van der Meulen P. Kühling
Inhalt
Teil III
Sprachdefinition
6. Van Wijngaarden-Grammatiken 6.1 Phrasenstruktur-Grammatiken (Chomsky-Hierarchie) 6.1.1 Typ-3-Grammatik ('finite state grammar') 6.1.2 Typ-2-Grammatik ('context-free grammar') 6.1.3 Typ-l-Grammatik ('context-sensitive grammar') 6.1.4 Typ-O-Grammatik ('phrasestructure grammar') 6.2 Van Wijngaarden-Grammatiken 1. und 2. Stufe 6.2.1 1VWG 6.2.2 2VWG 6.3 Der Gebrauch von "predicates" 6.3.1 Ein einfaches Beispiel 6.3.2 Identifizierung
13 14 16 17 18 19 20 20 22 29 29 31
7. Formale Definition von ALGOL68 7.1 Die Syntax der "strict language" 7.2 Die Semantik von ALGOL68 7.3 Die "representation language" 7.4 Das "standard environment" 7.4.1 Die standard-prelude 7.4.2 Die library-prelude 7.4.3 Die system-prelude 7.4.4 Die particular-prelude 7.4.5 Die particular-postlude
39 39 41 42 43 44 45 45 45 46
8. Die ALGOL68-Maschine 8.1 Objekte 8.1.1 Werte 8.1.2 "Modes" 8.1.3 "Locales" und "environs" 8.2 "Scope" 8.2.1 "scope"-Regel bei einer assignation 8.2.2 Der "scope" eines Wertes 8.2.3 Beispiele 8.3 Aktionen
47 47 47 47 49 53 53 54 55 59
Teil IV
Programm und Umgebung
9. Die Umgebung 9.1 Die Außenwelt eines Programms 9.1.1 Die peripheren Geräte
63 63 63
8
Inhalt 9.1.2 Steuerungsprogramme 9.1.3 Das Betriebssystem 9.2 Die Synchronisierung von Prozessen 9.2.1 "Serial", "collateral", "parallel" 9.2.2 Der Begriff "semaphore" 9.2.3 sema, level, up und down 9.2.4 Beispiele 9.3 Die Strukturierung der Umgebung 9.3.1 Der "mode" book 9.3.2 Der "mode" channel 9.3.3 Der "mode" füe 9.3.4 Die Transput-"modes" 9.4 Die Verwaltung der Umgebung 9.4.1 Verwaltungsroutinen 9.4.2 Informationsroutinen 9.4.3 Layoutroutinen 9.4.4 Ereignisroutinen 9.4.5 Die Standard-"files"
10. Ein-Ausgabe (Transput) 10.1 Unformatierter Transput 10.1.1 Format-Texte und Standard-Formate 10.1.2 Konvertierungsroutinen 10.1.3 Unformatierte Ausgabe 10.1.4 Unformatierte Eingabe 10.2 Formatierter Transput 10.2.1 "Füe" und Format 10.2.2 Formatierte Ein-Ausgabe 10.2.3 Der "mode" format 10.2.4 Beispiel eines format-text 10.2.5 Der äußere Aufbau des format-text 10.2.6 Type-pattern 10.3 Binärer Transput
Teil V
63 64 65 65 66 67 69 73 73 74 76 78 82 82 84 87 89 91 92 93 93 94 97 101 106 106 106 110 113 126 131 142
Spezielle Anwendungen
1 1 . Library-preludes
147
12. TORRIX (vekTOR-matRIX) 12.1 Darstellung von Vektoren und Matrizen 12.2 Die Verknüpfung von Vektoren und Matrizen
149 150 154
12.3 TORRIX-"modes", Konstanten und Grund-Routinen 12.4 Verschiedene Arten von Wert-Transport 12.5 Verschiedene Arten von Vektor-Matrix-Beschreibung
156 162 172
12.6 Die TORRIX-Routinen 12.6.1 Hilfsroutinen 12.6.2 Additionen und Subtraktionen 12.6.3 Multiplikationen 12.7 Anwendungsbeispiel
176 176 178 181 185
Inhalt 13. GRAPHIC 13.1 Darstellung von Bildern: die GRAPHIC-"modes" 13.2 Grund-Operationen 13.3 Operationen auf Bildern 13.3.1 Transformationen 13.3.2 Vereinigung 13.3.3 Zuweisung 13.4 Arithmetische Operationen auf Punkten 13.5 Anwendungsbeispiel Literaturhinweise Index Anhang
9 189 190 194 195 195 197 200 202 202 207 211 221
Teil III Sprachdefìnitìon
6. Van Wflngaarden-Grammatiken
Seit der Definition der Syntax von ALGOL6O durch eine kontextfreie Grammatik (Backus-Normal-Form:BNF, [27]) sind sehr viele Programmiersprachen mit Hilfe von kontextfreien Grammatiken definiert worden. Zum einen wegen der Einfachheit der grammatikalischen Regeln, zum anderen wegen der relativ einfachen Syntaxanalyse von kontextfreien Sprachen. Dabei müssen jedoch Kontextabhängigkeiten zusätzlich zu den kontextfreien Regeln verbal in natürlicher Sprache (z.B. Englisch) formuliert werden. Wir werden in den folgenden Paragraphen eine Art von Grammatik kennenlernen, die einfach zu handhaben ist und außerdem gestattet, Kontextabhängigkeiten zu behandeln. Eine solche nach ihrem Erfinder benannte Van Wijngaarden-Grammatik ist eine Zweistufen-Grammatik: sie besteht aus zwei übereinandergelagerten Systemen von kontextfreien Regeln. Wegen der grundsätzlichen Bedeutung für die Erzeugung von Sprachen wollen wir uns jedoch zunächst mit den Phrasenstruktur-Grammatiken beschäftigen. Darüber hinaus ist dies für das Verständnis der Van Wijngaarden-Grammatiken von Nutzen, auch werden wir dadurch deren Mächtigkeit besser einschätzen können.
14
6. Van Wijngaaiden-Grammatiken
6.1 Phrasenstruktur-Grammatiken (Chomsky-Hierarchie) Zur Erzeugung von Sprachen führte N. Chomsky [14] sogenannte Phrasenstruktur-Grammatiken ein. Gleichzeitig gab er eine Klassifikation dieser Phrasenstruktur-Grammatiken an: abhängig von der Gestalt der grammatikalischen Regeln definierte er vier Typen und nannte sie Typ-{0,1,2,3}Grammatiken. Jede Phrasenstruktur-Grammatik besteht aus vier Teilen: 1) Einer endlichen Zeichenmenge V x , aus deren Elementen sich die Sätze der Sprache zusammensetzen. Diese Elemente heißen terminale Elemente. 2) Einer endlichen Menge V N , bestehend aus den grammatikalischen Begriffen ('notions'): den nicht-terminalen Elementen. Die nicht-terminalen Elemente werden dabei unterschieden von den terminalen Elementen; die Vereinigung bildet das Gesamt-Vokabular V . Also: V N n V T = 0 und V = V N U V T . 3) Einer endlichen Menge P von Produktions-Regeln, die angeben, wie nicht-terminale und terminale Elemente miteinander kombiniert und nichtterminale Elemente ersetzt werden müssen, um die Sprache zu erzeugen. 4) Einem ausgezeichneten nicht-terminalen Element S , dem Startzeichen. In formaler Schreibweise wird gewöhnlich eine Phrasenstruktur-Grammatik durch das Quadrupel G= ( V N , V T , P, S) gegeben. Mit Hilfe der Produktions-Regeln werden die Sätze der Sprache erzeugt. Eine Produktions-Regel besteht dabei aus einer linken und einer rechten Seite, getrennt durch einen Pfeil . Im allgemeinen sind sowohl linke als auch rechte Seite Folgen von nicht-terminalen und terminalen Elementen. Durch wird der Übergang von linker zu rechter Seite angedeutet, der bei der Erzeugung von Sätzen der Sprache vorgenommen wird. Man lese daher wie: 'geht über in'. Die Erzeugung von Sätzen geschieht auf folgende Weise: Zunächst wähle man eine Produktions-Regel, deren linke Seite aus dem Startzeichen S allein besteht. Man ersetze sodann S durch die rechte Seite dieser Produktions-Regel. Innerhalb dieser Folge ersetze man Teilfolgen (bestehend aus mindestens einem nicht-terminalen Element) durch rechte Seiten von solchen Produktions-Regeln, deren linke Sejten mit diesen Teilfolgen übereinstimmen. Dieser Ersetzungsprozeß wird so lange vorgenommen, bis man eine Folge erhält, die nur noch aus terminalen Elementen besteht. Solch eine Folge heißt dann ein Satz der Sprache. Die Menge aller (nur aus terminalen Elementen bestehenden) Sätze, die sich aus dem Startzeichen durch Anwendung von Produktions-Regeln ableiten lassen, ist die von der Phrasenstruktur-Grammatik erzeugte Sprache.
15
6.1 Phrasenstruktur-Grammatiken (Chomsky-Hierarchie)
Man beachte, daß die einzelnen Sätze der Sprache unabhängig voneinander erzeugt werden. Sie nehmen insbesondere keinen Bezug aufeinander, im Gegensatz zu vielen Sätzen in natürlichen Sprachen. Wir wollen die Erzeugung einer Sprache durch eine vorgegebene Phrasenstruktur-Grammatik anhand zweier Beispiele aufzeigen. Beispiel 1: Phrasenstruktur-Grammatik zur Erzeugung von Zügen VN = { < Z u g > , < L o k > , < W a g g o n » Vt
= { / £ • ,
S
=
P
= {
}
W
^ < L o k > | < Z u g > ,
->
,
->•
}
Wenn ein nicht-terminales Element durch mehrere Alternativen ersetzt werden kann, so wollen wir dies in einer Produktions-Regel durch Trennung der Alternativen mit Hilfe des Zeichens T ausdrücken. Es kann gelesen werden wie : 'oder'. Züge, d.h. Sätze der durch die angegebene Phrasenstruktur-Grammatik erzeugten Sprache sind z.B.
O
o
o o
O O
U O
UV
O V
D Cr
O U
t7 tj
U O TJ o
Nicht aber oder
¿ Ö
oder
^ K ^ H ^ *
Beispiel 2: Phrasenstruktur-Grammatik zur Erzeugung von einfachen arithmetischen Ausdrücken, frei nach dem ALGC)L60-Revised Report [27] V N = { , < t e r m > , , < f a c t o r > , , < p r i m a r y > , , , < l e t t e r > , < d i g i t » VT = { a , b , • c , • • • , x , y , z , 0 , 1 , 2 , • • • , 9 , 1 " , • , / , + , —
6. Van Wijngaarden-Grammatiken
16
S
P
{
| < t e r m > |
< t e r m > ,
| < t e r m > , |
t , |
(),
,
| < l e t t e r > | < d i g i t > ,
a | b | c | ••• | x | y | z ,
0 | 1 | 2 | ••• | 9
* I / I *
+ I -
1
Wie leicht ersichtlich, sind z.B. die folgenden arithmetischen Ausdrücke Sätze der durch die angegebene Phrasenstruktur-Grammatik erzeugten Sprache: varl t var2 + var3 * var4 a + b * ( u - v t ( p - q ) ) t (e + f )
6.1.1 Typ-3-Grammatik ('finite state grammar') Alle Produktions-Regeln einer Typ-3-Grammatik müssen eine der beiden folgenden Formen haben: a) Ein einzelnes nicht-terminales Element geht über in ein einzelnes terminales Element, also: N ->• t
mit N e
vN ,
te
vx
6.1 Phiasenstruktur-Grammatiken (Chomsky-Hieraichie)
17
b) Ein einzelnes nicht-terminales Element geht über in eine Folge, bestehend aus einem einzelnen nicht-terminalen Element, gefolgt von einem einzelnen terminalen Element, also: N
Mt
mit N , M e V N , t e V T
Die von einer Typ-3-Grammatik erzeugte Sprache wird auch regulär genannt. Beispiel 1: Die Menge {an | n > 1} ist eine reguläre Sprache (a n bedeutet die n-malige Aneinanderreihung von a). Sie wird z.B. von folgender Typ-3-Grammatik erzeugt: G
= (v N , V T , P , S) mit
V N = {S} V T = {a} P
= {S -> S a , S
a}
Beispiel 2: Die Menge {a n b m | n , m > 1} ist eine reguläre Sprache. Sie wird z. B. von folgender Typ-3-Grammatik erzeugt: G
= (V N , V T , P , S) mit
V N = {S , A} V T = {a , b} P
= {S ->• Sb , S -»• Ab , A ->• Aa , A ->• a}
Auch die in Beispiel 1 in 6.1 angegebene Menge von Zügen kann man mit einer Typ-3-Grammatik erzeugen.
6.1.2 Typ-2-Grammatik ('context-free grammar') Alle Produktions-Regeln einer Typ-2-Grammatik müssen von folgender Gestalt sein: Ein einzelnes nicht-terminales Element geht über in eine Folge, bestehend aus nicht-terminalen und terminalen Elementen, also: N->-y
mit N E V N , y £ V +
(V=VNUVT)
V* ist hierbei die Menge aller endlichen Folgen von Elementen aus V, die nicht leer sind. Eine Typ-2-Grammatik wird auch kontextfrei genannt, ebenso die von ihr erzeugte Sprache.
6. Van Wijngaaiden-Grammatiken
18
Beispiel: Die Menge {an b" | n > 1} ist eine kontextfreie Sprache. Sie wird z.B. von folgender kontextfreien Grammatik erzeugt: G
= (V N , V T , P , S) mit
V N = {S}
vx
= {a , b}
P
={S->-aSb,S->ab}
Es ist bemerkenswert, daß es keine Typ-3-Grammatik gibt, die die Sprache { a n b n | n > 1} erzeugt. Die in Beispiel 2 in 6.1 angegebene Grammatik zur Erzeugung einfacher arithmetischer Ausdrücke ist kontextfrei.
6.1.3 Typ-1-Grammatik ('context-sensitive grammar') Alle Produktions-Regeln einer Typ-1-Grammatik müssen die folgende Gestalt haben: Vi A y 2 ^ y , y y i
mit A 6 V N ; y x , y 2 £ V * , y e V '
(V= V N U V T )
y steht wieder für eine Folge, bestehend aus nicht-terminalen und terminalen Elementen, die jedoch nicht leer sein darf. Dagegen dürfen die Folgen y l , y 2 auch leer sein. Eine Typ-1-Grammatik wird auch kontextabhängig genannt, da A nur im Kontext von y t und y 2 in y übergeht. Man beachte, daß jede kontextfreie Grammatik ein Spezialfall einer kontextabhängigen Grammatik ist, denn y j , y 2 dürfen beide leer sein. Kontextabhängig heißt auch die Sprache, die von einer kontextabhängigen Grammatik erzeugt wird. Beispiel: Die Menge {an b" c n | n > 1} ist eine kontextabhängige Sprache. Sie wird z.B. von folgender kontextabhängigen Grammatik erzeugt: G
= (V N , V T , P , S) mit
V N = {S , B , C , D} V T = {a , b , c}
6.1 Phrasenstruktur-Grammatiken (Chomsky-Hierarchie)
P
={
19
S ->• a S B D , S
abD ,
D B -> C B , CB
CD,
C D -> B D , bB
bb ,
D
c }
An dieser Grammatik sieht man deutlich, daß durch die Produktions-Regeln, deren linke Seiten aus mehr als einem Element bestehen, ein nicht-terminales Element stets abhängig von einem bestimmten Kontext ersetzt wird. Auch hier ist es bemerkenswert, daß es keine kontextfreie Grammatik gibt, die die Sprache {an b n c" | n > 1} erzeugt. 6.1.4 Typ-O-Grammatik ('phrasestructure grammar') Die Produktions-Regeln einer Typ-O-Grammatik können jede beliebige Gestalt annehmen, mit der einzigen Bedingung, daß die linke Seite einer ProduktionsRegel mindestens ein nicht-terminales Element enthält. Es gibt Typ-O-Sprachen, die von keiner kontextabhängigen Grammatik erzeugt werden können. Diese sind recht kompliziert, Beispiele hierfür findet man z.B. in [15]. Andererseits gibt es Sprachen, die von keiner Typ-O-Grammatik, d.h. von überhaupt keiner Phrasenstruktur-Grammatik erzeugt werden können. Diese Bemerkung sowie die aufgeführte Klassifikation der PhrasenstrukturGrammatiken führen zu folgender Hierarchie innerhalb der Menge aller Sprachen: Sei
L
die Menge aller Sprachen,
L 0 die Menge aller Typ-O-Sprachen (aufzählbaren Mengen), die Menge aller Typ-1-Sprachen (kontextabhängigen Sprachen), L2 die Menge aller Typ-2-Sprachen (kontextfreien Sprachen), L 3 die Menge aller Typ-3-Sprachen (regulären Sprachen), dann gilt: L 3 C L , C L, C L 0 C L , *
*
*
#
wobei (man denke an die angegebenen Beispiele) jeweils die echte Inklusion gilt.
20
6. Van Wijngaarden-Grammatiken
6.2 Van Wijngaarden-Grammatiken 1. und 2. Stufe Bei der Entwicklung seiner Zweistufen-Grammatik gab A . van Wijngaarden eine Form für kontextfreie Grammatiken an, die sich nur in der Schreibweise von der BNF unterscheidet, jedoch etwas leichter zu lesen ist. Diese Schreibweise einer kontextfreien Grammatik wird auch Van Wijngaarden-Grammatik 1. Stufe ( 1 V W G ) genannt. Da durch die eigentliche Van Wijngaarden-Grammatik zwei Systeme kontextfreier Regeln miteinander kombiniert werden, wird sie auch Van WijngaardenGrammatik 2. Stufe genannt ( 2 V W G ) .
6.2.1
1VWG
Bei der Definition der Phrasenstruktur-Grammatiken wurden nicht-terminale und terminale Elemente jeweils durch ein einziges Zeichen dargestellt. Dadurch wird zwar Platz gespart, man hat jedoch kaum die Möglichkeit, die syntaktischen Begriffe ihrer Bedeutung nach entsprechend zu benennen; dazu benötigt man mehr als nur ein Zeichen. In der BNF-Notation hat man deshalb auch die nicht-terminalen Elemente durch entsprechende Wörter dargestellt. Um sie jedoch voneinander und von den terminalen Elementen zu unterscheiden, hat man sie in spitze Klammern eingeschlossen. In einer 1VWG werden sowohl die nicht-terminalen als auch die terminalen Elemente durch Wörter über ein und demselben Alphabet dargestellt. Z. B. kann dies das Alphabet der Klein-Buchstaben sein. Dabei werden die terminalen Elemente stets durch Wörter dargestellt, die auf die Folge 'symbol' enden. Linke und rechte Seite einer Produktions-Regel werden durch einen Doppelpunkt ' : ' (statt '->') voneinander getrennt. U m auf der rechten Seite einer Produktions-Regel die einzelnen nicht-terminalen bzw. terminalen Elemente voneinander zu unterscheiden, werden diese durch Kommata
getrennt.
Mehrere rechte Seiten für ein und dasselbe nicht-terminale Element können in einer Produktions-Regel zusammengefaßt werden; sie werden dann jeweils durch ein Semikolon ';' (statt 'I') getrennt. Jede Produktions-Regel wird durch einen Punkt
abgeschlossen.
Unabhängig von der Grammatik existiert für die terminalen Elemente eine Repräsentation, die je nach Bedarf und zur Verfügung stehendem Zeichenvorrat verschieden sein kann. Beispiele: a) Die im Beispiel 1 in 6.1 angegebene Menge von Zügen kann durch die folgende 1VWG erzeugt werden:
6.2 Van Wijngaarden-Grammatiken 1. und 2. Stufe
zug
: lok ; zug , waggon .
lok
: loksymbol .
21
waggon : waggonsymbol . Repräsentation: loksymbol waggonsymbol :
»
b) Wir geben die Syntax eines assignment statement frei nach dem ALGOL60Revised Report [27] durch eine 1VWG an: left part
variable , becomes symbol.
left part list
left p a r t ; left part list, left p a r t .
assignment statement : left part list, arithmetic expression ; left part list, boolean expression . Eine Repräsentation für das becomes symbol ist z.B. '."='. Nach dieser Syntax besteht also ein assignment Statement aus einer left part Iist, gefolgt von einem arithmetischen oder booleschen Ausdruck, unabhängig von welchem Typ die Variablen in der left part list sind. Ist z.B. v eine integer-Variable, so ist nach dieser Syntax v • = true ein assignment Statement. Daß v •'= true doch kein korrektes ALGOLöO-assignment Statement ist, liegt daran, daß im ALGOLöO-Revised Report unter der Überschrift 'semantics' für dieses assignment Statement u.a. folgende Einschränkung gemacht wird: Ist der Typ der Variablen in der left part list (der übrigens für alle auftretenden Variablen derselbe ist) boolean , muß die rechte Seite ein boolescher Ausdruck, ist der Typ der Variablen real oder integer , muß die rechte Seite ein arithmetischer Ausdruck sein. Diese Einschränkung kann durchaus als Teil der Syntax angesehen werden, und es wäre daher wünschenswert, sie auch formal durch Regeln erfassen zu können, anstatt verbal wie im ALGOLöO-Revised Report. Wie wir diese Kontextabhängigkeit in Regeln formulieren können, werden wir im nächsten Paragraphen sehen.
22
6. Van Wijngaarden-Grammatiken
6.2.2 2VWG Eine 2VWG ist eine Zweistufen-Grammatik: Sie besteht aus zwei Systemen von kontextfreien Regeln, die man sich in zwei Stufen übereinander gelegt denken kann. Mit Hilfe der kontextfreien Regeln der oberen Stufe werden die kontextfreien Regeln der unteren Stufe erzeugt. Genauer: Die kontextfreie Grammatik der oberen Stufe erzeugt Zeichenketten, die auf einer Zwischenstufe in ein Muster von Regeln eingesetzt werden. Durch dieses Einsetzen werden kontextfreie Regeln der unteren Stufe erzeugt, mit deren Hilfe die Sätze der Sprache erzeugt werden. Bevor wir uns mit der 2VWG eingehender beschäftigen, geben wir ein Beispiel an, das (hoffentlich) für sich selbst spricht. Wenn nicht, betrachte man es später noch einmal. Beispiel: Obere Stufe: TYP
: d a m p f ; diesel ; elektro .
Zwischenstufe: T Y P zug
: T Y P lok ; T Y P zug , w a g g o n .
T Y P lok
: T Y P lok Symbol .
waggon
: waggon s y m b o l .
Untere Stufe: dampfzug
: dampflok ; dampfzug , waggon .
dieselzug
: diesellok ; dieselzug , w a g g o n .
elektrozug : elektrolok ; elektrozug , w a g g o n . dampflok
: dampflok symbol .
diesellok
: diesellok s y m b o l .
elektrolok
: elektrolok s y m b o l .
waggon
: waggon symbol .
Repräsentation: waggon symbol dampflok symbol diesellok s y m b o l elektrolok s y m b o l
:
6.2 Van Wijngaaiden-Grammatiken 1. und 2. Stufe
23
Um verständlich und genau über die beiden Stufen einer 2VWG zu sprechen, müssen wir uns leider mit etwas Terminologie vertraut machen. Wir tun dies anhand einer 2VWG, die die kontextabhängige Sprache {an bn cn I n > 1} erzeugt (vgl. 6.1.3). Die kontextfreien Regeln der oberen Stufe heißen "metaproductions". Dabei werden nicht-terminale Elemente als Wörter über dem Alphabet der GroßBuchstaben, terminale Elemente dagegen als Wörter über dem Alphabet der Klein-Buchstaben dargestellt. Die Unterscheidung zwischen nicht-terminalen und terminalen Elementen geschieht also mit Hilfe von zwei verschiedenen Alphabeten. Nicht-terminale Elemente heißen "metanotions". Die Form der "metaproductions" ist ähnlich der einer 1VWG: Linke und rechte Seite werden durch einen Doppel-Doppelpunkt ': :' voneinander getrennt. Auf der rechten Seite einer "metaproduction" werden die einzelnen nicht-terminalen bzw. terminalen Elemente voneinander durch Zwischenräume getrennt. Mehrere rechte Seiten für ein "metanotion" können in einer "metaproduction" zusammengefaßt werden; sie werden jeweils durch ein Semikolon ';' getrennt. Jede "metaproduction" wird durch einen Punkt '.' abgeschlossen. "Metaproductions" sind z.B. (Ml) (M2)
AXBXC : : a ; b ; c . NUMB : : i ; NUMB i .
Durch die "metaproductions" kann man verschiedene Meta-Sprachen erzeugen, je nachdem, welches "metanotion" man als Startelement auswählt. Die Sätze dieser Meta-Sprachen setzen sich aus Wörtern zusammen, die ihrerseits aus Klein-Buchstaben bestehen. Die Sätze selbst sind demnach auch Folgen von Klein-Buchstaben. Folgen von Klein-Buchstaben werden auch als "protonotions" bezeichnet. Die kontextfreien Regeln der unteren Stufe sind die Regeln, mit denen die Sätze der Sprache erzeugt werden. Diese Regeln haben die Form der einer 1VWG. Z.B. Start : iiia , ¡üb , i ü c . iii a : letter a s y m b o l ,
ü a.
j a : letter a s y m b o l .
Die nicht-terminalen und terminalen Elemente, insbesondere also auch das Startelement, werden dabei durch Wörter über dem Alphabet der Klein-Buchstaben dargestellt, wobei die terminalen Elemente stets auf die Folge 'symbol' enden.
24
6. Van Wijngaaiden-Grammatiken
Für die terminalen Elemente existiert wieder eine entsprechende Repräsentation. Die beiden Stufen einer 2VWG sind verbunden durch eine grammatikalische Konstruktion, bestehend aus "hyperrules". "Hyperrules" sind Pseudo-Regeln, in ihnen treten "protonotions" und "metanotions" gemischt auf. Z.B. (Hl)
Start : NUMB a , N U M B b , NUMBc.
(H2)
i NUMB AXBXC : letter AXBXC symbol, NUMB AXBXC .
(H3)
i AXBXC : letter AXBXC symbol.
"Hyperrules" dienen nicht zur Erzeugung von Sätzen der Sprache, sondern werden dazu benutzt, die kontextfreien Regeln der unteren Stufe zu erzeugen. Dies geschieht durch konsistente (einheitliche) Ersetzung der in den "hyperrules" auftretenden "metanotions" durch die aus ihnen mit Hilfe der "metaproductions" (Regeln der oberen Stufe) ableitbaren "protonotions". Dies bedeutet, daß ein "metanotion" auf der linken und rechten Seite einer "hyperrule" bei jedem Auftreten durch das gleiche "protonotion" ersetzt wird. Gerade diese konsistente Ersetzung gestattet es, kontextabhängige Sprachen zu erzeugen. Unsere 2VWG, gegeben durch die "metaproductions" : (Ml)
AXBXC : : a ; b ; c .
(M2)
NUMB
: : i ; NUMB i .
und die "hyperrules": (Hl) (H2)
Start : NUMB a , N U M B b , NUMBc. ¡NUMB AXBXC : letter AXBXC symbol , NUMB AXBXC .
(H3)
i AXBXC : letter AXBXC symbol .
arbeitet dann in folgender Weise: Mit Hilfe der "metaproduction" (Ml) sind aus dem "metanotion" AXBXC nur a oder b oder c ableitbar. Aus NUMB sind durch (M2) Folgen von i 's der Länge > 1 ableitbar. Durch konsistente Ersetzung des "metanotion" NUMB in der "hyperrule" (Hl) erhalten wir die folgenden Regeln der unteren Stufe:
6.2 Van Wijngaaiden-Grammatiken 1. und 2. Stufe
25
Start : ia , ib , ic . start : i i a , ü b ,
iic.
Start : i ü a , ¡ ü b , iiic .
usw. Man beachte, daß hierbei beliebig viele kontextfreie Regeln erzeugt werden können. Andererseits kann eine Regel, wie z.B. Start : i a , i i b ,
iiic.
hierbei nicht entstehen; denn dann wäre NUMB nicht konsistent durch die gleiche Folge von i's ersetzt worden: in (Hl) wäre das erste NUMB durch i , das zweite NUMB durch ü und das dritte NUMB durch iii ersetzt worden. Durch konsistente Ersetzung in (H2) und (H3) von NUMB durch Folgen von i 's sowie von AXBXC durch a oder b oder c werden weitere Regeln der unteren Stufe erzeugt, z.B. i iii a : letter a s y m b o l , ia
iii a .
: letter a s y m b o i .
Durch diese Regeln werden genau so viele letter a symbol bzw. letter b symbol bzw. letter c symbol erzeugt, wie jeweils i 's vorhanden sind. Als Repräsentation haben wir dabei letter a s y m b o l
: a
letter b s y m b o l : b letter c s y m b o l
: c
Insgesamt wird durch unsere 2VWG mit start als Startelement die Menge {anbncn | > 1 } erzeugt. Wie wir wissen, ist diese Menge eine kontextabhängige Sprache, die von keiner kontextfreien Grammatik erzeugt werden kann (vgl. 6.1.3). Demnach sind also die 2VWG's mächtiger als die kontextfreien Grammatiken; denn sie erzeugen zumindest eine Sprache mehr. Es ist sogar in [16] gezeigt worden, daß die 2VWG's den Typ-O-Grammatiken, d.h. den allgemeinen Phrasenstruktur-Grammatiken äquivalent sind.
26
6. Van Wijngaarden-Grammatiken
Beispiele: a) Wir geben die Syntax eines ALGOLöO-assignment statement mit Hilfe von "metaproductions" und "hyperrules" an. Dabei werden wir sehen, wie die im zweiten Beispiel von 6.2.1 verbal formulierte Kontextabhängigkeit durch die "hyperrules" wiedergegeben wird. "metaproductions": TYPE
: : ARITHMETIC;
ARITHMETIC
: : real ; integral .
MIXED
boolean.
: ARITHMETIC .
"hyperrules": T Y P E left part
T Y P E variable , becomes symbol .
T Y P E left part list
T Y P E left part ; T Y P E left part list, T Y P E left part.
assignment statement
A R I T H M E T I C left part list, M I X E D expression; boolean left part list, boolean expression.
Hiernach besteht ein assignment Statement aus einer left part list (in der alle auftretenden Variablen desselben Typs sind), gefolgt von einem arithmetischen oder booleschen Ausdruckte nach T y p der Variablen in der left part list. Also genau so, wie es im ALGOLöO-Revised Report verbal formuliert ist. Man beachte, daß sowohl A R I T H M E T I C als auch MIXED jeweils real oder integral erzeugen, jedoch unabhängig voneinander. Dies hat zur Folge, daß in einem assignment Statement z.B. die Variablen auf der linken Seite vom T y p real sein können, der arithmetische Ausdruck auf der rechten Seite jedoch einen Wert vom T y p integral liefern kann. Hätten wir dagegen die "metaproduction" für M I X E D nicht eingeführt und würde in der "hyperrule" für das assignment Statement statt MIXED das "metanot i o n " A R I T H M E T I C stehen, so müßte stets der T y p der linken Seite mit dem T y p der rechten Seite übereinstimmen. b ) Im Report sind in R l . 3 . 3 "hyperrules" angegeben, die der Verkürzung der Syntax von A L G O L 6 8 dienen und deren Lesbarkeit erhöhen sollen. Wir geben diese "hyperrules" zusammen mit den zugehörigen "metaproductions" aus Rl.2.1, R l . 3 . 1 und R l . 3 . 3 hier an. Wir werden auf diese Regeln insbesondere in 10.2.5 bei der Angabe der Syntax eines format-text durch eine 2VWG zurückkommen.
6.2 Van Wijngaarden-Grammatiken 1. und 2. Stufe
27
' 'met aproductions' ' (Ml) (M2) (M3) (M4) (M5)
STYLE TALLY NOTION NOTETY THING
(M6)
ALPHA
(M7)
EMPTY
: : : : :
brief ; bold ; style T A L L Y . i ; T A L L Y i. A L P H A ; NOTION ALPHA . NOTION ; EMPTY . NOTION ; (NOTETY1) NOTETY2 ; THING (NOTETY1) NOTETY2 . : : a; b ;c ;d ; e;f ;g;h;i ;j ;k ;I ; m r;s;t;u;v;w;x;y;z.
"hyperrules": (Hl)
NOTION option
NOTION; EMPTY.
(H2)
NOTION sequence : NOTION ; NOTION , NOTION sequence .
(H3)
NOTION list
(H4)
N O T E T Y S T Y L E pack : S T Y L E begin symbol, N O T E T Y , S T Y L E end symbol.
(H5)
NOTION S T Y L E bracket : S T Y L E sub symbol, NOTION , S T Y L E bus symbol .
(H6)
THING1 or alternatively THING2 : THING1 ; THING2 .
: NOTION ; NOTION , and also symbol, NOTION list.
Als Repräsentation finden wir in R9.4.1.f:
brief begin symbol brief end symbol bold begin symbol bold end symbol brief sub symbol brief bus symbol style i sub symbol style i bus symbol and also symbol
: : : : : : : : :
( J begin end [ ] ( ) ,
Im Report werden tokens und symbols voneinander unterschieden: ein token ist ein symbol , dem wahlweise ein Kommentar vorangehen kann. Durch tokens wird also festgelegt, wo im Programmtext ein Kommentar möglich ist (vgl. R9.1).
6. Van Wijngaarden-Grammatiken
28
Wir haben bei der Übernahme der "hyperrules" aus dem Report die vorkommenden tokens durch ihre symbols ersetzt. Die in der "metaproduction" (M5) auftretenden Klammern werden nur dazu benutzt, die eindeutige Anwendung dieser "metaproduction" zu gewährleisten. Die "metanotions" NOTETY1 und NOTETY2 sowie THING1 und THING2 sind implizit definiert durch die "metaproductions": NOTETY1 NOTETY2 THING1 THING2
: : : :
: : : :
NOTETY. NOTETY. THING . THING .
Solche zusätzlichen "metanotions" werden insbesondere immer dann benötigt, wenn in einer "hyperrule" die konsistente Ersetzung für mehrere Vorkommen eines "metanotion" verhindert werden soll.
6.3 Der Gebrauch von "predicates"
29
6.3 Der Gebrauch von "predicates" Im vorhergehenden Paragraphen haben wir am Beispiel eines ALGOLöOassignment Statement gesehen, wie man einfache Kontextabhängigkeiten (hier: Einschränkung des Typs der rechten Seite auf den Typ der auf der linken Seite auftretenden Variablen) mit Hilfe einer 2VWG grammatikalisch formulieren kann. Hierbei haben wir nichts anderes getan, als die sonst verbal formulierte Einschränkung direkt als Produktions-Regeln anzugeben. Dabei gestatten uns die "metanotions", mehrere Produktions-Regeln zu einer zusammenzufassen. Um mit Hilfe einer 2VWG wesentlich schwierigere Probleme von Kontextabhängigkeit, wie z. B. die Identifizierung eines identifier (vgl. 6.3.2), lösen zu können, hat man sogenannte "predicates" in die 2VWG eingeführt. Die Idee ist dabei die folgende: Um bei der Erzeugung einer Sprache durch eine Grammatik nur solche Sätze zu erhalten, die vorgegebenen Bedingungen genügen, führt man in die Grammatik nicht-terminale Elemente ein, die bei der Erzeugung von Sätzen nur dann weiter ersetzt werden ("productive" sind), wenn diese Bedingungen erfüllt sind. Sind die Bedingungen nicht erfüllt, führt also die bereits begonnene Erzeugung nicht zu einem Satz der Sprache, sondern (wie man sagt) in eine Sackgasse. Diese speziellen nicht-terminalen Elemente heißen "predicates". Für sie gilt stets: Ihre Ersetzung führt entweder in eine Sackgasse oder aber in das leere Wort. Im ersten Fall wird die Erzeugung eines bestimmten Satzes verhindert, im zweiten Fall läuft die Erzeugung weiter, jedoch ohne, daß dazu das "predicate" einen Beitrag liefert.
6.3.1 Ein einfaches Beispiel Wir wollen die Menge aller Zeichenfolgen erzeugen, die aus zwei verschiedenen Buchstaben bestehen derart, daß der erste Buchstabe in der Reihenfolge des Alphabets vor dem zweiten Buchstaben auftritt. Die Menge dieser Zeichenfolgen kann man natürlich mit Hilfe einer einfachen kontextfreien Grammatik erzeugen, jedoch auf recht mühsame Art; denn letztlich wird man die gewünschten Zeichenfolgen alle (13-25=325) aufzählen müssen. Die Benutzung einer 2VWG unter Verwendung von "predicates" macht uns dagegen das Leben leichter (vgl. [17]):
30
6. Van Wijngaarden-Grammatiken
"metaproductions": (Ml)
ALPHA
: a ; b ;c ;d ;e ;f ; g ; h ; i ;j ; k ; I ; m ; n ;o ; p ;q ;
(M2)
ALPHA1
(M3)
ALPHA2
: : ALPHA.
(M4)
NOTETY
: : EMPTY ; N O T E T Y ALPHA . : : NOTETY .
r ; s ; t; u ; v ; w ; x ; y ; z . : : ALPHA.
(M5)
NOTETY1
(M6)
NOTETY2 : : NOTETY .
(M7)
NOTETY3 : : NOTETY .
(M8)
EMPTY
"hyperrules": (HI)
start : letter A L P H A 1 symbol , letter A L P H A 2 symbol , where
(H2)
where A L P H A 1 precedes A L P H A 2 in N O T E T Y 1 A L P H A 1 N O T E T Y 2
ALPHA1 precedes A L P H A 2 in abcdefghijklmnopqrstuvwxyz . ALPHA2 NOTETY3 : EMPTY .
Mit Hilfe der "metaproductions" (M2) und (Ml) bzw. (M3) und (Ml) kann man aus ALPHA1 und ALPHA2 unabhängig voneinander einen der Buchstaben a , b , c , - - - , x , y , z ableiten. Setzt man je einen dieser Buchstaben in ( H l ) für ALPH A1 und ALPH A2 ein, so erhalten wir auf der rechten Seite zwei terminale Elemente, gefolgt von einem "predicate" (das "protonotiori", welches mit 'where' beginnt). Man kann dann mit Hilfe dieses "predicate" nachprüfen, ob die beiden terminalen Elemente in der lexikographischen Reihenfolge stehen oder nicht: Nur wenn die beiden terminalen Elemente in der lexikographischen Reihenfolge stehen, kann man das ihnen folgende "predicate" mit Hilfe von (H2) durch das leere Wort ersetzen, so daß die beiden terminalen Elemente eine gewünschte Zeichenfolge bilden. Ersetzen wir z.B. in (Hl) ALPHA1 durch c und ALPHA2 durch f , so erhalten wir die Regel (Hla)
start : letter c symbol, letter f symbol, where c precedes f in abcdefghijklmnopqrstuvwxyz .
Für dieses "predicate" erhalten wir aus (H2) die Regel ALPHA1
(H2a)
where
c
ALPHA2
precedes
f
in
ALPHAI
ALPHA2
ab
de
NOTETV1
NOTETY2
ghijklmnopqrstuvwxyz : . NOTETY3
6.3 Der Gebrauch von "predicates"
31
Wie man sieht, erzeugt hiernach das "predicate" das leere Wort, also ist cf eine gewünschte Zeichenfolge, wenn man c und / als Repräsentation für das letter c symbol und letter f symbol hat. Ersetzen wir dagegen z.B. in ( H l ) ALPHA1 durch f und ALPHA2 durch c , so erhalten wir die Regel (Hlb)
Start : letter f symbol , letter c symbol , where f precedes c in abcdefghijklmnopqrstuvwxyz .
Für dieses "predicate" erhalten wir aus (H2) keine Regel, d.h. in ( H l b ) können wir das "predicate" nicht weiter ersetzen, also ist fc keine gewünschte Zeichenfolge. 6.3.2 Identifizierung Ein in fast allen Programmiersprachen auftretendes Problem von Kontextabhängigkeit stellt die Identifizierung von identif iers dar: die Suche nach dem defining-identifier für einen irgendwo im Programm auftretenden applied-identifier.
Durch die Identifizierung wird einem applied-identifier eine Bedeutung, nämlich die seines defining-identifier, beigegeben. Im 1. Band in 2.4.2 haben wir schon den Identifizierungsprozeß in ALGOL68 kennengelernt. Wir wollen nun sehen, wie er im Report syntaktisch mit Hilfe einer 2VWG beschrieben wird. Wir werden dabei gleichzeitig einige wichtige, im Report verwendete "metanotions" kennenlernen. Wir benötigen zur Identifizierung eine Art Symboltabelle, in die alle durch Deklarationen neu in das Programm eingeführten identifiers sowie ihre zugehörigen "modes" eingetragen werden. Diese Einträge entsprechen also den im Programm auftretenden Deklarationen. Solch eine Symboltabelle muß für das gesamte Programm zur Verfügung stehen, so daß im Programm auftretende applied-identifiers auf sie Bezug nehmen können, um so ihre Bedeutung zu erhalten. Wie wir wissen, ist ein ALGOL68-Programm ein in begin (oder ( ) und end (oder ) ) eingeschlossener ränge , in dem weitere, möglicherweise ineinander geschachtelte, ranges auftreten können. Bei Eintritt in jeden ränge werden dann entsprechend den in ihm vorkommenden Deklarationen die Einträge in die Symboltabelle vorgenommen. Bei Austritt aus dem ränge werden sie wieder gelöscht; denn nur innerhalb eines ränge sind die darin deklarierten identifier gültig, haben also nur dort ihre in der Deklaration erhaltene Bedeutung ("property"). Die Identifizierung von identifiers geschieht im Falle von ineinander geschachtelten ranges von innen nach außen.
32
6. Van Wijngaaiden-Grammatiken
In der im R e p o r t angegebenen 2VWG, die den Identifizierungsprozeß von identifiers beschreibt, finden wir zunächst das " m e t a n o t i o n " T A G , das die Darstellung eines identifier als Folge von Buchstaben u n d Z i f f e r n , beginnend mit einem Buchstaben, liefert: TAG : :
LETTER; TAG LETTER ; TAG DIGIT .
Sodann das " m e t a n o t i o n " DEC , das einen identifier mit einem " m o d e " koppelt: DEC : : MODE T A G . Dies geschieht also mit Hilfe des " m e t a n o t i o n " M O D E , aus d e m sich alle A L G O L 6 8 - " m o d e s " (außer void) ableiten lassen: MODE
: : PLAIN ; STOWED ; REF t o MODE ; P R O C E D U R E ; U N I T E D ; MU definition of MODE ; MU application .
PLAIN
I N T R E A L ; boolean ; character .
INTREAL
SIZETY integral ; SIZETY real .
SIZETY
long LONGSETY ; short S H O R T S E T Y ; EMPTY .
EMPTY STOWED
structured with FIELDS m o d e ; F L E X E T Y ROWS of MODE .
usw. (vgl. R l . 2 . 1 ) Schließlich brauchen wir n o c h die " m e t a n o t i o n s " LAYER u n d
NEST.
LAYER liefert die Einträge in die Symboltabelle für jeden neuen r ä n g e , gegeben d u r c h eine (eventuell leere) Folge von DECS , stets mit ' n e w ' beginnend : LAYER : : new DECSETY . NEST ist eine Folge von L A Y E R ' s , die der Schachtelung von ranges entspricht: NEST : : LAYER ; NEST L A Y E R . NEST liefert alle bis zu einem b e s t i m m t e n Z e i t p u n k t in die Symboltabelle vorgenommenen Einträge. Dabei entspricht NEST einer range-Schachtelung
6.3 Der Gebrauch von "predicates"
33
von außen nach innen, wobei die äußere Umgebung, in die jedes ALGOL68Programm eingebettet ist (vgl. 7.4), durch den anfänglichen Eintrag 'new' charakterisiert wird. Zusammenfassend haben wir also folgende "metaproductions": NEST
: LAYER ; NEST L A Y E R .
LAYER
: : new D E C S E T Y .
DEC
: : MODE T A G .
DECS
: DEC ; DECS D E C .
D E C S E T Y : : DECS ; EMPTY. EMPTY TAG
: LETTER ; TAG LETTER ; TAG DIGIT.
LETTER
: : letter A B C .
ABC
::
DIGIT
a;b;c;d;e;f;g;h;i;j;k;l;m;n;o;p;q;r;s; t;u;v;w;x;y;z. : digit zero ; digit one ; digit two ; digit three ; digit four, digit five ; digit six ; digit seven ; digit eight ; digit nine .
Anmerkung: Im Report wird der Identifizierungsprozeß allgemein für indicators (also indentifiers, mode-indications und operators) beschrieben. Wir dagegen haben die im Report angegebenen "metaproductions" und "hyperrules" soweit abgemagert, daß sie nur den Identifizierungsprozeß für identifiers beschreiben. Betrachten wir folgendes Beispiel: * * * ; begin int a := 0 ; int b := 0 ; begin real a := 3.14 ; printfa) ; printfb) ; printfc) end end ; * * *
34
6. Van Wijngaaiden-Grammatiken
Gehen wir davon aus, daß obige closed-clause in einem ALGOL68-Programm eingebettet ist, so wird entsprechend den drei variable-declarations • int a:=0,
int b := 0 und real a := 3.14
das NEST erweitert um 'new reference to integral letter a reference to integral letter b new reference to real letter a' Hierbei sind die "modes" 'reference to integral' (refint) und 'reference to real' (refreal) Ableitungen des "metanotion" MODE. Im inneren range treten a , b und c (jeweils als aktuelle Parameter in einem pnnf-Aufruf) als applied-identifier auf. Ein applied-identifier ist im Report in R4.8.1.b syntaktisch beschrieben durch die "hyperrule" a) MODE NEST applied identifier with TAG : where MODE TAG identified in NEST , TAG token . Wir müssen also die in dem Beispiel auftretenden applied-identifier in ihrem NEST identifizieren. Dazu haben wir die im Report in R7.2.1 angegebenen "hyperrules" für unsere Zwecke folgendermaßen abgeändert: bl)
where DEC identified in NEST new DECSETY : where DEC resides in DECSETY ; where DEC identified in NEST .
b2)
where DEC1 resides in DECS2 DEC2 : where DEC1 resides in DEC2 ; where DEC1 resides in DECS2 .
b3)
where MODE1 TAG resides in MODE2 TAG : where MODE1 equivalent MODE2 .
Dazu gehören die weiteren "metaproductions": DEC1 DEC2 DECS2 MODE1 MODE2
: : : :: :: ::
DEC. DEC. DECS. MODE. MODE .
6.3 Der Gebrauch von "predicates"
35
Man beachte, daß in den " h y p e r r u l e s " b l ) - b 3 ) ausschließlich "predicates" auftreten. Im Report sind "predicates" leicht zu erkennen: sie beginnen stets mit 'where' (oder 'unless'). In das leere Wort führt ein "predicate" stets über die "hyperrule" where true : EMPTY, (bzw. unless false : EMPTY.) Führt dagegen ein "predicate' in das "protonotion" 'where false' (bzw. 'unless true'), dann ist man in eine Sackgasse geraten, da es für dieses "protonotion" keine "hyperrule" gibt. Für das "predicate" 'where MODE1 equivalent MODE2' haben wir aus dem Report keine "hyperrule" übernommen. Dies würde an dieser Stelle zu weit führen; denn mit Hilfe dieses "predicate" wird die 'Gleichheit' zweier "modes" geprüft (vgl. Band 1, 3.1.6). Der Algorithmus hierfür ist nicht ganz einfach, und es kostet schon einige Mühe, seine Beschreibung durch eine 2VWG mit entsprechenden "predicates" in R7.3.1 zu verstehen. In unserem Beispiel kommen nur einfache "modes" in Betracht, von denen wir leicht feststellen können, ob sie gleich sind oder nicht. Durch die Syntax eines applied-identifier wird also unter den durch NEST gelieferten "modes" fur den TAG des applied-identifier ein "mode" (falls vorhanden) ausgewählt. Dabei wird diese Auswahl in eindeutiger Weise entsprechend der range-Schachtelung von innen nach außen vorgenommen. So kann der "mode" des im obigen Beispiel auftretenden applied-identifier a nur 'reference to real'
(ref real)
sein, wie sein Syntaxbaum zeigt:
6. Van Wijngaarden-Grammatiken
36 MODE reference to real
NEST
N E S T new reference to integral letter a reference to integral letter b new reference to real letter < applied identifer with letter a
where reference to real letter a identified in •
letter a token
nest *
\
N E S T new reference to integral letter a reference to integral letter b new reference to real letter a DECSETY
(vgl. 6 . 2 . 2 , Beispiel b )
bl-1) MODE1
TAG
where reference to real letter a resides in reference to real letter a MODE2
TAG
b3) where reference to real equivalent reference to real
where true
EMPTY
Der "defining-range" von a ist demnach der innere range , a identifiziert also den defining-identifier a , der in 'real a := 3.14' (und nicht in 'int a := 0') auftritt. Betrachten wir den Syntaxbaum für den applied-identifier b , so sehen wir, daß er nur vom "mode" 'reference to integral' sein kann:
(ref int)
37
6.3 Der Gebrauch von "predicates"
reference to integral
NEST
N E S T new reference to integral letter a reference to integral letter b new reference t o real letter a applied identifier w i t h letter b
a) where reference to integral letter b identified in
NEST
N E S T new reference to integral letter a reference to integral letter b new reference to real letter a DECSETY bl-2) DEC where reference to integral letter b identified in N E S T new reference to integral letter a reference to integral letter b DECSETY bl-1) OEC1 where reference to integral letter b resides in reference to integral letter a
reference t o integral letter b
DECS2 b2—1)
where reference to integral reference to integral
letter b resides in letter b TAG
b3) where reference to integral equivalent reference to integral
where true
EMPTY
letter b t o k e n
38
6. Van Wijngaaiden-Grammatiken
Der "defining-range" von b ist demnach der äußere ränge , b identifiziert also den defining-identifier b , der in 'int b •'= 0' auftritt. Für den applied-identifier c finden wir keinen Eintrag im NEST , wobei wir davon ausgehen, daß für c auch in dem NEST, das dem ALGOL68-Programm entspricht, in dem die im Beispiel angegebene closed clause eingebettet ist, kein Eintrag vorgenommen wurde. Zu dieser Feststellung gelangen wir durch mehrmalige Anwendung der zweiten Alternative von bl), wobei wir schließlich folgendes "predicate" erhalten 'where M O D E letter c identified in new'
Für dieses "predicate" gibt es jedoch im ganzen Report keine Regel, so daß wir es nicht weiter ersetzen können. Der applied-identifier c bleibt also ohne Bedeutung, das angegebene Beispiel ist demnach syntaktisch inkorrekt. Im Report werden in Teil III insbesondere durch entsprechende "predicates" alle Kontextbedingungen syntaktisch beschrieben, denen ein korrektes ALGOL68-Programm genügen muß. Dazu gehören u.a. (vgl. R7.1.1, R7.2.1, R7.4.1): — Jeder applied-indicator muß einen defining-indicator identifizieren. — Ein identifier oder eine mode-indication darf in einem "reach" nur einmal definiert sein (ein "reach" ist ein ränge unter Ausschluß aller in ihm enthaltenen ranges, vgl. R3.0.2). — Die Rekursion innerhalb von "modes" darf nicht zur Erzeugung von Werten unbegrenzter Speichergröße fuhren und nicht eine mehrdeutige Anwendung von "coercions" erlauben ("well-formed modes", vgl. R7.4).
7. Formale Definition von ALGOL 68
Die Programmiersprache ALGOL68 wird im Report definiert durch Angabe ihrer Syntax und ihrer Semantik sowie einer "representation language" und eines "standard environment".
7.1 Die Syntax der "strict language" Die Syntax von ALGOL68 ist gegeben durch eine 2VWG (vgl. 6.2.2). Insbesondere durch Verwendung von entsprechenden "predicates" (vgl. 6.3) in dieser 2VWG ist erreicht worden, daß alle Kontextbedingungen (vgl. 6.3.2) Teil der Syntax von ALGOL68 sind. Die von der 2VWG erzeugte Sprache ist die "strict language" von ALGOL68 (vgl. R l . l . l . b . (ii)). Die kontextfreien Regeln der oberen Stufe der 2VWG, die "metaproduction rules", findet man im Report in den Abschnitten, deren Überschriften mit "Syntax", "Metasyntax" oder "Metaproduction rules" beginnen. Dies sind insbesondere die Abschnitte R1.2 sowie Abschnitte in Teil II—V. Eine alphabetische Auflistung der "metaproduction rules" ist in R12.5 gegeben. Die im Report angegebenen "metaproduction rules" haben die Form der "metaproductions", die wir aus 6.2.2 kennen (vgl. Rl.1.3.3). Es werden die "metanotions" durch endliche Folgen von "large syntactic marks" dargestellt (vgl. Rl.1.3.1 (ii)). Die terminalen Elemente der "metaproduction rules" werden durch endliche Folgen von "small syntactic marks" (vgl. R. 1.1.3.1 (i)) dargestellt. Allgemein wird eine Folge von "small syntactic marks" als ein "protonotion" bezeichnet (vgl. R1.1.3.1.b). Die kontextfreien Regeln der unteren Stufe, also die Regeln, mit denen die Sätze der "strict language" erzeugt werden, heißen im Report "production rules". Sie werden aus den "hyper-rules" abgeleitet. Die in R l . 1.3.2 angegebene Form der "production rules" entspricht der der Produktions-Regeln einer 1VWG, die wir aus 6.2.1 kennen. Die terminalen Elemente dieser "production rules", also die "protonotions", die auf 'symbol' enden, heißen im Report "symbols". Die "hyper-rules" findet man im Report in den Abschnitten, deren Überschriften mit "Syntax" beginnen. Dies sind insbesondere die Abschnitte R1.3 und die Abschnitte in Teil II—V. Die in R l . 1.3.4 angegebene Form der "hyperrules" entspricht derjenigen, die wir aus 6.2.2 kennen.
40
7. Formale Definition von ALGOL68
Ein "protonotion", für das man eine "production rule" erhält, heißt "notion" (vgl. R1.1.3.1.C). Die aus einem "notion" mit Hilfe von "production rules" ableitbaren Folgen von "symbols" werden zusammen mit ihren Ableitungsbäumen im Report als Konstrukte ("constructs") der "strict language" bezeichnet (vgl. R1.1.3.2.e). Die sich aus dem speziellen "notion" program ergebenden Konstrukte werden als Programme (programs) der "strict language" bezeichnet (vgl. R l . l . l . b (iii), R2.2). Zur Repräsentation der in einem Programm auftretenden "symbols" findet man in R9.4 einen Zeichenvorrat angegeben (vgl. 7.3). Jedes Programm der "strict language" muß die Bedingungen des "standard environment" erfüllen (vgl. 7.4). An dieser Stelle wäre es sinnvoll aufzuzeigen, wie sich eines der im 1. Band aufgeführten Beispiele mit Hilfe der im Report angegebenen 2VWG aus dem "notion" program ableiten läßt, das Beispiel somit ein Programm der "strict language" von ALGOL68 ist. Leider stoßen wir dabei auf Schwierigkeiten: Jedes einigermaßen vernünftige ALGOL68-Programm wird wohl print sowie ein oder mehrere Standard-"modes" und Standard-Operatoren als appliedindicators enthalten. Ihre Identifizierung geschieht, wie wir aus 6.3.2 wissen, innerhalb des syntaktischen Ableitungsbaumes für das Programm. Dazu muß dieser Syntaxbaum das NEST sowohl der gesamten standard-prelude (vgl. 7.4.1) als auch der gesamten particular-prelude (vgl. 7.4.4) enthalten; denn erst in diesem NEST werden print und die Standard-"modes" und die Standard-Operatoren identifiziert. Also selbst für ein einfaches, halbwegs vernünftiges Programm würde der Syntaxbaum zu viel Platz in Anspruch nehmen, so daß wir darauf verzichten, ihn hier anzugeben. Für denjenigen Leser, der sich innerhalb der Syntax von ALGOL68 schnell orientieren möchte, haben wir im Anhang ein Syntax-Diagramm angegeben, das wir mit freundlicher Genehmigung der Autoren aus [19] übernommen haben.
7.2 Die Semantik von ALGOL68
41
7.2 Die Semantik von ALGOL68 Durch die Semantik von ALGOL68 wird jedem Programm der "strict language" eine Bedeutung zugeschrieben. Dies geschieht in den Abschnitten von Teil II—V des Reports jeweils unter der Überschrift "Semantics" durch Angabe der Aktionen, die bei der Abarbeitung ("elaboration") eines Programms von einem Computer ausgeführt werden. Hierzu wird im Report ein idealisierter Computer beschrieben, den wir die 'ALGOL68-Maschine' nennen (vgl. Kapitel 8 und auch Band 1, 1.2). Die Abarbeitung eines Programms setzt sich dabei zusammen aus der Abarbeitung der in dem Programm enthaltenen Konstrukte (vgl. 7.1). Bei der Abarbeitung von Konstrukten kann nach dem Report die Beschreibung weiterer Aktionen "undefined" sein (vgl. Beispiel 1 in 8.2.3). Dies bedeutet, daß die weitere Abarbeitung nicht mehr durch den Report definiert ist. Es liegt dann im Ermessen einer jeweiligen Implementation von ALGOL68 zu entscheiden, welche Aktionen in diesem Undefinierten Fall vorgenommen werden sollen (vgl. Rl.1.4.3). Wird die Abarbeitung eines Programms allein durch den Report definiert, so wird dieses als "meaningful" bezeichnet (vgl. R1.1.4.3.c).
42
7. Formale Definition von ALGOL68
7.3 Die "representation language" Zur Darstellung der in einem Programm der "strict language" auftretenden "symbols" benötigt man einen Zeichenvorrat: ihre "representations". Ersetzt man dann die "symbols" durch ihre "representations", erhält man ein Programm der "representation language". Eine solche "representation language" ist im Report in R9.4 als die "reference language" von ALGOL68 angegeben. Beispiele von anderen "representations" findet man in Band 1, 1.4.7. In der im Report angegebenen "reference language" von ALGOL68 sind die "representations" so gewählt, daß eine Implementation der "reference language" mit einem minimalen Zeichenvorrat auskommen kann (vgl. RO.1.4.5). Dies wurde dadurch erreicht, daß in den Fällen, wo es nicht zu syntaktischen Mehrdeutigkeiten führen kann, für verschiedene "symbols" ein und dieselbe "representation" gewählt wurde. So ist z.B. die "represent a t i o n " V' gegeben für das routine-symbol, für das colon-symbol u n d für
das up-to-symbol (vgl. R9.4.1.f). Wo dies aber zu erheblichen Schwierigkeiten bei der Syntaxanalyse fuhrt, hat man die Möglichkeit, innerhalb von bestimmten syntaktischen Konstruktionen ein "symbol" durch ein anderes "symbol" zu ersetzen und somit dann auch eine andere "representation" zu wählen. So sind z.B. die beiden "representations" bzw. V' u.a. für das brief-begin-symbol u n d f ü r d a s s t y l e - i - s u b - s y m b o l b z w . f ü r d a s brief-end-
symbol und für das style-i-bus-symbol gegeben (vgl. R9.4.1 .f). Schreibt man dann in seinem Programm z.B. x(i) so kann dies eine Repräsentation sowohl für ein call (vgl. R5.4.3.1.a, R1.3.3.d) als auch für ein slice (vgl. R5.3.2.1.a, R1.3.3.e) sein, und es ist für die Syntaxanalyse nicht einfach zu entscheiden, welches der beiden Konstrukte gemeint ist. Da man jedoch innerhalb eines slice das style-i-sub-symbol bzw. style-i-bus-symbol durch das brief-sub-symbol bzw. brief-bus-symbol ersetzen kann und für diese beiden "symbols" die "representations" '[' bzw. ']' in der "reference language" zur Verfügung stehen (vgl. R9.4.1.f), kann man im Falle eines slice auch
*[/] schreiben. Dies sollte man auch immer tun, die meisten Implementationen von ALGOL68 werden es sogar fordern.
7.4 Das "standard environment"
43
7 . 4 Das "standard environment" Ein vom Programmierer erstelltes Programm wird im Report particular-program genannt: es ist stets eine enclosed-clause (vgl. Band 1, Seite 59) oder eine loop-clause , der eine Folge von labels vorangehen kann (vgl. RIO.l.l.g). Ein particular-program ist eingebettet in einen program-text (vgl. RIO. 1.1.a), der außerdem die standard-prelude , eine library-prelude , eine system-prelude und system-tasks, möglicherweise weitere particularprograms, eine oder mehrere particular-preludes (jeweils eine für jedes particular-program) und eine oder mehrere particular-postludes enthält. Ein program-text hat stets die Form (vgl. RIO.1.1): begin standard-prelude; library-prelude ; system-prelude ; par begin system-task-1 , system-task-n, ( user-task-1^, ( user-task-rrV end end Dabei deutet das "symbol" par an, daß die system-tasks und die in Klammern eingeschlossenen user-tasks parallel abgearbeitet werden, wobei die bei dieser Parallelverarbeitung vorgenommenen Operationen entsprechend den in der standard prelude angegebenen declarations (vgl. R10.2.4) synchronisiert werden (vgl. auch 9.2). Ein user-task hat stets die Form (vgl. RIO. 1.1.f): particular-prelude ; begin co particular-program co label 1: label n: enclosed-clause end ; particular-postlude Die preludes, system-tasks und postludes sind im einzelnen in R10.2—RIO.5 beschrieben. Wie man aus den dort angegebenen Formen zu einer Darstellung des "standard environment" gelangt, ist in RIO. 1.3 beschrieben.
7. Formale Definition von ALGOL68
44
Unter einem program der "strict language" (vgl. 7.1) wird stets ein program-text verstanden (vgl. R2.2, R10.1.2.a), welcher neben den einzelnen particular-programs die genannten preludes , system-tasks und postludes mit einschließt.
7.4.1 Die standard-prelude Es gibt nur eine standard-prelude, die in jedem program-text enthalten sein muß. Sie ist in RIO.2 und R10.3 angegeben und besteht aus einer Vielzahl von declarations : a) "environment enquiries" (vgl. RIO.2.1): operation-declarations fur abs und repr , also eine Code-Tabelle; identity-declarations für Konstanten, die dem Benutzer Informationen über die jeweilig vorhandene Implementation von ALGOL68 liefern, z.B.
max int, int lengths , bits width . b) Standard-"modes" (vgl. R10.2.2): mode-declarations fur "modes", die in ALGOL68 standardmäßig verwendet werden, deren Bedeutung also vom Programmierer in von ihm selbstgeschriebenen mode-declarations nicht geändert werden darf: void , b o o l , i n t , r e a l , char , c o m p l , bits , bytes , string . c) Standard-Operatoren und Standard-Funktionen (vgl. RIO.2.3): operation-declarations für Standard-Operatoren; priority-declarations zur Festlegung der Prioritäten dieser StandardOperatoren; procedure-declarations fur Standard-Funktionen; identity-declarations für mathematische Konstanten. d) Operationen zur Synchronisierung (vgl. R10.2.4): declarations zur Synchronisierung der Operationen bei Parallelverarbeitung (vgl. 9.2). e) Deklarationen für den Transput (vgl. R10.3 und auch 9.3, 9.4, Kapitel 10). Alle in der standard-prelude definierten implementationsspezifischen Konstanten sowie die Standard-Prozeduren, -Operatoren und -"modes" kann der Programmierer in seinem particular-program als applied-indicators benutzen, muß sie also nicht mehr selbst deklarieren. Wenn er will, kann er sie jedoch in seinem particular-program neu definieren (aber nicht die in R10.2.2 angegebenen Standard-"modes").
7.4 Das "standard environment"
45
7.4.2 Die library-prelude
Die Syntax eines program-text gestattet es, die standard-prelude um library-preludes zu erweitern, wenn man fur spezielle Anwendungen noch weitere declarations fur "modes", Operatoren, Prozeduren und Konstanten benötigt (vgl. Kapitel 11). Diese declarations dürfen jedoch nicht im Widerspruch zu den in der standard-prelude enthaltenen declarations stehen.
Für welche Anwendungen library-preludes und wieviele davon dem Benutzer zur Verfügung stehen, ist abhängig von der jeweiligen Implementation von ALGOL68. Nach dem Report bestimmt jede vorhandene library-prelude formal eine neue Implementation. Auf jeden Fall muß eine library-prelude fur den Benutzer zur Verfugung stehen, sie kann jedoch aus dem unit skip allein bestehen, also praktisch nicht vorhanden sein. 7.4.3 Die system-prelude
In der system-prelude findet man über die standard-prelude und die library-prelude hinausgehende declarations für Konstanten, Prozeduren und Operatoren, die es dem Benutzer ermöglichen, bestimmte Funktionen der auf der Implementationsmaschine vorhandenen Betriebssysteme zu verwenden: die Abfrage von Systemparametern, z.B. zur Bestimmung der abgelaufenen Ausfuhrungszeit oder des noch zur Verfügung stehenden Speicherplatzes; vorzeitige Aktivierung des 'garbage-collectors' usw. Auch die system-prelude muß in einem program-text enthalten sein, so daß sie fur alle Benutzer zur Verfügung steht. Dabei dürfen die in der system-prelude auftretenden declarations nicht im Widerspruch zu den in d e r standard-prelude u n d library-prelude e n t h a l t e n e n declarations s t e h e n .
Die Grenze zwischen library-prelude und system-prelude ist im Report nicht klar definiert, sie ist in vieler Hinsicht Geschmackssache der jeweiligen Implementation. 7.4.4 Die particular-prelude
Um die Möglichkeit zu haben, die von verschiedenen Benutzern erstellten particular-programs parallel abarbeiten zu können, ohne daß sie sich dabei gegenseitig stören, geht jedem von ihnen eine eigene particular-prelude voran. In jeder particular-prelude müssen die in R10.5.1 angegebenen declarations und units enthalten sein. Insbesondere werden also in jeder
46
7. Formale Definition von ALGOL68
particular-prelude die in ihr definierten Standard-"files" stand out und stand back eröffnet (vgl. 9.4.5). Darüber der particular-prelude auch die in einer library-prelude definierten 'Standard'-"files" (wenn gewünscht) eröffnet
stand in , hinaus können in eventuell zusätzlich werden.
7.4.5 Die particular-postlude Jedem particular-program folgt eine eigene particular-postlude , die auf jeden Fall die in RIO.5.2 angegebenen calls enthalten muß. Es müssen also in jeder particular-postlude die Standard-"files" stand in , standout und stand back (vgl. 9.4.5) sowie die möglicherweise in der particular-prelude zusätzlich eröffneten "files" geschlossen werden.
8. Die ALGOL 68-Maschine
Wie wir aus Band 1, 1.2 wissen, wird im Report die Abarbeitung eines Programms anhand eines idealisierten Computers, der ALGOL68-Maschine, beschrieben. Genauer: es werden im Report die Aktionen beschrieben, die die ALGOL68-Maschine bei der Abarbeitung eines Programms ausfuhrt. Wir wollen in diesem Kapitel auf einige im Zusammenhang mit der ALGOL68Maschine im Report verwendete Begriffe (vgl. R2) etwas genauer eingehen.
8.1 Objekte Es werden im Report externe und interne Objekte unterschieden. Dabei werden die Konstrukte (vgl. 7.1) als externe Objekte bezeichnet, da sie Teile des Programmtextes bestimmen. Die Abarbeitung der in einem Programm enthaltenen externen Objekte führt zu Aktionen auf internen Objekten. Als interne Objekte werden nicht nur Werte, sondern auch "locales" und "environs" bezeichnet (vgl. 8.1.3). 8.1.1 Werte Ein Wert in ALGOL68 ist entweder ein "piain value", d.h. ein Wert einer der Grund-"modes" void , b o o l , char , int oder real, ein "structured-value", ein "multiple value" oder eine Routine ("routine"). Die Werte und ihre Relationen zueinander haben wir im 1. Band ausführlich, dem Report entsprechend, behandelt. Sie sind im Report in den Abschnitten R2.1.3 und R2.1.2 im einzelnen beschrieben.
8.1.2 "Modes" Jeder Wert in ALGOL68 hat einen bestimmten "mode". Dies ist eine, jedem Wert zugeordnete Eigenschaft, die angibt, in welcher Relation ein Wert zu anderen Werten steht und welche Aktionen auf ihn anzuwenden sind (vgl. R2.1.1.2). Durch diese Zuordnung von "modes" werden die Werte aufgeteilt in zueinander disjunkte Mengen, die durch die "modes" gekennzeichnet sind. Im Report werden die "modes" durch "protonotions" beschrieben, die sich aus dem "metanotion" MODE ableiten lassen (vgl. R.l.2.1). Dabei kann es
48
8. Die ALGOL68-Maschine
durchaus vorkommen, daß verschiedene "protonotions" denselben "mode" darstellen. Dies ergibt sich z.B. zwangsläufig bei rekursiv definierten "modes". Beispiel (vgl. Band 1,3.1.6): mode simple = struct (ref simple s) ; mode clumsy = struct (ref struct (ref clumsy s) sj; Hierbei spezifizieren die mode-indications simple und clumsy denselben "mode". Dieser "mode" kann durch verschiedene "protonotions" dargestellt werden, z.B. durch 'mu i definition of structured with reference to mu i application field letter s mode' oder durch 'mu ii definition of structured with reference to structured with reference to mu ii application field letter s mode field letter s m o d e ' . Anhand dieser beiden "protonotions" sieht man außerdem, wie man in ALGOL68 'unendliche' "modes" durch "protonotions" endlicher Länge darstellen kann. Erreicht wird dies durch die beiden "metaproduction rules" MODE : : MU definition of MODE . MODE : : ML) application . (im Report in R1.2.1.A mit anderen Alternativen zu einer "metaproduction rule" fur MODE zusammengefaßt) Für MU finden wir in R1.2.1.V die "metaproduction rule" MU : : mu TALLY. und für TALLY in Rl.2.1.W die "metaproduction rule" TALLY : : i ; TALLY i . Durch 'MU definition' werden also die unterschiedlichen "protonotions" markiert. Zu dieser Markierung korrespondierend tritt innerhalb des "protonotion" 'MU application' auf. Hierdurch wird einerseits die endliche Länge des "protonotion" gewährleistet und andererseits angegeben, daß innerhalb des "protonotion" 'MU application' ersetzt werden kann durch den MODE des korrespondierenden 'MU definition of MODE'.
8.1 Objekte
49
Auch im Zusammenhang mit "united modes" (vgl. Band 1,4.3.1) ergibt sich, daß verschiedene "protonotions" denselben "mode" darstellen. Beispiel: mode ir = union /'int, real); mode ri = union (real, inty ; Die mode-indications ir und ri spezifizieren denselben "mode". Dieser "mode" kann durch die beiden "protonotions" 'union of integral real mode' und 'union of real integral mode' dargestellt werden. Im Report (vgl. R2.1.1.2) werden verschiedene "protonotions" (ableitbar aus dem "metanotion" MOID), die denselben "mode" darstellen, als zueinander äquivalent ("equivalent to") bezeichnet. Ob zwei "protonotions" zueinander äquivalent sind, wird durch die Syntax in R7.3 festgestellt. So gesehen stellt also ein "mode" eine Äquivalenzklasse dar, bestehend aus zueinander äquivalenten "protonotions", die diesen "mode" darstellen.
8.1.3 "Locales" und "environs" In Band 1, 1.2.1 haben wir ein "locale" aufgefaßt als ein Paar, bestehend aus einem Wert (dargestellt durch eine 'box') und seiner Adresse. Im Report wird dagegen unter einem "locale" der gesamte Speicherplatz verstanden, der während der Abarbeitung eines ränge reserviert wird. Dieser gesamte reservierte Speicherplatz dient zur Aufnahme der einzelnen Werte, zu denen die in dem ränge definierten indicators Zugriff ("access") haben (vgl. R2.1.1.1.b). Die in einem Programm enthaltenen Konstrukte werden abgearbeitet in bestimmten "environs" (Umgebungen). Diese "environs" entstehen während der Abarbeitung des Programms bei Eintritt in jeden neuen ränge (insbesondere beim Aufruf von Routinen) und werden beim Austritt aus dem ränge wieder zerstört. Dabei entsteht ein "environ" bei Eintritt in einen ränge aus dem "environ", in dem der ränge abgearbeitet wird, durch Hinzunahme des dem ränge entsprechend reservierten "locale". Diese Bildung eines neuen "environ" aus einem alten durch Hinzunahme eines neu reservierten "locale" wird im Report ausgedrückt durch das "establishing around" (vgl. R3.2.2.b). Das "environ", in dem ein program selbst als Konstrukt abgearbeitet wird, ist leer und wird im Report als "primal environ" bezeichnet (vgl. R2.2.1.a).
50
8. Die ALGOL68-Maschine
Betrachten wir das Beispiel aus Band 1, Seite 124: begin co range 1 co int count := 0; co this is count I co proc findcount = /char stop) void : while next f stop do count plusab 1 od ; serial-clause / begin co range2 co int count; co this is count2 co serial-clause / findcount (repr (abs "a" + count)); serial-clause end ; serial-clause end
Zum Zeitpunkt der Abarbeitung der ersten serial-clause in range2 sind zwei "environs" El und E2 entsprechend rangel und range2 entstanden: El setzt sich zusammen aus dem "environ", in dem der rangel abgearbeitet wird, und dem "locale" zur Aufnahme der Werte, zu denen die identifier count (und zwar hier count 1) und findcount sowie die möglicherweise in den beiden serial-clauses von rangel definierten indicators Zugriff haben. E2 setzt sich zusammen aus dem "environ" El und dem "locale" zur Aufnahme der Werte, zu denen der identifier count (und zwar hier countT) und die möglicherweise in den beiden serial-clauses von range2 definierten indicators Zugriff haben. Wenn dann die Routine von findcount mit dem aktuellen Parameter repr /'abs "a" + count) aufgerufen wird, entstehen zwei neue "environs" E3 und E4 (vgl. R5.4.3.2): E3 setzt sich zusammen aus dem "environ" E2 und einem leeren "locale". Was die Bereitstellung von Speicherplatz anbelangt, unterscheidet sich E3 nicht von E2; E3 ist jedoch jünger als E2 (vgl. 8.2). In diesem "environ" E3 wird der aktuelle Parameter repr /'abs "a" + count) abgearbeitet. E4 setzt sich zusammen aus dem "environ" El und dem "locale", das dem ränge der aufgerufenen Routine entspricht (dient zur Aufnahme des Wertes, zu dem der formal-parameter stop Zugriff hat). In diesem "environ" E4 wird das unit (hier also die angegebene loop-clause) des routine-text der aufgerufenen Routine abgearbeitet.
8.1 Objekte
51
Somit geschieht also die Abarbeitung des routine-text einer aufgerufenen Routine stets im "environ" der Prozedurdeklaration, während die Abarbeitung der aktuellen Parameter im "environ" des Aufrufs (des call) der Routine geschieht (vgl. Band 1, Seite 122, 124). Allgemein kann man sagen, daß ein "environ" angibt, in welchem Zustand der "elaboration" sich ein Programm befindet. Ein "environ" ist entweder "local" oder "nonlocal", abhängig davon, in welcher Weise sein 'jüngstes' "locale" reserviert worden ist: Entspricht das jüngste "locale" einem range , der mindestens eine mode declaration , eine identifier-declaration oder eine operation-declaration enthält, so ist das "environ" "local". Enthält der dem jüngsten "locale" entsprechende range keine derartige declaration , so heißt das "environ" "nonlocal". Betrachten wir das Beispiel aus Band 1, Seite 159, wo wir eine Prozedur deklariert haben, die bei jedem ihrer Aufrufe eine neues Listenelement erzeugt und an eine (vielleicht sogar leere) Liste anhängt: begin co rangel co int n ; readf n); mode element = struct ([l:n\ real row, ref element next); mode list = struct (ref element begin, end); proc generate = (ref list list) void : /'heap element new; if ref element (begin of list) is nil then begin of list else next of end of list fi := new; end of list := new; next of new := nil ); list my list := /'nil, nity ; generate (mylist); * ** Das "environ", das dem rangel entspricht, ist "local". Auch das "environ", in dem das unit des routine-text der aufgerufenen Routine von generate abgearbeitet wird, ist "local"; denn in dem der aufgerufenen Routine entsprechenden range tritt auf jeden Fall eine identity-declaration (nämlich ref list list = mylist) auf, durch die die Parameterübergabe vorgenommen wird. Betrachten wir dagegen das Beispiel aus Band 1, Seite 157, wo wir mit Hilfe einer loop-clause eine Dreiecksmatrix aufgebaut haben:
52
8. Die ALGOL68-Maschine
begin co rangel co mode refrow = ref [ ] real ; int n ; read (n) ; [l:n] refrow trimat; for i to n do trimat [/] := loc [7:/] real od ; * ** Hierbei ist zwar das "environ" "local", das dem rangel entspricht, jedoch ist das "environ" "nonlocal", in dem die assignation trimat [/'] := loc real abgearbeitet wird, da in dem range zwischen do und od keine declaration auftritt.
53
8.2 "Scope"
8.2 "Scope" In ALGOL68 hat jeder Wert eine bestimmte Lebensdauer, die im Report als "scope" bezeichnet wird (vgl. R2.1.1.3). Im Report wird auch von dem "scope" eines "environ" gesprochen. Dieser gibt das Alter des "environ" relativ zu einem anderen "environ" an. So ist ein "environ" A 'jünger' ("newer") als ein "environ" B, wenn B in A enthalten ist und A mindestens ein "locale" enthält, das zeitlich gesehen (bei der "elaboration" ein Programms) später reserviert worden ist als alle "locales", aus denen sich B zusammensetzt. Diese sowohl räumliche als auch zeitliche Relation zwischen "environs" können wir durch ein Bild folgendermaßen verdeutlichen: EO ("primal environ") | ' l o c a l e 1" v
| "locale2" j
El v
"locale3"
|
'
E2 *
V E3
'
Räumlich betrachtet, gilt: EO (leer) C El C E2 C E3 Zeitlich betrachtet, gilt: EO (leer) älter als El älter als E2 älter als E3 oder E3 jünger als E2 jünger als El jünger als EO (leer). Im Report wird der "scope" eines Wertes definiert als der "scope" eines bestimmten "environ" (vgl. R2.1.1.3.a). Dies bedeutet, daß der "scope" eines Wertes gleich der Existenzdauer eines bestimmten "environ" ist.
8.2.1 "scope"-Regel bei einer assignation Wenn sich eine Adresse N auf einen Wert W bezieht ("to refer to"), so darf der "scope" von N nicht größer sein als der "scope" von W. Dadurch wird verhindert, daß man versucht, über eine noch lebende Adresse einen bereits nicht mehr existierenden Wert zu erreichen.
^
54
8. Die ALGOL68-Maschine
Damit man dieses Verbot nicht umgeht, wird durch die Semantik der assignation vorbeugend verlangt: der "scope" eines Wertes, der einer Adresse zugewiesen werden soll, darf nicht kleiner sein als der "scope" der Adresse selbst (vgl. R5.2.1.2.b, R2.1.1.3). Man betrachte dazu die Beispiele 1 , 4 in 8.2.3.
8.2.2 Der "scope" eines Wertes Für den "scope" der Werte von verschiedenem "mode" gilt folgendes: a) Der "scope" eines "plain value" (vgl. 8.1.1) ist gleich der Existenzdauer des "primal environ" (vgl. 8.1.3, R2.1.3.i). "Plain values" existieren also während der Abarbeitungszeit des gesamten Programms. b) Der "scope" einer Adresse ("name") ist gleich der Existenzdauer eines speziellen "environ" (vgl. R2.1.3.2.c). Im einzelnen gilt: bl)
Der "scope" der Adresse einer durch einen local-generator erzeugten Variablen ist gleich der Existenzdauer eines "environ" E , für das gilt (vgl. R5.2.3.2): Sei EO das "environ", in dem der local-generator abgearbeitet wird. Ist dann EO "local" (vgl. 8.1.3), so ist E gleich EO; anderenfallsist E das jüngste "local" "environ", das älter ist als EO. Vgl. hierzu die Beispiele 1,2 in 8.2.3.
b2)
Der "scope" der Adresse einer durch einen heap-generator erzeugten Variablen ist gleich der Existenzdauer des "environ", in dem das vom Benutzer erstellte particular-program abgearbeitet wird (vgl. R5.2.3.2.a, vgl. auch 7.4). Hierbei wird vorausgesetzt, daß der heap-generator in dem particular-program auftritt. Vgl. hierzu Beispiel 3 in 8.2.3.
b3)
Der "scope" der Adresse von nil ist stets gleich der Existenzdauer des "primal environ" (vgl. R2.1.3.2.c).
b4)
Aus Band 1 wissen wir: Bezieht sich eine Adresse ("name") N auf ein "multiple value" bzw. auf ein "structured value", so erhält man durch "slicing" bzw. selection eine Adresse ("subname") M, die sich auf den ausgewählten Teil bzw. auf das ausgewählte "field" bezieht (vgl. Band 1, Seite 94, 102). Der "scope" von M ist dann gleich dem "scope" von N . (vgl. R2.1.3.3.e, R2.1.3.4.g).
c) Der "scope" eines "structured value" ist gleich dem kleinsten "scope" seiner "fields" (vgl. R2.1.3.3.c).
8.2 "Scope"
55
d) Der "scope" eines "multiple value" ist gleich dem kleinsten "scope" seiner Elemente, sofern der "descriptor" nicht " f l a t " ist, das "multiple value" also aus mindestens einem Element besteht (vgl. Band 1, Seite 93). Ist der "descriptor" "flat", besteht also das "multiple value" aus keinem Element, so ist der "scope" dieses leeren "multiple value" gleich der Existenzdauer des "primal environ" (vgl. R2.1.3.4.e). e) Der "scope" einer Routine, geliefert von einem routine-text R in einem "environ" E , ist gleich der Existenzdauer des für R in E notwendigen ("necessary") "environ". Dieses für R in E notwendige "environ" ist folgendermaßen definiert (vgl. R5.4.1.2, R7.2.2.c): Es werden alle diejenigen "environs" betrachtet, die -
in E enthalten sind (einschließlich E selbst) und
-
ranges entsprechen, in denen die defining-indicators enthalten sind, die von den in R enthaltenen applied-indicators (ausgenommen eventuelle formal-declarers) identifiziert werden.
Dann ist das jüngste von diesen "environs" das für R in E notwendige "environ". Vgl. hierzu Beispiel 4 in 8.2.3. 8.2.3 Beispiele Beispiel 1: begin co ränge 1 co int a; ref int aa ; begin co range2 co int b := 2; a := b; b := aa := b end ; * * *
1;
Die rangel und range2 entsprechenden "environs" heißen E l und E2 , wobei E2 aus E l entsteht durch Hinzunahme eines "locale" zur Aufnahme der Variablen von b (vgl. 8.1.3). Dabei sind sowohl E l also auch E2 "local" Dementsprechend ist der "scope" der Adresse von a und der Adresse von aa jeweils gleich der Existenzdauer von E l ; der "scope" der Adresse von b ist dagegen gleich der Existenzdauer von E2. Durch die assignation a := b soll der Adresse von a der Wert, auf den sich die Adresse von b bezieht, zugewiesen werden. Da dieser Wert ein "plainvalue" ist (er ist vom " m o d e " int), ist sein "scope" gleich der Existenzdauer
56
8. Die ALG0L68-Maschine
des "primal environ", also nicht kleiner als der "scope" der Adresse von a . Somit ist also die assignation a := b sowohl syntaktisch als auch semantisch korrekt. Anders verhält es sich dagegen mit der assignation aa := b. Durch sie soll der Adresse von aa (vom "mode" ref ref int) die Adresse von b (vom "mode" ref int) zugewiesen werden. Der "scope" der Adresse von b ist aber kleiner als der "scope" der Adresse von aa . Nach den in 8.2.1 über die Semantik einer assignation gemachten Bemerkungen ist dies nicht zulässig; die weitere Abarbeitung von aa := b ist "undefined" (vgl. 7.2). Das 'runtime-system' der jeweiligen Implementationsmaschine von ALGOL68 wird eine entsprechende Fehlermeldung ausgeben und die Abarbeitung des gesamten rangel unterbrechen, um zu verhindern, daß nach Abarbeitung von range2 die noch weiter existierende Adresse von aa sich auf eine bereits nicht mehr existierende Adresse bezieht.
Beispiel 2: Betrachten wir noch einmal das Beispiel aus Band 1, Seite 157, in dem mit Hilfe einer loop-clause eine Dreiecksmatrix aufgebaut wird (vgl. auch 8.1.3): begin co rangel co mode refrow = ref [ ] real ; int n ; read (n) ; [l:n] refrow trimat; for i to n do trimat [/'] := loc [l:i] real od ; * **
Aus 8.1.3 wissen wir: das dem rangel entsprechende "environ" ist "local", jedoch nicht das "environ", in dem der local generator loc [7.z] real abgearbeitet wird. Demnach ist der "scope" der Adresse der durch loc [/:/] real erzeugten Variablen gleich der Existenzdauer des "environ", das dem rangel entspricht; die Adresse der erzeugten Variablen bleibt also auch nach Abarbeitung der gesamten loop-clause am Leben.
Beispiel 3: Betrachten wir noch einmal das Beispiel aus Band 1, Seite 159, in dem wir eine Prozedur deklariert haben, die bei jedem ihrer Aufrufe ein neues Listenelement erzeugt und an eine (vielleicht sogar leere) Liste anhängt (vgl. auch 8.1.3):
57
8.2 "Scope"
begin co range 1 co int n ; read (n) ; mode element = struct ([l:n]real row, mode list = struct (ref element begin, proc generate = (ref list list) void : /'heap element new; if ref element (begin then begin of list else next of end of fi := new ; end of list := new; next of new := nil ); list mylist := fnil, nil,/ ; generate (mylist); * **
ref element end);
next);
of list) is nil list
Aus 8.1.3 wissen wir, daß das "environ", in dem das unit des routine-text der aufgerufenen Routine von generate abgearbeitet wird, " l o c a l " ist. Würde bei dem Aufruf generate (mylist) das neue element durch einen localgenerator erzeugt werden, würde seine Adresse nach dem Aufruf, also nach Abarbeitung des routine-text, nicht mehr existieren. Das next-"field" des bisher letzten element von mylist würde also ins Leere zeigen. Um jedoch die Adresse des neuen element auch nach Aufruf von generate zur Verfugung zu haben, so haben wir das neue element mit Hilfe eines heap-generator e r z e u g t .
Beispiel 4 (vgl. R7.2.2.c): begin co range 1 co proc void pp; int n := 4711 ; begin co range2 co proc p = void : print (n) ; end
PP •= P
end Die rangel und range2 entsprechenden "environs" heißen El und E2 , wobei E2 aus El entsteht durch Hinzunahme eines "locale" zur Aufnahme der Routine von p .
58
8. Die ALG0L68-Maschine
Da der im routine-text auftretende applied-identifier n seinen defining-identifier im rangel identifiziert, ist der " s c o p e " der Routine von p gleich der Existenzdauer von E l . Da dies auch für den "scope" der Adresse von pp zutrifft, ist die assignation pp := p sowohl syntaktisch als auch semantisch korrekt (vgl. die in 8.2.1 angegebene "scope"-Regel einer assignation).
8.3 Aktionen
59
8.3 Aktionen Bei der Abarbeitung ("elaboration") eines Konstruktes in einem "environ" werden von der ALGOL68-Maschine Aktionen ("actions") ausgeführt (vgl. 7.2). Diese Aktionen und die Reihenfolge, in der sie ausgeführt werden, sind im Report in den Abschnitten mit der Überschrift "Semantics" angegeben. Aktionen sind danach z.B. -
das Herstellen von Relationen zwischen Objekten (vgl. Band 1, 1.2.3,1.2.4, 1.2.5) - der Wert-Transput (vorgenommen z.B. bei der Abarbeitung einer assignation , vgl. Band 1, 1.3.1) — die Erzeugung von Variablen (vgl. Band 1, 3.4.1) — das Ausführen von "coercions" (vgl. Band 1 , 4 . 1 ) Aktionen bestehen ihrerseits aus weiteren Aktionen, ihren "direct actions". Eine Aktion ist entweder seriell ("serial") oder kollateral ("collateral") (vgl. R2.1.4.2, R2.1.4.3): a) Ist eine Aktion seriell, so werden ihre "direct actions" zeitlich nacheinander ausgeführt: erst nachdem eine "direct a c t i o n " vollständig beendet ("completed") ist, wird die nächste "direct a c t i o n " initiiert ("initiated"). Dabei wird eine serielle Aktion initiiert durch Initiierung ihrer ersten "direct action"; sie ist vollständig beendet, wenn ihre letzte "direct action" vollständig beendet ist. b) Ist eine Aktion kollateral, so werden ihre "direct actions" in irgendeiner, im Report nicht definierten zeitlichen Reihenfolge ausgeführt. Dabei wird eine kollaterale Aktion initüert durch gleichzeitige Initiierung aller ihrer "direct actions"; sie ist vollständig beendet, wenn alle ihre "direct actions" vollständig beendet sind. Die "elaboration" eines Konstruktes kann selbst als eine Aktion angesehen werden (obwohl sie i.a. aus mehreren Aktionen besteht, vgl. R2.1.4.2.d,f), man kann daher auch von serieller bzw. kollateraler "elaboration" sprechen (vgl. Band 1,1.3.5).
Teil IV Programm und Umgebung
9. Die Umgebung
9.1 Die Außenwelt eines Programms 9.1.1 Die peripheren Geräte Zum Verkehr mit der Außenwelt findet man an einer modernen Großrechenanlage die verschiedensten Geräte. Sie lassen sich grob einteilen in: a) Eingabegeräte, wie z. B. Lochkartenleser, Lochstreifenleser, Belegleser b) Aijsgabegeräte, wie z.B. Schnelldrucker, Lochkartenstanzer, Lochstreifenstanzer, Zeichengeräte c) Hintergrundspeicher, wie z.B. Magnetbandspeicher, Magnetplattenspeicher, Magnettrommelspeicher
Alle diese Geräte haben ihr eigenes Arbeitstempo, so daß die Übertragungsgeschwindigkeit von Gerät zu Gerät sehr verschieden sein kann: von den langsamen Geräten, wie z.B. Lochstreifenstanzer (50—100 Zeichen pro Sekunde), über schon recht schnelle Geräte, wie z.B. Lochkartenleser, Schnelldrucker (1000—3000 Zeichen pro Sekunde), bis hin zu den sehr schnellen Geräten, wie z.B. Magnetplatten-, Magnettrommelspeicher (einige Hunderttausend Zeichen pro Sekunde). Viele dieser Geräte arbeiten eng miteinander zusammen: z.B. können die von einem Lochkartenleser eingegebenen Daten an einen Magnetband- oder Magnetplattenspeicher weitergegeben werden;es können auch berechnete Daten von einem Magnetplattenspeicher zum Ausdrucken an einen Schnelldrucker übergeben werden. Diese enge Zusammenarbeit macht es erforderlich, die verschiedenen Arbeitsgeschwindigkeiten aufeinander abzustimmen.
9.1.2 Steuerungsprogramme Jedes einzelne Gerät hat außer seinem Arbeitstempo noch weitere Eigenschaften. So hat z.B. jedes Gerät neben seiner eigenen Codierung einen, ihm spezifischen Arbeitszyklus:
9. Die Umgebung
64
z.B. Lochkartenleser: Schnelldrucker:
Magnetplattenspeicher:
Zusammenfassung von z.B. 80 Zeichen zu einer Karte als Übertragungseinheit Zusammenfassung von z.B. 120 Zeichen zu einer Zeile als Übertragungseinheit; Seitenvorschub nach dem Ausdrucken von z.B. 60 Zeilen Positionierung des Lese/Schreibkopfes an eine angegebene Spur
Um mit diesen Eigenschaften fertig zu werden, hat jedes Gerät sein eigenes Steuerungsprogramm, das durch gewisse Teile des Betriebssystems ergänzt werden kann. Von diesen Steuerungsprogrammen weraen u.a. auch die notwendigen geräte-spezifischen Synchronisierungen vorgenommen. Dem Programmierer gegenüber liefern die Steuerungsprogramme insbesondere eine gewisse Vereinheitlichung der verschiedenen Geräte. In 9.3 werden wir hierüber noch eingehender sprechen. 9.1.3 Das Betriebssystem Eine wichtige Aufgabe des Betriebssystems ist es, sowohl die Abarbeitung der Benutzer- und Steuerungsprogramme als auch die Verwaltung des Speichers und der peripheren Geräte zu synchronisieren. Ein Programmierer verkehrt mit der Außenwelt stets über das Betriebssystem. In ALGOL68 hat der Programmierer auch die Möglichkeit, mit dem Betriebssystem selbst zu verkehren, so daß es für ihn eigentlich als Bestandteil der Außenwelt anzusehen ist. So hat man in ALGOL68 z.B. die Möglichkeit, in seinem Programm Dateien als Datenstrukturen zu verwenden oder bestimmte Anfragen über Ein-Ausgabegeräte an das Betriebssystem zu richten (ob z.B. bei einem bestimmten Gerät Lesen oder Schreiben erlaubt ist oder ob die Möglichkeit besteht, ein Magnetband zurückzuspulen). Für den ALGOL68-Programmierer ist also die Außenwelt nicht ein unantastbares abgeschlossenes System, sondern er hat sehr viele Möglichkeiten, von seinem Programm aus mit der Außenwelt in Verbindung zu treten.
65
9.2 Die Synchronisierung von Prozessen
9.2 Die Synchronisierung von Prozessen 9.2.1 "Serial", "collateral", "parallel" Aus dem 1. Band (vgl. 1.3.5) wissen wir, daß es in ALGOL68 zwei verschiedene Arten der Abarbeitung gibt: a) "serial elaboration" (serielle Abarbeitung): die zeitliche Ausfiihrungsfolge entspricht völlig der textlichen Reihenfolge (abgesehen von einem Sprung). Syntaktisch kommt die "serial elaboration" explizit in der serial-clause zum Ausdruck: phrasel ; phrase2 ; phrase3 ; . . . ; unitN b) "collateral elaboration" (kollaterale Abarbeitung): die zeitliche Ausführungsfolge ist in keiner Weise von der textlichen Reihenfolge her abzuleiten. Syntaktisch kommt die "collateral elaboration" explizit in der collateralclause zum Ausdruck: f u n i t l , unit2 , u n i t 3 , . . . ,
unitN^
Bei der kollateralen Abarbeitung kann man sich durchaus vorstellen, daß sich die ALGOL68-Maschine in mehrere Prozessoren trennt, die voneinander unabhängig die einzelnen units abarbeiten. Die Abarbeitung einer serial-clause ist beendet, wenn die Abarbeitung ihres letzten unit beendet ist; die Abarbeitung einer collateral-clause ist beendet, wenn alle ihre units bis zum Ende abgearbeitet sind. Bei der Abarbeitung einer serial-clause hat man alle möglichen Nebeneffekte jederzeit unter Kontrolle. Wenn dagegen die einzelnen units einer collateral-clause Nebeneffekte aufeinander ausüben sollten, so sind diese völlig Undefiniert (vgl. Band 1, Seite 47). Andererseits ergeben sich für die ALGOL68-Maschine bei der Abarbeitung einer collateral-clause Möglichkeiten der Optimierung: durch Abspalten gewisser Teilaktionen kann der Compiler einen effizienten Code fur die Ausführung herstellen; durch Trennung der ALGOL68-Maschine in mehrere Prozessoren können die einzelnen units gleichzeitig abgearbeitet werden. Wie wir im vorigen Abschnitt 9.1 gesehen haben, kommt es beim Verkehr mit der Außenwelt häufig vor, daß mehrere Prozessoren gleichzeitig arbeiten, sie jedoch dabei Nebeneffekte aufeinander ausüben. So z.B., wenn mehrere EinAusgabegeräte gleichzeitig arbeiten und dabei auf ein und denselben Puffer
9. Die Umgebung
66
zugreifen. In solchen Fällen muß dann das gleichzeitige Arbeiten der Prozessoren aufeinander abgestimmt (synchronisiert) werden. In ALGOL68 hat man hierfür die syntaktische Konstruktion der parallel-clause :
par funitl , unit2 , u n i t 3 , . . . ,
unitN^
Dabei wird die Synchronisierung der einzelnen units innerhalb der units selbst vorgenommen, vgl. 9.2.3. In 9.2.4 werden wir sehen, daß sowohl die serielle als auch die kollaterale Abarbeitung jeweils als Spezialfälle der Parallel-Verarbeitung angesehen werden können. 9.2.2 Der Begriff "semaphore" Die im vorigen Paragraphen angegebenen verschiedenen Arten der Abarbeitung können wir uns anhand eines Bildes aus dem täglichen Leben veranschaulichen: Man denke an den Straßenverkehr in einer Großstadt mit den verschiedenen Verkehrsteilnehmern sowie den Straßen, auf denen der Verkehr abläuft. Für die Planung des Straßenverkehrs könnte man sich theoretisch die beiden folgenden Verkehrsregelungen vorstellen: a) 'Serielle Verkehrsregelung' Die verschiedenen Verkehrsteilnehmer dürfen sich nur zeitlich nacheinander in den Straßenverkehr auf folgende Weise begeben: ein Verkehrsteilnehmer darf sich erst dann in Bewegung setzen, wenn der zeitlich vor ihm im Straßenverkehr sich befindende Verkehrsteilnehmer sein Ziel erreicht hat. Es dürfen also nicht zwei oder mehr Verkehrsteilnehmer gleichzeitig sich im Verkehr befinden. Insbesondere kann es nie vorkommen, daß ein Verkehrsteilnehmer einen anderen behindert; Unfälle sind also ausgeschlossen. b) 'Kollaterale Verkehrsregelung' Jeder Verkehrsteilnehmer benutzt stets eine solche Route, die von keinem anderen Verkehrsteilnehmer benutzt oder gekreuzt wird. So kann nie ein Verkehrsteilnehmer einen anderen behindern, auch dann nicht, wenn alle Verkehrsteilnehmer gleichzeitig sich im Verkehr befinden. Auch hier sind Unfälle ausgeschlossen. Die Realität sieht jedoch anders aus: Alle Verkehrsteilnehmer können gleichzeitig alle vorhandenen Straßen benutzen. Um dabei Kollisionen (unerwünschte Nebeneffekte) zu vermeiden, hat man Verkehrsregeln eingeführt, die den Ablauf des Verkehrs synchronisieren. So gibt es insbesondere Verkehrsampeln, deren Funktionsweise wir durch folgendes Bild darstellen können:
9.2 Die Synchionisierung von Prozessen
67
Solch eine Ampel nennt man auch "semaphore". Für die Beschreibung eines "semaphore" hat man in ALGOL68 einen eigenen "mode" zur Verfügung. Damit hat man dann die Möglichkeit, "semaphores" zu erzeugen, "semaphores" auf 'Rot' oder 'Grün' zu setzen sowie das Warten auf 'Grün' zum Ausdruck zu bringen.
9.2.3 sema, level, up und down Ein "semaphore" ist standardmäßig in RIO.2.4.a definiert durch mode sema = struct (ref int ¡ ^ Der int-Wert des "semaphore" ist stets > 0 , dabei gilt: int-Wert > 0 entspricht 'Giün' int-Wert = 0 entspricht 'Rot' Da der Programmierer den field-selector K nicht benutzen darf (vgl. Band 1, Seite 172,174), hat er keine Möglichkeit, das ref int-"field" auszuwählen. Dadurch wird der Programmierer daran gehindert, das "semaphore" auf 'illegale' Weise zu manipulieren. Um ein "semaphore" zu erzeugen und ihm gleichzeitig einen Anfangswert ('Rot' oder 'Grün') zu geben, haben wir den Operator level (vgl. R10.2.4.b): op level = (int a) sema ; (sema s ; N of s .= heap int .= a; sj Man beachte hierbei, wie der aktuelle int-Wert in ein im "heap" reserviertes "locale" transportiert wird, so daß seine Adresse während der Abarbeitung des gesamten Programms zur Verfügung steht.
9. Die Umgebung
68
Der Vollständigkeit halber sei hier angemerkt, daß es noch einen weiteren Operator level gibt, mit dessen Hilfe man das int-"field" eines "semaphore" erhält (vgl. R10.2.4.c): op level = fsema a) int : K of a Die einzig 'legale' Weise, ein bereits erzeugtes "semaphore" auf 'Rot' oder 'Grün' zu setzen, geschieht durch die Operatoren up und down , wobei man mit Hilfe von down auch das Warten auf 'Grün' zum Ausdruck bringt. Diese beiden Operatoren sind standardmäßig in R10.2.4 definiert. Der Operator down allerdings ist dabei auf eine Weise definiert, die nur für Eingeweihte verständlich ist (vgl. [20]). Wir können uns jedoch seine Bedeutung durch ein einfaches Flußdiagramm klar machen:
Operator down : C warte auf'Grün'; vermerke einen Durchgang durch Herabsetzen des Zählers um 1 C
K of sema -:= 1
Entsprechend haben wir für up : Operator up : C Erhöhung des Zählers um 1 mit dem Nebeneffekt: Ampel wird immer auf'Grün' gesetzt C Die "semaphores" kann man also als 'zählende' Ampeln auffassen: nach level n können genau n Prozesse über eine down-Operation die Ampel bei
69
9.2 Die Synchronisierung von Prozessen
'Grün' passieren; jede up-Operation gestattet einem weiteren Prozeß, die Ampel bei 'Grün' zu passieren. Solch eine zählende Ampel kann man sinnvoll einsetzen, um z.B. den Zuund Abgang eines Parkplatzes mit beschränkter Anzahl von Plätzen zu überwachen: Bei der erstmaligen Eröffnung des Parkplatzes wird die Ampel mit level anzahl der plätze initialisiert. Jeder einfahrende Pkw kann die Ampel nur über eine down-Operation passieren, jeder abfahrende Pkw verläßt den Parkplatz mit einer up-Operation. Man sieht leicht ein, so lange die Ampel 'Grün' zeigt, kann noch mindestens ein weiterer Pkw den Parkplatz benutzen. 9.2.4 Beispiele Beispiel 1: Kollaterale Abarbeitung als Spezialfall der Parallel-Verarbeitung sema sl = level par /'/'down sl; /"down s2; /'down s3;
1 , s2 = level 1 , s3 = level 1 ; unitl), unit2 / l, unit3j
); Die hierbei auftretende funitl , unit2,
parallel-clause
ist äquivalent mit der
collateral-clause:
unit3y
Die "semaphores" sind hier völlig überflüssig, da es nichts zu synchronisieren gibt. Interessanter ist das Beispiel 2: Serielle Abarbeitung als Spezialfall der Parallel-Verarbeitung sema sl = level 1 , s2 par ((down sl ; u n i t l ; /"down s2 ; unit2 ; /'down s3; u n i t 3 ;
= level 0, up s2) , up s3) , up sl)
s3 = level
0;
); Die hierbei auftretende
parallel-clause
clause : f u n i t l ; unit2 ; unit3 )
ist äquivalent mit der closed-serial-
70
9. Die Umgebung
Die Operation up si ist dann notwendig, wenn obige parallel-clause mehrmals abgearbeitet werden soll (z.B. in einer loop-clause). Beispiel 3: Ein nicht ganz so einfaches Beispiel für die Synchronisierung parallel ablaufender Prozesse mit Hilfe von "semaphores" stellt das folgende ProgrammStück dar. Es simuliert bei einem Bridge-Spiel den Vorgang des Bietens sowie dabei das simultane Denken der vier Spieler nach jedem Bieten. Hierbei beschränken wir uns auf den reinen Ablauf des Bietens und der Denkprozesse, gehen also nicht im einzelnen auf die Spielregeln und auch nicht auf die Denkprozesse selbst ein, sondern begnügen uns mit entsprechenden Kommentaren: mode suit = struct fstring card, ref suit next), hand = struct (suit clubs , diamonds , hearts , spades); mode bid = struct fstring bid, ref bid last, next); ref bid last bid := nil; mode guess = struct /'hand partner, left competitor, right competitor), tree = C a tree-structure suitable for backtracking C, mode player = struct /'hand cards, tree assumptions, bool turn, sema think); proc deal = (ref player recipient) void: C a card selected from a random-distribution is joined to the recipients hand C, [0 : 3] player player ; for i from 0 to 3 do turn of player [i] := false ; think of player [;] := level 0 od; to 13 do for i from 0 to 3 do deal (player [/y od od, proc update = (tree assumptions, hand given , bid heard) void : C by backtracking, the tree assumptions will be updated on the ground of the hand given and the bid heard C;
71
9.2 Die Synchronisierung von Prozessen
proc call = /"tree assumptions, hand given, bid heard) string : C on the ground of the updated assumptions tree, the hand given and the bid heard, the next bid will be joined to the list of bids and yielded as the result of the procedure C; proc pass = (ref bid bid) bool: if bid isnt nil then bid of bid = "no bid" else false fi; proc round pass = bool : pass (last bid) and pass (last of last bid) and pass (last of last of last bid) ; proc activate = (ait t) void ; (turn of player [f mod 4] := true; up think of player [t mod 4]; for i from t + 1 to t + 3 do turn of player [/ mod 4] := false; up think of player [/ mod 4] od
); proc thoughts and bids of player = fint i) void : do down think of player [/] ; update (assumptions of player [/], cards of player [/], last bid); if turn of player [/'] then if not round pass then print (call (assumptions of player cards of player [ i ] , last bid)
); activate (i + 1) else play begin fi fi od;
[/'],
9. Die Umgebung
72 activate
Rentier (random
par ( thoughts thoughts thoughts thoughts );
and and and and
bids bids bids bids
X 4j) ; of of of of
player (0), player (1), player (2), player (3)
Der Vorgang des Bietens ist also beendet, wenn nach dem Bieten eines Spielers die drei anderen Spieler passen. Sodann beginnt der eigentliche Spielvorgang, was in unserem Programm-Stück durch Sprung zum label play begin zum Ausdruck gebracht wird. Durch diesen Sprung wird die Abarbeitung der parallel-clause beendet. Dies bedeutet, daß die durch die "semaphores" synchronisierten Denkprozesse der vier Spieler beendet werden. Die Spieler haben sich sodann auf das Ausspielen der Karten zu konzentrieren. Das simultane Denken dabei könnte man ebenfalls mit Hilfe von "semaphores" beschreiben.
9.3 Die Struktuiierung der Umgebung
73
9.3 Die Strukturierung der Umgebung In R 10.3 wird der Transput (Ein-Ausgabe) in ALGOL68 anhand von Deklarationen für "modes", Operatoren, Prozeduren und Konstanten beschrieben. Dabei wird eine sehr detaillierte Beschreibung der Umgebung und der in ihr ablaufenden Vorgänge gegeben, die auch solche Informationen über das Betriebssystem und über die peripheren Geräte beinhaltet, die dem Programmierer nicht direkt zugänglich sein dürfen. Daher werden im Report bestimmte indicators mit einem 'f-' versehen, die dann für den Programmierer tabu sind, d.h. der Programmierer darf sie nicht in seinem Programm benutzen. Auch wir werden das 'f-' zu diesem Zweck benutzen. 9.3.1 Der "mode" book Ein "book" stellt eine Abstraktion der verschiedenen Ein-Ausgabemedien dar. Konkretisierungen eines "book" sind etwa: — ein Paket von Lochkarten, bestimmt zur Eingabe oder herstammend von der Ausgabe; — gedruckte Formulare, bestimmt als Eingabe für einen Belegleser oder herstammend von einem Schnelldrucker; — ein Magnetband, bestimmt zur Ein- und Ausgabe. In dieser Abstraktion findet man die für die Eingabe bestimmten bzw. die von der Ausgabe her stammenden Daten in einem aus chars bestehenden Text. Dieser Text erstreckt sich im "book" über mehrere Seiten; jede davon besteht aus mehreren Zeilen, die ihrerseits aus mehreren Zeichen (chars) bestehen. Dabei ist die Anzahl der Seiten, der Zeilen pro Seite und der Zeichen pro Zeile nicht fest vorgegeben, sondern vielmehr abhängig von der jeweiligen Information (flextext text). Innerhalb des Textes wird diejenige Stelle (Position), von der ein Zeichen gelesen bzw. an die ein Zeichen geschrieben werden kann, durch ein Tripel ip, l, c) gekennzeichnet. Dabei bedeutet: p = Seitennummer, l = Zeilennummer, c = Zeichennummer. Innerhalb eines " b o o k " ist stets die Position angegeben, bis zu der das "book" mit dem Text angefüllt ist. Diese Position wird als "logical end" Ipos bezeichnet. Jedes "book" hat einen Namen, gegeben durch einen string idf, der auch mehr als nur den Namen enthalten kann (z.B. den Namen des Besitzers, Passwort, etc.). Ein "book" kann von mehreren Benutzern (int users) gelesen werden, jedoch kann nur ein Benutzer in das "book" schreiben (bool putting).
9. Die Umgebung
74
Um alle "books" verwalten zu können, sind diese auf verschiedene Weise zu "backfiles" (bfile) miteinander verkettet. Das Lesen eines " b o o k " von verschiedenen Benutzern wird durch ein "semaphore" (sema f - b f i l e p r o t e c t ) synchronisiert (vgl. 9.2.2, 9.2.3). Zusammenfassend entnehmen wir dem Report (vgl. R10.3.1.1): mode mode mode mode
*text *flextext -?pos -%ook
= = = =
ref [ ] [ ] [ ] char; ref flex [ ] flex [ ] flex [ ] char, struct (int p, I, c); struct (flextext text, pos Ipos, string idf, bool putting, int users);
mode *bfile = struct (ref book book , ref bfile next) ; sema Qbfileprotect = C level 1 C ;
9.3.2 Der " m o d e " Channel So wie ein " b o o k " die Abstraktion eines Ein-Ausgabemediums ist, so stellt ein "channel" die Abstraktion eines oder mehrerer Ein-Ausgabegeräte dar. Es gibt also "Channels", die z.B. Lochkartenlesern, Lochkartenstanzern, Schnelldruckern, Magnetband-Geräten, etc. entsprechen. Die Möglichkeiten der EinAusgabe (z.B. Lesen, Schreiben, Zurückspulen) können sowohl vom Medium als auch vom Gerät selbst abhängig sein. So kann es z.B. für ein Magnetbandgerät, welches Magnetbänder lesen und beschreiben kann, ein Magnetband geben, das nur gelesen werden darf. Deswegen sind in einem "channel" fast alle Routinen zur Abfrage der verschiedenen Möglichkeiten nicht proc bools , sondern proc /ref book,/ bools. Der Aufruf dieser Routinen gibt also stets an, welche Möglichkeiten der EinAusgabe für ein mit dem "channel" verbundenes " b o o k " besteht. Aus dem Report (vgl. R10.3.1.2) entnehmen wir im einzelnen: mode channel = struct (proc (ref bookj bool freset, fset, ?get, *put, f-bin, f-compress, freidf, proc bool *estab, proc pos *maxpos, proc (ref book) conv fstandconv, int channel numberj;
9.3 Die Strukturierung der Umgebung
75
Hierbei bedeuten: freset = true 7*s et = true fget = true fput = true ?H)in = true ficompress = true
freidf
= true
festab
= true
fmaxpos
fistandconv ^channel
number
Zurücksetzen auf die Anfangsposition (1,1,1) ist möglich (z.B. Zurückspulen eines Magnetbandes) Setzen auf eine beliebige Position ist möglich (Möglichkeit des 'random access') Lesen ist möglich (Möglichkeit der Eingabe) Schreiben ist möglich (Möglichkeit der Ausgabe) Binärer Transput ist möglich (vgl. 10.3) Komprimierung des Textes bei der Ausgabe ist möglich (z.B. Unterdrückung von Leerzeichen); dies bedeutet, daß auf den Seiten (in den Zeilen) die Anzahl der Zeilen (Zeichen) verringert werden kann (man denke daran, der Text in einem "book" ist ein flextext) Änderung des string idf in einem "book" ist möglich;z.B. Umbenennung eines Magnetbandes. Die Erzeugung eines neuen (leeren) "book" zur Ausgabe ist möglich. Man beachte hierbei, daß estab = false sein kann, auch wenn put = true gilt, jedoch nicht umgekehrt. Gibt die größtmögliche Position, d.h. den größtmöglichen Umfang eines "book" für den "channel" an. Gibt die Konvertierungsroutine für den "channel" an Gestattet eine Numerierung des "channel"
Man beachte, daß alle diese field-selectors für den Benutzer tabu sind, er also keinen direkten Zugriff zu den einzelnen Routinen hat. Wie wir bald sehen werden, geschieht der Zugriff zu ihnen stets über andere Routinen, wie z.B. die Informationsroutinen (vgl. 9.4.2). Standardmäßig sind die drei folgenden "channels" definiert (vgl. R10.3.1.2.e, f.g): stand in Channel (Standard-Eingabe)
die Routine von get of stand in channel liefert als Ergebnis stets true
stand out channel (Standard-Ausgabe)
die Routine von put of stand out channel liefert als Ergebnis stets true
stand back channel (Standard-Hintergrundspeicher)
die durch set, reset, get, put, bin ausgewählten Routinen liefern als Ergebnis stets true
9. Die Umgebung
76
Die anderen "fields" dieser Standard-"channels" haben Werte, die von den Eigenschaften der Geräte abhängig sind. Entspricht z.B. stand in channel einem Lochkartenleser, standout channel einem Schnelldrucker und standback channel einem Plattenspeicher, so gibt die folgende Tabelle an, welche Werte einzelne field-selectors z.B. liefern können:
reset set get put bin compress reidf estab max pos standconv channel number
stand in channel stand out channel Lochkartenleser Schnelldrucker
stand back channel Plattenspeicher
false false true false false false false false (1, ?, 80)
true true true true true
?
false false false true false true false true (?, 60,120) ?
?
?
? ? ?
(1, 1, ?) ? ?
Hierbei deutet ? an, daß die entsprechenden Werte sehr stark von der jeweiligen Implementation abhängen. 9.3.3 Der "mode" file Will der Programmierer von seinem Programm aus über einen "Channel" ein bestimmtes "book" ansprechen, so möchte er dabei z.B. die folgenden Möglichkeiten haben: Angabe über das Format der Ein- und Ausgabe; Mitteilung, ob gelesen oder geschrieben, ob zeichenweise oder binär geschrieben bzw. gelesen werden kann; Abfrage nach der laufenden Position im Text des "book"; Angabe über den zur Verfügung stehenden Konvertierungsschlüssel. Darüber hinaus möchte der Programmierer eventuell in den Fällen, in denen unerwünschte Ereignisse eintreten (z.B. Schreiben oder Lesen außerhalb der Begrenzung eines "book"), die Möglichkeit haben, eigene Aktionen anzugeben. Alle diese Möglichkeiten sind zusammengefaßt in dem Begriff "file". Für die Ein-Ausgabe wird stets ein "book" über einen "channel" mit einem "file" verbunden. Somit ist für den Programmierer ein "file" das 'Interface', durch das er über den "channel" Zugriff zu dem angeschlossenen "book" hat.
9.3 Die Strukturierung der Umgebung
77
Aus dem Report (vgl. R10.3.1.3) entnehmen wir im einzelnen: mode file = struct (ref book fi>ook, union (flextext, text^ •fiext, channel -9chan, ref format *format, ref int f f o r p , ref bool fread mood, fwrite mood, fchar mood, *bin mood, fopened, ref pos fcpos, string fterm, conv fconv , proc (ref file,/ bool logical file mended, *physical file mended, •fpage mended, •Mine mended, fformat mended, fvahie error mended, proc (ref file, ref charj bool fchar error mended
); Hierbei bedeuten: fbook Hext fchan f'format fforp freadmood = true fwrite mood = true fcharmood = true fi)in mood = true fopened f-cpos
= true
Gibt das "book" an, welches mit dem file verbunden ist Gibt den Text (flextext oder text) des "book" an Gibt den "channel" an, über den das "book" mit dem file verbunden ist Gibt das laufende Format für den Transput an (vgl. 10.2.1) Gibt die laufende Stelle innerhalb des laufenden Formats an (vgl. 10.2.1) Das file wird zur Eingabe benutzt Das file wird zur Ausgabe benutzt Das file wird für einen zeichenweise vorgenommenen Transput benutzt Das file wird für einen binären Transput benutzt Das "book" ist mit dem file verbunden Gibt die laufende Position im Text des angeschlossenen "book" an (vgl. 9.4.3)
9. Die Umgebung
78
Herrn
fconv logical file mended
•^physical file mended
fpage mended
•Mine mended
fformat mended fvalue
error mended
fchar error mended
Gibt fur das file einen string an, dessen einzelne chars als Begrenzer ("terminator") bei der Eingabe von chars dienen Gibt den Konvertierungsschlüssel an Gibt eine Routine an, die aufgerufen wird, wenn bei der Eingabe die Position "logical end" erreicht ist Gibt eine Routine an, die aufgerufen wird, wenn beim Transput die laufende Seitennummer die Anzahl der Seiten im "book" überschreitet Gibt eine Routine an, die aufgerufen wird, wenn beim Transput die laufende Zeilennummer die Zeilenanzahl auf der laufenden Seite überschreitet Gibt eine Routine an, die aufgerufen wird, wenn beim Transput die laufende Zeichennummer die Anzahl der Zeichen in der laufenden Zeile überschreitet Gibt eine Routine an, die aufgerufen wird, wenn beim formatierten Transput fur den weiteren Transput kein Format mehr angegeben ist Gibt eine Routine an, die aufgerufen wird, wenn entweder beim formatierten Transput ein falsches Format angegeben ist oder wenn der Eingabe'string' nicht in einen Wert des angegebenen "mode" konvertiert werden kann Gibt eine Routine an, die aufgerufen wird, wenn eine Zeichen-Konvertierung ohne Erfolg blieb oder ein "unerwartetes" Zeichen gelesen wurde
Wie bei einem Channel sind auch bei einem file die einzelnen field-selectors für den Programmierer tabu, er hat also keinen direkten Zugriff zu den "fields". Diesen Zugriff erhält der Programmierer jedoch z.B. über die in 9.4.1, 9.4.2 und 9.4.4 angegebenen Routinen, mit deren Hilfe er auch einzelnen "fields" andere Werte geben kann.
9.3.4 Die Transput-"modes" Beim Transput können stets die amode-Werte, die man ausgibt, auch als amode-Werte wieder eingegeben werden. Jedoch Adressen und Routinen
9.3 Die Strukturierung der Umgebung
79
können nicht ausgegeben, somit auch nicht eingegeben werden. Wird dann doch ein ref amode bzw. proc amode vom Programmierer zur Ausgabe angeboten, wird auf diesen Wert so lange das "dereferencing" bzw. "deproceduring" angewendet, bis er in einen Wert übergeführt worden ist, der tatsächlich zur Ausgabe geeignet ist. Solch ein Wert ist stets ein outtype (vgl. R10.3.2.2.b): mode-?outtype = C ein actual-declarer, dereinen umon- 'mode" spezifiziert für eine genügend große Menge von "modes", von denen keiner void ist oder flex, ref, proc oder union enthält C Allerdings, in einem outtype können noch Strukturen und (ein- oder mehrdimensionale) Reihen enthalten sein. Daher wird auf einen outtype der Operator straightout angewendet, der ein outtype in eine lineare Reihe von simplouts überfuhrt (vgl. R10.3.2.3.a): op ^straightout = (outtype x) [] simplout : C das Ergebnis des "straightening" von x C Dabei ist (vgl. R10.3.2.2.a): mode ^simplout = union (L int, L real, L compl, bool, L bits, char, [ ]char j Durch L wird hierbei die Möglichkeit der verschiedenen long- bzw. shortVersionen gegeben (vgl. Band 1, 4.2.3). So steht z.B. L int für . . . , short short int, short int, int, long int, long long i n t , . . . Um bei der Eingabe von amode-Werten zum Ausdruck zu bringen, an welche Stelle innerhalb des Speichers (in welche "locales") die amodes transportiert werden sollen, ist der Eingabe-"mode" stets ein ref amode . Dabei kann amode entweder ein outtype oder ein string sein. Entsprechend diesen Werten haben wir den Eingabe-"mode" intype , definiert durch (vgl. RIO.3.2.2.d):
80
9. Die Umgebung mode -^intype = C ein actual-declarer, dereinen union-"mode" spezifiziert fir ref flex [ ] char und einer genügend großen Menge von "modes", die mit ref beginnen und kein flex, ref, proc oder union enthalten C
Wie wir gesehen haben, wird ein outtype , bevor er ausgegeben wird, durch den Operator straightout in ein [ ] simplout übergeführt. Entsprechend wird ein intype durch den Operator straightin in eine lineare Reihe von simplins übergeführt (vgl. R10.3.2.3.b): op -^straightin = ^intype x) [] simplin: C das Ergebnis des "straightening" C
von x
Dabei ist (vgl. R10.3.2.2.c): mode -isimplin = union (ref ref ref ref ref ref ref ref
L int, L real, L compl, bool, L bits, char, [ ] char, stringj
Durch L wird hier wieder die Möglichkeit der verschiedenen long- bzw. short-Versionen gegeben (vgl. die mode-declaratiori für simplout). Die Operatoren straightout und straightin sind durch den Prozeß "straightening" erklärt. Dieser Prozeß überfuhrt ein outtype (intype) in ein [] simplout ( [ ] simplin) auf folgende Weise: Es wird ein [] simplout ( [ ] simplin) erzeugt, dessen Elemente sich wie folgt ergeben: — bei Strukturen durch Selektion der "fields" in der textlichen Reihenfolge, — bei eindimensionalen Reihen durch Auswahl der Elemente von lwb bis upb , — bei mehrdimensionalen Reihen durch zeilenweise Auswahl der Elemente (der jeweils erste Index läuft am langsamsten). Sind dabei die Elemente der Reihen bzw. die "fields" der Strukturen selbst Reihen oder Strukturen, so wird auf sie ebenfalls das "straightening" angewendet.
81
9.3 Die Strukturierung der Umgebung
Um das "straightening" braucht der Programmierer sich nicht zu kümmern, es wird beim Transput stets automatisch vorgenommen. Haben wir z.B. deklariert [0:m, 0:n] compl mat ; so können wir z.B. ohne Schwierigkeiten schreiben print (( "example of straightening:",
mat))
Wir werden bald sehen (vgl. 10.1.3, 10.1.4), daß print (read) als Parameter u.a. sogar ein [] outtype ([] intype) akzeptiert. Es wird dann das "straightening" auf jedes einzelne outtype (intype) angewendet. Im obigen Beispiel wird also die Matrix von mat zeilenweise ausgegeben, wobei auf jedes einzelne Element (compl) noch einmal das "straightening" angewendet wird. Hat man jedoch z. B. man henry8; woman anna boleyn ; wife of henry8 := anna boleyn ; husband of anna boleyn := henry8;
(vgl. Band 1, Seite 24)
so darf man nicht print ((anna boleyn,
henry8))
schreiben; denn ein outtype kann weder ein woman noch ein man sein (sie enthalten beide ein ref). Würde man obigen pn/ii-Aufruf zulassen, so würde die Ausgabe in eine Endlos-Schleife geraten. Das wäre auch gut so; denn selbst die Ehe zwischen henry8 und anna boleyn ließ sich nicht einfach durch einen Aufruf von print wieder trennen.
9. Die Umgebung
82
9.4 Die Verwaltung der Umgebung Im vorigen Abschnitt 9.3 haben wir in aller Ausführlichkeit "books", "Channels" und "files" behandelt. Dabei haben wir festgestellt, daß für den Benutzer zwar die "modes" Channel und f i l e zur Verfügung stehen, jedoch nicht die einzelnen "fields" und auch nicht der "mode" book. Der Programmierer kann jedoch diese Objekte mit Hilfe von bestimmten Routinen manipulieren. Wir haben diese Routinen nach Art und Zweck in Verwaltungs-, Informations-, Layout- und Ereignisroutinen eingeteilt. Bei Aufruf dieser Routinen (und noch weiterer Transput-Routinen, vgl. Kapitel 10) können unter Umständen Ereignisse eintreten, die zu Aktionen führen, welche implementationsabhängig sind und durch den Report nicht weiter beschrieben werden können. Dies ist z.B. bei dem Aufruf der Routine von undefined der Fall. Durch diesen Aufruf wird eine, von der Implementation abhängige und dem Ereignis entsprechende Aktion ausgeführt. Von welcher Art diese Aktion ist, wird durch ein int mitgeteilt, der stets beim Aufruf der Routine als Ergebnis geliefert wird. Wir haben also (vgl. R10.3.1.4.a): proc fundefined
= int ; C eine 'vernünftige'System-Aktion, die als Ergebnis ein int liefert, um anzudeuten, was getan wurde.
9.4.1 Verwaltungsroutinen Aus 9.3 wissen wir, daß "books", "Channels" und " f i l e s " über entsprechende "fields" sehr eng miteinander verbunden sind. Durch die Verwaltungsroutinen wird diese Verbindung hergestellt bzw. wieder unterbrochen. identifier
"mode"
Effekt
establish
proc (ref f i l e ,
Es wird ein neues "book" erzeugt, dessen maximale Größe durch die drei ints und dessen idf (vgl. 9.3.1) durch den gegebenen string festgelegt wird.
string, channel, int, int
i n t , int;
Dabei wird dieses "book" über den gegebenen Channel mit dem gegebenen file verbunden, d.h. alle relevanten Verwaltungsin-
9.4 Die Verwaltung der Umgebung
identifier
"mode"
83
Effekt formationen werden in dem file festgelegt. Insbesondere wird das opened-"i\ield" auf true gesetzt, wodurch das file für dieses "book" an dem gegebenen channel eröffnet wurde. Dieses neu erzeugte "book" ist in erster Linie zur Ausgabe geeignet. Vgl. R10.3.1.4.b.
create
proc (ref file, channel,/ int
Es wird establish aufgerufen. Dabei wird ein "book" erzeugt, dessen maximale Größe durch den channel bestimmt und dessen idf unbestimmt ist. Vgl. R10.3.1.4.C.
open
proc (ref file, string, channel^ int
Es wird die Kette der "backfiles" (vgl. 9.3.1) nach einem "book" durchsucht, dessen idf gleich dem gegebenen string ist. Für dieses "book" wird das file an dem gegebenen channel eröffnet. Vgl. R10.3.1.4.d.
Alle drei obigen Routinen liefern als Ergebnis Null, wenn sie erfolgreich abgelaufen sind, sonst den Wert von undefined (vgl. zu Beginn dieses Kapitels 9.4). associate
proc ( ref file, ref [ ] [ ] [ ] char) void
Es wird ein []char bzw. [][]char (durch "rowing") oder ein [][][]char im Hauptspeicher als ein "book" aufgefaßt, welches über einer, fiktiven "channel" mit dem gegebenen file verbunden wird. Man hat
84 identifier
9. Die Umgebung
"mode"
Effekt so für dieses sich im Hauptspeicher befindende "book" alle Transput-Möglichkeiten, insbesondere die Möglichkeit der Konvertierung. Vgl. R10.3.1.4.e.
close
proc ( ref file,/ void
Die Verbindung zwischen dem "book" und dem gegebenen file wird unterbrochen. Die Information des "book" bleibt erhalten, das "book" selbst wird in die Kette der "backfiles" eingehängt. Jederzeit kann für dieses "book" ein neues "file" eröffnet werden. Vgl. R10.3.1.4.n.
lock
proc (ref filej void
Wie bei close , jedoch kann für das abgetrennte "book" kein neues "file" (ohne Eingriff des Betriebssystems) eröffnet werden. Vgl. R10.3.1.4.0.
scratch
proc (KÌ file,! void
Das abgetrennte "book" wird aufgegeben, alle Information wird gelöscht. Vgl. R10.3.1.4.p.
9.4.2 Informationsroutinen Ist ein "file" für ein "book" an einem "channel" eröffnet worden, so kann der Benutzer die für ihn relevante Information aus dem "file" und über das "file" aus dem "channel" und aus dem "book" mit Hilfe der folgenden Routinen erhalten. Dabei liefern einige Routinen die benötigte Information aus dem "channel" auch ohne Kenntnis des "file".
9.4 Die Verwaltung der Umgebung
85
Effekt
identifier
"mode"
char
number
proc (tti int
file,/
Liefert die Zeichennummer der laufenden Position (vgl. 9.4.3). Vgl. RIO.3.1.5.
line
number
proc fref file,/ int
Liefert die Zeilennummer der laufenden Position (vgl. 9.4.3). Vgl. R10.3.1.5.
proc (tti int
Liefert die Seitennummer der laufenden Position (vgl. 9.4.3). Vgl. RIO.3.1.5.
page
number
filej
get
possible
proc (rtf fileJ bool
Liefert true , wenn das file zur Eingabe benutzt werden kann. Vgl. R10.3.1.3.b.
put
possible
proc (ref file,/ bool
Liefert true , wenn das file zur Angabe benutzt werden kann. Vgl. R10.3.1.3.C
bin possible
proc (ref filej bool
Liefert true , wenn das file für binären Transput benutzt werden kann. Vgl. R10.3.1.3.d.
compressible
proc (ref file^ bool
Liefert true , wenn der Text des "book" bei der Ausgabe komprimiert werden kann (vgl. 9.3.2). Vgl. R10.3.1.3.e.
reset
proc fref file^ bool
Liefert true , wenn man auf die Anfangsposition (1,1,1) zurücksetzen kann ('rewind', vgl. 9.3.2). Vgl. R10.3.1.3.f.
proc (tcf file,/ bool
Liefert true , wenn man auf eine beliebige Position setzen kann ('random access', vgl. 9.3.2). Vgl. R10.3.1.3.g.
possible
set possible
9. Die Umgebung
86
identifier
"mode"
Effekt
reidf possible
proc (rei fileni bool
Liefert true , wenn man das idf-"field" in dem "book" ändern kann (vgl. 9.3.1,9.3.2). Vgl. R10.3.1.3.h.
reìdf
proc (rtf file, string^ void
Ändert das /¿/-"field" des "book" durch den gegebenen string (vgl. 9.3.1, 9.3.2). Vgl. RIO.3.1.3.s.
chart
proc (ref file,/ channel
Liefert den Channel, an dem das file eröffnet wurde. Vgl. R10.3.1.3.i.
proc ( ref file, st ring/ void
Für das file wird durch den gegebenen string ein Begrenzungs-'string' ("terminator") angegeben (vgl. 9.3.3). Vgl. R10.3.1.3.k.
make
term
make conv
proc ( ref file, In dem file wird das convproc /'ref book ) conv,/ "field" durch einen anderen Konvertierungsschlüssel void (wenn in der libraryprelude vorhanden) geändert (vgl. 9.3.3). Vgl. R10.3.1.3.j.
stand conv
proc ( channel,/ proc /'ref book,/ conv
Liefert den 'default'-Konvertierungsschlüssel des Channel. Vgl. R10.3.1.2.d.
estab possible
proc f channel,/ bool
Liefert true , wenn an dem gegebenen Channel ein (weiteres) "book" durch Aufruf von establish (vgl. 9.4.1) erzeugt werden kann. Vgl. R.10.3.1.2.C.
87
9.4 Die Verwaltung der Umgebung
9.4.3 Layoutroutinen Aus 9.3.3 wissen wir, daß innerhalb eines "file", eröffnet für ein "book" an einem "channel", ein Zeiger auf die laufende (Lese/Schreib-) Position (cpos) innerhalb des "book" vorhanden ist. Sind mehrere "files" für ein und dasselbe "book" eröffnet, so existieren also mehrere solche Zeiger für das "book". Die 'laufende Position' gibt die Stelle innerhalb des Textes eines "book" an, an die das nächste Zeichen geschrieben bzw. von der das nächste Zeichen gelesen werden kann (vgl. 9.3.1). Sie wird bei jeder Transput-Operation entsprechend um die Anzahl der geschriebenen bzw. gelesenen Zeichen erhöht. Mit Hilfe der in 9.4.2 angegebenen Prozeduren char number , lirte number und page number kann der Benutzer die laufende Position abfragen. Durch die Layoutroutinen hat der Programmierer die Möglichkeit, die laufende Position zu ändern, ohne dabei den Inhalt des Textes zu ändern. Dabei kann es passieren, daß die laufende Position bei der Eingabe über das "logical end" (Ipos) bzw. bei der Ausgabe über die maximale Größe des "book" (vgl. 9.4.1 establish , create) hinaus gerät, sie somit ungültig wird. Desweiteren bringt es der flextext des "book" mit sich (insbesondere, wenn der Text des "book" komprimiert werden kann, vgl. 9.3.2), daß die laufende Position auch auf andere Weise ungültig werden kann. Im Falle einer ungültigen Position werden, falls definiert, die entsprechenden Ereignisroutinen (vgl. 9.4.4) aufgerufen, ansonsten wird versucht, durch newline bzw. newpage (s. unten) eine gültige Position herzustellen ("good position", vgl. R10.3.1.6.cc). Gelingt dies nicht, so wird undefined aufgerufen (vgl. zu Beginn von 9.4). identifier
"mode"
Effekt
space
proc (ref fileJ void
Bei Eingabe: Die Zeichennummer der laufenden Position wird um 1 erhöht; falls nötig, wird newline aufgerufen. Bei Ausgabe : Wenn bei der laufenden Position schon etwas steht, wird die Zeichennummer um 1 erhöht, wenn nicht, wird zusätzlich ein 'blank' ausgegeben. Falls nötig, wird in beiden Fällen newline aufgerufen.
88
9. Die Umgebung
"mode"
identifier
Effekt Man beachte, daß print (("a", backspace, und print (("a", backspace, space)) unterschiedlichen Effekt haben. Vgl. R10.3.1.6.a. Die Zeichennummer der laufenden Position wird um 1 erniedrigt, jedoch wird nur bis zum Zeilenanfang zurückgesetzt. Vgl. R10.3.1.6.b.
backspace
proc f'ref file,/ void
newline
proc (tef file,/ void
Die laufende Position wird auf den Anfang der nächsten Zeile gesetzt; falls nötig, wird newpage aufgerufen. Vgl. R10.3.1.6.C.
newpage
proc (ref file,/ void
Die laufende Position wird auf den Anfang der nächsten Seite (Zeile 1, Zeichen 1) gesetzt. Vgl. R10.3.1.6.d.
set
proc (ref file , i n t , i n t , int,/ void
reset
proc (ref file,/ void
Die laufende Position wird auf die durch die drei ints angegebene gesetzt, vorausgesetzt, sie liegt nicht außerhalb des "logical e n d " und set possible liefert true (vgl. 9.4.2). Vgl. RIO.3.1.6.i Die laufende Position wird auf die Anfangsposition (1, 1, 1) gesetzt, vorausgesetzt, reset possible liefert true (vgl. 9.4.2). Vgl. R10.3.1.6.j.
set char
number
proc (ref file , int; void
Die laufende Position wird in der laufenden Zeile auf das durch das int bestimmte Zeichen gesetzt (durch space bzw. backspace). Vgl. R10.3.1.6.k.
89
9.4 Die Verwaltung der Umgebung
9.4.4 Ereignisroutinen In 9.3.3 haben wir gesehen, daß ein "file" eine Anzahl von Ereignisroutinen enthält, die aufgerufen werden, wenn während des Transput unerwünschte Ereignisse eintreten (z.B. Erreichen eines Seitenendes, Schreiben oder Lesen außerhalb der Begrenzung eines "book"). Wenn ein "file" für ein "book" an einem "channel" eröffnet wurde, so enthält das "file" 'by default' Ereignisroutinen, die stets bei ihrem Aufruf false liefern. Der Programmierer hat jedoch die Möglichkeit, mit Hilfe der folgenden "on"-Routinen eigene Ereignisroutinen anzugeben, also die entsprechenden "fields" im "file" zu ändern. Tritt dann ein unerwünschtes Ereignis ein, so passiert folgendes: Die gerade stattfindende Transput-Routine wird unterbrochen und die entsprechende Ereignisroutine wird aufgerufen. Dabei gilt: a) Die Ereignisroutine liefert false . Es wird eine 'default'-Aktion ausgeführt. Z.B. Aufruf von newline bei Zeilenende, Aufruf von newpage bei Seitenende (vgl. 9.4.3). Oft wird jedoch undefined aufgerufen (vgl. zu Beginn von 9.4). b) Die Ereignisroutine liefert true . Die Ereignisroutine meldet hierdurch, daß die unerwünschte Situation bereinigt wurde. Wenn möglich, wird dann die unterbrochene Transput-Routine fortgesetzt. Man beachte (vgl. R10.3.1.3.1— r), wie durch eine "on"-Routine das entsprechende Ereignis-"field" im "file" durch Zuweisung die vom Programmierer angegebene Routine erhält. Auch bei dieser Zuweisung müssen die "scope"Regeln beachtet werden (vgl. 8.2.1): es darf der "scope" der vom Programmierer angegebenen Routine nicht kleiner sein als der "scope" des "file" (vgl. dazu das Beispiel in R10.3.1.3.cc). on -Prozedur
Die entspr. Ereignisroutine wird aufgerufen:
proc on logical file end = fref file / , proc (ref file,) bool p) void: logical file mended of f:=p ;
Bei Eingabe oder durch Aufruf der Prozedur set (vgl. 9.4.3) wurde das "logical end" im "book" überschritten.
proc on physical file end = fref file / , proc (ref file,/ bool p) void : physical file mended of f:=p ;
Beim Transput überschreitet die laufende Seitennummer die zulässige Anzahl (vgl. establish , create in 9.4.1).
90
9. Die Umgebung
"on" -Prozedur
Die entspr. Ereignisroutine wird aufgerufen:
proc on page end = fref file / , proc fref fileJ bool p) void. page mended of f:=p ;
Beim Transput überschreitet die laufende Zeilennummer die Zeilenanzahl auf der laufenden Seite.
proc on line end = fref file / , proc fref fileJ bool p) void : line mended of f:=p ;
Beim Transput überschreitet die laufende Zeichennummer die Anzahl der Zeichen in der laufenden Zeile.
proc on format end = fref file f , proc fref fileJ bool p) void : format mended of f:=p ;
Beim formatierten Transput (vgl. 10.2.2) ist für den weiteren Transput kein Format mehr angegeben. Liefert die Ereignisroutine true , so wird, falls kein neues format durch die Routine zur Verfügung gestellt wurde, undefined (vgl. zu Beginn von 9.4) aufgerufen; anderenfalls wird das laufende format wiederholt.
proc on value error = fref file f , proc fref file,/ bool p) void ; value error mended of /:=p ;
a) Beim formatierten Transput wurde ein falsches Format angegeben (vgl. 10.2.5). b) Der Eingabe-'string' konnte nicht in den angegebenen "mode" konvertiert werden (z.B. wenn ein int größer als max int gelesen werden soll).
proc on char error = fref file / , procfref file,ref charybool p) void : char error mended of f:=p ;
Bei der Eingabe blieb eine Zeichenkonvertierung ohne Erfolg, oder es wurde ein 'unerwartetes' Zeichen gelesen. Was hierbei ein 'unerwartetes' Zeichen ist und wie man es 'reparieren' kann, wird in 10.2.6 erklärt.
9.4 Die Verwaltung der Umgebung
91
9.4.5 Die Standard-'Tiles" Jedem Benutzer stehen in seiner particular-prelude (vgl. 7.4.4) drei Standard'Tiles" zur Verfügung (vgl. R10.5.1.c): file stand in, stand out,
stand
back;
Sie werden in der particular-prelude eröffnet durch: open (stand in, "", stand in channel); open (stand out, "", stand out channel) ; open (stand back, "", stand back channel) ; (Für die Standard-"channels" vgl. 9.3.2) Nach Abarbeitung seines Programms (evtl. durch einen jump zum label stop:) werden in seiner particular-postlude (vgl. 7.4.5) die drei Standard'Tiles" wieder geschlossen durch (vgl. R10.5.2.a): stop:
lock (stand in); lock (stand out);
lock (stand
back)
10. Ein-Ausgabe (Transput)
Im Report werden Ein- und Ausgabe zu dem Begriff Transput zusammengefaßt. Bisher (vgl. 9.3, 9.4) sind wir stets davon ausgegangen, daß beim Transput ein internes (maschinenabhängiges) Bit-Muster in einen text (Folge von chars) bzw. ein text in ein Bit-Muster umgewandelt wird. Wir wollen deswegen vom "character"-Transput sprechen. Diese zeichenweise vorgenommene Ein- und Ausgabe kann insbesondere bei den Standard-"files" stand in und stand out benutzt werden. Für die dabei vorgenommenen Konvertierungen gibt es Konvertierungsroutinen (vgl. 10.1.2), die jedoch i.a. recht zeitaufwendig und meistens mit Genauigkeitsverlusten verbunden sind. Will der Programmierer nur interne Umspeicherungen von Daten (z.B. vom Hauptspeicher auf Magnetband oder -platte) vornehmen, ist er also an der Lesbarkeit der Daten nicht interessiert, kann er sich die aufwendigen Konvertierungen ersparen, indem er den binären Transput benutzt. Dabei wird von einem Speichermedium ein Bit-Muster in ein entsprechendes Bit-Muster eines anderen Speichermediums übertragen. Solch ein binärer Transput wird z.B. bei dem Standard-"file" stand back vorgenommen. Wir werden in 10.3 über den binären Transput sprechen, wollen uns jedoch zunächst ausführlicher mit dem "character"-Transput beschäftigen.
10.1 Unformatierter Transput
93
10.1 Unformatierter Transput 10.1.1 Format-Texte und Standard-Formate Unter Konvertierung verstehen wir die Umwandlung eines Bit-Musters in einen text bzw. eines text in ein Bit-Muster, die bei dem ' character"Transput vorgenommen wird. Bei dieser Konvertierung möchte der Programmierer eine Vielzahl von Wünschen berücksichtigt wissen. So möchte er vielleicht das dem int 153307 entsprechende Bit-Muster auf verschiedene Weise ausgedruckt haben, z.B. 15 h 3 3 ' 0 7 " dm 1533.07 153 307
*)
Umgekehrt möchte er dann sicher auch jede dieser drei Zeichenfolgen wieder in ein Bit-Muster umgewandelt haben, welches dem int 153307 entspricht. Um derartige Wünsche zu erfüllen, stehen dem Programmierer Format-Texte (format-texts) zur Verfügung, mit deren Hilfe er die Konvertierung bis in das letzte Detail selbst bestimmen kann. Die Angabe eigener Format-Texte ist bei der Benutzung des formatierten Transput möglich (vgl. 10.2). Ist der Programmierer jedoch nicht an einer detaillierten Ein-Ausgabe interessiert, kann er auf die Angabe von Format-Texten verzichten, indem er den unformatierten Transput benutzt. Beim unformatierten Transput werden standardmäßige Format-Texte verwendet, die ein bestimmtes StandardFormat der Zeichenfolgen bei der Ein- und Ausgabe voraussetzen. Bei der Eingabe von Zahlen (int, real, compl) entspricht das StandardFormat den üblichen Zeichenfolgen, wie z.B. int : 37 , +37 , +0037 , 037 real : 3 . 1 4 , +3.14, +003.14, 3 1 4 e - 2 , 0.00314e+3 compl : 3.14 ¡2.71 , + 3 1 4 e - 2 i+0.00271e+3 Dabei werden die verschiedenen Zeichenfolgen bei der Eingabe umgewandelt in ein Bit-Muster, welches der ganzen Zahl 37 bzw. der reellen Zahl 3.14 bzw. der komplexen Zahl 3.14 + i 2.71 entspricht. Bei der Ausgabe wird die durch die Umwandlung erzeugte Zeichenfolge im Standard-Format stets in derselben Weise ausgegeben: z.B. werden bei der *) Um die einzelnen Zeichen, die ein- bzw. ausgegeben werden, deutlich voneinander zu unterscheiden, setzen wir hier und im folgenden Ein- Ausgabegeräte voraus, die sowohl Groß- als auch Klein-Buchstaben einlesen bzw. ausgeben können.
94
10. Ein-Ausgabe (Transput)
Ausgabe von ints führende Nullen durch 'blanks' ersetzt (bei der Zahl 0 natürlich nur bis auf die 0 selbst) und das Vorzeichen mit ausgegeben, also z.B. + 37 , - 4 7 1 1 Wie im einzelnen die Standard-Formate beim unformatierten Transput aussehen, erfahren wir in 10.1.3 und 10.1.4. Bei Verwendung des unformatierten Transput gibt es für die Ausgabe einige spezielle Konvertierungsroutinen (vgl. den nächsten Paragraphen 10.1.2), mit deren Hilfe man die Standard-Formate abändern kann, um so ein wenig den 'layout' zu bestimmen. 10.1.2 Konvertierungsroutinen In R10.3.2.1 sind drei spezielle Konvertierungsroutinen whole, fixed und float definiert, mit deren Hilfe der Programmierer ein wenig den 'layout' bei der unformatierten Ausgabe steuern kann. Wir haben sie schon in Band 1, Seite 39,40 kennengelernt, jedoch hat sich ihre Bedeutung kurz vor Erscheinen des Revised Report etwas geändert, worauf wir gleich zu sprechen kommen. Ein Aufruf dieser Routinen bewirkt stets eine Umwandlung eines number in einen string , der die gewünschte Zeichenfolge angibt. Dabei ist number definiert als die Vereinigung (union) von int und real sowie deren möglichen short- und long-Versionen (vgl. R10.3.2.1 .a): mode -^number = union fL real, L int^ (durch L wird die Möglichkeit der verschiedenen short- bzw. long-Versionen gegeben; vgl. 9.3.4; Band 1,4.2.3) Jede dieser drei Routinen hat einen int-Parameter width , dessen absoluter Betrag die Länge des string angibt, in den der number umgewandelt werden soll. Ist dabei die Umwandlung in einen string der durch width geforderten Länge nicht möglich (z.B. wenn ein int aus mehr Ziffern besteht als die Länge von width angibt), so wird ein string , bestehend aus einer durch ,width bestimmten Anzahl von Fehlerzeichen erzeugt. Das dabei auftretende Fehlerzeichen wird bestimmt durch die in der standard-prelude in R10.2.1.t definierte char-Konstante error char : char error char = C das char, welches zur Darstellung von arithmetischen Werten benutzt wird, die beim Transput nicht konvertierbar sind C
10.1 Unformatierter Transput
95
Der Wert von error char ist implementationsabhängig, kann z.B. "#" sein. Bei der Umwandlung eines number durch die Konvertierungsroutinen gilt stets folgendes: Führende Nullen werden durch 'blanks' ersetzt. Gilt width >0 , so werden sowohl '+' als auch ' - ' als Vorzeichen eingefügt (stellt den Normalfall dar). Gilt width i£?//z-Parameter gegenüber dem in Band 1, Seite 40 Gesagten geändert hat: es sind dort a) und b) zu vertauschen. Wird dann ein Aufruf einer der Konvertierungsroutinen als aktueller Parameter der pwif-Prozedur (vgl. 10.1.3) übergeben, so wird die gewünschte Zeichenfolge (also der string) ausgegeben. Wir wollen die Bedeutung der drei Routinen anhand einiger Beispiele aufzeigen: Zu whole (vgl. R10.3.2.1.b): Durch Aufruf von whole wird ein number stets in einen string zur ZiffernDarstellung einer ganzen Zahl umgewandelt. Ist dabei ein number ein real, so wird nur der ganzzahlige Anteil konvertiert. Beispiele: a) print (whole (i, 5)) Je nach Wert von i wird hierdurch ausgegeben: "+4711", "
-99","
+0", "-1000" ;
*)
ist i=3.14 , so wird ausgegeben: "
+3" ;
ist i> 99999, "#****"
so wird ausgegeben: ("*" ist der Wert von error char)
*) Man beachte hier und im folgenden, daß die Anführungszeichen nicht mit ausgegeben werden, sie dienen nur als Begrenzungszeichen für die auszugebenden Zeichenfolgen.
96
10. Ein-Ausgabe (Transput)
b) print (whole (i,
-5jj
Je nach Wert von i wird hierdurch ausgegeben: "4711","
-99","
0","-1000"
c) print (whole (i, 0)) Je nach Wert von i wird hierdurch ausgegeben: "4711", " - 9 9 " , " 0 " , "-1000", "99999999" Zu fixed (vgl. R10.3.2.1.c): Durch Aufruf von fixed wird ein number stets in einen string zur Dezimalpunkt-Darstellung einer reellen Zahl umgewandelt. Ist dabei ein number ein int, so wird dieses zunächst durch das "widening" in einen real übergeführt. Die Prozedur fixed hat noch einen dritten int-Parameter after , der jeweils die Anzahl der Stellen nach dem Dezimalpunkt angibt. Beispiele: a) print (fixed (x , 8,
3))
Je nach Wert von x wird hierdurch ausgegeben: "
+3.141","
-2.718" , "+133.123" , "+1331.23" , "-13312.3"
(in den letzten beiden Fällen wurde der Wert von after verringert, um die Zahl noch darstellen zu können); ist jedoch x>l 000000 , so wird ausgegeben: a* * * * * * * * " b) print (fixed (x , -8, 3)) Je nach Wert von x wird hierdurch ausgegeben: " 3.141", " "13312.38"
-2.718", " 133.123", "1331.238", "-13312.3",
(in den letzten beiden Fällen wurde der Wert von after verringert, um die Zahl noch darstellen zu können); ist jedoch x>l 0000000 , so wird ausgegeben: a* * * * * * * * a c) print (fixed (x , 0, 3)) Je nach Wert von x wird ausgegeben: "3.141", "-2.718" , "133.123", "1331.238", "-13312.384" , "999999999.999"
10.1 Unformatierter Transput
97
Zu float (vgl. R10.3.2.1.d): Durch Aufruf von float wirdein number stets in einen string zur Dezimalpunkt-Darstellung mit Exponententeil einer reellen Zahl umgewandelt. Ist dabei ein number ein int, so wird dieses zunächst durch das "widening" in einen real übergeführt. Die Prozedur float hat noch einen vierten int-Parameter exp , der die Länge des Exponenten angibt. Dabei werden führende Nullen durch 'blanks' ersetzt. Bezüglich des Exponententeils hat exp die Bedeutung wie sie width für die ganzzahlige Darstellung hat. Beispiele: a) print (float (x , 10, 3 , 2j) Je nach Wert von x wird hierdurch ausgegeben: " -3.141e+0" , "+31.415e-5" , "-31.41e+10" (im letzten Fall wurde der Wert von after verringert, um die Zahl mit dem unerwartet hohen Exponenten noch darstellen zu können) b) print (float (x , -10, 3, -2)) Je nach Wert von x wird hierdurch ausgegeben: " -3.141e 0 " , " 31.415e-5" , "-31.415e10" , " - 3 1 . 4 1 e - 1 0 " (im letzten Fall wurde der Wert von after verringert, um die Zahl mit dem unerwartet kleinen Exponenten noch darstellen zu können). Man beachte, daß bei allen drei Routinen der width-Parameter (wenn er *0 ist) stets die Länge des erzeugten string angibt, unabhängig davon, welche Werte die beiden anderen Parameter after und exp haben, ja sogar unabhängig davon, ob der number auf die geforderte Weise konvertierbar ist oder nicht. 10.1.3 Unformatierte Ausgabe In R10.3.3.1.a ist die eigentliche Prozedur put für die unformatierte Ausgabe definiert. Der "mode" ihrer Routine ist: proc (ref file, []union /'outtype, proc (ref file^ void^ void Die Prozedur put hat also zwei Parameter: Der erste Parameter gibt das file an, über das die Ausgabe vorgenommen wird. Mit dem (aktuellen) file ist dann angegeben, über welchen "Channel" in welches "book" geschrieben wird, vorausgesetzt das file wurde an
10. Ein-Ausgabe (Transput)
98
einem "channel" für ein "book" eröffnet (vgl. 9.4.1). Ob diese erfüllt ist, wird zu Beginn von der Routine von put überprüft. Fall, werden durch die Routine in dem file die "fields" write char mood auf true gesetzt (vgl. 9.3.3). Der zweite Parameter ist eine Reihe, deren Elemente entweder (vgl. 9.3.4) oder ein proc (ref file) void sind.
Voraussetzung Ist dies der mood und ein outtype
Z.B. können wir schreiben: put (standout,
(" this is output" , 3.14, newline, "we are now on a new line"))
In diesem Beispiel wird die Ausgabe über das Standard-"file" standout vorgenommen (vgl. 9.4.5). Dabei besteht die auszugebende Reihe aus einem string, einem real, einem proc (ref file,) void und einem string. Von der Routine von put werden die einzelnen Elemente der Reihe nacheinander bearbeitet, dabei wird entweder ein outtype bearbeitet oder eine Routine vom "mode" proc /"ref file) void aufgerufen. Solch eine Routine kann z.B. eine der in 9.4.3 angegebenen Layoutroutinen sein. Zu Beginn der Bearbeitung eines outtype wird dieser durch das "straightening" in eine lineare Reihe von simplouts übergeführt (vgl. 9.3.4). Sodann werden die einzelnen simplouts der Reihe nach ausgegeben, also in eine Zeichenfolge umgewandelt. Je nach simplout hat die Zeichenfolge folgendes Aussehen: a) simplout ist ein bool : Für true wird das char von flip , für false das char von flop ausgegeben. Ist dabei die laufende Zeile im "book" voll, so wird zur Ausgabe des entsprechenden char eine gültige Position auf der nächsten Zeile gesucht (vgl. 9.4.3). flip und flop sind in der standard-prelude in R10.2.1.r,s als char-Konstanten definiert: char flip = C das char, welches beim Transput zur Darstellung von true benutzt wird C, char flop= C das char, welches beim Transput zur Darstellung von false benutzt wird C, Diese chars sind implementationsabhängig, sie können z.B. gegeben sein durch "1" und "0" bzw. "t" und "f" .
10.1 Unformatierter Transput
99
b) simplout ist ein L bits Es werden die einzelnen bools von L bits der Reihe nach ausgegeben, wie unter a) beschrieben. Wenn erforderlich, wird auf eine neue Zeile übergegangen. c) simplout ist ein char : Das char selbst wird ausgegeben. Ist dabei die laufende Zeile voll, so wird zur Ausgabe des char eine gültige Position auf der nächsten Zeile gesucht (vgl. 9.4.3). d) simplout ist ein [ ]char : Die einzelnen chars werden der Reihe nach ausgegeben, wie unter c) beschrieben. Wenn erforderlich, wird auf eine neue Zeile übergegangen. e) Ist simplout ein L int, L real oder L compl, so werden diese durch Aufruf der beiden Konvertierungsroutinen whole und float (vgl. 10.1.2) in den für die Ausgabe vorgesehenen string umgewandelt. Dabei werden als aktuelle Parameter die in R10.3.2.1.m,n,o definierten int-Konstanten L int width , L real width und L exp width verwendet: int L int width
= C der kleinste ganzzahlige Wert, so daß 'L max int' ohne Fehler konvertiert werden kann C, int L real width = C der kleinste ganzzahlige Wert, so daß '1.0' und '1.0+L smallreal' in unterschiedliche string s konvertiert werden können C; int L exp width = C der kleinste ganzzahlige Wert, so daß 'L max real' ohne Fehler konvertiert werden kann C;
L steht hier für die Menge der verschiedenen long- bzw. s/iori-Folgen. Für L max int, L small real und L max real vgl. R10.2.1.c,g,f und auch Band 1, Seite 22, 176. e l ) simplout ist ein L int i : Zunächst wird festgestellt, ob auf der laufenden Zeile genug Platz für L int width +2 "characters" ist. Dabei ist noch Platz für ein führendes Trennungs-'blank' und für das Vorzeichen berücksichtigt worden. Reicht
100
10. Ein-Ausgabe (Transput)
der Platz aus, so wird auf der laufenden Zeile, anderenfalls ab gültiger Position (vgl. 9.4.3) auf der nächsten Zeile zunächst ein 'blank' und sodann der string ausgegeben, den der call whole (i, L int width +1) liefert (vgl. 10.1.2). Ist dabei der Beginn der nächsten Zeile eine gültige Position, wird kein Trennungs-'blank' ausgegeben. e2) simplout ist ein L real x : Zunächst wird festgestellt, ob auf der laufenden Zeile genug Platz für L real width + L exp width +5 "characters" ist. Dabei ist noch Platz für ein führendes Trennungs-'blank', für das Vorzeichen der reellen Zahl, für den Dezimalpunkt, für das Zeichen "e" und für das Vorzeichen des Exponententeils berücksichtigt worden. Reicht der Platz aus, so wird auf der laufenden Zeile, anderenfalls ab gültiger Position (vgl. 9.4.3) auf der nächsten Zeile zunächst ein 'blank' und sodann der string ausgegeben, den der call float (x, L real width + L exp width +4, L real width -1 , L exp width +1) liefert (vgl. 10.1.2). Ist dabei der Beginn der nächsten Zeile eine gültige Position, wird kein Trennungs-'blank' ausgegeben. e3) simplout ist ein L compl (x , y) : Zunächst wird festgestellt, ob auf der laufenden Zeile genug Platz für 2 * (L real width + L exp width) +11 "characters" ist. Dabei ist Platz für ein führendes Trennungs-'blank', für zwei reelle Zahlen (2 * (L real width + L exp width)) und jeweils zweimal Platz für das Vorzeichen der beiden reellen Zahlen, für den Dezimalpunkt, für das Zeichen "e" und für das Vorzeichen des Exponententeils sowie Platz für ein 'blank' und das Zeichen "i" berücksichtigt worden. Reicht der Platz aus, so wird auf der laufenden Zeile, anderenfalls ab gültiger Position (vgl. 9.4.3) auf der nächsten Zeile zunächst ein 'blank' und sodann der string ausgegeben, den die formula float (x, L L exp float (y , L L exp
real width + L exp width + 4, L real width -1 , width +1) + " i" + real width + L exp width +4, L real width -1 , width +1)
liefert (vgl. 10.1.2). Ist dabei der Beginn der nächsten Zeile eine gültige Position, wird kein Trennungs-'blank' ausgegeben.
101
10.1 Unformatierter Transput
Durch put kann über jedes "file" eine Ausgabe vorgenommen werden, wenn nur das "file" an einem "channel" (und damit für ein " b o o k " ) eröffnet worden ist, der zur Ausgabe geeignet ist, d.h. dessen pwi-"field" eine Routine ist, die true liefert (vgl. 9.3.2). Dies kann z.B. der Standard"channel" stand out Channel sein (vgl. 9.3.2). Da in der particular-prelude das Standard-"file" stand out an stand out Channel schon eröffnet ist (vgl. 9.4.5), kann der Programmierer die Ausgabe ohne weitere Überprüfung über stand out vornehmen. Da hierbei der erste Parameter von put überflüssig ist, sind für die Ausgabe über stand out in der particular-prelude die beiden Prozeduren print und write definiert, die etwas einfacher als put zu handhaben sind (vgl. R10.5.1.d): proc print
= ([ ] union (outtype , proc (ref file,/ void^ x) v o i d : put (stand out, x); proc write = ([ ] union /'outtype , proc (ref file,/ voidy x) v o i d : put (stand out, x); Wir haben schon in Band 1 und auch in 10.1.2 stets print
zur Ausgabe benutzt.
10.1.4 Unformatierte Eingabe In R10.3.3.2.a ist die eigentliche Prozedur get für die unformatierte Eingabe definiert. Der " m o d e " ihrer Routine ist: proc (ref file, [] union (intype, proc (ref filej void^ Die Prozedur get hat also zwei Parameter: Der erste Parameter gibt das file an, über das die Eingabe vorgenommen wird. Mit dem (aktuellen) file ist dann angegeben, aus welchem " b o o k " über welchen "channel" gelesen wird, vorausgesetzt, das file wurde an einem "channel" für ein " b o o k " eröffnet (vgl. 9.4.1). Ob diese Voraussetzung erfüllt ist, wird zu Beginn von der Routine von get überprüft. Ist dies der Fall, werden durch die Routine in dem file die "fields" read mood und char mood auf true gesetzt (vgl. 9.3.3). Der zweite Parameter ist eine Reihe, deren Elemente entweder ein intype (vgl. 9.3.4) oder ein proc (ref füe) void sind. Z.B. können wir schreiben: get (standin,
(textl
, realvar,
newline,
text2)J ,
wobei textl , text2 string-Variablen und realvar eine real-Variable sind. Dabei wird die Eingabe über das Standard-"file" standin vorgenommen (vgl. 9.4.5).
102
10. Ein-Ausgabe (Transput)
Von der Routine von get werden die einzelnen Elemente der Reihe nacheinander bearbeitet, dabei wird entweder ein intype bearbeitet oder eine Routine vom "mode" proc frei filej void aufgerufen. Solch eine Routine kann z.B. eine der in 9.4.3 angegebenen Layoutroutinen sein. Zu Beginn der Bearbeitung eines intype wird dieser durch das "straightening" in eine lineare Reihe von simplins übergeführt. Aus 9.3.4 wissen wir, daß ein simplin stets ein ref amode ist. Es werden sodann aus dem "book" der Reihe nach Zeichenfolgen in amode-Werte umgewandelt und diese den simplins zugewiesen. Je nach simplin werden folgende Zeichenfolgen erwartet: a) simplin ist ein ref bool : Die laufende Zeile wird nach dem ersten Zeichen abgesucht, das kein 'blank' ist (wenn nötig, wird Zeilenwechsel vorgenommen). Sodann wird dieses Zeichen gelesen. Ist dieses Zeichen gleich dem Wert von flip bzw. flop (vgl. 10.1.3), so wird der Wert von true bzw. false dem simplin zugewiesen; anderenfalls wird die der "on"-Routine on char error entsprechende Ereignisroutine aufgerufen, die das 'unerwartete' Zeichen durch den char von flip oder flop ersetzen kann (vgl. 9.4.4, 10.2.6). b) simplin ist ein ref L bits : Den einzelnen ref bools, die sich auf die bool-Elemente von L bits beziehen, werden der Reihe nach bools zugewiesen, die sich bei der Eingabe ergeben, wie in a) beschrieben. c) simplin ist ein ref char : Das nächste Zeichen in der laufenden Zeile wird gelesen und dem simplin zugewiesen. Ist jedoch das Ende der laufenden Zeile erreicht, wird ein Zeilenwechsel vorgenommen und das nächste Zeichen in gültiger Position gelesen (vgl. 9.4.3). d) simplin ist ein ref [ ] char : Den einzelnen ref chars , die sich auf die char-Elemente der [ ] char beziehen, werden der Reihe nach chars zugewiesen, die sich bei der Eingabe ergeben, wie in c) beschrieben. e) simplin ist ein ref string : Ab laufender Position werden so lange Zeichen eingelesen, bis ein Zeichen ("terminator") erreicht wird, welches in dem string terrn des "flle"
10.1 Unformatierter Transput
103
(vgl. 9.3.3) enthalten ist, der durch die Informationsroutine make term (vgl. 9.4) geliefert wurde. Dabei wird jeweils bei Erreichen eines Zeilenendes bzw. Seitenendes bzw. bei Überschreiten des "logical end" bzw. der zulässigen Seitenanzahl die Ereignisroutine aufgerufen, die der "on"Routine on line end bzw. on page end bzw. on logical file end bzw. on physical file end entspricht. Liefert die entsprechende Ereignisroutine true , werden weitere Zeichen eingelesen (vgl. 9.4.4). Der string , bestehend aus den eingelesenen Zeichen, wird sodann dem simplin zugewiesen. Hierbei hat man zu beachten, daß in den Fällen, in denen zu Beginn des Einlesens die laufende Position das Ende der laufenden Zeile erreicht hat bzw. sich am Anfang einer leeren Zeile befindet bzw. das "logical end" überschritten hat, jeweils dem simplin ein leerer string zugewiesen wird. f) simplin ist ein ref L int : Zunächst wird die laufende Zeile nach dem ersten Zeichen abgesucht, das kein 'blank' ist (wenn nötig, wird Zeilenwechsel vorgenommen). Sodann wird die längste Zeichenfolge gelesen, deren Aufbau einer der beiden Möglichkeiten entspricht: f l ) Ein Vorzeichen ("+" oder " - " ) , möglicherweise gefolgt von einer Anzahl von 'blanks', gefolgt von einer Anzahl (>1) von Dezimalziffern. f2) Eine Anzahl (>1) von Dezimalziffern. Es werden also z.B. folgende Zeichenfolgen bei der Eingabe akzeptiert: +
4711 , +4711 , 4711
Die eingelesene Zeichenfolge wird in ein int umgewandelt, das dann dem simplin zugewiesen wird. Ist dabei eine Konvertierung nicht möglich, wird die der "on"-Routine on value error entsprechende Ereignisroutine aufgerufen (vgl. 9.4.4). g) simplin ist ein ref L real : Zunächst wird die laufende Zeile nach dem ersten Zeichen abgesucht, das kein 'blank' ist (wenn nötig, wird Zeilenwechsel vorgenommen). Sodann wird die längste Zeichenfolge gelesen, deren Aufbau einer der folgenden Möglichkeiten entspricht: gl) Ein Vorzeichen ("+" oder " - " ) , möglicherweise gefolgt von einer Anzahl von 'blanks', möglicherweise gefolgt von einer Anzahl von Dezimalziffern, gefolgt von einem Dezimalpunkt, gefolgt von einer Anzahl (>1) von Dezimalziffern.
104
10. Ein-Ausgabe (Transput)
g2) Möglicherweise eine Anzahl von Dezimalziffern, gefolgt von einem Dezimalpunkt, gefolgt von einer Anzahl (>1) von Dezimalziffern. g3) Eine Zeichenfolge für ein i n t , aufgebaut nach f l ) bzw. f2), möglicherweise gefolgt von einem Dezimalpunkt. Hierbei wird dieser Aufbau für eine ganze Zahl als Aufbau für eine reelle Zahl akzeptiert, als ständen Dezimalpunkt und nachfolgende Nullen im „book". Man beachte jedoch, daß nach dem Einlesen die laufende Position sich entweder unmittelbar hinter der letzten Dezimalziffer oder unmittelbar hinter dem Dezimalpunkt befindet. g4) Eine der möglichen Zeichenfolgen nach gl)—g3), gefolgt von dem Zeichen "e" , möglicherweise gefolgt von einem Vorzeichen ("+" oder " - " ) , möglicherweise gefolgt von einer Anzahl von 'blanks', gefolgt von einer Anzahl (>1) von Dezimalziffern. g5) Eine der möglichen Zeichenfolgen nach gl)—g3), gefolgt von dem Zeichen "e" , möglicherweise gefolgt von einer Anzahl von 'blanks', gefolgt von einer Anzahl (>1) von Dezimalziffern. Es werden also z.B. folgende Zeichenfolgen bei der Eingabe akzeptiert: + 4711.145 , +4711.145 , + .145 , +.1 , 4711.145 , .145 , .1 , + 4711 , +4711 , 4711 , +4711. , -4711. , 4711. + 47.11145e + 2,+ 47.11145e+ 2, + 47.11145e+2 , + 47.11145e2, +47.11145e + 2 , +47.11145e+ 2, +47.11145e+2 , 47.11145e2 , 47.11145e + 2 , 47.11145e+ 2, 47.11145e+2 , 47.11145e2 , .4711145e4 , 4 7 1 1 1 4 5 e - 3 , 4711145.e-3 Die eingelesene Zeichenfolge wird in einen real umgewandelt, der dann dem simplin zugewiesen wird. Ist dabei eine Konvertierung nicht möglich, wird die der "on"-Routine on value error entsprechende Ereignisroutine aufgerufen (vgl. 9.4.4). h) simplin ist ein ref L compl : Zunächst wird eine reelle Zahl nach g) eingelesen und dem ref L real zugewiesen, der sich auf das re-"field" bezieht. Sodann wird nach dem ersten Zeichen gesucht, das kein 'blank' ist. Dieses Zeichen wird gelesen. Ist dieses Zeichen nicht "i" oder "l" , wird die der "on"-Routine
10.1 Unformatierter Transput
105
on char error entsprechende Ereignisroutine aufgerufen, die das 'unerwartete'Zeichen entweder durch "i" oder "i" ersetzen kann (vgl. 9.4.4, 10.2.6). Schließlich wird eine weitere reelle Zahl nach g) eingelesen und dem ref L real zugewiesen, der sich auf das w2-"field" bezieht. Es werden also z.B. folgende Zeichenfolgen bei der Eingabe akzeptiert: + 3 . 1 4 1 i + 2 . 7 1 8 , 3 . 1 4 1 ¡2.718 , 3 . 1 4 1 ¡+.718 , + . 1 4 1 ¡2.718 , . 1 4 1 L 7 1 8 , 3 i 2 . 7 1 8 , 3 . 1 4 1 ¡2 , 3i2 , + 314.1e 2 i 2 . 7 1 8 , 3 . 1 4 1 ¡0.002718e+3 , 0.3141e1i0.00002718e5 , 314.1e-2i0.2718e1 , .3141e1i.2718e1 Durch get kann über jedes "file" eine Eingabe vorgenommen werden, wenn nur das "file" an einem "channel" (und damit für ein " b o o k " ) eröffnet worden ist, der zur Eingabe geeignet ist, d.h. dessen get-"field" eine Routine ist, die true liefert (vgl. 9.3.2). Dies kann z.B. der Standard-"channel" stand in channel sein (vgl. 9.3.2). Da in der particular-prelude das Standard-"file" stand in an stand in channel schon eröffnet ist (vgl. 9.4.5), kann der Programmierer die Eingabe ohne weitere Überprüfung über stand in vornehmen. Da hierbei der erste Parameter von get überflüssig ist, ist für die Eingabe über stand in in der particularprelude die Prozedur read definiert, die etwas einfacher als get zu handhaben ist (vgl. R10.5.1 .e): proc read = ([ ] union fin type , proc (ref file,/ void,/ x) void: get (stand in, x); Auch diese Prozedur read haben wir bereits in Band 1 zur Eingabe benutzt.
10. Ein-Ausgabe (Transput)
106
10.2 Formatierter Transput 10.2.1 "File" und Format Mit Hilfe von Formaten hat der Programmierer die Möglichkeit, den Aufbau der Zeichenfolgen, die aus- bzw. eingegeben werden sollen, bis in das letzte Detail festzulegen. In ALGOL68 wird ein Format stets bestimmt durch einen format-text, der ein internes Objekt vom "mode" format liefert (vgl. 10.2.3). Durch die für den formatierten Transput vorgesehenen Routinen (vgl. nächsten Paragraphen 10.2.2) erhält das format-"üe\d" des "file", über das der (formatierte) Transput vorgenommen werden soll, die Adresse des vom Programmierer bestimmten format. Das format wird dann als das 'laufende Format' für den Transput bezeichnet. Mit Hilfe der Transput-Routinen kann der Programmierer das laufende Format auch ändern durch Angabe eines neuen format-text. Die Transput-Routinen sind so definiert, daß Daten, die unter Kontrolle eines bestimmten Formats ausgegeben worden sind, mit dem gleichen Format wieder eingegeben werden können. 10.2.2 Formatierte Ein- und Ausgabe In R10.3.5.1.a und RIO.3.5.2.a sind die eigentlichen Prozeduren putf und getf für den formatierten Transput definiert. Der "mode" ihrer Routinen ist proc (ref file , [ ] union (outtype , format// void proc frei file, [] union /'intype, format// void
bzw.
Die Prozeduren putf und getf haben also (wie put und get für den unformatierten Transput, vgl. 10.1.3, 10.1.4) zwei Parameter: Der erste Parameter gibt das file an, über das der Transput vorgenommen wird. Mit dem (aktuellen) file ist dann angegeben, über welchen "channel" in welches "book" geschrieben bzw. aus welchem "book" gelesen wird, vorausgesetzt, das file wurde an einem "Channel" für ein "book" eröffnet (vgl. 9.4.1). Ob diese Voraussetzung erfüllt ist, wird zu Beginn von den Routinen von putf und getf überprüft. Ist dies der Fall, werden durch die Routinen in dem file die "flelds" write mood und char mood bzw. read mood und char mood auf true gesetzt (vgl. 9.3.3). Der zweite Parameter ist eine Reihe, deren Elemente entweder ein outtype bzw. intype (vgl. 9.3.4) oder ein format (vgl. 10.2.3) sind. Von den Routinen werden die einzelnen Elemente nacheinander bearbeitet. Ist dabei ein Element ein format, so erhält das format-"field" des file , über das der Transput vorgenommen wird, durch die Prozedur
10.2 Formatierter Transput
107
associate format (vgl. R10.3.5.k) die Adresse dieses format. Dieses format wird somit zum laufenden Format gemacht. Desweiteren wird durch *associate format das forp-"field" des file (vgl. 9.3.3) auf 1 gesetzt. Ist das Element jedoch ein outtype bzw. intype , wird es zunächst durch das "straightening" (vgl. 9.3.4) in ein [] simplout bzw. [] simplin übergeführt. Sodann wird jedes einzelne simplout bzw. simplin der Reihe nach unter Kontrolle des nächsten picture (vgl. 10.2.5) innerhalb des laufenden Formats aus- bzw. eingegeben. So hat der Programmierer also in der Liste der aktuellen Parameter von putf und getf das von ihm gewünschte format stets unmittelbar vor den Daten einzufügen, die er unter Kontrolle dieses format aus- bzw. eingeben möchte. Natürlich hat er auch die Möglichkeit, mehrere formats anzugeben, also das laufende Format zu ändern. Stets werden Daten unter Kontrolle des laufenden Formats ein- bzw. ausgegeben. Ist das laufende Format 'ausgeschöpft', d.h. es steht kein weiteres picture mehr zur Verfügung, und stehen in der aktuellen Parameterliste von putf bzw. getf noch weitere Daten, jedoch kein weiteres format mehr, wird die der "on"-Routine on format end entsprechende Ereignisroutine aufgerufen (vgl. 9.4.4). Liefert sie false , wird das laufende Format wiederholt. Liefert sie aber true und wurde von der Routine ein neues format zur Vergügung gestellt, so werden die weiteren Daten unter Kontrolle dieses format ein- bzw. ausgegeben. Wurde jedoch kein neues format zur Verfügung gestellt, wird undefined (vgl. zu Beginn von 9.4) aufgerufen. Sollte der Programmierer bei Benutzung von putf und getf vergessen haben, wenigstens ein format anzugeben, so ist der Transput "undefined" im Sinne des Reports (vgl. 7.2), und es hängt von der jeweiligen Implementation ab, welche weiteren Aktionen vorgenommen werden. Zur Bestimmung der einzelnen formats stehen dem Programmierer die format-texts zur Verfügung. Über Syntax und Semantik der format-texts werden wir in 10.2.5 ausführlich sprechen. Durch putf und getf kann über jedes "file" eine Ausgabe bzw. Eingabe vorgenommen werden, wenn nur das "file" an einem "channel" (und damit für ein "book") eröffnet worden ist, der zur Ausgabe bzw. Eingabe geeignet ist, d.h. dessen put- bzw. £ef-"field" eine Routine ist, die true liefert (vgl. 9.3.2). Dies kann z.B. der Standard-"channel" stand out Channel bzw. stand in Channel sein (vgl. 9.3.2). Da in der particular-prelude die Standard-"files" stand in bzw. stand out an diesen Standard-"channels" schon eröffnet sind, kann der Programmierer den formatierten Transput ohne weitere Überprüfung über diese Standard"files" vornehmen. Da hierbei der erste Parameter von putf bzw. getf überflüssig ist, sind für den formatierten Transput über stand out bzw.
10. Ein-Ausgabe (Transput)
108
stand in in der particular-prelude die Prozeduren printf, writef bzw. readf definiert, die etwas einfacher als putf bzw. getf zu handhaben sind (vgl. R10.5.1.f,g): proc printf = ([ ] union (outtype , format^ x) void : putf (standout, x); proc writef = union ('outtype, format^ xj void: putf (standout, x) ; proc readf = ([ ] union fintype, format^ xj void: getf (standin, xj; Um aufzuzeigen, wie man mit Hilfe dieser Prozeduren einen formatierten Transput vornehmen kann, geben wir schon jetzt einige Beispiele, obwohl wir über format-texts erst in 10.2.4 und 10.2.5 sprechen werden. Die in den Beispielen angegebenen format-texts sind jedoch so gewählt, daß der Leser sie ohne große Mühe wird verstehen können. Andererseits hoffen wir, daß diese Beispiele zusammen mit dem Beispiel in 10.2.4 zum besseren Verständnis von 10.2.5 beitragen. Beispiele: a) In 10.1.1 hatten wir angenommen, daß der Programmierer z.B. die ganze Zahl 153307 auf verschiedene Weise ausgedruckt haben möchte: 15 h 33' 0 7 " dm 1533.07 153 307
Dies kann erreicht werden, wenn man schreibt: printf ((f 2d "h" 2d ""'
2d """"
printf (($ "dm" 4d.2d
$,
153307));
153307));
printf (($ 3d q 3d
153307));
Will man die ganze Zahl 153307 mit dem gleichen Format wieder eingeben, muß man schreiben: readf ((f 2d "h" 2d ""'
2d """"
readf (($ "dm" 4d.2d $, readf (($ 3d q 3d $,
i)) ;
i));
i));
wobei i eine int-Variable ist. Dabei werden bei der Eingabe genau die Zeichenfolgen erwartet, die durch die obigen prin¡/-Aufrufe ausgedruckt wurden. b) Im folgenden wollen wir für einige pn'ni-Aufrufe (also unformatierte Ausgabe) das Format für die auszudruckende Zeichenfolge explizit durch entsprechende printf-Aufrufe (also formatierte Ausgabe) angeben:
10.2 Formatierter Transput
109
print (whole (i, -5)) príntf (($ 3z-d $, iJ)
entspricht (vgl. 10.1.2)
print (fixed (x , 8 , 3)) printf (($ 2z+d.3d $, x)j
entspricht (vgl. 10.1.2)
print (float (x , 12 , 3 , -2)j printf (($ 3z+d.3de-d $, x))
entspricht (vgl. 10.1.2)
print (x) entspricht (vgl. 10.1.3) printf (($ +d.n (real width -I) de+n (exp width) d $, x)) Im letzten Fall sehen wir, welches Standard-Format bei der unformatierten Ausgabe angenommen wird. c) Für die Aufstellung eines Horoskops wollen wir uns eine Ein/Ausgabe-Prozedur definieren, mit der wir die benötigten astrologischen Daten ein- bzw. ausgeben können. Diese Daten seien auf folgende Weise definiert: mode astrodate = struct ([1:40] char name, birth time fate, [1:16] char birth place, int longitude, latitude); Dabei ist mode birthtime = struct fint time, short int day , month , year); Sodann definieren wir: proc io = fbool if then fi
input, ref astrodate next) void: input readf else writef (($ 40a, I 2d "h" 2d ""' 2d """", I zd, //r. tt u /• »i/ n tt tt ti qc ( jan , feb , mar , apr , tt.
n
tt.
in
a
tt
jun , jul , aug , "nov", "dec"),
tt
a
sep ,
ir
tt
u
may ,
oct
tt
,
q4d, 116a, I "long:" q3d "deg" 2d "min" 2d "sec", I "hit:" 3q2d "deg" 2d "min" 2d "sec" f. next
) );
110
10. Ein-Ausgabe (Transput)
Deklariert man dann astrodate
algol68;
so kann durch io (true , algol68) z.B. folgende Zeichenfolge eingelesen werden: revised
algorithmic
language
a Igo I6 8
1 1h 10 ' 3 0 '' 10 a u g 19 7 3 los
angeles
long: lat:
1 1 8 deg 23 m in 3 5sec 34deg11min21sec
Die eingelesene Zeichenfolge wird in ein astrodate umgewandelt und der Variablen algol68 zugewiesen. Nun denke man sich ein Programm, mit dem für algol68 ein Horoskop erstellt wird. Will man dabei zur Kontrolle die eingelesenen astrologischen Daten ausdrucken, kann man dies durch io ffalse, algol68) tun. Es wird dann genau die oben angegebene Zeichenfolge ausgedruckt.
10.2.3 Der "mode" format Ein format ist ein "structured value", also ein internes Objekt. Es wird stets beider "elaboration" eines format-text geliefert (vgl. 10.2.5). Dieses "structured value" besteht aus einem einzigen "field", das jedoch der Programmierer nicht auswählen kann (für ihn ist der field-selector N tabu, vgl. Band 1, Seite 172, 174). Er hat also keinen Zugriff zu den einzelnen Bestandteilen eines format, er kann dieses nur als Ganzes benutzen. In R10.3.5.a und auch R10.3.4.1.1 ist der "mode" format durch folgende mode-declarations definiert:
10.2 FormatierterTransput
111
A) mode format = struct /'flex [1:0] piece ft) ; B) mode Apiece = struct /int cp co pointer to current collection co, count co number of times piece is to be repeated c o , bp co backpointer co, flex [i. 0] collection c) ; C) mode ^ collection = union /picture, collitemj ; D) mode -i-collitem = struct /'insertion il, proc int rep co replicator c o , int p co pointer to another piece insertion i2) ;
co,
E) mode -f insertion = flex [1:0] struct /proc int rep co replicator union / string, char,/ sa) ;
co,
F) mode ^picture = struct /union /pattern, cpattern, fpattern, gpattern, voidj p , insertion i) ; G) mode -^pattern = struct /int type co of pattern co, flex [1:0] frame frames) ; H) mode
frame = struct /insertion i , proc int rep co replicator co, bool supp co true if suppressed char marker) ;
co,
I) mode ^cpattern = struct /insertion /', int type co boolean or integral co, flex [1:0] insertion c) ; J) mode ^-fpattern = struct /insertion i, proc format p f ) ; K) mode ^-gpattern = struct /insertion /', flex [1:0] proc int spec) ;
Um den Aufbau eines format besser zu verstehen, wollen wir die GesamtStruktur anhand eines "mode"-Baumes verdeutlichen:
112
10. E i n - A u s g a b e ( T r a n s p u t )
proc int
insertion
insertion
GD ©
©
void
int (type)
[
]
insertion
(frames)^
Q
int
(7)
insertion
proc f o r m a t
insertion
( 7 )
( p f )
( 7 )
I
insertion
proc int (
]
(type)
frame •
insertion
[
rep
)
bool ( supp )
\
[
] (spec)
proc int
char (marker)
Dabei bedeuten: •
string
char
: struct : union [] : flex [ 1 : 0 ] 0 : field-selector
10.2 Formatierter Transput
113
Wir haben hier deshalb die Gesamt-Struktur eines format in allen Einzelheiten angegeben, damit der Leser verstehen kann, wie der formatierte Transput in RIO.3.4 und R10.3.5 definiert ist. In diesem Buch wollen wir uns jedoch darauf beschränken, anhand des Aufbaus eines format-text auf informelle Weise dem Leser die Hilfsmittel zu geben, die er bei Verwendung des formatierten Transput benötigt.
10.2.4 Beispiel eines format-text Um beim formatierten Transput ein Format zu bestimmen, muß der Programmierer einen entsprechenden format-text angeben. Wir haben in 10.2.2 schon einige format-texts und ihre Verwendung als aktuelle Parameter innerhalb von printf- bzw. /•e 1 then if (k+i) < n then vector (k-h+1) [at (h+i)] eise vector (n-h-i+1) [at (h+i)] fi elif (k+i) < n then vector (k+i) eise vector (n) fi od, bandmat
); Bei dieser Definition gehen wir davon aus, daß die Hauptdiagonale als 0-te Diagonale bezeichnet wird (vgl. 12.5). Schreibt man dann z.B. vecrow band := bandmat (10, so erhalten wir das Bild
-1,
2);
12. TORRIX (vekTOR-matRIX)
170
Bei den bisher betrachteten Zuweisungen wurden die Grenzen der "multiple values" nicht kontrolliert, da durch die assignations nur Adressen transportiert wurden. Z.B. kann durch die assignation vecl := vec2 unabhängig von dem Indexbereich des "multiple value", welches vecl liefert, die Adresse eines "multiple value" mit beliebigem Indexbereich zugewiesen werden. Oft will man jedoch nur solch ein "multiple value" zuweisen, dessen Indexbereich mit dem Indexbereich des von vecl gelieferten "multiple value" übereinstimmt. Dies kann man mit Hilfe des cast ausdrücken, z.B. durch vector (vecl) := vec2 Da wir den Benutzer von TORRIX nicht mit der speziellen ALGOL68-Konstruktion des cast belästigen wollen, empfehlen wir ihm die Verwendung eines slice auf folgende Weise: vecl [] := vec2 ; Die Abarbeitung dieser assignation liefert folgendes Bild (vgl. Band 1, Seite 99):
Für Matrizen kann man entsprechend schreiben: matl [, ] .= mat2 ;
12.4 Verschiedene Arten von Wert-Transport
171
Zusammenfassend haben wir also die folgenden assignations, jeweils mit unterschiedlichem Effekt: a) vecl := vec2;
matl := mat2 ;
Keine Überprüfung der Grenzen, keine Kopie, nur Transport einer Adresse. b) vecl := copy vec2;
matl := copy mat2;
Keine Überprüfung der Grenzen; zunächst wird kopiert, sodann wird eine Adresse transportiert. c) vecl [ ] := vec2 ;
matl [, ] := mat2;
Zunächst Überprüfung der Grenzen, dann wird kopiert.
12. TORRIX (vekTOR-matRIX)
172
12.5 Verschiedene Arten von Vektor-Matrix-Beschreibung In vielen Anwendungsfällen (z.B. Gauß-Elimination, Bestimmung von Eigenvektoren) möchte man zu der i-ten Reihe, j-ten Spalte oder zu einer Diagonalen einer Matrix zugreifen, ohne jedoch diese zu kopieren. In TORRIX kann man hierfür z.B. schreiben: vector rowi := mat [/, ] ; vector colj := mat [, /] ; (vgl. Band 1, Seite 126) Danach gilt dann rowi [/] is mat [/, /'] und deswegen erst recht rowi [/] = mat [i, j] Ebenso gilt colj [/] is mat [/, /] und colj [/] = mat [/, j] Man beachte, daß man mit rowi \j] bzw. colj [/] weitaus effizienter zu dem ( i , ;')-ten Element zugreift als durch mat [/', /'], da man nur eine Indizierung benötigt. Schwieriger wird es, wenn wir zu einer der Diagonalen einer Matrix zugreifen wollen. Zunächst einiges zu der Bezeichnung der Diagonalen: Wir erinnern uns, daß wir allen Vektoren und Matrizen den gleichen Indexbereich -maxdex : +maxdex zugeordnet haben (vgl. 12.1). So gesehen, wird jede konkrete Matrix als Teilmatrix einer viel umfassenderen Matrix (die mit virtuellen Nullen aufgefüllt ist) aufgefaßt. In dieser umfassenden Matrix gibt es eine natürliche Hauptdiagonale: auf ihr liegen die Elemente ajj. Bezeichnen wir diese Hauptdiagonale als 0-te Diagonale, so können wir die k-te Diagonale als diejenige bezeichnen, auf der die Elemente ay liegen, für die j-i=k gilt. Es ist in ALGOL68 nicht gut möglich, eine Diagonale einer Matrix, ohne sie zu kopieren, als einen Vektor zu erhalten. Da es andererseits bei jeder ALGOL68-Implementation keine Schwierigkeiten bereiten wird, einen "descriptor" aufzustellen, der die Elemente einer Diagonalen beschreibt, so definieren wir in TORRIX:
12.5 Verschiedene Arten von Vektor-Matrix-Beschreibung
173
prio diag = 8; op diag = /'int k, matrix a) vector.C ein vector, d.h. ein ref [] scal, so daß gilt: (k diag a) [/'] is a [i, i+k] für k>0, (k diag a) [/] is a [i-k, /] für k.0, (k codiag aj [;] is a [k-i, /] für k 2 lwb b and 2 upb a < 2 upb b; Schließlich wollen wir noch feststellen können, ob ein Vektor bzw. eine Matrix mit dem Nullvektor bzw. der Nullmatrix identisch ist. Dazu definieren wir: op zero = fvector u) bool: u is op zero = /'matrix a) bool: a is
zerovec; zeromat;
Für einige Anwendungen sind die folgenden Operatoren von Nutzen, die entweder von zwei ganzen Zahlen die größere (kleinere) oder innerhalb eines Vektors bzw. einer Matrix das größte (kleinste) bzw. das betragsmäßig größte (kleinste) Element feststellen:
12.6 Die TORRIX-Routinen
prio max = 7, min = 7; op max = fint m, n) int : if m > n then m else n f i ; op min = finí m, n) int : if m < n then m else n fi; op max = /'vector u) seal ; ( seal max := scalO ; for i from lwb u to upb u do if u [i] > max then max := u [/] fi od; max
); op max = ( matrix a) seal : (seal submax, max := scalO ; for j from 2 lwb a to 2 upb a do submax := max a [, /] ; if submax > max then max := submax fi od'; max
); op min = (vector u) seal: /'seal min := scalO; for i from lwb u to upb u do if u [/] < min then min : = u [/] fi od; min J; op min = ( matrix a) seal : (seal submin, min := scalO ; for j from 2 lwb a to 2 upb a do submin := min a [, /] ; if submin < min then min := submin fi od; min
);
12. TORRIX (vekTOR-matRIX)
178
op maxabs = fvector u) scal; (scal maxabs := scalO; for i from lwb u to upb u do if abs u [z] > maxabs then maxabs := abs u [¡] fi od, maxabs ); op maxabs = (matrix aj scal : (scal submax , maxabs := scalO; for / from 2 lwb a to 2 upb a do submax := maxabs a [, /]; if submax > maxabs then maxabs := submax od, maxabs ); op minabs = fvector u) scal: scalO;
fi
op minabs = (matrix a) scal : scalO;
12.6.2 Additionen und Subtraktionen Zunächst definieren wir drei Operatoren, die der TORRIX-Anwender nicht in seinem Programm benutzen darf. Um dies anzudeuten, haben wir diese Operatoren mit dem Zeichen versehen (vgl. die Vorbemerkung in 9.3). Diese Operatoren sind deshalb für den Benutzer tabu, weil bei ihrer Definition davon ausgegangen wird, daß sie bestimmte Voraussetzungen erfüllen; ob diese Voraussetzungen erfüllt sind, wird also im einzelnen nicht überprüft. Die Operatoren werden bei den Definitionen anderer, dem Benutzer zugänglicher Operatoren benutzt, wobei gewährleistet ist, daß die entsprechenden Voraussetzungen für ihre Benutzung erfüllt sind. prio -9-plusab = 6 , -^minusab = 6 , ^ i n t r o = 2 ; op -?plusab = (vector u, v) vector: (fox i from lwb v to upb v do u [z] + := v [z] o d ; u
);
12.6 Die TORRIX-Routinen
179
op -9-plusab = /'matrix a, bj matrix; (for j from 2 lwb b to 2 upb b do a f, / ] plusab b [, / ] o d ; a ); op ^minab = /vector u , v) vector; (for i from lwb v to upb v do u [z] - := v [z] od ; u
); op ^-minab = /'matrix a, b) matrix. (for j from 2 lwb b to 2 upb b do a [, / ] minab b [, j] o d ; a
); op ^intro = /'vector u, v) vector: if zero v then zerovec else v [lwb u: upb u at lwb u\ := u; v fi; op ^intro = /'matrix a, b) matrix, if zero b then zeromat else b [1 lwb a: 1 upb a at 1 lwb a, 2 lwb a: 2 upb a at 2 lwb a] := a ; b
fi;
Um für die Addition und Subtraktion zweier Vektoren bzw. Matrizen den benötigten Speicherraum im "heap" zu reservieren und ihn mit scalO zu initialisieren, definieren wir den Operator span (vgl. 12.1): prio span = 8 ; op span = (vector u , v) vector : scalO into vector (upb u max upb v - lwb u min lwb v +1 j [at lwb u min lwb v ] ; op span = /'matrix a, b) matrix: scalO into matrix (1 upb a max 1 upb b - 1 lwb a min 1 lwb b +1 , 2 upb a max 2 upb b - 2 lwb a min 2 lwb b +1 ) [at 1 lwb a min 1 lwb b, 2 lwb a min 2 lwb b];
180
12. TORRIX (vekTOR-matRIX)
Für die Addition und Subtraktion zweier Vektoren bzw. Matrizen definieren wir: op + = /'vector u, vj vector: (u intro (u span j>)) plusab v; op + = (matrix a, b) matrix : (a intro (a span b)) plusab b; op - = /vector u, v) vector: (u intro (u span v) minab v; op - = /'matrix a, b) matrix : (a intro (a span b)) minab b; op - = /'vector u) vector: zerovec - u; op - = (matrix a) matrix : zeromat - a;
Man beachte hierbei, daß durch die Operatoren '+' und die Addition und Subtraktion genau so vorgenommen werden, wie wir diese in 12.1 bildhaft dargestellt haben. Als entsprechende zuweisende Operatoren definieren wir:
op +:= = ( k I vector u, vector vj ref vector: (if v fitsin u then u plusab v else u := u+v f i ; u
); op +:= = /"ref matrix a, matrix b) ref matrix : (if b fitsin a then a plusab b else a := a+b fi; a
); op - : = = (ref vector u, vector v) ref vector: (if v fitsin u then u minab v else u := u-v fi ; u
); op - : = = (ref matrix a, matrix bj ref matrix: (if b fitsin a then a minab b else a := a-b a
);
fi;
12.6 Die TORRIX-Routinen
181
Hierbei beachte man, daß in den Fällen, in denen v fitsin u bzw. b fitsin a zutrifft, kein neuer Speicherplatz im "heap" reserviert wird; es wird v zu u bzw. b zu a innerhalb des Speicherplatzes von u bzw. a addiert (subtrahiert). Um die einzelnen Elemente eines Vektors bzw. einer Matrix um einen bestimmten Skalarwert erhöhen (erniedrigen) zu können, definieren wir: op + : = = /Vector u, seal s) vector: /for i from Iwb u to upb u do u [;] +:= s od ; u
);
op + : = = /'matrix a, seal s) matrix : (for j from 2 lwb a to 2 upb a do a [, /'] +:= s od ; a
);
op - . = = /vector u, seal s) vector: /for / from lwb u to upb u do u [/] -:= s od ; u
);
op - : = = /matrix a, seal s) matrix: /for / from 2 lwb a to 2 upb a do a [, /] -:= s o d ; a
);
12.6.3 Multiplikationen Um die einzelnen Elemente eines Vektors bzw. einer Matrix mit einem Skalarwert multiplizieren bzw. durch einen (von scalO verschiedenen) Skalarwert dividieren zu können, definieren wir: op X:= = /vector u , seal s) vector: /for i from lwb u to upb u do u [/] X:= s od ; u
);
12. TORRIX (vekTOR-matRIX)
182
op X:= = (matrix a, seal s) matrix : (for j from 2 lwb a to 2 upb a do a [, /] X:= s o d ; a
); op / : = = /vector u, seal s) vector: if s = scalO then print ((newpage, "division by zero"j); else u X:= (1/s) fi;
stop
op / : = = (matrix a, seal s) matrix : if s = scalO then print ((newpage, "division by zero")); else a X:= (1/s) fi;
stop
Unabhängig davon, für welche Grundmenge, d.h. für welche der in 12.3 angegebenen Möglichkeiten für seal man sich entscheidet, möchte man die einzelnen Elemente eines Vektors bzw. einer Matrix mit einem bestimmten int multiplizieren bzw. durch einen (von Null verschiedenen) int dividieren Dazu definieren wir: op X:= = /'vector u, int n) vector: (for i from lwb u to upb u do u [/] X := n do ; u
); op X:= = /'matrix a, int n) matrix : (for j from 2 lwb a to 2 upb a do a [, y] X:= n od ; a
); op / : = = /'vector u, int n) vector: if n=0 then print ((newpage, "division by zero")) ; stop else u X:= (1/n) fi; op / : = = /'matrix a, int n) matrix : if n=0 then print ((newpage, "division by zero")) ; stop else a X:= (1/n) fi;
12.6 Die TORRIX-Routinen
183
Für viele Anwendungen will man nicht die Elemente selbst, sondern die kopierten Elemente eines Vektors bzw. einer Matrix mit einem Skalarwert (bzw. int) multiplizieren bzw. durch einen Skalarwert (bzw. i n t ) dividieren. Dazu definieren wir: op X = /'int n,
vector u)
vector;
/copy u) X : = n ; op X = /'seal s,
vector uj
/'copy u) X : = op X = /'int n,
vector:
s;
matrix a) matrix :
/copy a) X : = n ; op X = /seal s , matrix a) matrix : /copy a) X : = op / = /'vector u, /'copy u) /:= op / = ^vector u, /'copy uj /:= op / = /'matrix a, ( c o p y a) /;= op / = ( m a t r i x a, /'copy a) /:=
s;
int it)
vector:
n; seal s)
vector;
s; int n)
matrix.
n ; seal s) matrix : s;
Zur Berechnung des inneren Produktes SujVj zweier Vektoren definieren wir: prio inprod =
7;
op inprod = (vector u , v) seal :
/seal prod := scalO ; for i from Iwb u max Iwb v to upb u min upb v
do prod +:= u [/'] X v [;'] od ; prod
); Für die Definition des Cauchy-Produktes zweier Vektoren ist das 'umgekehrte' Summenprodukt 2UjV_j zweier V e k t o r e n von Nutzen: prio revprod =
7;
op revprod = /vector u,
v) seal :
/seal revprod := scalO; for i from Iwb u max / - u p b v) t o upb u min / - I w b
do revprod +:= u [/] X v [ - /] od ; revprod
);
v)
12. TORRIX (vekTOR-matRIX)
184
Benutzt man Vektoren zur Darstellung der Koeffizienten von Polynomen, so liefert das Cauchy-Produkt zweier Vektoren die Darstellung der Koeffizienten des Produktes zweier Polynome: prio cauchy =
8;
op cauchy = /'vector u, v) v e c t o r : /'int Iwbv = lwb v, Iwbu = lwb u ; vector w : = vector / / u p b u + upb v) - (Iwbu ) [at (Iwbu + Iwbv)]; for i from lwb w to upb w do w [i] : = u revprod v [at lwbv-i] od,
+ Iwbv)
w ); Schließlich benötigen wir noch einen Operator für die Multiplikation zweier Matrizen bzw. einer Matrix mit einem Vektor: op X = /matrix a, vector u) v e c t o r : if 2 upb a < lwb u or upb u < 2 lwb a then zerovec else int Iwbl = 1 lwb a, upbl = 1 upb a; vector v : = vector (upbl-lwbl + 1) [at for i from Iwbl to upbl do v [/] : = a [ i , ] X u o d ; v ü;
Iwbl];
op X = /vector u, matrix a) v e c t o r : /'trnsp a) X u; op X = (matrix a, b) matrix : if 1 upb b < 2 lwb a ox 2 upb a < 1 lwb b then zeromat else int blwb2 = 2 lwb b, bupb2 = 2 upb b ; matrix c := matrix (1 upb a - 1 lwb a +1 , bupb2 - blwb2 + 1 J [at 1 lwb a, at blwb2]; for j from blwb2 to bupb2 do c [, j] := a X b [, /'] o d ; c
fi,
+ 1
12.7 Anwendungsbeispiel
185
12.7 Anwendungsbeispiel Im folgenden gehen wir davon aus, daß mit scal die reellen Zahlen dargestellt werden (mode scal = real). Bekanntlich kann man ein lineares Gleichungssystem Ax = u
(det(A) * 0)
mit Hilfe des verketteten Gaußschen Algorithmus folgendermaßen lösen (vgl. [22]): 1) a) Elimination des Koeffizientenschemas A. Dies ist gleichbedeutend mit dem Aufbau der Dreiecksmatrizen C und B nach A= CB b) Ausdehnung der Elimination auf die rechte Seite u, d.h. Aufbau der neuen rechten Seite v nach u = Cv 2) Berechnung der Unbekannten x nach Bx = v
Sei A = (a i k ), dann gilt für die Elemente c i k und b i k der beiden Dreiecksmatrizen C und B: cik = 0
für k > i
und Ca = 1 sowie b i k = 0
für i > k
Darüber hinaus gilt: det(A) = b n - b 2 2
bnn
Ist dann A symmetrisch, d.h. gilt a i k = a k i , so folgt: c
ik ~ b k i / b k k
(1)
Ist A positiv definit, so ist bü > 0
(2)
12. TORRIX (vekTOR matRIX)
186
Im Fall einer symmetrischen, positiv definiten Matrix A kann die Dreieckszerlegung von A voll symmetrisch durchgeführt werden (vgl. [22]): (1) ist gleichbedeutend mit C T = D _1 B mit D = Diag(bjj). C T ist die Transponierte von C und D"1 die Inverse von D; für letztere gilt: D
1
= DiagO/bjO
Setzen wir D 1 / 2 = Diag (Vb^), so können wir schreiben: A = CB = B t D _ 1 B = B t (D 1 ' 2 )" 1 (D 1 / 2 )' 1 B = R t R = LLt mit der einen oberen Dreiecksmatrix R = (D 1 / 2 ) - 1 B bzw. der einen unteren Dreiecksmatrix L = R T = B ^ D 1 ' 2 ) 1 . Dabei ist (D 1 ' 2 )" 1 = Diag (l/\/b7i). Für die einzelnen Elemente von R bzw. L gilt also: r
ik = bik/Vbü
bzw.
l i k = bkj/Vbji.
Insbesondere gilt: rjj = lj; = bjj/Vb^ = V b j i . Demnach folgt: det(A) = n i - r j l
rn2=l,?-l2l
1„2 .
Diese Dreieckszerlegung für eine symmetrische, positiv definite Matrix wurde erstmals von Cholesky angegeben. Dieses Verfahren ist auch dann noch mit Erfolg anzuwenden, wenn die Matrix A fast singulär, ihre Determinante also sehr klein ist. Dies liegt daran, daß nicht mit den Diagonalelementen b u , sondern mit ihren Quadratwurzeln r H = l ü = Vbji gearbeitet wird, wodurch bei sehr kleinen bjj der Stellenverlust u.U. wesentlich gemildert werden kann. Wir definieren eine Prozedur cholesky , die für eine gegebene quadratische, symmetrische, positiv definite Matrix B die Dreieckszerlegung B = LLt vornimmt, wobei L eine untere Dreiecksmatrix ist:
12.7 Anwendungsbeispiel
187
proc cholesky = f matrix b) vector: if Square b and not zero b then matrix a = b [at 1, at 1\; int n := 1 upb a; scal norm = maxabs diag a; vector p = vector (n+1) [at 0]; ref scal det = p [0] := scall; for i to n while vector ai = a [/, ] ; for / to i-1 do (ai |/] -:= ai X a\j, :j-1]) X:= p [/] od; scal Iii = ai [/] - ai X ai[:i-l]; (det X:= Iii eps norm) > 0 do n := i; p [i] := 1/sqrt (Iii) od; p [0 : n at 1 lwb b -1] eise zerovec fi; Hierbei gilt: prio eps = 8 ; op eps = (scal s, r) scal : if abs s < abs r X small real then scalO eise s fi ; Normalerweise wird cholesky aufgerufen mit einer aktuellen matrix b , deren untere Grenzen 1 sind. In diesem Fall liefert der Aufruf einen vector p , dessen Indexbereich [0 : n j ist. Dabei enthält p [0] die Determinante von B, und p [7] bis p [n] enthalten die reziproken Diagonalelemente der unteren Dreiecksmatrix L. Ist dabei p [0] > 0 (d.h. det (B) > 0), so liefert n die obere Grenze von B. Ist dagegen p [0] = 0 (d.h. B wurde als singulär festgestellt) oder p [0] < 0 (d.h. B wurde als nicht positiv definit festgestellt), so liefert die obere Grenze des Ergebnisvektors p (d.h. der Wert von n) die Zahl der letzten erfolgreich durchgeführten Cholesky-Iteration, d.h. die obere Grenze deijenigen Untermatrix von B, die noch regulär (d.h. nichtsingulär) und positiv definit ist. Wurde cholesky aufgerufen mit einer quadratischen Matrix, deren untere Grenzen k+l sind, so wird der Indexbereich des Ergebnisvektors p verschoben zu j[k-l : k+n-1]). Um ein lineares Gleichungssystem zu lösen, definieren wir die Prozedur choleskysolve . Dabei wird die Dreieckszerlegung der Koeffizientenmatrix mit Hilfe von cholesky vorgenommen:
12. TORRIX (vekTOR-matRIX)
188
proc choleskysolve = (matrix b, ref vector p, u) void: begin if zero p then p := cholesky (b) fi; int k = lwb p + 1, kn = upb p; int Iwbu = lwb u, upbu = upb u; int m = k max Iwbu; if k < Iwbu or kn > upbu co not p [k : kn at k\ fitsin u co then vector up := u span p [k : kn at Ar] ; u := up +:- u
fi; for i from m to kn do (u [/] -.= b [ / , ] X u [m : i - 1 at m]) X:= p [i] od ; for i from kn by -1 to k do (u [/] -:= b [i+1 : kn at i+1] Xu) X:= p [i] od end;
Ein Aufruf choleskysolve
(b,
p,
u) löst das lineare Gleichungssystem
Bx = u derart, daß der Ein-Ausgabeparameter u , der bei der Eingabe den Vektor der rechten Seite liefert, als Ergebnis den Lösungsvektor x liefert (d.h. u := B"'u). Man beachte, daß nur dann die Dreieckszerlegung von B durch Aufruf von cholesky vorgenommen wird, wenn der Ein-Ausgabeparameter p bei der Eingabe den Nullvektor liefert (d.h. p is zerovec). In diesem Fall liefert dann p den Ergebnisvektor von cholesky. Durch mehrmaligen Aufruf von choleskysolve Gleichungssystem
hat man die Möglichkeit, das
Bx = u für verschiedene rechte Seiten u zu lösen. Man muß dabei nur darauf achten, daß p mit dem Nullvektor initialisiert wird, um somit die Dreieckszerlegung von B zu erhalten. Die Prozedur choleskysolve akzeptiert alle Matrizen b , die auch cholesky akzeptiert. Darüber hinaus akzeptiert choleskysolve alle Vektoren u unabhängig von ihren Grenzen. Als Ergebnis liefert u in jedem Fall den Lösungsvektor so weit, wie cholesky erfolgreich gearbeitet hat. Anhand von p [0] und der Länge von p kann man dies nachprüfen.
13. GRAPHIC
Die im folgenden angegebene library-prelude zur Beschreibung und Manipulation von Bildern ist ein kurzer Abriß des Programmiersystems GRAPHEX68, das von Mitarbeitern des Instituts für Softwaretechnik und Theoretische Informatik an der Technischen Universität Berlin entwickelt [23, 24, 25] sowie von Mitarbeitern der Universität Utrecht (Nederland) zum weiteren Ausbau verbessert wurde. Die Beschreibung einer Implementation von GRAPHEX68 findet man in [25], Wie die mit Hilfe der library-prelude aufgebauten Bilder von einem angeschlossenen graphischen System auf einem Bildschirm oder durch ein Zeichengerät ausgegeben werden, wird von uns nicht weiter untersucht. Auch werden von uns nicht die verschiedenen Möglichkeiten des interaktiven Arbeitens an einem Bildschirm behandelt (z.B. 'lightpen', alphanumerische Tastatur, programmierbare Funktionstasten, Tablett). Hierzu verweisen wir auf die oben genannten Arbeiten, insbesondere [25],
13. GRAPHIC
190
13.1 Darstellung von Bildern: die GRAPHIC-"modes" Bei der Darstellung von Bildern beschränken wir uns auf den zweidimensionalen Fall. Jedoch ist eine Ausdehnung auf drei Dimensionen ohne Schwierigkeiten möglich. Zunächst betrachten wir die primitiven Elemente, aus denen Bilder aufgebaut werden. Ausgangspunkt hierfür sind die Darstellungsmöglichkeiten üblicher Bildschirm- bzw. Zeichengeräte. So wird man wohl mit ihnen stets Punkte zeichnen und zwischen je zwei Punkten Linien ziehen können. Weiterhin verfügen viele Geräte über Zeichengeneratoren. Entsprechend deklarieren wir: mode point = struct f real x, y) ; mode line
= struct /'point sp , ep);
(die mode-declaration für string ist bereits in der standard-prelude enthalten) Auch einen Polygonzug, der mehrere Punkte miteinander verbindet, wollen wir als primitives Element ansehen. Um bei einem Polygonzug mit zum Ausdruck zu bringen, wie die einzelnen Punkte mit dem Elektronenstrahl eines Bildschirmgerätes bzw. mit dem Zeichenstift eines Zeichengerätes untereinander verbunden werden, deklarieren wir: mode step = struct fint beamode,
point p);
mode poly = ref [ ] step ; Dabei kann man sich das beamode-'Tield" z.B. folgendermaßen interpretiert denken: beamode-"field"
0 1 2 3 4
usw.
Wirkung des Elektronenstrahls eines Büdschirmgerätes
Wirkung des Zeichenstiftes eines Zeichengerätes
Strahl dunkel volle Linie nur der Endpunkt wird gezeichnet gestrichelte Linie strich-punktierte Linie
Zeichenstift ist angehoben Zeichenstift ist gesenkt nur der Endpunkt wird gezeichnet gestrichelte Linie strich-punktierte Linie
usw.
usw.
13.1 Darstellung von Bildern: die GRAPHIC-"modes"
191
Wir haben poly nicht direkt als eine Reihe von steps, sondern als deren Adresse deklariert. Dadurch haben wir einerseits die Möglichkeit, die Anzahl der Punkte in einem Polygonzug zu ändern, andererseits sparen wir Speicherplatz bei den Operationen auf Polygonzügen (vgl. 13.2, 13.3). Der "mode" line ist eigentlich überflüssig; denn man kann eine Linie, bestehend aus Anfangs- und Endpunkt, als Spezialfall eines Polygonzuges ansehen. Da jedoch viele graphische Systeme den Polygonzug nicht als primitives Element kennen, behalten wir line als primitives Element bei. Dabei setzen wir voraus, daß durch die Hardware bestimmt ist, wie Anfangs- und Endpunkt miteinander verbunden sind. Schließlich vereinigen wir die angegebenen "modes" zu einem |
mode prim = union fpoint, line, poly, stringj;
Ein Bild kann man sich aufgebaut denken aus einer Reihe von Unterbildern, die ihrerseits wieder aus Unterbildern bestehen usw. Auf der untersten Stufe der Hierarchie schließlich findet man die primitiven Bildelemente. Wichtig ist dabei folgendes: Hat man ein Bild aufgebaut, so kann es an verschiedenen Stellen als Unterbild von anderen Bildern auftreten. Dabei kann seine ursprüngliche Darstellung durch die drei Ähnlichkeits-Transformationen Translation, Skalierung und Rotation verändert worden sein. Man muß also unterscheiden zwischen der Erzeugung eines Bildes ("image"), die in einem gedachten Koordinatensystem vorgenommen wird, und seinem konkreten (vergrößerten, verkleinerten, gedrehten, mehrfachen) Auftreten ("instances") im Rahmen eines anderen Bildes. So definieren wir ein Bild durch |
mode pict = struct (ref [] basis sub);
Das aus einem gegebenen Bild durch Transformation veränderte Bild erhalten wir durch |
mode transform = struct fpoint position, real angle, factor, pict image);
Dabei gilt: |
mode basis = union (ref transform, ref pict, prim^;
Die Zusammenfassung der Unterbilder eines Bildes erfolgt also nicht wie üblicherweise durch eine verkettete Liste, sondern durch ein "multiple value", bestehend aus basis-Elementen. Die Anordnung dieser basis-Elemente innerhalb des "multiple value" kann dabei beliebig vorgenommen werden.
192
13. GRAPHIC
Was wir in 12.2 über die Verknüpfung von Vektoren und Matrizen gesagt haben, gilt auch für die Verknüpfung von Bildern (vgl. 13.3): Wegen des nur begrenzt zur Verfügung stehenden Speicherraumes wird man an die Verknüpfungsroutinen nicht die Bilder selbst, sondern ihre Adressen übergeben. Deshalb haben wir das sw£-"field" eines pict nicht direkt als Reihe von basis-Elementen definiert, sondern als die Adresse, die sich auf solch eine Reihe bezieht. Durch Änderung dieser Adresse hat man außerdem die Möglichkeit, Reihen mit verschiedener Anzahl von basis-Elementen zu manipulieren. Um der Syntax von ALGOL68 zu genügen, müssen wir leider solch eine Adresse als einziges "field" in eine Struktur einbetten, damit die beiden rekursiven "modes" pict und basis "wellformed" sind (vgl. R7.4). Hätten wir definiert mode pict
= ref [ ] basis,
mode basis = union (ref transform, pict, primj (odermode basis = union (ref transform, ref pict, prim,/), so wären pict und basis nicht "wellformed"; denn ihre Rekursion würde zu einer mehrdeutigen Anwendung von "coercions" führen, wie folgendes Beispiel zeigt: basis a, b ; a := b Durch diese assignation soll der Adresse von a ein basis zugewiesen werden. Die rechte Seite b kann zwar ein basis liefern, jedoch nicht auf eindeutige Weise: i) der "apriori"-Wert ref basis von b wird durch das "dereferencing" in ein basis übergeführt. ü) Wie wir aus 12.5 wissen, kann durch das "rowing" nicht nur ein amode in eine einelementige [ ] amode , sondern auch ein ref amode in ein ref [ ] amode übergeführt werden (vgl. R6.6). Der "apriori"-Wert ref basis von b kann also durch das "rowing" in ein ref f ] basis, also in ein pict übergeführt werden. Sodann kann man das pict durch das "uniting" in ein basis überführen. Um solche Mehrdeutigkeiten zu vermeiden, moniert der Compiler die letzten beiden mode-declarations als syntaktisch inkorrekt.
13.1 Darstellung von Bildern: die GRAPHIC-"modes"
193
Desweiteren benötigen wir noch einen "mode", durch den der Benutzer das Koordinatensystem für sein auszugebendes Bild auf dem Bildschirm bzw. auf dem Zeichenblatt bestimmen kann. Hierfür definieren wir |
mode frame = struct (point left lower, right upper) ;
Durch die beiden "fields" werden also die Extremwerte von (-x , -y) ('untere linke Ecke') und (+x , +y) ('obere rechte Ecke') festgelegt.
194
13. GRAPHIC
13.2 Grund-Operationen Als Grund-Operator definieren wir: prio connect = 4 ; op connect = ('point pl,
p2j line : (pi,
p2);
op connect = /'line I, point q) poly : heap [1:3] step .= ((0, sp of I), (1, op connect = ('poly po, point fint n = upb heap [ l : n + l ] pol [l:n] := pol [n+1] := pol );
ep of I), (1,
q));
q) poly. po; step pol; po; (1, q);
Durch Anwendung des Operators connect haben wir also die Möglichkeit, zwei Punkte durch eine Linie zu verbinden, eine Linie mit einem weiteren Punkt zu einem Polygonzug zusammenzufassen sowie einen Polygonzug um einen weiteren Punkt zu erweitern. Allerdings muß folgendes beachtet werden: Da structure-displays (und auch row-displays) nur im "strong-context", also nicht im "firm-context" von Operanden stehen dürfen (vgl. R3.3.1.h, i, vgl. auch Band 1, Seite 189), so ist z.B. folgender Ausdruck syntaktisch inkorrekt: (0.0,
0.0) connect (0.25,
0.75) connect (0.75,
1.0) connect (1.0,
Man muß hier vorher point-Konstanten (oder point-Variablen) einfuhren, z.B. point po = (0.0, 0.0), pl = (0.25, 0.75), p3 = (1.0, 1.0); po connect pl connect p2 connect p3;
p2 = (0.75,
1.0),
1.0)
195
13.3 Operationen auf Bildern
13.3 Operationen auf Bildern 13.3.1 Transformationen Um ein basis-Element durch Translation, Skalierung oder Rotation verändern zu können, definieren wir:
prio on = 5,
scale 5,
rot =
5;
op on = /'basis a, point pj ref transform. case a in /'ref transform t): (position of t := p; (ref pict q): heap transform := (p, 0.0, 1.0, /'heap pict b ; b := q ; b)
t),
>
out heap transform .= (p, 0.0, 1.0, fheap pict b ; sub of b := heap [7:7] basis ;= a) esac;
)
op scale = /"basis a, real f ) ref transform : case a in (ref transform t): (factor of t := f ; t). /ref pict q) : heap transform .= ((0.0, 0.0j, 0.0, f , /'heap pict b ; b := q ; b)
) out heap transform := ((0.0, 0.0), 0.0, f , /heap pict b ; sub of b := heap [l'l] esac;
)
basis := a)
196
13. GRAPHIC
op rot = f basis a , real p h i ) ref transform: case a
in /'ref transform t ) : (angle ( r e f pict q ) :
of t := p h i ;
t),
heap transform :=
((0..0,
0.0), phi,
1.0,
/"heap pict b ;
b := q ; b ) J
out heap transform .=
((0.0, 0.0), phi,
1.0,
/'heap pict b ; s u b of b : = heap [ 1 : 1 ] basis := a )
)
esac; Beispiel: point p : = ( 1 . 0 ,
1.0);
pict p i c t u r e ;
picture
on
p
scale
0.5
Hier ergibt sich folgendes Bild:
rot
180.0;
13.3 Operationen auf Bildern
197
Das image-"field" des neu erzeugten transform-Elementes enthält also eine Kopie des pict. Dieses Kopieren tut uns jedoch nicht weh, da nur eine einfache Adresse transportiert wurde. Wird dann picture ein neues pict zugewiesen, so bezieht sich das image"field" des transform nach wie vor auf die alte Reihe von basis-Elementen.
13.3.2 Vereinigung Um zwei basis-Elemente zu einem neuen Bild vereinigen zu können, definieren wir den Operator U auf folgende Weise: prio U = 3 ; op U = f basis a, b) ref pict : fheap pict l ; sub of I := case a in ('ref pict p): case b in /"ref pict q): fint i = upb sub of p, j = upb sub of q ; heap [l:i+j] basis r; r [:i] := sub of p ; r [/+/:] := sub of q; r
) out ^int i = upb sub of p; heap [l:i+l ] basis r ; r [:/] := sub of p ; r [i+1 ] . = b r
)
esac ouse b in (ref pict q) : fint i = upb sub of q; heap [l:i+l] basis r; r [ i ] := a; r [2:] := sub of r
>
i);
out heap [1:2] basis := (a, esac;
bj
q;
13. GRAPHIC
198
Die Routine von U liefert als Ergebnis stets ein ref pict. Wird der Operator U in einer formula mehrmals hintereinander angewendet, so wird dieses Ergebnis durch das "uniting" in ein basis-Element übergeführt, welches dann als Parameter an eine weitere Routine von U übergeben werden kann. Damit das ref pict als Ergebnis der Vereinigungsroutine auch nach Abarbeitung des der Routine entsprechenden ränge zur Verfügung steht, muß zur Aufnahme eines pict Speicherplatz im "heap" reserviert werden (vgl. 8.2.2.b und Band 1, Seite 133). Darüber hinaus wird im "heap" auch Speicherplatz zur Aufnahme einer neuen Reihe von basis-Elementen reserviert. Je nachdem, welche basis-Elemente die beiden Operanden liefern, werden dann einzelne basis-Elemente oder Reihen von basis-Elementen in diese neue Reihe transportiert und dort aneinandergefügt. Man beachte dabei, daß stets die basis-Elemente bzw. die Reihen von basis-Elementen transportiert werden, die der linke und rechte Operand auf der obersten Stufe der Bildhierarchie liefern. Vgl. hierzu die Definition des Zuweisungsoperators 46, 8 1
bits-pattern I I 1 3 5
Anpassungsdiagramm I 191 Anpassungsoperation I 161, 162, 163 "aposteriori-mode" I 61, 162, 191
bits shorts I 177 bits width I 172; II 4 4 Blockstruktur I 59, 85 bold-Alphabet I 18
applied-identifier I 1 1 3 , 1 6 3 ; I I 3 1 , 3 4 ,
35, 38 applied-indicator I 2 8 , 6 9 ; II 38 applied-operator I 2 0 8 , 2 0 9 "apriori-mode" I 6 1 , 162, 191
äquivalent II 4 9 arccos I 38 (s. Prozedur, Standard-) aresin I 38 (s. Prozedur, Standard-) aretan I 38 (s. Prozedur, Standard-) arg I 218 (s. Operator, Standard-) assignation I 3 5 , 6 0 , 138, 139, 163; 1153,54 associate II 83 ¿associate format II 107 at I 99 at-symbol I 9 9
Aufzählbare Menge II 19 Ausfuhrung I 17
174
bits lengths I 177 bitspack I 223
bold-tag I 1 8
bold-Ziffer I 18 'boldface shift' I 55 « b o o k II 74 " b o o k " II 73 bool I 2 2 ; I I 4 4 (s. " m o d e " , Standard-) boolean choice-pattern I I 1 1 7 , 1 2 1 ,
124, 130, 136 boolean frame I I 1 3 3 boolean marker I I 1 2 9 , 1 3 3 boolean-pattern II 1 3 0 , 1 3 3
by I 78 byte' I 1 7 4
bytes I 174, 221; II 44 (s. " m o d e " , Standard-) bytes lengths 1 1 7 7 bytespack I 179, 180, 223
212 bytes shorts I 177 bytes width I 174 call I 60, 123, 127, 141, 163, 167 'call by reference' 1127 'call by value' I 123, 124 case I 75, 186 case-clause I 75, 163 cast 161, 104, 148, 163, 190. 193 cauchy (TORRIX) II 184 chart II 86 "channel" II 74 channel II 74 char I 22; II 44 (s. "mode", Standard-) char number II 85 character-denotation I 168 character-frame II 134 character-marker II 129, 134 "chaiacter"-Transput II 92 choice-clause I 59 Cholesky II 186 Chomsky, N. II 14 close II 84 closed-clause I 64, 163 'closed-unit' I 59 co I 19 codiag (TORRIX) II 173 "coercend" I 162 "coercer" I 162 "coercion" I 62, 161, 162 col (TORRIX) II 175 "collateral action" II 59 collateral-clause I 81, 163, 169; II 65 "collateral elaboration" I 46, 81, 211; 1159,65 collection II 114, 116, 120, 128, 129, 130 ^collection II 111 ^collitem II 111 COMARK II 128 comment I 19 'compilation' I 17 Compiler I 17, 26 compl I 24; II 44 (s. "mode", Standard-) "complete" II 59 completer I 83 complex-frame II 134 complex marker II 129, 134 complex-pattern II 134 compressible II 85 conditional-clause I 49, 70, 163 "conform" I 29 conformity-clause I 75, 163, 185 conj I 43, 219 (s. Operator, Standard-) connect (GRAPHIC) II 194
Index "construct" I 26; II 40 'context-free grammar' II 17 'context-sensitive grammar' II 18 control-identifier I 78, 79 copy (TORRIX) II 164, 165, 166 cos I 38 (s. Prozedur, Standard-) ^cpattern II 111 create II 83 d (digit marker) II 129, 132, 139 D E C II 32, 33 declaration 1 5 8 , 5 9 , 6 0 'declaration-prelude' I 63 declaration-symbol I 19 declarer I 23, 113 D E C S II 33 D E C S E T V II 3 3
defining-identifier I 113, 125; II 31, 36, 38 defining-indicator 1 2 8 , 6 9 defining-operator I 205, 208, 209 "defining range" I 69; II 36, 38 Deklaration I 66, 116, 119, 125, 135, 140, 145 - einer Prozedur I 119 - einer Variablen I 135 denotation I 20, 21, 22, 60, 163 denoter I 163 "deproceduring" I 162, 166, 190, 191 "dereferencing" I 162, 164, 190, 191 "descriptor" 191 destination I 35, 138, 139 diag (TORRIX) II 173 DIGIT II 33, 128 digit-frame II 132 digit marker II 129, 132 "direct action" II 59 divab I 44 (s. Operator, Standard-) do I 78, 79 down II 68 (s. Operator, Standard-) Dreiecksmatrix I 157; II 168 'dummy statement' 1171 Dünnbesetzte Matrix II 152 duo-operation-declaration I 205 dyadic-formula I 204 Dyadischer Operator I 37, 204, 206 e (exponent marker) II 129, 133, 140 Eingabe - , formatierte II 106 -.unformatierte I 39; II 101 "elaboration" I 26, 211; II 59 - , "collateral" I 46, 81, 211; II 59, 65 - , "serial" I 45; II 59, 65 elem I 173, 222 (s. Operator, Standard-) elif I 73
213
Index else I 70 EMPTY II 27 empty I 22 enclosed-clause I 5 9 , 1 6 3 , 1 9 3 ; I I 1 2 6 end I 6 4 , 8 1
entiei I 42, 45, 217 (s. Operator, Standard-) enquiry-clause I 7 0 , 7 6 , 7 8
"enthalten" I 28 "environ" II 49 - . " l o c a l " II 51 - , "necessary" II 55 - , "nonlocal" II 51 "environment enquiry" II 44 eq I 41, 43, 44, 173, 175, 215, 216, 219, 220, 221 (s. Operator, Standard-) "equivalent t o " II 49 Ereignisroutine II 89 'erhalten' 1 3 1 error char II 94 esac I 75, 186 estab possible II 86 establish II 88 "establishing around" II 49 'execution' I 17 exp I 38 (s. Prozedur, Standard-) exp width II 99 exponent-frame I I 1 3 3 exponent marker I I 1 2 9 , 1 3 3 expression I 8 5
/ II 137 false I 22 fi I 70 "field" I 52, 100 field-selector I 2 4 , 1 0 0
"file" II 76, 106 - , Standard- II 46, 101, 105, 107, 143 file II 77 (s. "mode", Standard-) 'finite state grammar' II 16 "firm context' I 189, 190, 191, 207 fitsin (TORRIX) II 176 fixed I 40; II 94, 96 (s. Prozedur, Standard-) "flat descriptor" I 93; II 159 flex I 92, 93, 94 «flextext II 74 flip II 98, 102 float I 40; II 94, 97 (s. Prozedur, Standard-) flop II 98, 102 for I 78 formal-declarer I 1 0 4 , 1 1 3 , 1 1 7 , 1 2 0 ,
127, 193 formal-parameter I 1 0 4 formal-plan I 2 0 5
FORMAT II 126 Format II 106 - , laufendes II 106, 107 - , Standard- II 93, 94 format I 22; II 106, 107, 110, 111, 112 (s. "mode", Standard-) format-pattern I I 1 3 7 Format-Text II 9 3 format-text I 1 6 3 ; I I 9 3 , 1 0 6 , 1 0 7 ,
113, 119, 120, 126, 128, 129 Formatierte Ausgabe II 106 Formatierte Eingabe II 106 Formatierter Transput II 93, 106 formatter-symbol ($) I I 1 2 9 formula 1 6 0 , 1 6 3 , 2 0 4 , 2 1 1 , 2 1 2
Wpattern II 111 frame I I 1 2 8 , 1 3 8 , 1 3 9 , 1 4 0 - , boolean- I I 1 3 3 , 1 4 0 - , character- I I 1 3 4 , 1 3 9 , 1 4 1 - , complex- I I 1 3 4 , 1 4 0 , 1 4 1 - , digit- I I 1 3 2 , 1 3 9 , 1 4 1 -.exponent- II 1 3 3 , 140, 1 4 1 - , point- I I 1 3 3 , 1 4 0 , 1 4 1 - , radix- I I 1 3 5 , 1 4 0 - , sign- I I 1 3 2 , 1 3 9 - , zero- I I 1 3 2 , 1 3 9
«frame II 111 frame-Tabelle II 1 3 9 , 1 4 0
from I 78 Funktion, mathematische I 38 (s. Prozedur, Standard-)
g II 137 'garbarge collection' I 134 Gaußscher Algorithmus (verketteter) II 185 ge I 41, 44, 173, 175, 216, 220, 221 (s. Operator, Standard-) general-pattern II 1 3 7
Generator I 133 generator I 1 3 3 , 1 3 4 , 1 6 3
get II 101 get bin II 142 get possible II 85 getf II 106 "good position" II 87 go-on-token I 1 9 , 4 6 , 5 8 , 6 3 , 168 goto I 1 7 0 , 1 7 1 goto-token I 5 0
igpattern II 111 GRAPHIC-library-prelude
II 1 8 9
Grundmenge I 21 gt I 41, 44, 175, 216, 220 (s. Operator, Standard-) Gültige Position II 87
Index
214 "heap" I 134 heap I 133, 134, 135 heap-generator
I 133, 134, 157, 159
"hyperrules" II 24, 39 I (complex marker) I I 1 2 9 , 1 3 4 , 1 4 0
i I 43, 45, 217, 218 (s. Operator, Standard-) identifier I 18, 20, 60, 89, 112, 113, 116, 125, 136, 138, 139 identifier-declaration I 66, 112, 133 "identifizieren" I 28, 29 Identifizierung I 67, 69; II 31 - e i n e s identifier 1 1 3 1 , 3 2 , 3 3 - e i n e s Operators I 208, 209, 210, 211 identity-declaration I 105, 112, 113, 116, 120, 123, 125, 128, 133, 212 identity-relation I 149, 163 identity-relator I 149, 154 if I 70 im I 43, 218 (s. Operator, Standard-) in I 75, 186 in-choice-clause I 70, 76 indexer I 96 indication I 18 indicator I 20 Indirekte Adressierung I 146 Informationsroutine II 84 "initiate" II 59 inprod (TORRIX) II 183 insertion II 128, 129, 130 ^insertion II 111 int I 22; II 44 (s. "mode", Standard-) int lengths I 176; II 44 int shorts I 176 int width II 99 integral choice-pattern 11121,135 integral-pattern II 130, 131 into (TORRIX) II 161 INTREAL II 32 «intype II 80 is I 149, 154 is-defined-as-token I 19, 23, 54, 113 is-not-token I 19 isnt I 149, 154 is-token I 19 'Jensen-device' I 199, 200 jump I 49, 60, 163, 170, 198, 199 k (alignment-code) 11129,131 Kollaterale Abarbeitung 1 4 5 , 4 6 ; II 59, 65,69 Kollaterale Aktion II 59 Kollateralität I 48, 82
Kommentar I 19 Konsistente Ersetzung II 24 Konstante I 32, 33, 116 Konstrukt II 40 Kontext I 188, 194 - , Arteines I 189 - , Ausbalancieren eines I 194 Kontextabhängige Grammatik, Sprache II 18 Kontextabhängigkeit II 29, 31, 38 Kontextbedingung II 29, 31, 38 Kontextfreie Grammatik, Sprache II 17 Konvertierungsroutine II 94 /(alignment-code) II 129, 131 label 149 label-identifier I 66, 170 "large syntactic marks" II 39 'Last-In-First-Out' ('LIFO') I 134, 143 Laufende Position II 87 Laufendes Format II 106, 107 LAYER II 32, 33 Layoutroutine II 87 le I 41, 44, 173, 175, 216, 220, 222 (s. Operator, Standard-) Lebensdauer I 33, 133, 134; II 53 leng I 177 LETTER II 33 level II 67, 68 library-prelude II 4 3 , 4 5 , 147, 149, 189 'liefern' 1 3 1 'LIFO' I 134, 144 line (GRAPHIC) II 190 line number II 85 Linie II 190 Liste I 157, 158, 160 literal II 128, 130 In I 38 (s. Prozedur, Standard-) loc I 133, 134, 135 "local environ" II 51 local-generator I 133, 134, 157, 159 "locale" I 26, 27, 28, 30; II 49, 53 lock II 84 "logical end" II 73, 103 long I 23, 175, 176, 177, 178 (s. 'modemaker') long (long. . . long) bits width I 177 long (long. . . long) bytes width I 177 long (long. . . long) max int I 176 long (long. . . long) max real I 176 loop-clause I 51, 78, 118, 119, 163 It I 41, 44, 175, 216, 220 (s. Operator, Standard-) lwb I 42, 100 (s. Operator, Standard-) make conv II 86 make term II 86, 103
Index MARK II 128 Maschinenwort I 172, 174 matray (TORRIX) II 156, 158 Matrix II 150, 151, 154 - , Band- II 168 - , Dreiecks- I 157; II 168 - , dünnbesetzte II 152 - , positiv definite II 185, 186 - , singulare II 186 - , symmetrische II 185,186 matrix (TORRIX) II 156, 157 matrix (TORRIX) II 160 max (TORRIX) II 177 max int I 22; II 44, 150 max real 122 maxabs (TORRIX) II 178 "meaningful" II 41 "meek context" I 189, 190, 191 "metanotion" II 23 "metaproduction" II 23 "metaproduction rule" II 39 Meta-Sprache II 23 min (TORRIX) II 177 minabs (TORRIX) II 178 minusab I 44, 224 (s. Operator, Standard-) mod I 41, 45, 216 (s. Operator, Standard-) modab I 44, 224 (s. Operator, Standard-) MODE II 32, 48 "mode" I 23; 1147,48,49 - , Standard- I 214 bits I 172,221; II 44 bool I 22; II 44 bytes I 174,221; II 44 char I 22; II 44 compi I 24; II 44 füe II 77 format I 22; II 106, 107, 110, 111, 112 int I 22; II 44 real 1 22; II 44 sema II 67 string I 92; II 44 void I 22; II 44 mode-declaration I 23, 6 6 , 106
"mode-independent-parsing" I 110,212 mode-indication I 20, 21, 23, 107, 113
'mode-maker' I 23, 89, 90, 175 [] 1 2 3 , 9 0 , 9 1 , 9 2 , 9 3 , 9 4 , 9 9 long I 23, 175, 176, 177, 178 proc I 23, 90, 103, 120 ref I 23, 90 short I 23, 175, 176, 177, 178 struct I 23, 90, 100, 101 union I 23, 181, 182, 186
215 monadic-formula I 2 0 4
Monadischer Operator I 37, 204, 206 mono-operation-declaration I 205
MU II 48 "multiple value" 1 5 1 , 8 1 , 9 1 ; II 47 n (Bestandteil eines "dynamic" replicator) II 129 "name" I 30, 3 1
ne I 41, 4 3 , 4 4 , 173, 175, 215, 216, 219, 220 (s. Operator, Standard-) Nebeneffekt 1 4 7 , 4 8 , 8 1 "necessary environ" II 55 NEST II 32, 33 newline II 88, 131, 142 newpage II 88, 131, 142 nextrandom I 130 Nicht-terminales Element II 14 nihil I 163 nil I 153, 154 "nonlocal environ" II 51 nonref I 90, 91 not I 42, 215, 223 (s. Operator, Standard-) NOTETY II 27 NOTION II 27 'notion' II 14 "notion" II 40 ?-number II 94 Objekt - , externes I 26; II 47 - , internes I 26; II 47 Objekt-Code I 17 od I 78, 79 odd I 42, 45, 217 (s. Operator, Standard-) on (GRAPHIC) II 195 on char error II 90, 102, 105, 138 on format end II 90, 107 on line end II 90, 103 on logical file end II 89, 103 on page end II 90, 103 on physical file end II 89, 103 "on"-Prozedur II 89, 90 "on"-Routine II 89, 90 on value error II 90, 103, 136, 137, 138 open II 83 'open-unit' 159 operand I 2 0 4 operation-declaration I 6 6 , 2 0 4
Operator I 37, 202, 203 - , dyadischer I 37, 204, 206 - , monadischer I 37, 204, 206 - , Standard- I 41, 214 + I 4 1 , 4 2 , 4 3 , 4 4 , 216, 219, 220
Index
216 - I 4 1 , 4 2 , 4 3 , 216, 219 X 1 41,43,216,219,220 / 141,43,217,219 i 1222 abs I 4 2 , 4 3 , 4 5 , 173, 215, 216, 218, 222 and I 41, 173, 215, 221 arg I 218 bin I 173, 222 conj I 43, 219 divab /:= I 44 down II 68 elem I 173, 222 entier 1 4 2 , 4 5 , 2 1 7 eq = 1 4 1 , 4 3 , 4 4 , 1 7 3 , 1 7 5 , 2 1 5 , 216, 219, 220, 221 ge » > = 1 4 1 , 4 4 , 1 7 3 , 1 7 5 , 2 1 6 , 220, 221 gt > 1 4 1 , 4 4 , 1 7 5 , 2 1 6 , 2 2 0 i 1 I 4 3 , 4 5 , 217, 218 im I 43, 218 le < < = I 41, 44, 173, 175, 216, 220, 221 leng I 177 level 1 1 6 7 , 6 8 It < 1 4 1 , 4 4 , 1 7 5 , 2 1 6 , 2 2 0 lwb I 42, 100 minusab - : = I 44, 224 mod 1 4 1 , 4 5 , 2 1 6 modab I 44, 224 ne f /= 1 4 1 , 4 3 , 4 4 , 1 7 3 , 1 7 5 , 2 1 5 , 2 1 6 , 2 1 9 , 2 2 0 , 221 not I 42, 215, 223 odd 1 4 2 , 4 5 , 2 1 7 or I 41, 173, 215, 221 over -r 1 4 1 , 4 5 , 2 1 6 overab = I 44, 224 plusab +:= 1 4 4 , 4 5 , 2 2 4 plusto +=: I 44, 224 re 1 4 3 , 2 1 8 repr I 42, 45; II 44 round 1 4 2 , 4 5 , 2 1 7 shorten I 177 sign 1 4 2 , 4 5 , 2 1 7 timesab X. - I 44, 224 up t XX 1 4 1 , 4 3 , 4 5 , 1 7 3 , 2 1 7 , 2 1 9 , 2 2 2 ; II 68 upb I 42, 100 —, zuweisender I 44, 223 operator I 2 0 4 operator-indication I 2 0
or I 41, 173, 215, 221 (s. Operator, Standard-) "orthogonal design" I 23 ouse I 76 out I 75
out-choice-clause I 7 0 , 7 6 ^ o u t t y p e II 7 9
over I 41, 45, 216 (s. Operator, Standard-) overab I 44, 224 (s. Operator, Standard-) p (alignment-code) II 1 2 9 , 1 3 1
page number II 85 par II 4 3 , 6 6 , 6 9 , 7 1 parallel-clause I 163;; II 6 6
Parallel-Verarbeitung 1 1 6 6 , 6 9 particular-postlude II 4 3 , 4 5 particular-prelude II 4 3 , 4 5 particular-program II 4 3 pattern - , boolean- II 1 3 0 , 1 3 3 - , boolean choice- I I 1 3 0 , 1 3 6 - , bits- II 1 3 5 - , complex- I I 1 3 4 - , format- II 1 3 7 general- I I 1 3 7 - , integral- II 1 3 0 , 1 3 1 - , integral choice- I I 1 2 1 , 1 3 5 - , real- II 1 3 0 , 1 3 2 - , string- II 1 3 0 , 1 3 4 - , type- II 1 3 0 , 1 3 1
«pattern II 111 Peripheres Gerät II 6 3 phrase I 5 8 , 5 9
'phrasestructure grammar' II 19 Phrasenstruktur-Grammatik II 14 pict (GRAPHIC) II 191 pictplus (GRAPHIC) II 200 picture II 1 0 7 , 1 1 4 , 1 1 6 , 1 2 0 , 1 2 8 , 1 2 9 ,
130,131 •»picture II 111 Apiece II 111 PLAIN II 32 "plain value" II 47 plusab I 44, 45, 224 (s. Operator, Standard-) plusto I 44, 224 (s. Operator, Standard-) point (GRAPHIC) II 190 'pointer' I 145, 146 point-frame II 133 point marker (.) II 1 1 7 , 1 2 9 , 1 3 3 , 1 4 0
poly (GRAPHIC) II 190 Polygonzug II 190, 191 ? p o s II 74 Position II 73 - , gültige II 87 - , laufende II 87 - , ungültige II 87 Positiv definite Matrix II 185, 186 pragment-symbol I 19
217
Index "predicate" II 29, 30, 35, 38 prim (GRAPHIC) II 191 "primal environ" II 49 primary I 1 6 3
print I 39; II 101 (s. Prozedur, Standard-) printf II 108 Priorität (eines Operators) I 38, 204, 206 priority-declaration
I 66, 206
proc I 23, 90, 103, 120 (s. 'modemaker') procedure-declaration
I 118, 120
"production rule" II 39 Produktions-Regel II 14 program I I 4 0 , 4 4 program-text I I 4 3 , 4 4
Programm I 20, 58; II 40 Programmtext I 17, 20 "property" I 66, 208 "protonotion" II 23, 39 Prozedur I 119, 120, 121, 128 - . A u f r u f einer I 121, 123, 127, 166, 167 - , Deklaration einer I 119 - , rekursive I 144 Standard- I 38, 214 arc cos I 38 arc sin I 38 arctan I 38 cos I 38 exp I 38 fixed I 40; II 94, 96 float I 40; II 94, 97 In I 38 print I 39; II 101 read I 39; II 105 sin I 38 sqrt I 38 tan I 38 whole I 40; II 94, 95 Prozeduraufruf I 121, 123, 127 Punkt II 190 put II 97, 98 put bin II 142 put possible II 85 putf II 106 q (alignment-code) II 129, 131 r (radix marker) II 134, 135 radix II 135, 140 "radix" I 173, 174 radix-frame II 135 radix marker II 135 range I 67, 70, 76, 78, 104, 187, 209 rational (TORRIX) II 156 re I 43, 218 (s. Operator, Standard-)
"reach" II 38 read I 39; II 105 (s. Prozedur, Standard-) read bin II 143 readf II 108 real I 22; II 44 (s. "mode", Standard-) real lengths I 176 real-pattern II 130, 132 real shorts I 176 real width II 99 ReguläreSprache II 17 Relation I 28, 29, 31 ref I 23, 90 (s. 'mode-maker') "reference language" II 42 Referenz-Stufe 191 ref-Stufe I 145, 146, 148, 150, 155 refmod I 90, 91 reidf II 86 reidf possible II 86 Reihe I 51,91, 155 replicator II 116, 117, 118, 121, 125, 128, 129, 131, 140 - , "dynamic" II 116, 131 - , unsuppressible I I 1 2 8
repr I 4 2 , 4 5 ; II 44 (s. Operator, Standard-) Repräsentation II 20, 23 "representation" 117; II 42 "representation language" II 39, 42 reset II 88 reset possible II 85 revprod (TORRIX) II 183 rot (GRAPHIC) II 195, 196 Rotation II 191, 195 round I 42, 45, 217 (s. Operator, Standard-) Routine I 37, 53, 103, 104, 105; II 47, 55 - , rekursive I 142 "routine" I 53; II 47 routine-text
I 37, 54, 103, 120, 127,
163, 205; II 55 row (TORRIX) II 175 row-display
181
row-of-character-denotation I 168 "rowing" I 162, 167, 190, 191; II 175, 192 'runtime'-System I 17, 26 s (suppression) I I 1 2 9 , 1 3 2 , 1 3 3 , 1 3 4 ,
139,140 sample-generator I 138 Satz II 14 Satzbau 158 seal (TORRIX) II 156
218 scalO (TORRIX) II 156 scall (TORRIX) II 156 scale (GRAPHIC) II 195 Schaufelbagger I 135 "scope" I 33, 133, 159; II 53, 54, 55 scratch II 84 secondary I 163 selection I 60, 102, 110, 163 sema II 67 (s. " m o d e " , Standard-) Semantik II 41 "semaphore" II 66, 67 "serial action" II 59 serial-clause I 49, 63, 70, 76, 78; II 65 "serial elaboration" I 45; II 59, 65 Serielle Abarbeitung 1 4 5 , 6 3 ; 1 1 5 9 , 6 5 , 69 Serielle Aktion II 59 set II 88 set char number II 88, 131 set possible II 85 short I 23, 175, 176, 177, 178 (s. 'mode-maker') short (short. . . short) bits width I 177 short (short. . . short) bytes width I 177 shorten I 177 (s. Operator, Standard-) sign I 42, 45, 217 (s. Operator, Standard-) sign-frame II 132 sign marker (+, - ) II 129, 132, 139 fsimplin II 80 ^simplout II 79 sin I 38 (s. Prozedur, Standard-) Singulare Matrix II 186 size (TORRIX) II 176 SIZETY II 32 Skalar II 153 Skalierung II 191, 195 skip I 163, 171 skip I 171 slice 1 6 0 , 9 5 , 110, 163 "slicing" I 94 small real 1 2 2 "small syntactic marks" II 39 "soft context" I 164, 189, 190, 191 "softly deproceduring" I 191 source I 35, 113, 120, 205 source-text I 17 space II 87, 131 span (TORRIX) II 179 'sparse-matrix' II 152, 158 specification I 186 Sprache II 14 sqrt I 38 (s. Prozedur, Standard-) square (TORRIX) II 176 "stack" I 134 stand back 1 1 4 6 , 9 1 , 143
Index stand back channel II 75, 143 stand conv II 86 stand in 1 1 4 6 , 9 1 , 101, 107 stand in channel II 75, 101, 107 standout 1146,91,101,107 stand out channel II 75, 105, 107 "standard environment" II 39, 4 3 Standard-"file" II 46, 101, 105, 107, 143 Standard-Format II 93, 94 Standard-"mode" I 214 (s. " m o d e " , Standard-) Standard-Operator I 41. 214 (s. Operator, Standard-) standard-prelude I 24, 38, 214; II 43, 44 Standard-Prozedur I 38, 214 (s. Prozedur, Standard-) start-unit I 78, 79 Startzeichen II 14 statement I 85 step (GRAPHIC) II 190 step-unit I 78, 79 Steuerungsprogramm II 63 stop-unit I 78, 79 STOWED II 32 "straightening" II 80, 98, 102, 107, 142 «•straightin II 80 i-straightout II 79 "strict language" II 39, 40 string I 92; II 44 (s. " m o d e " , Standard-) string-denotation I 168 string-pattern II 130, 134 "strong c o n t e x t " I 178, 189, 190, 191, 193 struct I 23, 90, 100, 101 (s. 'modemaker') structure-display 1 8 1 "structured value" I 52, 81, 100; II 47 Struktur I 52, 100, 155 STYLE II 27 submat (TORRIX) II 156, 158 "subscript" I 96 "subvalue" I 95 "suggestion" II 138, 139, 140 suppression II 117, 126, 129, 132, 133, 134 'switch' I 196 symbol I 18, 20; II 20, 23, 39 "symbol" II 39 Symmetrische Matrix II 185, 186 Synchronisierung II 65, 66 syntactic-symbol I 19 Syntaktische Position I 188 — eines Operanden I 207 Syntax I 58; II 39
Index system-prelude II 4 3 , 4 5 system-task II 4 3
TAG II 32, 33 TALLY 1127,48 tan I 38 (s. Prozedur, Standard-) Terminales Element II 14 "terminator" II 78, 86, 102 tertiary I 163
?-text II 74 then I 70 T H I N G II 27
timesab I 44, 224 (s. Operator, Standard-) to I 78 "to access" I 31, 113, 125 "to be of the same mode as" I 29 " t o be smaller than" I 29 " t o be widenable t o " I 29 "to coerce" I 162 "to contain" I 28 "to identify I 28 token 1 1 8 ; II 2 7
"to refer t o " I 29, 30 TORRIX-library-prelude II 1 4 9
transform (GRAPHIC) II 191 Translation II 191, 195 Transponierte (einer Matrix) II 174 Transput II 92 - , binärer II 92, 142 "character"- II 92 - , formatierter II 93, 106 - , unformatierter II 93 trimat (TORRIX) II 168 trimmer I 9 8
trnsp (TORRIX) II 174 true I 22 Typ-O-Grammatik II 19 Typ-l-Grammatik II 18 Typ-2-Grammatik II 17 Typ-3-Grammatik II 16 TYPE II 128 type-pattern II 1 3 0 , 1 3 1
Übersetzung I 17 Umgebung ("environ") II 49 "undefined" II 41, 107 *undefined II 82, 107, 136, 137, 138 Unformatierte Ausgabe I 39; II 97 Unformatierte Eingabe I 39; II 101 Unformatierter Transput II 93 Ungültige Position II 87 union I 23, 181, 182, 186 (s. 'modemaker') unit 1 5 8 , 5 9 , 104, 113, 116, 163 'unit-sequence' I 63 "united mode" I 181; II 49
219 "uniting" I 162, 183, 190, 191 UNSUPPRESSETY
II 1 2 8
up I 41, 43, 45, 173, 217, 219, 222; II 68 (s. Operator, Standard-) up-to-symbol I 98 upb I 42, 100 (s. Operator, Standard-) user-task II 4 3
"value" I 21 Van Wijngaarden, A. II 20 Van Wijngaarden-Grammatik 1. und 2. Stufe (1VWG, 2VWG) II 20, 22 Variable 1 3 0 , 3 1 , 3 3 , 9 0 - , Deklaration einer I 135 - , Erzeugung einer I 133, 134 - , Initialisierung einer I 138, 139 variable-declaration I 1 1 2 , 1 3 6 , 1 3 9
vecrow (TORRIX) II 156, 157 vecrow (TORRIX) II 160 Vektor II 150, 154 vector (TORRIX) II 156, 157 vector (TORRIX) II 160 Vereinigung (von Bildern) II 197 Verwaltungsroutine II 82 void I 22; II 44 (s. "mode", Standard-) "voiding" I 162, 168, 190, 191 Vokabular, Gesamt- II 14 "weak context" I 189, 190, 191 "well-formed mode' II 38, 192 Wert I 26; II 47 Wert-Transport I 35 while I 78 whole I 40; II 94, 95 (s. Prozedur, Standard-) "widening" I 162, 178, 190 191 write II 101 write bin II 143 writef II 108 x (alignment code) II 1 2 9 , 1 3 1 y (alignment code) II 1 2 9 , 1 3 1
"yield" I 31 z (zero marker, digit marker) II 1 2 9 ,
132, 139 zero (TORRIX) II 176 zero-frame II 1 3 2 zero marker II 1 2 9 , 1 3 2
zeromat (TORRIX) II 159 zerovec (TORRIX) II 159 Zugriff I 113, 125 136 Zuweisender Operator I 44, 223; II, 155 Zuweisung (von Bildern) II 198 Zweistufen-Grammatik II 13, 20, 22
Anhang parti cular-prograrc
ENCLOSEû-cl ause| -jclosec-clausel
-begin
Hcol 1 ateral -cl ause}- -{s)-
—begin
seri a 1 - cl aus e end
-{s]-par begin
-jpa rail ei-c1 ausë|
Lçid.-i)
ENCLOSED-clause
end
fs-uni 11ì,J {s-uniili,}
eni
-|condi tional-clausel m-enquiry-clause
-|c a s e - c 1 a u s e|
then
e Ine elif
seri al-ci ause
serial-clause | boolean-chooser)
Lei "t-m-enqui ry-cl ause in
-|conformi ty- ci ause| lIZ
- enq u i ry-ci ause in
^ -1 cop-cl ause|
'—t—^ —i — H ^~ W— W-i—— u b + i l e -for +
id from —•
ffdec {,. tf r o l d )
{unitil,)
1
m-enqui ry-cl ause do
m-unit b%_ ra-unit to_ m-unit +—4 + +—+
:
un
s-seri al-ci ause
repeating-part Wl/WWVWWV\i
[ loo
vari abledeclaration
-fdec
{id = s-unitl,)
-proa
(id » routine-text I,)
Hadec
theapj{proa
-|operati ondeclarati on
priori tydeclarati on
-prio
{operator » dgtl,} $dgt * OÌ
-[(m-uni t . m-uni ti,)) adec
vdec
- ^ { f d e c l j j j ^ j
( (adec
{TAG-sy I,) I,) ;
¡formai -KODE-decl arerl
C {fdec
{TAG-sy I,) I,) )
tROWS-of
—r-true Lf -false
only}
{TAG-sy |,) I,) ;
„(ch)„
stringdenotation
"{j^jll}"
Hb 11 s denotation
fäör.gT}*) ({short I )J
INTEGRALdenota ti on
¡¡¡MM
Lf.EAldenotati on
S {long
I)
int real igjwpZ
, . ïiMïll
16
HMM !!
|i denti fi er| LfTÄG^-—LETTER-(j)^ |operato"r|
bol d-1
(iHZi
-file
-t( + .-J,}] vdec ( {vdec
-pooTeandenotation
I
-format
vi rtual -MODE-decI arer| - f i e s vdec
•bool •char
: I,}] fdec
empty
tbut a REAL-denotati on is not and must have at least one d
ÌROWS-of only}
adec
^Throughout Throughout throughout throughout
{id := routine-text I,}
•ref
Hvo iddenotation
-character denotati on
: = s-unitl,)
{operator = s-unitl,)
actual- MODE-declarert-
-struct
{id
•££_ {operator = routi ne-text I,}
t:•££Cfdec, fdec;
-e trust
(adec] IJ \void
{bold-TAG-sy
i denti tydeclaration
+
od
Idenotati on|
—mode -frodedeci arati on
-fiez
lout serial-clause ) {fliege UN I TED-choose r )
':t)
¡deci arationi
^—struct
i o u t serial-clause 1 jöusa integral-chooserj
-sema bold-TAG-synbol
a declarer or slice one may replace [, ] an ENCLOSED-clause , begin, end a conditional-ci ause , then , e l i f , else a case- or conformity-clause, case, in, ouae, out,
ia monadic-operator does not begin with x, *, /, or = by by , fi by caac by
(, C, (, (,
) ; /; I , |,
etc I , I ,
Syntax-Diagramm von ALGOL68 (entnommen aus dem ALGOL-Bulletin, Nr. 3 7 )
?r®l?5!í? |e n q u i r y - c i a u s a[ |pro 1 ogu^
unitij (cxit
•. id
{unitl;}
( { u n i t ; 1}
ip-ologue
E
^ l ^ u
jrologus
•s o f t-TERT IARY i d r l
-Uumpl
(s)
go
(s}
g kip
TERTIARYl—[-jforirij'l at—•
s-TERTIARY
c ; : {operatorl}
f-SECONOARY
L-oprr prnd o p e r a t o r |oprnd|-{">}
f-forr,iul a
uL F: - :S E C O N D A R Y
nil_
ISCCONDARYI—Hselectionl
If i e l d - s e l e c t o r l o £
|PRIWARY|
Hgenerator| -identi fier
s-unit
s-TERTIARY |idrl| s o f t - T E R T I A R Y t o id
MiTTpj
L|n i h i 1
Report}
s o f t - T E R T I A R Y := ffdeci
Tt]—r-|a s s -i q 'i a 11 o nf-
ijçffj
W-SECONOARY
-TAG-sy actual-MOCE-declarer
K i d !
-Ens-
(
fs-uni 11,J
[ { in-uni t m-uni t
+
}
j
)
K
{RAOiX-digitl}
Cdgtl} (dgtI)
. (dgtI}
j'J
jtjtdgtl}
is n o t an I N T E G R A L - d e n o t a t i o n o n e d i g i t b e f o r e the e
C (A I I B}
(A IB} fcnot d e f i n e d h e r e bold-TAG-symbol x, *
— i : or
i [X *
/
< > =
etc.
and
4 = ne
8 down
m + - u r . i t• at + at
A 8
j j
2 or 3
s-ENCLOSED-cl.use
w-PRTWY
ENCLOSED-cl a u s e r
Standard priorities 1 + ; = x: * % : , - : = / : = %x: = + =:
7 x /
m-PRIMARY
2 4 8 —•f 16
SYNTAX CHART J.M.Wait Live"pocl J. E.l.Pzcfc Kaxtiiuk M.Sintzcj^ Slutitii April IS O
6 + -
-format-text
j
68
(revised)
5 < >«
-denotation
-Is 1 i eel
ALGOL
0
( d e c 1 a r a t i on I , } ; ! }
is not a p a r a n o t i o n of the R e v i s e d
i denti ty-fr e l a t i onl
: ;
LETTER-symbol, DIGIT-symbol, RADIX-di g i t , character-glyph, others t r i ng-i tem, bold-TAG-symbol, format-text i
is}-A
I,H
ehl 8h?
e
ler:
lub upb
9 1
m-uni t ^
A is e i t h e r B or C or D or E either A or B or C ABA ABABA etc.
[{AMB} j A can occur only in a strong position abed
abed +-- +
m - u n i+t
%
is a range
abed is ODtional
wmfs-
weakmeekf i rms trong-
adec
a c t u a l -f.GDEdeclarer character-glyph eh or others t r i n g - i teir DIGIT-symbol dgt formal-MODEf dec declarer i denti f i e r id i cien t i t y - re 1 a t o r idrl ciiooser-chc i ceKODEchooser us i ng-MODE dyadi c - o p e r a n d oprnd symbol sy vi r t u a l - H O D E vdec decIarer
tA comment or p r a g m a t , i . e . , a s e q u e n c e o f symbols e n c l o s e d by t> ki c o > comment , p r o r pragmat can occur anywhere except w i t h i n s y m b o l s , d e n o t a t i o n s and f o r m a t - t e x t s . }
1