summaryrefslogtreecommitdiff
path: root/doc/programming/programmierhandbuch.2b
diff options
context:
space:
mode:
Diffstat (limited to 'doc/programming/programmierhandbuch.2b')
-rw-r--r--doc/programming/programmierhandbuch.2b1395
1 files changed, 1395 insertions, 0 deletions
diff --git a/doc/programming/programmierhandbuch.2b b/doc/programming/programmierhandbuch.2b
new file mode 100644
index 0000000..c2103ba
--- /dev/null
+++ b/doc/programming/programmierhandbuch.2b
@@ -0,0 +1,1395 @@
+#headandbottom("52","EUMEL-Benutzerhandbuch","TEIL 2 : ELAN","2")#
+#pagenr ("%", 52)##setcount(1)##block##pageblock#
+#headeven#
+#center#EUMEL-Benutzerhandbuch
+#center#____________________________________________________________
+
+#end#
+#headodd#
+#center#TEIL 2 : ELAN
+#center#____________________________________________________________
+
+#end#
+#bottomeven#
+#center#____________________________________________________________
+2 - % #right#GMD
+#end#
+#bottomodd#
+#center#____________________________________________________________
+GMD #right#2 - %
+#end#
+
+
+2.5 Programmstruktur
+
+Ein ELAN-Programm kann aus mehreren Moduln (Bausteinen) aufgebaut sein, die in
+ELAN PACKETs genannt werden. Das letzte PACKET wird "main packet" genannt,
+weil in diesem das eigentliche Benutzerprogramm (Hauptprogramm) enthalten ist.
+Dies soll eine Empfehlung sein, in welcher Reihenfolge die Elemente eines PACKETs
+geschrieben werden sollen:
+
+Ein "main packet" kann aus folgenden Elementen bestehen:
+
+a) Deklarationen und Anweisungen. Diese müssen nicht in einer bestimmten Reihen­
+ folge im Programm erscheinen, sondern es ist möglich, erst in dem Augenblick zu
+ deklarieren, wenn z.B. eine neue Variable benötigt wird. Es ist jedoch gute Pro­
+ grammierpraxis, die meisten Deklarationen an den Anfang eines Programms oder
+ Programmteils (Refinement, Prozedur) zu plazieren.
+
+ <Deklarationen> ;
+ <Anweisungen>
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ INT VAR erste zahl, zweite zahl;
+
+ page;
+ put ("erste Zahl = "); get (erste zahl);
+ put ("zweite Zahl ="); get (zweite zahl)
+
+____________________________________________________________________________
+
+
+b) Deklarationen, Refinements und Anweisungen. In diesem Fall ist es notwendig, die
+ Refinements hintereinander zu plazieren. Refinement-Aufrufe und/oder
+ Anweisungen sollten textuell vorher erscheinen.
+
+ <Deklarationen> ;
+ <Refinement-Aufrufe und/oder Anweisungen> .
+ <Refinements>
+
+ Innerhalb der Refinements sind Anweisungen und/oder Deklarationen möglich.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ INT VAR erste zahl, zweite zahl;
+
+ loesche bildschirm;
+ lies zwei zahlen ein.
+
+ loesche bildschirm:
+ page.
+
+ lies zwei zahlen ein:
+ put ("erste Zahl = "); get (erste zahl);
+ put ("zweite Zahl ="); get (zweite zahl).
+
+____________________________________________________________________________
+
+
+c) Deklarationen, Prozeduren und Anweisungen. Werden Prozeduren vereinbart,
+ sollte man sie nach den Deklarationen plazieren. Danach sollten die Anweisungen
+ folgen:
+
+ <Deklarationen> ;
+ <Prozeduren> ;
+ <Anweisungen>
+
+ Mehrere Prozeduren werden durch ";" voneinander getrennt. In diesem Fall sind
+ die Datenobjekte aus den Deklarationen außerhalb von Prozeduren statisch, d.h.
+ während der gesamten Laufzeit des Programm vorhanden. Solche Datenobjekte
+ werden auch PACKET-Daten genannt. Im Gegensatz dazu sind die Datenobjekte
+ aus Deklarationen in Prozeduren dynamische Datenobjekte, die nur während der
+ Bearbeitungszeit der Prozedur existieren. Innerhalb einer Prozedur dürfen wieder­
+ um Refinements verwendet werden. Ein Prozedur-Rumpf hat also den formalen
+ Aufbau wie unter a) oder b) geschildert.
+
+ Die Refinements und Datenobjekte, die innerhalb einer Prozedur deklariert wurden,
+ sind lokal zu dieser Prozedur, d.h. können von außerhalb nicht angesprochen
+ werden.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ INT VAR erste zahl, zweite zahl;
+
+ PROC vertausche (INT VAR a, b):
+ INT VAR x;
+
+ x := a;
+ a := b;
+ b := x
+ END PROC vertausche;
+
+ put ("erste Zahl = "); get (erste zahl);
+ put ("zweite Zahl ="); get (zweite zahl);
+ IF erste zahl > zweite zahl
+ THEN vertausche (erste zahl, zweite zahl)
+ FI
+
+____________________________________________________________________________
+
+
+d) Deklarationen, Prozeduren, Anweisungen und PACKET-Refinements. Zusätzlich
+ zu der Möglichkeit c) ist es erlaubt, neben den Anweisungen außerhalb einer
+ Prozedur auch Refinements zu verwenden:
+
+ <Deklarationen> ;
+ <Prozeduren> ;
+ <Anweisungen> .
+ <Refinements>
+
+ Diese Refinements können nun in Anweisungen außerhalb der Prozeduren benutzt
+ werden oder auch durch die Prozeduren (im letzteren Fall spricht man analog zu
+ globalen PACKET-Daten auch von PACKET-Refinements oder globalen Refine­
+ ments). In PACKET-Refinements dürfen natürlich keine Datenobjekte verwandt
+ werden, die lokal zu einer Prozedur sind.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ INT VAR erste zahl, zweite zahl;
+
+ PROC vertausche (INT VAR a, b):
+ INT VAR x;
+
+ x := a;
+ a := b;
+ b := x
+ END PROC vertausche;
+
+ loesche bildschirm;
+ lies zwei zahlen ein;
+ ordne die zahlen.
+
+ loesche bildschirm:
+ page.
+
+ lies zwei zahlen ein:
+ put ("erste Zahl = "); get (erste zahl);
+ put ("zweite Zahl ="); get (zweite zahl).
+
+ ordne die zahlen:
+ IF erste zahl > zweite zahl
+ THEN vertausche (erste zahl, zweite zahl)
+ FI
+
+____________________________________________________________________________
+#page#
+
+2.6 Zusammengesetzte Datentypen
+
+In ELAN gibt es die Möglichkeit, gleichartige oder ungleichartige Datenobjekte zu
+einem Objekt zusammenzufassen.
+
+
+2.6.1 Reihung
+
+Die Zusammenfassung gleichartiger Datenobjekte, wird in ELAN eine Reihung (ROW)
+genannt. Die einzelnen Objekte einer Reihung werden Elemente genannt.
+
+Eine Reihung wird folgendermaßen deklariert:
+
+- Schlüsselwort #on("i")##on("b")#ROW#off("i")##off("b")#
+- Anzahl der zusammengefaßten Elemente
+ (INT-Denoter oder durch LET definierter Name)
+- Datentyp der Elemente
+- Zugriffsrecht ( #on("i")##on("b")#VAR#off("i")##off("b")# oder #on("i")##on("b")#CONST#off("i")##off("b")# )
+- Name der Reihung.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ ROW 10 INT VAR feld
+
+____________________________________________________________________________
+
+
+Im obigen Beispiel wird eine Reihung von 10 INT-Elementen deklariert. ROW 10 INT
+ist ein (neuer, von den elementaren unterschiedlicher) Datentyp, für den keine Opera­
+tionen definiert sind, außer der Zuweisung. Das Accessrecht (VAR im obigen Bei­
+spiel) und der Name ('feld') gilt - wie bei den elementaren Datentypen - für diesen
+neuen Datentyp, also für alle 10 Elemente.
+
+Warum gibt es keine Operationen außer der Zuweisung? Das wird sehr schnell
+einsichtig, wenn man bedenkt, daß es ja sehr viele Datentypen (zusätzlich zu den
+elementaren) gibt, weil Reihungen von jedem Datentyp gebildet werden können:
+
+
+ROW 1 INT ROW 1 REAL
+ROW 2 INT ROW 2 REAL
+ : :
+ROW maxint INT ROW maxint REAL
+
+ROW 1 TEXT ROW 1 BOOL
+ROW 2 TEXT ROW 2 BOOL
+ : :
+ROW maxint TEXT ROW maxint BOOL
+
+
+Für die elementaren INT-, REAL-, BOOL- und TEXT-Datentypen sind unter­
+schiedliche Operationen definiert. Man müßte nun für jeden dieser zusammengesetz­
+ten Datentypen z.B. auch 'get'- und 'put'-Prozeduren schreiben, was allein vom
+Schreibaufwand sehr aufwendig wäre. Das ist der Grund dafür, daß es keine vorgege­
+bene Operationen auf zusammengesetzte Datentypen gibt.
+
+Zugegebenermaßen könnte man mit solchen Datentypen, die nur über eine Operation
+verfügen (Zuweisung), nicht sehr viel anfangen, wenn es nicht eine weitere vorgege­
+bene Operation gäbe, die Subskription. Sie erlaubt es, auf die Elemente einer Reih­
+ung zuzugreifen und den Datentyp der Elemente "aufzudecken".
+
+Form:
+
+Rowname #on("i")##on("b")#[#off("i")##off("b")# Indexwert #on("i")##on("b")#]#off("i")##off("b")#
+
+Beispiel:
+
+
+feld [3]
+
+
+bezieht sich auf das dritte Element der Reihung 'feld' und hat den Datentyp INT. Für
+INT-Objekte haben wir aber einige Operationen, mit denen wir arbeiten können.
+
+____________________________________________________________________________
+ ........................... Beispiele: ........................
+ feld [3] := 7;
+ feld [4] := feld [3] + 4;
+
+____________________________________________________________________________
+
+
+Eine Subskription "schält" also vom Datentyp ein ROW ab und liefert ein Element der
+Reihung. Die Angabe der Nummer des Elements in der Reihung nennt man Subskript
+oder Index (in obigem Beispiel '3'). Der Subskript wird in ELAN in eckigen Klammern
+angegeben, um eine bessere Unterscheidung zu den runden Klammern in Ausdrücken
+zu erreichen. Ein subskribiertes ROW-Datenobjekt kann also überall da verwendet
+werden, wo ein entsprechender Datentyp benötigt wird (Ausnahme: nicht als Schlei­
+fenvariable).
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ PROC get (ROW 10 INT VAR feld):
+ INT VAR i;
+ FOR i FROM 1 UPTO 10 REP
+ put (i); put ("tes Element bitte:");
+ get (feld [i]);
+ line
+ END REP
+ END PROC get;
+
+ PROC put (ROW 10 INT CONST feld):
+ INT VAR i;
+ FOR i FROM 1 UPTO 10 REP
+ put (i); put ("tes Element ist:");
+ put (feld [i]);
+ line
+ END REP
+ END PROC put
+
+____________________________________________________________________________
+
+
+In diesen Beispielen werden Reihungen als Parameter benutzt.
+
+Diese beiden Prozeduren werden im folgenden Beispiel benutzt um 10 Werte einzu­
+lesen und die Summe zu berechnen:
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ ROW 10 INT VAR werte;
+ lies werte ein;
+ summiere sie;
+ drucke die summe und einzelwerte.
+
+ lies werte ein:
+ get (werte).
+
+ summiere sie:
+ INT VAR summe :: 0, i;
+ FOR i FROM 1 UPTO 10 REP
+ summe INCR werte [i]
+ END REP.
+
+ drucke die summe und einzelwerte:
+ put (werte);
+ line;
+ put ("Summe:"); put (summe).
+
+____________________________________________________________________________
+
+
+Da es möglich ist, von jedem Datentyp eine Reihung zu bilden, kann man natürlich
+auch von einer Reihung eine Reihung bilden:
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ ROW 5 ROW 10 INT VAR matrix
+
+____________________________________________________________________________
+
+
+Für eine "doppelte" Reihung gilt das für "einfache" Reihungen gesagte. Wiederum
+existieren keine Operationen für dieses Datenobjekt (außer der Zuweisung), jedoch ist
+es durch Subskription möglich, auf die Elemente zuzugreifen:
+
+
+matrix [3]
+
+
+liefert ein Datenobjekt mit dem Datentyp ROW 10 INT.
+
+Subskribiert man jedoch 'matrix' nochmals, so erhält man ein INT:
+
+
+matrix [2] [8]
+
+
+(jede Subskription "schält" von Außen ein ROW vom Datentyp ab).
+#page#
+
+2.6.2 Struktur
+
+Strukturen sind Datenverbunde wie Reihungen, aber die Komponenten können unglei­
+chartige Datentypen haben. Die Komponenten von Strukturen heißen Felder (Reihun­
+gen: Elemente) und der Zugriff auf ein Feld Selektion (Reihungen: Subskription). Eine
+Struktur ist - genauso wie bei Reihungen - ein eigener Datentyp, der in einer
+Deklaration angegeben werden muß.
+
+Die Deklaration einer Struktur sieht folgendermaßen aus:
+
+- Schlüsselwort #schl ("STRUCT#off("i")##off("b")#
+- unterschiedliche Datenobjekte in Klammern. Die Datenobjekte werden mit Datentyp und Namen angegeben
+- Zugriffsrecht ( #on("i")##on("b")#VAR#off("i")##off("b")# oder #on("i")##on("b")#CONST#off("i")##off("b")# )
+- Name der Struktur.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ STRUCT (TEXT name, INT alter) VAR ich
+
+____________________________________________________________________________
+
+
+Wiederum existieren keine Operationen auf Strukturen außer der Zuweisung und der
+Selektion, die es erlaubt, Komponenten aus einer Struktur herauszulösen.
+
+Die Selektion hat folgende Form:
+
+Objektname #on("i")##on("b")#.#off("i")##off("b")# Feldname
+
+Beispiele:
+
+
+ich . name
+ich . alter
+
+
+Die erste Selektion liefert einen TEXT-, die zweite ein INT-Datenobjekt. Mit diesen
+(selektierten) Datenobjekten kann - wie gewohnt - gearbeitet werden (Ausnahme:
+nicht als Schleifenvariable).
+
+Zum Datentyp einer Struktur gehören auch die Feldnamen:
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ STRUCT (TEXT produkt name, INT artikel nr) VAR erzeugnis
+
+____________________________________________________________________________
+
+
+Die obige Struktur ist ein anderer Datentyp als im ersten Beispiel dieses Abschnitts,
+da die Namen der Felder zur Unterscheidung hinzugezogen werden. Für Strukturen -
+genauso wie bei Reihungen - kann man sich neue Operationen definieren.
+
+Im folgenden Programm werden eine Struktur, die Personen beschreibt, die Prozedu­
+ren 'put', 'get' und der dyadische Operator HEIRATET definiert. Anschließend werden
+drei Paare verHEIRATET.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ PROC get (STRUCT (TEXT name, vorname, INT alter) VAR p):
+ put ("bitte Nachname:"); get ( p.name);
+ put ("bitte Vorname:"); get ( p.vorname);
+ put ("bitte Alter:"); get ( p.alter);
+ line
+ END PROC get;
+
+ PROC put (STRUCT (TEXT name, vorname, INT alter) CONST p):
+ put (p.vorname); put (p.name);
+ put ("ist");
+ put (p.alter);
+ put ("Jahre alt");
+ line
+ END PROC put;
+
+ OP HEIRATET
+ (STRUCT (TEXT name, vorname, INT alter) VAR w,
+ STRUCT (TEXT name, vorname, INT alter) CONST m):
+ w.name := m.name
+ END OP HEIRATET;
+
+____________________________________________________________________________
+
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ ROW 3 STRUCT (TEXT name, vorname, INT alter) VAR frau,
+ mann;
+
+ personendaten einlesen;
+ heiraten lassen;
+ paardaten ausgeben.
+
+ personendaten einlesen:
+ INT VAR i;
+ FOR i FROM 1 UPTO 3 REP
+ get (frau [i]);
+ get (mann [i])
+ END REP.
+
+ heiraten lassen:
+ FOR i FROM 1 UPTO 3 REP
+ frau [i] HEIRATET mann [i]
+ END REP.
+
+ paardaten ausgeben:
+ FOR i FROM 1 UPTO 3 REP
+ put (frau [i]);
+ put ("hat geheiratet:"); line;
+ put (mann [i]); line
+ END REP.
+
+____________________________________________________________________________
+
+
+Reihungen und Strukturen dürfen miteinander kombiniert werden, d.h. es darf eine
+Reihung in einer Struktur erscheinen oder es darf eine Reihung von einer Struktur
+vorgenommen werden. Selektion und Subskription sind in diesen Fällen in der Reihen­
+folge vorzunehmen, wie die Datentypen aufgebaut wurden (von außen nach innen).
+#page#
+
+2.6.3 LET-Konstrukt für zusammengesetzte Datentypen
+
+
+Die Verwendung von Strukturen oder auch Reihungen kann manchmal schreibauf­
+wendig sein. Mit dem LET-Konstrukt darf man Datentypen einen Namen geben.
+Dieser Name steht als Abkürzung und verringert so die Schreibarbeit. Zusätzlich wird
+durch die Namensgebung die Lesbarkeit des Programms erhöht.
+
+Form:
+
+#on("i")##on("b")#LET#off("i")##off("b")# Name #on("i")##on("b")#=#off("i")##off("b")# Datentyp
+
+Der Name darf nur aus Großbuchstaben (ohne Blanks) bestehen.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ LET PERSON = STRUCT (TEXT name, vorname, INT alter);
+
+ PROC get (PERSON VAR p):
+ put ("bitte Nachname:"); get ( p.name);
+ put ("bitte Vorname:"); get ( p.vorname);
+ put ("bitte Alter:"); get ( p.alter);
+ line
+ END PROC get;
+
+ PROC put (PERSON CONST p):
+ put (p.vorname); put (p.name); put ("ist");
+ put (p.alter); put ("Jahre alt"); line
+ END PROC put;
+
+ OP HEIRATET (PERSON VAR f, PERSON CONST m):
+ f.name := m.name
+ END OP HEIRATET;
+
+ ROW 3 PERSON VAR mann, frau;
+
+____________________________________________________________________________
+
+
+Überall, wo der abzukürzende Datentyp verwandt wird, kann stattdessen der Name
+PERSON benutzt werden. Wohlgemerkt: PERSON ist kein neuer Datentyp, sondern
+nur ein Name, der für STRUCT (....) steht. Der Zugriff auf die Komponenten des
+abgekürzten Datentyps bleibt erhalten (was bei abstrakten Datentypen, die später
+erklärt werden, nicht mehr der Fall ist).
+
+Neben der Funktion der Abkürzung von Datentypen kann das LET-Konstrukt auch
+zur Namensgebung für Denoter verwandt werden (siehe 2.3.1.2).
+
+
+
+2.6.4 Denoter für zusammengesetzte
+ Datentypen (Konstruktor)
+
+
+Oft ist es notwendig, Datenverbunden Werte zuzuweisen (z.B.: bei der Initialisierung).
+Dies kann durch normale Zuweisungen erfolgen:
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ LET PERSON = STRUCT (TEXT name, vorname, INT alter);
+
+ PERSON VAR mann;
+
+ mann.name := "meier";
+ mann.vorname := "egon";
+ mann.alter := 27
+
+____________________________________________________________________________
+
+
+Eine andere Möglichkeit für die Wertbesetzung von Datenverbunden ist der Konstruk­
+tor:
+
+Form:
+
+Datentyp #on("i")##on("b")#:#off("i")##off("b")# #on("i")##on("b")#(#off("i")##off("b")# Wertliste #on("i")##on("b")#)#off("i")##off("b")#
+
+In der Wertliste wird für jede Komponente des Datentyps, durch Kommata getrennt,
+ein Wert aufgeführt. Besteht eine der Komponenten wiederum aus einem Datenver­
+bund, muß innerhalb des Konstruktors wiederum ein Konstruktor eingesetzt werden.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ LET PERSON = STRUCT (TEXT name, vorname, INT alter);
+
+ PERSON VAR mann, frau;
+
+ frau := PERSON : ( "niemeyer", "einfalt", 65);
+ frau HEIRATET PERSON : ( "meier", "egon", 27)
+
+____________________________________________________________________________
+
+
+Ein Konstruktor ist also ein Mechanismus, um ein Datenobjekt eines Datenverbundes
+in einem Programm zu notieren.
+
+Konstruktoren sind natürlich für Reihungen auch möglich:
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ ROW 7 INT VAR feld;
+ feld := ROW 7 INT : ( 1, 2, 3, 4, 5, 6, 7);
+____________________________________________________________________________
+#page#
+
+2.7 Abstrakte Datentypen
+
+
+2.7.1 Definition neuer Datentypen
+
+Im Gegensatz zur LET-Vereinbarung für Datentypen, bei der lediglich ein neuer
+Name für einen bereits vorhandenen Datentyp eingeführt wird und bei der somit auch
+keine neuen Operationen definiert werden müssen (weil die Operationen für den
+abzukürzenden Datentyp verwandt werden können), wird durch eine TYPE-Verein­
+barung ein gänzlich neuer Datentyp eingeführt.
+
+Form:
+
+#on("i")##on("b")#TYPE#off("i")##off("b")# Name #on("i")##on("b")#=#off("i")##off("b")# Feinstruktur
+
+Der Name darf nur aus Großbuchstaben (ohne Blanks) bestehen. Die Feinstruktur
+(konkreter Typ, Realisierung des Datentyps) kann jeder bereits definierte Datentyp
+sein.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ TYPE PERSON = STRUCT (TEXT name, vorname, INT alter)
+
+____________________________________________________________________________
+
+
+Der neudefinierte Datentyp wird abstrakter Datentyp genannt. Im Gegensatz zu
+Strukturen und Reihungen stehen für solche Datentypen noch nicht einmal die Zuwei­
+sung zur Verfügung. Ein solcher Datentyp kann genau wie alle anderen Datentypen
+verwendet werden (Deklarationen, Parameter, wertliefernde Prozeduren, als Kompo­
+nenten in Reihungen und Strukturen usw.).
+
+Wird der Datentyp über die Schnittstelle des PACKETs anderen Programmteilen zur
+Verfügung gestellt, so müssen Operatoren und/oder Prozeduren für den Datentyp
+ebenfalls "herausgereicht" werden. Da dann der neudefinierte Datentyp genauso wie
+alle anderen Datentypen verwandt werden kann, aber die Komponenten (Feinstruktur)
+nicht zugänglich sind, spricht man von abstrakten Datentypen.
+
+Welche Operationen sollten für einen abstrakten Datentyp zur Verfügung stehen?
+Obwohl das vom Einzelfall abhängt, werden meistens folgende Operationen und
+Prozeduren definiert:
+
+- 'get'- und 'put'-Prozeduren.
+- Zuweisung (auch für die Initialisierung notwendig).
+- Denotierungs-Prozedur (weil kein Konstruktor für den abstrakten Datentyp außer­
+ halb des definierenden PACKETs zur Verfügung steht)
+
+
+
+2.7.2 Konkretisierung
+
+Um neue Operatoren und/oder Prozeduren für einen abstrakten Datentyp zu schrei­
+ben, ist es möglich, auf die Komponenten des Datentyps (also auf die Feinstruktur)
+mit Hilfe des Konkretisierers zuzugreifen. Der Konkretisierer arbeitet ähnlich wie die
+Subskription oder Selektion: er ermöglicht eine typmäßige Umbetrachtung vom ab­
+strakten Typ zum Datentyp der Feinstruktur.
+
+Form:
+
+#on("i")##on("b")#CONCR#off("i")##off("b")# #on("i")##on("b")#(#off("i")##off("b")# Ausdruck #on("i")##on("b")#)#off("i")##off("b")#
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ TYPE MONAT = INT;
+
+ PROC put (MONAT CONST m):
+ put ( CONCR (m))
+ END PROC put;
+
+____________________________________________________________________________
+
+
+Der Konkretisierer ist bei Feinstrukturen notwendig, die von elementarem Datentyp
+sind. Besteht dagegen die Feinstruktur aus Reihungen oder Strukturen, dann wird
+durch eine Selektion oder Subskription eine implizite Konkretisierung vorgenommen.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ TYPE LISTE = ROW 100 INT;
+
+ LISTE VAR personal nummer;
+ ...
+ personal nummer [3] := ...
+ (* das gleiche wie *)
+ CONCR (personal nummer) [3] := ...
+
+____________________________________________________________________________
+
+
+2.7.3 Denoter für abstrakte
+ Datentypen (Konstruktor)
+
+
+Denoter für neudefinierte Datentypen werden mit Hilfe des Konstruktors gebildet:
+
+Form:
+
+Datentyp #on("i")##on("b")#:#off("i")##off("b")# #on("i")##on("b")#(#off("i")##off("b")# Wertliste #on("i")##on("b")#)#off("i")##off("b")#
+
+In der Wertliste wird für jede Komponente des Datentyps, durch Kommata getrennt,
+ein Wert aufgeführt. Besteht eine der Komponenten wiederum aus einem Datenver­
+bund, muß innerhalb des Konstruktors wiederum ein Konstruktor eingesetzt werden.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ TYPE GEHALT = INT;
+
+ GEHALT VAR meins :: GEHALT : (10000);
+
+____________________________________________________________________________
+
+
+Besteht die Feinstruktur aus einem Datenverbund, muß der Konstruktor u.U. mehrfach
+geschachtelt angewandt werden:
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ TYPE KOMPLEX = ROW 2 REAL;
+
+ KOMPLEX CONST x :: KOMPLEX : ( ROW 2 REAL : ( 1.0, 2.0));
+
+____________________________________________________________________________
+
+
+Auf die Feinstruktur über den Konkretisierer eines neudefinierten Datentyps darf nur in
+dem PACKET zugegriffen werden, in dem der Datentyp definiert wurde. Der Konstruk­
+tor kann ebenfalls nur in dem typdefinierenden PACKET verwandt werden.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ PACKET widerstaende DEFINES WIDERSTAND, REIHE, PARALLEL,
+ :=, get, put:
+
+ TYPE WIDERSTAND = INT;
+
+ OP := (WIDERSTAND VAR l, WIDERSTAND CONST r):
+ CONCR (l) := CONCR (r)
+ END OP :=;
+
+ PROC get (WIDERSTAND VAR w):
+ INT VAR i;
+ get (i);
+ w := WIDERSTAND : (i)
+ END PROC get;
+
+ PROC put (WIDERSTAND CONST w):
+ put (CONCR (w))
+ END PROC put;
+
+ WIDERSTAND OP REIHE (WIDERSTAND CONST l, r):
+ WIDERSTAND : ( CONCR (l) + CONCR (r))
+ END OP REIHE;
+
+ WIDERSTAND OP PARALLEL (WIDERSTAND CONST l, r):
+ WIDERSTAND :
+ ((CONCR (l) * CONCR (r)) DIV (CONCR (l) + CONCR (r)))
+ END OP PARALLEL
+
+ END PACKET widerstaende
+
+____________________________________________________________________________
+
+
+Dieses Programm realisiert den Datentyp WIDERSTAND und mit den Operationen
+eine Fachsprache, mit dem man nun leicht WIDERSTANDs-Netzwerke berechnen
+kann, wie z.B. folgendes:
+
+
+
+ +---R4---+
+ | |
+ +---R1---+ +---R5---+
+ | | | |
+ ---+ +---R3---+ +---
+ | | | |
+ +---R2---+ +---R6---+
+ | |
+ +---R7---+
+
+
+Zur Berechnung des Gesamtwiderstandes kann nun folgendes Programm geschrieben
+werden:
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ ROW 7 WIDERSTAND VAR r;
+ widerstaende einlesen;
+ gesamtwiderstand berechnen;
+ ergebnis ausgeben.
+
+ widerstaende einlesen:
+ INT VAR i;
+ FOR i FROM 1 UPTO 7 REP
+ put ("bitte widerstand R"); put (i); put (":");
+ get (r [i]);
+ END REP.
+
+ gesamtwiderstand berechnen:
+ WIDERSTAND CONST rgesamt :: (r [1] PARALLEL r [2]) REIHE
+ r [3] REIHE (r [4] PARALLEL r [5] PARALLEL r [6]
+ PARALLEL r [7]).
+
+ ergebnis ausgeben:
+ line;
+ put (rgesamt).
+____________________________________________________________________________
+#page#
+
+2.8 Dateien
+
+Dateien werden benötigt, wenn
+
+- Daten über die Abarbeitungszeit eines Programms aufbewahrt werden sollen;
+- der Zeitpunkt oder Ort der Datenerfassung nicht mit dem Zeitpunkt oder Ort der
+ Datenverarbeitung übereinstimmt;
+- die gesamte Datenmenge nicht auf einmal in den Zentralspeicher eines Rechners
+ paßt;
+- die Anzahl und/oder Art der Daten nicht von vornherein bekannt sind.
+
+Eine Datei ("file") ist eine Zusammenfassung von Daten, die auf Massenspeichern
+aufbewahrt wird. Dateien sind in bestimmten Informationsmengen, den Sätzen ("re­
+cords") organisiert.
+
+
+
+2.8.1 Datentypen FILE und DIRFILE
+
+In ELAN gibt es zwei Arten von Dateien. Sie werden durch die Datentypen FILE
+und DIRFILE realisiert:
+
+
+
+FILE:
+sequentielle Dateien. Die Sätze können nur sequentiell gelesen bzw. geschrieben
+werden. Eine Positionierung ist nur zum nächsten Satz möglich.
+
+
+DIRFILE:
+indexsequentielle Dateien. Die Positionierung erfolgt direkt mit Hilfe eines Schlüssels
+("key") oder Index, kann aber auch sequentiell vorgenommen werden.
+
+#on("b")#Wichtig: #off("b")#
+DIRFILEs sind auf dem EUMEL-System standardmäßig nicht implementiert! Deswe­
+gen wird auf diesen Dateityp hier nicht weiter eingegangen.
+#page#
+
+2.8.2 Deklaration und Assoziierung
+
+Dateien müssen in einem ELAN-Programm - wie alle anderen Objekte auch -
+deklariert werden.
+
+Form:
+
+#on("i")##on("b")#FILE#off("i")##off("b")# #on("i")##on("b")#VAR#off("i")##off("b")# interner Dateibezeichner
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ FILE VAR f
+
+____________________________________________________________________________
+
+
+Dabei ist zu beachten, daß im EUMEL-System alle FILEs als VAR deklariert werden
+müssen, denn jede Lese/Schreib-Operation verändert einen FILE.
+
+Dateien werden normalerweise vom Betriebsystem eines Rechners aufbewahrt und
+verwaltet. Somit ist eine Verbindung von einem ELAN-Programm, in dem eine Datei
+unter einem Namen - wie jedes andere Datenobjekt auch - angesprochen werden
+soll, und dem Betriebssystem notwendig. Dies erfolgt durch die sogenannte Assozi­
+ierungsprozedur. Die Assoziierungsprozedur 'sequential file' hat die Aufgabe, eine in
+einem Programm deklarierte FILE VAR mit einer bereits vorhandenen oder noch
+einzurichtenden Datei des EUMEL-Systems zu koppeln.
+
+Form:
+
+#on("i")##on("b")#sequential file#off("i")##off("b")# #on("i")##on("b")#(#off("i")##off("b")# Betriebsrichtung, Dateiname #on("i")##on("b")#)#off("i")##off("b")#
+
+Es gibt folgende Betriebsrichtungen (TRANSPUTDIRECTIONs):
+
+
+input:
+Die Datei kann vom Programm nur gelesen werden. Durch 'input' wird bei der Asso­
+ziierung automatisch auf den ersten Satz der Datei positioniert. Ist die zu lesende
+Datei nicht vorhanden, wird ein Fehler gemeldet.
+
+
+output:
+Die Datei kann vom Programm nur beschrieben werden. Durch 'output' wird bei der
+Assoziierung automatisch hinter den letzten Satz der Datei positioniert (bei einer
+leeren Datei also auf den ersten Satz). Ist die Datei vor der Assoziierung nicht vor­
+handen, wird sie automatisch eingerichtet.
+
+
+modify:
+Im EUMEL-System gibt es noch die Betriebsrichtung 'modify'.
+Die Datei kann vom Programm in beliebiger Weise gelesen und beschrieben werden.
+Im Gegensatz zu den Betriebsrichtungen 'input' und 'output', bei denen ausschließlich
+ein rein sequentielles Lesen oder Schreiben erlaubt ist, kann bei 'modify' beliebig
+positioniert, gelöscht, eingefügt und neu geschrieben werden.
+
+Nach erfolgter Assoziiierung ist auf den zuletzt bearbeiteten Satz positioniert. Die
+Datei wird automatisch eingerichtet, wenn sie vor der Assoziierung nicht vorhanden
+war.
+
+Der zweite Parameter der Assoziierungsprozedur gibt an, unter welchem Namen die
+Datei in der Task existiert oder eingerichtet werden soll.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ FILE VAR meine datei :: sequential file (output, "xyz");
+
+____________________________________________________________________________
+
+
+Folgendes Beispiel zeigt ein Programm, welches eine Datei liest und auf dem Ausga­
+bemedium ausgibt:
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ FILE VAR f :: sequential file (input, "datei1");
+ TEXT VAR satz;
+ WHILE NOT eof (f) REP
+ getline (f, satz);
+ putline (satz);
+ END REP.
+
+____________________________________________________________________________
+
+
+Eine genau Übersicht der für Dateien existierende Operatoren und Prozeduren finden
+Sie im Teil 5.3.
+#page#
+
+2.9 Abstrakte Datentypen
+ im EUMEL-System
+
+
+
+2.9.1 Datentyp TASK
+
+Tasks müssen im Rechnersystem eindeutig identifiziert werden; sogar im EUMEL-
+Rechner-Netz sind Tasks eindeutig identifizierbar. Dazu wird der spezielle Datentyp
+'TASK' benutzt, denn die Identifizierung einer Task über den Namen ist nicht eindeu­
+tig. Der Benutzer kann ja einen Tasknamen ändern, eine Task löschen und eine
+neue Task mit gleichem Namen einrichten, die jedoch nicht gleich reagiert. Somit
+werden Tasks eindeutig über Variablen vom Datentyp TASK identifiziert.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ TASK VAR plotter := task ("PLOTTER 1")
+
+____________________________________________________________________________
+
+
+Die Taskvariable 'plotter' bezeichnet jetzt die Task im System, die augenblicklich den
+Namen "PLOTTER 1" hat. Die Prozedur 'task' liefert den systeminternen Taskbe­
+zeichner.
+
+Nun sind Taskvariablen auch unter Berücksichtigung der Zeit und nicht nur im aktuel­
+len Systemzustand eindeutig. Der Programmierer braucht sich also keine Sorgen
+darüber zu machen, daß seine Taskvariable irgendwann einmal eine "falsche" Task
+(nach Löschen von "PLOTTER 1" neu eingerichtete gleichen oder anderen Namens)
+identifiziert. Wenn die Task "PLOTTER 1" gelöscht worden ist, bezeichnet 'plotter'
+keine gültige Task mehr.
+
+Unbenannte Tasks haben alle den Pseudonamen "-". Sie können nur über Taskvari­
+ablen angesprochen werden.
+
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ PROC generate shutup manager:
+ TASK VAR son;
+ begin ("shutup", PROC shutup manager, son)
+ END PROC generate shutup manager;
+
+ PROC shutup manager:
+ disable stop;
+ command dialogue (TRUE);
+ REP
+ break;
+ line;
+ IF yes ("shutup")
+ THEN clear error;
+ shutup
+ FI
+ PER
+ END PROC shutup manager
+
+____________________________________________________________________________
+
+
+Ein Taskvariable wird zum Beispiel als Parameter für die Prozedur 'begin' benötigt.
+
+begin
+ #on("b")#PROC begin (TEXT CONST son name, PROC start,
+ TASK VAR new task)#off("b")#
+ Die Prozedur richtet eine Sohntask mit Namen 'son name' (im Beispiel: shutup)
+ ein, die mit der Prozedur 'start' (im Beispiel: shutup manager) gestartet wird. 'new
+ task' (im Beispiel: son) identifiziert den Sohn, falls die Sohntask korrekt eingerich­
+ tet wurde.
+#page#
+
+2.9.2 Datentyp THESAURUS
+
+Ein Thesaurus ist ein Namensverzeichnis, das bis zu 200 Namen beinhalten kann.
+Dabei muß jeder Name mindestens ein Zeichen und höchstens 100 Zeichen lang sein.
+Steuerzeichen (code < 32) werden im Namen folgendermaßen umgesetzt:
+
+#on("i")##on("b")#steuerzeichen#off("b")##off("i")# wird umgesetzt in #on("i")##on("b")#"""" + code(steuerzeichen) + """"#off("b")##off("i")#
+
+Ein Thesaurus ordnet jedem eingetragenen Namen einen Index zwischen 1 und 200
+(einschließlich) zu. Diese Indizes bieten dem Anwender die Möglichkeit, Thesauri zur
+Verwaltung benannter Objekte zu verwenden. (Der Zugriff erfolgt dann über den Index
+eines Namens in einem Thesaurus). So werden Thesauri u.a. von der Dateiverwaltung
+benutzt. Sie bilden die Grundlage der ALL- und SOME-Operatoren.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ initialisiere;
+ arbeite thesaurus ab.
+
+ initialisiere:
+ THESAURUS VAR eine auswahl :: SOME (myself);
+ TEXT VAR thesaurus element;
+ INT VAR index :: 0.
+
+ arbeite thesaurus ab:
+ REPEAT
+ get (eine auswahl, thesaurus element, index);
+ IF thesaurus element = ""
+ THEN LEAVE arbeite thesaurus ab
+ FI;
+ fuehre aktionen durch
+ PER.
+
+ fuehre aktionen durch:
+ edit (thesaurus element);
+ lineform (thesaurus element);
+ pageform (thesaurus element);
+ print (thesaurus element).
+
+____________________________________________________________________________
+
+
+Dieses Beispiel führt für eine Auswahl der in der Task befindlichen Dateien nachein­
+ander die Kommandos 'edit', 'lineform', 'pageform' und 'print' aus.
+
+Die benutzten Operatoren und Prozeduren leisten folgendes:
+
+#ix("SOME")#
+ #on("b")#THESAURUS OP SOME (TASK CONST task) #off("b")#
+ Der Operator bietet das Verzeichnis der in der angegeben Task befindlichen
+ Dateien zum Editieren an. Namen, die nicht gewünscht sind, müssen aus dem
+ Verzeichnis gelöscht werden.
+
+
+#ix("get")#
+ #on("b")#PROC get (THESAURUS CONST t, TEXT VAR name, INT VAR index)
+ #off("b")# Die Prozedur liefert den nächsten Eintrag aus dem angegebenen Thesaurus 't'.
+ 'Nächster' heißt hier, der kleinste vorhandene mit einem Index größer als 'index'.
+ Dabei wird in 'name'der Name und in 'index'der Index des Eintrags geliefert.
+#page#
+
+2.9.3 Datenräume
+
+Datenräume sind die Grundlage von Dateien im EUMEL-System. Einen Datenraum
+kann man sich als eine Sammlung von Daten vorstellen (u.U. leer). Man kann einem
+Datenraum durch ein Programm einen Datentyp "aufprägen". Nach einem solchen
+"Aufpräge"-Vorgang kann der Datenraum wie ein "normaler" Datentyp behandelt
+werden.
+
+Standarddateien (FILEs) sind eine besondere Form von Datenräumen. Sie können nur
+Texte aufnehmen, da sie ja hauptsächlich für die Kommunikation mit dem Menschen
+(vorwiegend mit Hilfe des Editors bzw. Ein-/ Ausgabe) gedacht sind. Will man Zahlen
+in einen FILE ausgeben, so müssen diese zuvor in Texte umgewandelt werden. Hier­
+für stehen Standardprozeduren zur Verfügung (z.B. 'put (f, 17)').
+
+Will man aber Dateien zur Kommunikation zwischen Programmen verwenden, die
+große Zahlenmengen austauschen, verursachen die Umwandlungen von Zahlen in
+TEXTe und umgekehrt unnötigen Rechenaufwand. Zu diesem Zweck werden im
+EUMEL-System Datenräume eingesetzt, die es gestatten, beliebige Strukturen
+(Typen) in Dateien zu speichern. Solche Datenräume kann man weder mit dem Editor
+noch mit dem Standarddruckprogramm (print) bearbeiten, da diese ja den Typ des in
+dem Datenraum gespeicherten Objektes nicht kennen.
+
+
+
+2.9.3.1 Datentyp DATASPACE
+
+Datenräume können als eigener Datentyp (DATASPACE) in einem Programm behan­
+delt werden. Somit können Datenräume (als Ganzes) ohne Kenntnis eines eventuell
+(vorher oder später) aufgeprägten Typs benutzt werden.
+
+Als Operationen auf DATASPACE-Objekte sind nur Transporte, Löschen und Zuwei­
+sung zugelassen.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ DATASPACE VAR ds
+
+____________________________________________________________________________
+
+
+Für Datenräume ist die Zuweisung definiert. Der Zuweisungsoperator (':=') bewirkt
+eine Kopie des Datenraums vom rechten auf den linken Operanden.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ DATASPACE VAR datenraum :: nilspace;
+
+____________________________________________________________________________
+
+
+Die Prozedur 'nilspace' liefert einen leeren Datenraum. Der Datenraum 'datenraum' ist
+also eine Kopie des leeren Datenraums.
+
+Die Prozeduren und Operatoren für Datenräume werden im Teil 5.4.7 beschrieben.
+#page#
+
+2.9.3.2 BOUND-Objekte
+
+Wie bereits erwähnt, kann man einem Datenraum einen Datentyp aufprägen. Dazu
+werden #ib#BOUND#ie#-Objekte benutzt. Mit dem Schlüsselwort #on("i")##on("b")#BOUND#off("i")##off("b")#, welches in der
+Deklaration vor den Datentyp gestellt wird, teilt man dem ELAN-Compiler mit, daß
+die Werte eines Datentyps in einem Datenraum gespeichert sind bzw. gespeichert
+werden sollen.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ BOUND ROW 1000 REAL VAR liste
+
+____________________________________________________________________________
+
+
+Die Ankopplung des BOUND-Objekts an eine Datei erfolgt mit dem Operator #on("i")##on("b")#:=#off("i")##off("b")#.
+
+Form:
+
+BOUND-Objekt #on("i")##on("b")#:=#off("i")##off("b")# Datenraum
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ BOUND ROW 1000 REAL VAR gehaltsliste := new ("Gehälter")
+
+____________________________________________________________________________
+
+
+Die Prozedur 'new' kreiert dabei einen leeren Datenraum (hier mit dem Namen 'Ge­
+hälter'), der mit Hilfe der Zuweisung (hier: Initialisierung) an die Variable 'gehaltsliste'
+gekoppelt wird.
+
+Nun kann man mit der 'gehaltsliste' arbeiten wie mit allen anderen Feldern auch. Die
+Daten, die in 'gehaltsliste' gespeichert, werden eigentlich im Datenraum 'Gehälter'
+abgelegt.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ gehaltsliste [5] := 10 000.0; (* Traumgehalt *)
+ gehaltsliste [index] INCR 200.0; (* usw. *)
+
+____________________________________________________________________________
+
+
+Man kann auch Prozeduren schreiben, die auf der Gehaltsliste arbeiten.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ PROC sort (ROW 1000 REAL VAR liste):
+ ...
+ END PROC sort;
+ ...
+ sort (CONCR (gehaltsliste));
+ ...
+
+____________________________________________________________________________
+
+
+Man beachte, daß der formale Parameter der Prozedur 'sort' nicht mit BOUND spezi­
+fiziert werden darf (BOUND wird nur bei der Deklaration des Objekts angegeben). Das
+ist übrigens ein weiterer wichtiger Vorteil von BOUND-Objekten: man kann alle
+Prozeduren des EUMEL-Systems auch für BOUND-Objekte verwenden, nur die
+Datentypen müssen natürlich übereinstimmen.
+
+
+Häufige Fehler bei der Benutzung von Datenräumen
+
+- Wenn man an ein DATASPACE-Objekt zuweist (z.B.: DATASPACE VAR ds :=
+ new ("mein datenraum")), so erhält man, wie bereits erwähnt, eine Kopie des
+ Datenraums in 'ds'. Koppelt man jetzt 'ds' an ein BOUND-Objekt an und führt
+ Änderungen durch, so wirken diese nur auf die Kopie und nicht auf die Quelle.
+ Für Änderungen in der Quelle, also in der vom Datei-Manager verwalteten Datei,
+ ist stets direkt anzukoppeln.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ BOUND ROW 10 INT VAR reihe;
+ INT VAR i;
+
+ PROC zeige dsinhalt (TEXT CONST datenraum):
+ BOUND ROW 10 INT VAR inhalt := old (datenraum);
+ INT VAR j;
+ line;
+ putline ("Inhalt:" + datenraum);
+ FOR j FROM 1 UPTO 10 REP
+ put (inhalt (j))
+ PER
+ END PROC zeige dsinhalt;
+
+ (* falsch: es wird auf der Kopie gearbeitet: *)
+ DATASPACE VAR ds := new ("Gegenbeispiel: Zahlen 1 bis 10");
+ reihe := ds;
+ besetze reihe;
+ zeige dsinhalt ("Gegenbeispiel: Zahlen 1 bis 10");
+
+ (* richtig: es wird auf dem Datenraum gearbeitet: *)
+ reihe := new ("Beispiel: Zahlen 1 bis 10");
+ besetze reihe;
+ zeige dsinhalt ("Beispiel: Zahlen 1 bis 10").
+
+ besetze reihe:
+ FOR i FROM 1 UPTO 10 REP
+ reihe (i) := i
+ PER.
+
+____________________________________________________________________________
+
+
+ Der Datenraum 'Gegenbeispiel: Zahlen 1 bis 10' wird nicht mit Werten besetzt,
+ sondern die Kopie dieses Datenraums, der unbenannte Datenraum 'ds'. Auf dem
+ direkt angekoppelten Datenraum 'Beispiel: Zahlen 1 bis 10' werden die Werte
+ gespeichert.
+
+
+- Wenn man ein DATASPACE-Objekt benutzt, ohne den Datei-Manager zu
+ verwenden, so muß man selbst dafür sorgen, daß dieses Objekt nach seiner
+ Benutzung wieder gelöscht wird. Das Löschen geschieht durch die Prozedur
+ 'forget'. Ein automatisches Löschen von DATASPACE-Objekten erfolgt nicht bei
+ Programmende (sonst könnten sie ihre Funktion als Datei nicht erfüllen). Nur
+ durch 'forget' oder beim Löschen einer Task werden alle ihr gehörenden
+ DATASPACE-Objekte gelöscht und der belegte Speicherplatz freigegeben.
+
+
+- Ferner ist zu beachten, daß vor der Ankopplung an ein BOUND-Objekt das
+ DATASPACE-Objekt initialisiert wird (im Normalfall mit 'nilspace').
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ DATASPACE VAR ds := nilspace;
+ BOUND ROW 1000 REAL VAR real feld := ds;
+ ....
+ real feld [index] := wert;
+ ....
+ forget (ds) (* Datenraum löschen,
+ damit der Platz wieder verwendet wird *)
+
+____________________________________________________________________________
+
+
+- Will man auf die Feinstruktur eines BOUND-Objekts zugreifen, so muß man
+ strenggenommen den Konkretisierer benutzen:
+
+ Form:
+
+ #on("i")##on("b")#CONCR#off("i")##off("b")# #on("i")##on("b")#(#off("i")##off("b")# Ausdruck #on("i")##on("b")#)#off("i")##off("b")#
+
+ Der Konkretisierer ermöglicht eine typmäßige Umbetrachtung vom BOUND-Objekt
+ zum Datentyp der Feinstruktur. Ist der Zugriff jedoch eindeutig, so wird 'CONCR'
+ automatisch vom Compiler ergänzt.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ BOUND INT VAR i := old ("i-Wert");
+ INT VAR x;
+ x := wert.
+
+ wert:
+ IF x < 0
+ THEN 0
+ ELSE CONCR (i)
+ FI.
+
+____________________________________________________________________________
+
+
+In diesem Beispiel muß der Konkretisierer benutzt werden, da sonst der Resultattyp
+des Refinements nicht eindeutig ist (BOUND oder INT?).
+
+
+
+2.9.3.3 Definition neuer Dateitypen
+
+Durch die Datenräume und die Datentyp-Definition von ELAN ist es für Programmie­
+rer relativ einfach, neue Datei-Datentypen zu definieren. In der Regel reicht der
+Datentyp FILE für "normale" Anwendungen aus, jedoch kann es manchmal sinnvoll
+und notwendig sein, neue Datei-Typen für spezielle Aufgaben zu definieren.
+
+In diesem Abschnitt soll an dem Beispiel DIRFILE (welcher zwar im ELAN-Standard
+definiert, aber nicht im EUMEL-System realisiert ist) gezeigt werden, wie ein neuer
+Datei-Datentyp definiert wird:
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ PACKET dirfiles DEFINES DIRFILE, :=, dirfile, getline, ...:
+
+ LET maxsize = 1000;
+
+ TYPE DIRFILE = BOUND ROW maxsize TEXT;
+ (* DIRFILE besteht aus TEXTen; Zugriff erfolgt ueber einen
+ Schluessel, der den Index auf die Reihung darstellt *)
+
+ OP := (DIRFILE VAR dest, DATASPACE CONST space):
+ CONCR (dest) := space
+ END OP :=;
+
+ DATASPACE PROC dirfile (TEXT CONST name):
+ IF exists (name)
+ THEN old (name)
+ ELSE new (name)
+ FI
+ END PROC dirfile;
+
+ PROC getline (DIRFILE CONST df, INT CONST index,
+ TEXT VAR record):
+ IF index <= 0
+ THEN errorstop ("access before first record")
+ ELIF index > maxsize
+ THEN errorstop ("access after last record")
+ ELSE record := df [index]
+ FI
+ END PROC getline;
+
+ PROC putline (DIRFILE CONST df, INT CONST index,
+ TEXT VAR record):
+ ...
+ END PROC putline;
+
+ ...
+ END PACKET dirfiles;
+
+____________________________________________________________________________
+
+
+Die Prozedur 'dirfile' ist die Assoziierungsprozedur für DIRFILEs (analog 'sequential
+file' bei FILEs). 'dirfile' liefert entweder einen bereits vorhandenen Datenraum oder
+richtet einen neuen ein. Um eine Initialisierung mit der 'dirfile'-Prozedur vorneh­
+men zu können, braucht man auch einen Zuweisungsoperator, der den Datenraum an
+den DIRFILE-Datentyp koppelt.
+
+Zugriffe auf einen DIRFILE sind nun relativ einfach zu schreiben. Im obigen Beispiel
+wird nur die Prozedur 'getline' gezeigt.
+
+Nun ist es möglich, Programme zu schreiben, die den DIRFILE-Datentyp benut­
+zen.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ DIRFILE VAR laeufer :: dirfile ("Nacht von Borgholzhausen");
+ INT VAR nummer;
+ TEXT VAR name;
+
+ REP
+ put ("Startnummer bitte:");
+ get (nummer);
+ line;
+ put ("Name des Laeufers:");
+ get (name);
+ putline (laeufer, nummer, name);
+ line
+ UNTIL no ("weiter") END REP;
+ ...
+
+____________________________________________________________________________
+#page#
+
+2.9.4 Datentyp INITFLAG
+
+Im Multi-User-System ist es oft notwendig, Pakete beim Einrichten einer neuen
+Task in dieser neu zu initialisieren. Das muß z.B. bei der Dateiverwaltung gemacht
+werden, da die neue Task ja nicht die Dateien des Vaters erbt. Mit Hilfe von
+INITFLAG-Objekten kann man zu diesem Zweck feststellen, ob ein Paket in dieser
+Task schon initialisiert wurde.
+
+
+INITFLAG
+ #on("b")#TYPE INITFLAG #off("b")#
+ Erlaubt die Deklaration entsprechender Flaggen.
+
+:=
+ #on("b")#OP := (INITFLAG VAR flag, BOOL CONST flagtrue) #off("b")#
+ Erlaubt die Initialisierung von INITFLAGs
+
+initialized
+ #on("b")#BOOL PROC initialized (INITFLAG VAR flag) #off("b")#
+ Wenn die Flagge in der Task A auf TRUE oder FALSE gesetzt wurde, dann liefert
+ sie beim ersten Aufruf den entsprechenden Wert, danach immer TRUE (in der
+ Task A!).
+
+ Beim Einrichten von Söhnen wird die Flagge in den Sohntasks automatisch auf
+ FALSE gesetzt. So wird erreicht, daß diese Prozedur in den neu eingerichteten
+ Söhnen und Enkeltasks genau beim ersten Aufruf FALSE liefert.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ PACKET stack DEFINES push, pop:
+
+ INITFLAG VAR in this task := FALSE ;
+ INT VAR stack pointer ;
+ ROW 1000 INT VAR stack ;
+
+ PROC push (INT CONST value) :
+
+ initialize stack if necessary ;
+ ....
+
+ END PROC push ;
+
+ PROC pop (INT VAR value) :
+
+ initialize stack if necessary ;
+ ....
+
+ END PROC pop ;.
+
+ initialize stack if necessary :
+ IF NOT initialized (in this task)
+ THEN stack pointer := 0
+
+ FI .
+
+ END PACKET stack
+____________________________________________________________________________
+