From 04e68443040c7abad84d66477e98f93bed701760 Mon Sep 17 00:00:00 2001 From: Lars-Dominik Braun Date: Mon, 4 Feb 2019 13:09:03 +0100 Subject: Initial import --- doc/user-manual/1.7.3-pd/doc/pd.Handbuch.Teil6b | 1425 +++++++++++++++++++++++ 1 file changed, 1425 insertions(+) create mode 100644 doc/user-manual/1.7.3-pd/doc/pd.Handbuch.Teil6b (limited to 'doc/user-manual/1.7.3-pd/doc/pd.Handbuch.Teil6b') diff --git a/doc/user-manual/1.7.3-pd/doc/pd.Handbuch.Teil6b b/doc/user-manual/1.7.3-pd/doc/pd.Handbuch.Teil6b new file mode 100644 index 0000000..7fdaf39 --- /dev/null +++ b/doc/user-manual/1.7.3-pd/doc/pd.Handbuch.Teil6b @@ -0,0 +1,1425 @@ + EUMEL-Benutzerhandbuch + + + TEIL 6: Erste Hilfe in ELAN + +Prozeduren + +Prozeduren werden verwendet, wenn + +- Anweisungen und Datenobjekte unter einem Namen zusammengefaßt werden + sollen ("Abstraktion"). + +- gleiche Anweisungen von mehreren Stellen eines Programms verwandt werden + sollen (Codereduktion) u.U. mit verschieden Datenobjekten (Parameter); + +- wenn Datenobjekte nur kurzfristig benötigt werden (dynamische Speicherver- + waltung) und diese nicht von dem gesamten Programm angesprochen werden + sollen (lokale, globale Datenobjekte); + +Im folgenden Programm stellen wir ein Fragment vor, in dem zwei Werte ver- +tauscht werden. In der einen (linken) Lösung wird ein Refinement, in der +anderen eine Prozedur verwandt. + +Programm 19: + + ... PROC vertausche a und b: + IF a > b INT CONST x :: a; + THEN vertausche a und b a := b; + END IF; b := x + ... END PROC vertausche a und b; + vertausche a und b; ... + ... IF a > b + THEN vertausche a und b + vertausche a und b: END IF; + INT CONST x :: a; ... + a := b; vertausche a und b; + b := x. ... + +Beim ersten Hinsehen leisten beide Programme das Gleiche. Es gibt jedoch +drei wichtige Unterschiede: + +1) Das Refinement 'vertausche a und b' wird zweimal (vom ELAN-Compiler) + eingesetzt, d.h. der Code ist zweimal vorhanden. Die Prozedur dagegen ist + vom Code nur einmal vorhanden, wird aber zweimal - durch das Aufführen + des Prozedurnamens - aufgerufen. + +2) Die Variable 'x' ist in der linken Programmversion während des gesamten + Ablauf des Programms vorhanden. Solche Datenobjekte nennt man statische + Datenobjekte oder auch (aus Gründen, die erst etwas später offensichtlich + werden) Paket-Objekte. Das Datenobjekt 'x' der rechten Version dagegen + ist nur während der Bearbeitung der Prozedur vorhanden. Solche Daten- + objekte, die nur kurzfristig Speicher belegen, werden dynamische Daten- + objekte genannt. + + Prozeduren sind also ein Mittel, um die Speicherbelegung zu beeinflussen, + was besonders bei großen Datenobjekten notwendig ist. + +3) 'x' kann in der linken Programmversion - obwohl sie in einem Refinement + deklariert wurde - von jeder Stelle des Programms angesprochen werden. + Solche Datenobjekte werden globale Datenobjekte genannt. Das Datenobjekt + 'x' der Prozedur dagegen kann nur innerhalb der Prozedur angesprochen + werden, sie ist also ein lokales Datenobjekt hinsichtlich der Prozedur. + Innerhalb der Prozedur dürfen globale Datenobjekte (also Objekte, die + außerhalb von Prozeduren deklariert wurden) angesprochen werden. + + Eine Prozedur in ELAN bildet im Gegensatz zu Refinements einen eigenen + Gültigkeitsbereich hinsichtlich Datenobjekten und Refinements, die inner- + halb der Prozedur deklariert werden. Prozeduren sind somit ein Mittel, um + die in ihr deklarierten Datenobjekte hinsichtlich der Ansprechbarkeit + nach Außen "abzuschotten". + +Prozeduren wie die in Programm 19 werden mit dem Schlüsselwort PROC, dem +Namen der Prozedur und einem Doppelpunkt eingeleitet. Dies nennt man den +Prozedurkopf. Der Prozedurkopf entspricht den Definitionen, die wir bereits +in vorigen Abschnitten dieses Skripts gegeben haben. Nach dem Prozedurkopf +folgt der Prozedurrumpf, der Datenobjekt-Deklarationen, Anweisungen und +Refinements enthalten kann. Abgeschlossen wird die Prozedur durch END PROC +und dem Prozedurnamen. + + +Aufgabe (HSG): + + a) Erkläre den Unterschied zwischen einer Prozedur und einem Refinement. + b) Was sind globale bzw. lokale Datenobjekte? +Übungsziel: Begriffe, die mit Prozeduren zusammenhängen + + +Aufgabe (TSW): + + Gegeben sei folgendes Programmfragment: + INT VAR a, b; + ... (*1*) + PROC x: + INT VAR x1; + ... (*2*) + END PROC x; + TEXT VAR t; + PROC y: + REAL VAR y1 + ... (*3*) + END PROC y; + ... (*4*) + + 1.) Welche Objekte (einschließlich Prozeduren) sind an den Punkten + (*1*) : + (*2*) : + (*3*) : + (*4*) : + ansprechbar? + + 2.) Welche Datenobjekte sind in der Prozedur 'y' + global: + lokal: +Übungsziel: Globale und lokale Objekte + + +Prozeduren mit Parametern erlauben es, gleiche Anweisungen mit unterschied- +lichen Datenobjekten auszuführen: + + +Programm 20: + + PROC vertausche (INT VAR a, b): + INT VAR x :: a; + a := b; + b := x + END PROC vertausche; + + INT VAR eins :: 1, + zwei :: 2, + drei :: 3; + vertausche (eins, zwei); + vertausche (zwei, drei); + vertausche (eins, zwei); + put (eins); put (zwei); put (drei) + +Die Datenobjekte 'a' und 'b' der Prozedur 'vertausche' werden formale Para- +meter genannt. Sie stehen als Platzhalter für die bei einem Prozeduraufruf +einzusetzenden aktuellen Parameter (in unserem Beispiel die Datenobjekte +'eins', 'zwei' und 'drei'). + + +Aufgabe (HSG): + + Welche Werte werden in dem Programm 20 ausgedruckt? +Übungsziel: Arbeiten mit Prozeduren und Parameter-Mechanismus. + + +Parameter werden im Prozedurkopf nach dem Prozedurnamen in Klammern mit +Datentyp und Accessrecht angegeben. Dabei bedeutet CONST, daß auf den +Parameter nur lesend zugegriffen wird, während auf einen VAR-Parameter auch +z.B. eine Zuweisung angewandt werden kann. CONST-Parameter sind also +Eingabe-Parameter, während VAR-Parameter Ein-/Ausgabe-Parameter realisieren. + +Bei den aktuellen Parametern ist folgendes zu beachten: + +a) Wird ein VAR-Parameter in der Definition der Prozedur vorgeschrieben (wie + z.B. im Programm 20), darf kein Ausdruck als aktueller Parameter "überge- + ben" werden, weil an einen Ausdruck nichts zugewiesen werden kann. + Gegenbeispiel: + + vertausche ( eins * zwei, drei) + + Ausdrücke haben - wie bereits erwähnt - das Accessrecht CONST. + +b) Wird ein CONST-Parameter verlangt, dann darf in diesem Fall ein Ausdruck + als aktueller Parameter geschrieben werden. Aber auch ein VAR-Datenobjekt + darf angegeben werden. In diesem Fall wird eine Wandlung des Accessrechts + (CONSTing) vorgenommen: der aktuelle Parameter erhält sozusagen für die + Zeit der Abarbeitung der Prozedur das Accessrecht CONST. + +Es ist auch möglich, Prozeduren als Parameter zu definieren, worauf wir aber +hier nicht eingehen wollen. + +Eine Werte liefernde Prozedur erhält man, wenn der Prozedurrumpf einen Wert +liefert, d.h. die letzte ausführbare Anweisung des Prozedurrumpfes muß einen +Wert liefern (analog Werte liefernde Refinements) und der zu liefernde +Datentyp vor den Prozedurkopf geschrieben wird. + + +Programm 21: + + INT PROC max (INT CONST a, b): + IF a > b + THEN a + ELSE b + END IF + END PROC max; + + put (max (3, 4)) + +(In unserem Beispiel liefert die IF-Anweisung einen Wert. Das erfolgt da- +durch, daß beide Zweige der Anweisung einen Wert liefern.) + + + +Neudefinierte Operatoren + +Neue, zusätzliche Operatoren können in ELAN wie Prozeduren definiert werden. +Es ist nur notwendig, bei der Definition das Wort PROC gegen OP zu vertau- +schen. Es sind aber auch nur 1 oder 2 Parameter bei Operatoren erlaubt. + + +Programm 22a: + + TEXT OP * (INT CONST mal, TEXT CONST t): + INT VAR zaehler :: mal; + TEXT VAR ergebnis :: ""; + WHILE zaehler > 0 REP + ergebnis := ergebnis + t; + zaehler := zaehler - 1 + END REP; + ergebnis + END OP *; + +Dieser Operator vervielfältigt TEXTe ( 2 * "ha" liefert "haha"). Der Name +des Operators ist '*'. Man kann als Operatornamen die vorhandenen, bereits +benutzten Sonderzeichen verwenden. In diesem Fall bekommt der neudefinierte +Operator die gleiche Priorität wie der bereits vorhandene oder ein Schlüssel- +wort. + +Der "Aufruf" eines Operators unterscheidet sich von einer Prozedur durch die +infix-Schreibweise. Im übrigen gilt das für Prozeduren Gesagte. + + + +Optimierungen + +Optimierungen werden vorgenommen, wenn man mit den Laufzeiten bzw. Speicher- +bedarf eines Programms nicht zufrieden ist. Kleinere, lokale Optimierungen +sind meist nicht sinnvoll und notwendig und bringen mehr Fehler, als Ver- +besserungen: + + +Programm 22b: + + TEXT OP * (INT CONST mal, TEXT CONST t): + INT VAR i; + TEXT VAR ergebnis :: ""; + FOR i FROM 1 UPTO mal REP + ergebnis CAT t + END REP; + ergebnis + END OP *; + +Wir haben hier die WHILE-Schleife durch eine Zählschleife und 'ergebnis := +ergebnis + t' durch 'ergebnis CAT t' ersetzt. Dies ist nur eine minimale +Optimierung (wenn sie überhaupt etwas einbringt). Leider sind solche +"Optimierungen" sehr häufig anzutreffen. Besser ist es, eine Lösung zu +finden, die algorithmisch oder von den Datenstrukturen her prinzipiell +besser ist. Wir haben dies für das Programm 22 getan. Lösungsidee: jeweilige +Verdopplung eines Zwischentextes ("Russische Multiplikation"). + + +Programm 22c: + + TEXT OP * (INT CONST mal, TEXT CONST t): + INT VAR zaehler :: mal; + TEXT VAR einer :: "", + dopplung :: t; + IF fehlerhafter aufruf + THEN LEAVE * WITH "" + ELSE verdopplung + END IF; + dopplung + einer. + + fehlerhafter aufruf: + zaehler < 1. + + verdopplung: + WHILE zaehler > 1 REP + IF zaehler ist ungerade + THEN einer CAT t + END IF; + dopplung CAT dopplung; + zaehler := zaehler DIV 2 + END REP. + + zaehler ist ungerade: + zaehler MOD 2 = 1. + + END OP *; + + +In diesem Programm wurde eine Anweisung verwendet (LEAVE), die wir im +folgenden Abschnitt erklären wollen. + + + +Das LEAVE-Konstrukt + +Das LEAVE-Konstrukt wird verwendet, um eine benannte Anweisung (Refinement, +Prozedur oder Operator) vorzeitig zu verlassen. Es ist auch möglich, mehr- +fach geschachtelte Refinements zu verlassen. Durch eine (optionale) +WITH-Angabe kann auch ein wertelieferndes Refinement verlassen werden. + + + +Reihungen + +Wir haben bis jetzt bereits zusammengesetzte algorithmische Objekte kennen- +gelernt, die man unter einem Namen als Ganzes ansprechen kann (Prozeduren). +Die gleiche Möglichkeit gibt es auch bei Datenobjekten, wobei wir gleich- +artige oder ungleichartige Objekte zu einem Objekt zusammenfassen können. +Zuerst zu der Zusammenfassung gleichartiger Datenobjekte, die in ELAN eine +Reihung (ROW) genannt wird. Die einzelnen Objekte einer Reihung werden +Elemente genannt. Beispiel (Deklaration einer Reihung von 10 INT-Elementen): + + ROW 10 INT VAR feld + +Die Angabe hinter dem Schlüsselwort ROW muß ein INT-Denoter sein (oder +durch ein LET definierter Name). Dabei ist ROW 10 INT ein (neuer, von den +elementaren unterschiedlicher) Datentyp, für den keine Operationen definiert +sind, außer der Zuweisung. Das Accessrecht (VAR in unserem Beispiel) 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 uns sehr +schnell einsichtig, wenn wir uns vorstellen, 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 +unterschiedliche Operationen definiert. Man müßte nun für jeden dieser +zusammengesetzten 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 vorgegebene Operationen auf zusammengesetzte +Datentypen gibt. + +Zugegebenermaßen könnte man mit solchen Datentypen, die nur über eine Opera- +tion verfügen (Zuweisung), nicht sehr viel anfangen, wenn es nicht eine wei- +tere vorgegebene Operation gäbe, die #ib#Subskription#ie#. Sie erlaubt es, +auf die Elemente einer Reihung zuzugreifen und den Datentyp der Elemente +"aufzudecken". 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 (in unserem Fall '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 über- +all da verwendet werden, wo ein entsprechender Datentyp benötigt wird (Aus- +nahme: Schleifenvariable). Als Beispiel zeigen wir zwei Prozeduren, die eine +Reihung einlesen bzw. ausgeben: + + +Programm 23: + + 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 + + +Wie bereits erwähnt, ist es erlaubt, Reihungen überall dort zu verwenden, wo +auch die elementaren Datentypen verwandt werden können, also auch als +Parameter. Zudem haben wir die generischen Eigenschaften von Prozeduren in +ELAN bei der Benennung der Prozeduren benutzt. + +Diese beiden Prozeduren benutzen wir gleich im nächsten Programm, welches +10 Werte einliest und die Summe berechnet: + + +Programm 24: + + 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). + + +Aufgabe (HSG): + + Wie kann man vermeiden, daß 'summe > maxint' ("overflow"-Bedingung) + wird? + + +Oft benötigt man die Werte einer Reihung sortiert. Das Programm 25 zeigt +einen (sehr dummen und ineffizienten) Sortieralgorithmus: + + +Programm 25: + + ROW 10 INT VAR wert; + lies die werte ein; + sortiere in eine zweite liste; + drucke die zweite liste. + + lies die werte ein: + get (wert). + + sortiere in eine zweite liste: + INT VAR i; + FOR i FROM 1 UPTO 10 REP + suche kleinstes element aus der werte liste; + bringe dieses in die zweite liste; + entferne es aus der werte liste + END REP. + + suche kleinstes element aus der werte liste: + INT VAR kleinstes element :: maxint, position kleinstes element :: 0, k; + FOR k FROM 1 UPTO 10 REP + IF wert [k] < kleinstes element + THEN kleinstes element := wert [k]; + position kleinstes element := k + END IF + END REP. + + bringe dieses in die zweite liste: + ROW 10 INT VAR liste2; + liste2 [i] := kleinstes element. + + entferne es aus der werte liste: + wert [position kleinstes element] := maxint. + + drucke die zweite liste: + put (liste2). + +Anmerkung: Bei diesem einfachen Sortieralgorithmus (der übrigens "lineare +Auswahl" heißt), wurde der Wert 'maxint' als zulässiger Wert ausgeschlossen. +Der Algorithmus ist ziemlich der schlechteste, den wir uns ausdenken können. +Einmal braucht er den doppelten Speicherplatz für die zu sortierende Liste, +andererseits sind für N Werte N*N Durchläufe durch die Liste notwendig (man +sagt, der Algorithmus ist von der Ordnung N Quadrat). + +Da es möglich ist, von jedem Datentyp eine Reihung zu bilden, kann man +natürlich auch von einer Reihung eine Reihung bilden: + + 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 zuzu- +greifen: + + matrix [3] + +liefert ein Datenobjekt mit dem Datentyp ROW 10 INT, für den wir bereits in +Programm 23 die Prozeduren 'get' und 'put' geschrieben haben, die wir +verwenden können: + + get (matrix [4]) + +Subskribieren wir jedoch 'matrix' nochmals, so erhalten wir ein INT: + + matrix [2] [8] + +(jede Subskription "schält" von Außen ein ROW vom Datentyp ab). + + +Aufgabe (HSG): + + a) Geben Sie Datentyp, Accessrecht und Name der folgenden Datenobjekte + an: + ROW 17 INT CONST alpha; + ROW 3 ROW 4 TEXT VAR matrix; + ... + beta [3] := 7; + gamma [4] := gamma [5] + + b) Was führt zu Fehlern? Wenn ja, warum? + ROW 17 INT VAR alpha; + ROW 3 ROW 4 TEXT VAR beta, gamma; + ROW 4 ROW 3 TEXT CONST delta; + INT VAR x :: 7; + ROW x BOOL VAR y; + get (alpha); + get (beta [7]); + FOR x FROM 1 UPTO 3 REP + get (beta [x]) + END REP; + beta := delta; + delta [1] [2] := "mist"; + beta := gamma; + beta [3] := gamma [3]; + get (beta [1] [1]); + gamma [1] [5] := beta [1] [1] + "ELAN" + x := alpha [3]; + x := 20; + alpha [x] := alpha [3] + 7 +Übungsziel: Umgang mit Reihungen + + + +Strukturen + +Strukturen sind Datenverbunde wie Reihungen, aber die Komponenten können +ungleichartige Datentypen haben. Die Komponenten von Strukturen heißen +Felder (bei Reihungen: 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ß. +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: + + 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: + + STRUCT (TEXT produkt name, INT artikel nr) VAR erzeugnis + +ist ein anderer Datentyp als im ersten Beispiel dieses Abschnitts. Für +Strukturen - genauso wie bei Reihungen - kann man sich neue Operationen +definieren. Im folgenden Programm definieren wir für eine Struktur, die +Personen beschreibt, die Operationen 'put', 'get' und den dyadischen +Operator HEIRATET. Anschließend werden drei Paare verHEIRATET. + + +Programm 26a: + + 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; + + 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 Reihenfolge vorzunehmen, wie die Datentypen aufgebaut wurden (von +außen nach innen). + + +Aufgabe (HSG): + + In ELAN heissen + a1) Datenverbunde gleichartiger Komponenten: + a2) Datenverbunde ungleichartiger Komponenten: + b1) die Komponenten eines ROWs: + b2) die Komponenten eines STRUCTs: + c1) die Zugriffe auf die Komponenten eines ROWs: + c2) die Zugriffe auf die Komponenten eines STRUCTs: +Übungsziel: Begriffe von ROWs und STRUCTs kennenlernen + + + +LET-Konstrukt + +Wie wir in Programm 26 gesehen haben, ist die Verwendung von Strukturen +oder auch Reihungen manchmal schreibaufwendig. Mit dem LET-Konstrukt darf +man Datentypen (und Denotern) 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. Beispiel: + + +Programm 26b: + + 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 werden kann, kann 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 wir +etwas später erklären, nicht mehr der Fall ist). + +Neben der Funktion der Abkürzung von Datentypen kann das LET-Konstrukt +auch für die Namensgebung für die Denoter verwandt werden. Beispiele: + + LET pi = 3.14159; + LET blank = " "; + LET anzahl = 27 + +Der Einsatz von LET-Namen für INT-Denoter macht es möglich, Programme +leicht zu ändern: + + +Programm 26c: + + LET anzahl paare = 3; + ROW anzahl paare PERSON VAR frau, mann; + + personendaten einlesen; + heiraten lassen; + paardaten ausgeben. + + personendaten einlesen: + INT VAR i; + FOR i FROM 1 UPTO anzahl paare REP + get (frau [i]); + get (mann [i]) + END REP. + ... + +Ebenso wie die Abkürzung von Datentypen (LET PERSON = STRUCT (...)) wird +im obigen Beispiel für den Namen 'anzahl paare' bei jedem Auftreten der +Denoter '3' vom ELAN-Compiler eingesetzt. Um nun (z.B.) 27 Paare "heiraten" +zu lassen, brauchen wir nur die LET-Anweisung in '27' zu verändern... +(Scheidungen erfordern etwas mehr Aufwand). + + +Aufgabe (HSG): + + Was ist falsch? + LET anz = 5, + max = 5*5, + MAT = ROW anz ROW anz TEXT; + + PROC get (MAT CONST m): + FOR i FROM 1 UPTO max REP + get (m [i]) + END REP + END PROC get; + + MAT VAR x,y; + get (x); + x := y + 1 + + +Aufgabe (HSG): + + Schreibe ein Programm, das mit den Deklarationen + LET anz = 5, + VEC = ROW anz INT, + MAT = ROW anz VEC; + folgende Prozeduren realisiert: + PROC get (VEC VAR v) + PROC get (MAT VAR m) + PROC put (VEC CONST v) + PROC put (MAT CONST m) + INT PROC reihensumme (VEC CONST v) +Übungsziel: Reihungen als Parameter + + + +Denoter für Datenverbunde: Konstruktoren + +Denoter für die elementaren Datentypen haben wir kennengelernt. Oft ergibt +sich auch die Notwendigkeit (z.B. bei Initialisierungen), Datenverbunde in +einem Programm Werte zu geben. Das 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 + +Aber man möchte auch Denoter für Datenverbunde z.B. in Ausdrücken verwenden, +was durch die Konstruktoren ermöglicht wird. 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 Datenver- +bundes in einem Programm zu notieren. Ein Konstruktor besteht aus der Angabe +des Datentyps (der auch durch einen LET-Namen abgekürzt sein darf), einem +Doppelpunkt und den in Klammern eingefaßten Komponenten (hier Denoter). +Besteht eine der Komponenten wiederum aus einem Datenverbund, muß inner- +halb des Konstruktors wiederum ein Konstruktor eingesetzt werden usw. Kon- +struktoren sind natürlich für Reihungen auch möglich: + + ROW 7 INT VAR feld; + feld := ROW 7 INT : ( 1, 2, 3, 4, 5, 6, 7); + + +Aufgabe (HSG): + + Geben Sie Datentyp, Accessrecht und Name der folgenden Datenobjekte an: + STRUCT (INT alter, TEXT name) VAR mensch; + STRUCT (INT jahrgang, ROW 2 TEXT lage) CONST wein; + ROW 100 STRUCT (PERSON p, NUMMER n) VAR betriebsangehoeriger; + STRUCT (INT anz terminals, STRUCT (TEXT systemname, INT version) art) + CONST betriebsystem; + mensch := ...; + betriebsangehoeriger [2] := ...; + betriebsangehoeriger [2]. n := NUMMER: (...); + betriebsystem.art.systemname := "EUMEL"; + wein.lage := ROW 2 TEXT: ("Loire", "Frankreich"); + wein.lage [1] := "Kroever Nacktarsch"; +Übungsziel: Umgang mit Strukturen. + + + +Rekursive Prozeduren und Operatoren + +Alle Prozeduren und Operatoren dürfen in ELAN rekursiv sein. + + +Programm 27: + + INT PROC fakultaet (INT CONST n): + IF n > 0 + THEN fakultaet (n-1) * n + ELSE 1 + END IF + END PROC fakultaet + +Dieses Beispiel ist aber (leider) kein gutes Beispiel für eine Rekursion, +denn das Programm kann leicht in eine iterative Version umgewandelt werden: + + +Programm 28: + + INT PROC fakultaet (INT CONST n): + INT VAR prod :: 1, i; + FOR i FROM 2 UPTO n REP + prod := prod * i + END REP; + prod + END PROC fakultaet + +Die Umwandlung von einem rekursiven Programm in ein iteratives ist übrigens +immer möglich, jedoch oft nicht so einfach wie in diesem Fall. Beispiel +(Ackermann-Funktion): + + +Programm 29: + + INT PROC acker (INT CONST m, n): + IF m = 0 + THEN n + 1 + ELIF n = 0 + THEN acker (m-1, 0) + ELSE acker (m - 1, acker (m, n - 1)) + ENDIF + END PROC acker + + +Aufgabe (HSG): + + a) Beschreibe die Unterschiede zwischen Iteration und Rekursion. Worauf + muß man bei Rekursionen achten? + b) Wie groß ist der Wert von 'acker (2, 2)'? Hilfreicher Tip: stelle + dabei eine Tabelle auf! + c) Zudem enthält die Programmierung der Ackermann-Funktion (mindestens) + einen Fehler. Welchen? +Übungsziel: Umgang mit Rekursion + + +Das eigentliche Einsatzgebiet von rekursiven Algorithmen liegt aber bei den +'backtrack'-Verfahren. Diese werden eingesetzt, wenn eine exakte algorithmi- +sche Lösung nicht bekannt ist oder nicht gefunden werden kann und man ver- +schiedene Versuche machen muß, um zu einem Ziel (oder Lösung) zu gelangen. + +Als Beispielprogramm zeigen wir das Spiel "Maus sucht Käse". In einem Laby- +rinth (realisiert durch eine Reihung von einer Reihung), das mit Hindernis- +sen bestückt ist, wurde ein Käse versteckt. Eine sehr dumme Maus sucht +systematisch die umliegenden Felder (in allen vier Himmelsrichtungen) nach +dem Käse ab. Ist sie auf einem neuen Feld und ist das Feld frei, sucht sie +erneut. Felder, auf denen sie bereits war, werden von ihr markiert. Da die +Maus sehr kurzsichtig ist und nicht richtig riechen kann, bemerkt sie den +Käse erst, wenn sie sozusagen mit allen vier Pfoten in ihm gelandet ist +(analog bei Hindernissen, die nicht überklettert werden können). Damit die +Maus nicht aus dem Labyrinth entfliehen kann, wird der Rand als Hindernis +angesehen. + + +(Teil-) Programm 30: + + PROC suche weg (INT CONST x, y): + IF labyrinth [x] [y] = kaese + THEN kaese gefunden + ELIF labyrinth [x] [y] = frei + THEN suche weiter + END IF. + + suche weiter: + labyrinth [x] [y] := markiert; + INT VAR richtung; + FOR richtung FROM osten UPTO sueden REP + versuche diese richtung + END REP; + labyrinth [x] [y] := frei. + + versuche diese richtung: + IF richtung = osten + THEN suche weg (x + 1, y) + ELIF richtung = norden + THEN suche weg (x, y + 1) + ... + + + +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 Massenspei- +chern aufbewahrt wird. Dateien sind in bestimmten Informationsmengen, den +Sätzen ("records") organisiert. + +In ELAN gibt es zwei Arten von Dateien: + +a) FILE: sequentielle Dateien. Die Sätze können nur sequentiell gelesen bzw. + geschrieben werden. Eine Positionierung ist nur zum nächsten Satz möglich. +b) DIRFILE: indexsequentielle Dateien. Die Positionierung erfolgt direkt mit + Hilfe eines Schlüssels ("key") oder Index, kann aber auch sequentiell + vorgenommen werden. + + Wichtig: + DIRFILEs sind auf dem EUMEL-System nicht implementiert! Deswegen wird + auf diesen Dateityp hier nicht weiter eingegangen. + +Dateien werden normalerweise von dem #ib#Betriebsystem#ie# 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 Betriebsystem notwendig. Dies erfolgt durch +sogenannte Assoziierungsprozeduren. Beispiele: + + FILE VAR meine datei :: sequential file (output, "xyz"); + FILE CONST eine andere datei :: sequential file (input, "abc") + +Die Assoziierungsprozedur heißt 'sequential file' für FILEs. Der erste +Parameter einer Assoziierungsprozedur gibt immer die sogenannte Betriebs- +richtung ("TRANSPUTDIRECTION") an. Es gibt folgende Betriebsrichtungen: + + input nur Lesen der Datei + output nur Schreiben der Datei + + Anmerkung: + Im EUMEL-System gibt es noch die Betriebsrichtung 'modify', die es er- + laubt, beliebig zu positionieren, Sätze zu löschen und/oder einzufügen + usw. Dafür gibt es keine DIRFILEs. Siehe dazu auch das Kapitel über + Dateien in diesem Benutzerhandbuch. + +Der zweite Parameter einer Assoziierungsprozedur gibt an, unter welchem +Namen die Datei in dem Betriebsystem bekannt ist. Mit Hilfe dieses Namens +wird die Datei an das Datenobjekt gekoppelt, das bei der FILE-Deklaration im +Programm erzeugt wurde. + +Welche Operationen sind nun für Dateien zugelassen? Wir beschreiben die +wichtigsten für die beiden Dateiarten und Betriebsrichtungen getrennt: + +a) FILE mit 'input' (nur lesen): + + PROC getline (FILE CONST f, TEXT VAR zeile) + PROC get (FILE CONST f, TEXT VAR t) + PROC get (FILE CONST f, REAL VAR r) + PROC get (FILE CONST f, INT VAR i) + BOOL PROC eof (FILE CONST f) + (* Abfrageprozedur auf das Ende eines FILEs (letzter Satz) *) + + Als Beispiel zeigen wir ein Programm, welches eine Datei liest und auf + dem Ausgabemedium ausgibt. + + + Programm 31: + + FILE CONST f :: sequential file (input, "datei1"); + TEXT VAR satz; + WHILE NOT eof (f) REP + getline (f, satz); + put (satz); line + END REP. + +b) FILE mit 'output' (nur schreiben): + + PROC putline (FILE VAR f, TEXT CONST zeile) + PROC put (FILE VAR f, TEXT CONST t) + PROC put (FILE VAR f, REAL CONST r) + PROC put (FILE VAR f, INT CONST i) + PROC line (FILE VAR f, INT CONST zeilenzahl) + + +Aufgabe (HSG): + + a) Das Arbeiten mit Dateien ist manchmal notwendig, weil ... + b) Wenn man mit Dateien in ELAN arbeitet, sind Assoziierungsprozeduren + notwendig. + b1) Wie heißen diese? + b2) Was gibt man in diesen an? + c) Welche Betriebsrichtungen gibt es bei FILES und was bewirken sie? +Übungsziel: Datei-Begriffe + + +Aufgabe (TSW): + + Welche Fehler befinden sich in den folgenden Programmfragmenten? + a) FILE VAR f :: sequential file (input, "MIST"); + TEXT VAR zeile; + REP + getline (f, zeile); + ... + UNTIL eof (f) END REP + + b) FILE VAR f :: sequential file (output, "NOCHMAL"); + TEXT VAR zeile; + REP + getline (f, zeile); + put (zeile) + UNTIL eof (f) END REP + + c) FILE VAR f :: sequential file (input, "VERDAMMT"), + g :: sequential file (input, "DAEMLICH"); + TEXT VAR zeile; + kopiere g in f. + + kopiere g in f: + FOR i FROM 1 UPTO 100 REP + getline (g, zeile); + putline (f, zeile) + UNTIL eof (g) END REP. +Übungsziel: Arbeiten mit Dateien + + + +Programmstruktur 1 + +Bis jetzt haben wir noch nicht vollständig erklärt, wie ein ELAN-Programm +formal als Ganzes aufgebaut sein muß, d.h. wie und in welcher Reihenfolge +die Anweisungen, Refinements, Prozeduren und Deklarationen geschrieben +werden müssen. + +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. In diesem Abschnitt wollen wir uns nur mit dem Aufbau eines +solchen PACKETs beschäftigen. Wir werden dabei nicht alle Möglichkeiten +besprechen, sondern nur die wichtigsten Anwendungen beschreiben, mit einer +Empfehlung, in welcher Reihenfolge die Elemente geschrieben werden sollten. + +Ein "main packet" kann aus folgenden Elementen bestehen: + +a) Deklarationen und Anweisungen. Diese müssen nicht in einer bestimmten + Reihenfolge 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 Programmierpraxis, die meisten Deklarationen an den + Anfang eines Programms (außer z.B. Datenobjekte, die nur lokal oder + kurzfristig benötigt werden, wie Hilfsvariablen oder Laufvariablen) zu + plazieren. + + ; + + +b) Deklarationen, Refinements und Anweisungen. In diesem Fall ist es notwen- + dig, die Refinements hintereinander zu plazieren. Refinement-Aufrufe + und/oder Anweisungen sollten textuell vorher erscheinen. Die Refinements + werden durch einen Punkt von den Aufrufen getrennt: + + ; + . + + + Innerhalb der Refinements sind Anweisungen und/oder Deklarationen möglich. + +c) Deklarationen, Prozeduren und Anweisungen. Werden Prozeduren vereinbart, + sollte man sie nach den Deklarationen plazieren. Danach sollten die + Anweisungen folgen: + + ; + ; + + + Mehrere (parallele) 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 wiederum 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. + +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: + + ; + ; + . + + + 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 Refinements). In PACKET-Refinements dürfen natürlich keine + Datenobjekte verwandt werden, die lokal zu einer Prozedur sind. + + + +Moduln (PACKETs) + +PACKETs sind in ELAN eine Zusammenfassung von Datenobjekten, Prozeduren/ +Operatoren und Datentypen. Man kann sich ein PACKET als ein 'main packet' +mit Zusätzen vorstellen. PACKETs können separat übersetzt werden, so +daß der "Zusammenbau" eines umfangreichen Programms aus mehreren PACKETs +möglich ist. + +Elemente eines PACKETs (Prozeduren/Operatoren, Datentypen) können außerhalb +des PACKETs nur angesprochen werden, wenn sie in der Schnittstelle des +PACKETs, die auch "interface" genannt wird, aufgeführt wird. Mit anderen +Worten: es können alle Elemente eines PACKETs von außen nicht angesprochen +werden, sofern sie nicht über die Schnittstelle "nach außen gereicht" wird. +Damit wird gewährleistet, daß mehrere Programmierer an einem gemeinsamen +Projekt arbeiten können und daß eine gemeinsame Benutzung (oder Störung) von +Programmteilen nur über die in den Schnittstellen von PACKETs aufgeführten +Objekte erfolgen kann. + +Im Gegensatz zu einer Prozedur kann ein PACKET nicht aufgerufen werden (nur +die Elemente der Schnittstelle können benutzt werden). Beispiel: + + +Programm 32: + + PACKET fuer eine prozedur DEFINES swap: + + PROC swap (INT VAR a, b): + INT CONST x :: a; + b := a; + a := x + END PROC swap + + END PACKET fuer eine prozedur + +Dies ist ein PACKET, das eine Tausch-Prozedur für INT-Datenobjekte bereit- +stellt. Das PACKET kann übersetzt werden und dem ELAN-Compiler bekannt +gemacht werden (EUMEL: "insertieren"). Ist das geschehen, kann man 'swap' +wie alle anderen Prozeduren (z.B. 'put', 'get') in einem Programm verwenden. +Tatsächlich werden die meisten Prozeduren und Operatoren (aber auch einige +Datentypen), die in ELAN zur Verfügung stehen, nicht durch den ELAN-Compiler +realisiert, sondern durch solche PACKETs. Um solche Objekte einigermaßen +zu standardisieren, wurde in der ELAN-Sprachbeschreibung festgelegt, welche +Datentypen, Prozeduren und Operatoren in jedem ELAN-System vorhanden +sein müssen. Solche PACKETs werden Standard-Pakete genannt. Jeder Installa- +tion - aber auch jedem Benutzer - steht es jedoch frei, zu den Standard- +Paketen zusätzliche PACKETs mit in den Compiler aufzunehmen und damit den +ELAN-Sprachumfang zu erweitern. + +Ein ELAN-PACKET beginnt mit dem PACKET-Schlüsselwort. Danach folgt der Name +des PACKETs (der am Ende des PACKETs hinter END PACKET wieder erscheinen +muß), gefolgt von der DEFINES-Liste. In dieser Schnittstelle werden die Ob- +jekte angegeben, die nachfolgenden PACKETs zur Verfügung gestellt werden +sollen. + +In der Schnittstelle werden Prozeduren/Operatoren nur mit ihrem Namen ange- +geben. Weiterhin können Datentypen und mit CONST vereinbarte Datenobjekte +in der Schnittstelle aufgeführt werden, aber keine VAR-Datenobjekte, weil +diese sonst über PACKET-Grenzen hinweg verändert werden könnten. + +Im obigen Programm 32 haben wir ein PACKET in der Funktion als spracher- +weiterndes Instrument gezeigt. Im folgenden Beispiel zeigen wir ein Programm, +in dem das PACKET-Konzept verwandt wird, um Datenobjekte vor unbefugten +Zugriff zu schützen. + + +Programm 33: + + PACKET stack handling DEFINES push, pop, init stack: + + LET max = 1000; + ROW max INT VAR stack; + INT VAR stack pointer; + + PROC init stack: + stack pointer := 0 + END PROC init stack; + + PROC push (INT CONST dazu wert): + stack pointer INCR 1; + IF stack pointer > max + THEN errorstop ("stack overflow") + ELSE stack [stack pointer] := dazu wert + END IF + END PROC push; + + PROC pop (INT VAR von wert): + IF stack pointer = 0 + THEN errorstop ("stack empty") + ELSE von wert := stack [stack pointer]; + stack pointer DECR 1 + END IF + END PROC pop + + END PACKET stack handling; + +Nun kann man den Stack über die Prozeduren 'init stack', 'push' und 'pop' +benutzen (in einem 'main packet'). + + +Programm 34: + + init stack; + werte einlesen und pushen; + werte poppen und ausgeben. + + werte einlesen und pushen: + INT VAR anzahl :: 0, wert; + REP + get (wert); + push (wert); + anzahl INCR 1 + UNTIL ende kriterium END REP. + + werte poppen und ausgeben: + INT VAR i; + FOR i FROM 1 UPTO anzahl REP + pop (wert); + put (wert) + END REP. + +Die Datenobjekte 'stack' und 'stack pointer' haben nur Gültigkeit innerhalb +des PACKETs 'stack handling'. Anweisungen wie z.B. + + put (stack [3]); + stack [27] := 5 + +außerhalb des PACKETs 'stack handling' sind also verboten und werden vom +ELAN-Compiler entdeckt. + +Ein PACKET bietet also auch einen gewissen Schutz vor fehlerhafter Verwen- +dung von Programmen und Datenobjekten. Wichtig ist weiterhin, daß die Reali- +sierung des Stacks ohne weiteres geändert werden kann, ohne daß Benutzer- +programme im 'main packet' geändert werden müssen, sofern die Schnittstelle +nicht verändert wird. Beispielsweise kann man sich entschließen, den Stack +nicht durch eine Reihung, sondern durch eine gekettete Liste zu realisieren. +Davon bleibt ein Benutzerprogramm unberührt. + +Die letzte Funktion von PACKETs ist die Realisierung von abstrakten Daten- +typen. Dazu müssen wir uns aber zuvor die Möglichkeiten anschauen, neue +Datentypen zu definieren. + + + +Die Definition neuer Datentypen + +Im Gegensatz zur LET-Vereinbarung, bei der lediglich ein neuer Name für +einen bereits vorhandenen Datentyp eingeführt wurde 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- +Vereinbarung ein gänzlich neuer Datentyp eingeführt. Im Gegensatz zu +Strukturen und Reihungen stehen für solche Datentypen noch nicht einmal die +Zuweisung zur Verfügung. Beispiel: + + TYPE PERSON = STRUCT (TEXT name, vorname, INT alter) + +Ein solcher Datentyp kann wie auch alle anderen Datentypen verwandt werden +(Deklarationen, Parameter, Werte liefernde Prozeduren, als Komponenten in +Reihungen und Strukturen usw.). + +Der neudefinierte Datentyp wird abstrakter Datentyp genannt. Er kann mit +Hilfe eines PACKETs (vergl. nächsten Abschnitt) anderen Programmteilen zur +Verfügung gestellt werden. Die rechte Seite der TYPE-Vereinbarung wird +"konkreter Typ", "Realisierung des Datentyps" oder Feinstruktur genannt. + +Um neue Operatoren und/oder Prozeduren für einen abstrakten Datentyp zu +schreiben, 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 abstrakten Typ zum Datentyp der Feinstruktur. +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 Struk- +turen, dann wird durch eine Selektion oder Subskription eine implizite Kon- +kretisierung vorgenommen. Beispiel: + + TYPE LISTE = ROW 100 INT; + + LISTE VAR personal nummer; + ... + personal nummer [3] := ... + (* das gleiche wie *) + CONCR (personal nummer) [3] := ... + +Denoter für neudefinierte Datentypen werden mit Hilfe des Konstruktors +gebildet: + + TYPE GEHALT = INT; + + GEHALT VAR meins :: GEHALT : (1 000 000); + +Besteht die Feinstruktur aus einem Datenverbund, muß der Konstruktor u.U. +mehrfach geschachtelt angewandt werden: + + TYPE KOMPLEX = ROW 2 REAL; + + KOMPLEX CONST x :: KOMPLEX : ( ROW 2 REAL : ( 1.0, 2.0)); + + + +Abstrakte Datentypen + +Auf die Feinstruktur über den Konkretisierer eines neudefinierten Datentyps +darf nur in dem PACKET zugegriffen werden, in dem der Datentyp definiert +wurde. Der Konstruktor kann ebenfalls nur in dem typdefinierenden PACKET +verwandt werden. + +Wird der Datentyp über die Schnittstelle des PACKETs anderen Programmteilen +zur Benutzung zur Verfügung gestellt, so müssen Operatoren und/oder Proze- +duren für den Datentyp ebenfalls "herausgereicht" werden. Da dann der neude- +finierte Datentyp genauso wie alle anderen Datentypen verwandt werden kann, +aber die Komponenten 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ßerhalb des definierenden PACKETs zur Verfügung steht) + + +Programm 35: + + 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: + + 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). + + +Aufgabe (HSG): + + Was ist ein Modul? Was ist ein Interface? Was ist der Unterschied + zwischen einem PACKET und einer Prozedur? + Die Realisierung von WIDERSTAND durch INTs ist nicht in allen Fällen + befriedigend. Warum? (Beachte besonders die Realisierung des OP + PARALLEL). + Wenn man bei der Typ-Vereinbarung von WIDERSTAND INT gegen REAL + austauschen würde, wo müßte man noch Änderungen vornehmen? Sind + insbesondere Änderungen im Benutzer-Programm (hier im 'main packet') + notwendig? +Übungsziel: PACKET-Begriff + + + +Programmstruktur 2 + +Nun können wir auch erklären, wie ein ELAN-Programm mit mehreren PACKETs +aussieht. Ein Programm besteht aus einer Folge von PACKETs, dem ein 'main +packet' folgt. Es ist auch möglich, PACKETs vorübersetzen zu lassen, so daß +es für einen Nutzer so aussieht, als ob er nur ein 'main packet' übersetzen +läßt. Tatsächlich sind zumindest die Standard-Packets vorübersetzt vorhanden. + + -- cgit v1.2.3