ELAN ist eine Programmiersprache aus der ALGOL-Familie. Ursprüglich als Schulsprache entworfen, hat ELAN Stärken in Hinsicht auf Lesbarkeit, Sicherheit und Ausdrucksmöglichkeit. Durch Anforderungen, die im Laufe der L3 Entwicklung erwuchsen, ist jedoch die 'reine Lehre' zugunsten wichtiger Leistungen an manchen Stellen aufgeweicht worden.
Lexikalische Elemente einer Programmiersprache sind die Elemente, in denen ein Programm notiert wird.
ELAN besteht aus folgenden Elementen:
Schlüsselwörter besitzen in ELAN eine festgelegte Bedeutung. Sie werden in Großbuchstaben geschrieben und dürfen keine Leerzeichen enthalten.
Beispiele:
VAR, CONST,
INT, REAL, BOOL, TEXT,
IF THEN ELSE ENDIF
Bezeichner
Bezeichner werden benutzt, um Objekte (zum Beispiel Variablen oder Prozeduren) in einem Programmtext zu benennen und zu identifizieren. Sie formulieren Bezeichner in ELAN folgendermaßen :
das ist ein langer name
x koordinate
nr 1
Falsche Bezeichner:
x*1
1 exemplar
Nr 1
Sonderzeichen
Sonderzeichen sind Zeichen, die weder Klein- oder Großbuchstaben, noch Ziffern sind. Sonderzeichen dienen in ELAN vorrangig als Trennzeichen oder als Operatoren.
ELAN kennt folgende Trennzeichen:
! $ % & ' * + - /
< = > ? @ `
ä ü ö Ä Ü Ö ß
Vordefinierte Kombinationen von Sonderzeichen:
:: := <= >= <> **
Kommentare
Kommentare dienen ausschließlich der Dokumentation eines Programms. Sie werden vom Compiler überlesen und haben keinen Einfluß auf die Ausführung eines Programms. Kommentare können an jeder beliebigen Stelle eines Programms, außer in Schlüsselworten und Namen, eingefügt werden. Ein Kommentar darf mehrere Zeilen lang sein. Kommentare werden durch Kommentarklammern umschlossen:
(* *) oder { } oder # #.
Kommentare dürfen verschachtelt sein und alle beliebigen Zeichen enthalten.
Einfache Datentypen: BOOL, INT, REAL, TEXT
Für Datenobjekte dieser denotierbaren Datentypen gibt es eine eindeutig vorgeschriebene Werterepräsentation:
(* INT *) 1 123 0x123fff 0b 1111 0000 1100 1010 (* REAL *) 3.14 6.123456 (* BOOL *) TRUE FALSE (* TEXT *) "das ist ein Text" "Leerer TEXT: " ""
Alle Datenobjekte müssen deklariert werden. Eine Initialisierung ist optional. Für Objekte, auf die Schreib- und Leserecht erteilt wird, muß das Zugriffsattribut VAR angegeben werden. Das Zugriffsattribut CONST für Objekte, auf die nur Leserecht erteilt wird, ist optional.
INT VAR i ;
REAL CONST pi := 3.1412 ;
REAL zehn :: 10.0 ;
BOOL VAR option := FALSE ;
TEXT VAR name := "Pulvermüller" ;
TEXT nix := "" ;
Zusammengesetzte Datentypen
Anweisungen
Jede Anweisung liefert einen Wert, der auch »void« (= nichts) sein kann. Setzt sich eine Anweisung aus mehreren einzelnen zusammen, so liefert sie den Wert der letzten ausgeführten Anweisung.
Operatoren
Operatoren werden in ELAN durch ein oder zwei Sonderzeichen oder als Schlüsselwort (in Großbuchstaben) dargestellt.
Als Operanden (Datenobjekte, auf die ein Operator wirken soll) dürfen verwendet werden :
Man unterscheidet zwei Operator-Arten :
- a
NOT x
Der Operator - liefert den Wert von a mit umgekehrtem Vorzeichen. Dabei muß a vom Datentyp INT oder REAL sein.
Der Operator NOT realisiert die logische Negation. Dabei muß x vom Datentyp BOOL sein.
Beispiele: a, b sind beide vom Datentyp REAL bzw. INT (bei DIV nur INT) x, y sind vom Datentyp BOOL.
Priorität von Operatoren
Es ist erlaubt, einen Ausdruck wieder als Operanden zu verwenden. Praktisch bedeutet dies, daß Sie mehrere Operatoren und Datenobjekte zusammen in einen Ausdruck schreiben dürfen.
Beispiele:
a + 3 - b * cDie Reihenfolge der Auswertung entspricht den folgenden Prioritäten, wobei 9 die höchste Priorität hat, d.h. zuerst ausgeführt wird:
- a * b
Operatoren mit gleicher Priorität werden von links beginnend ausgeführt.
Durch entsprechend gesetzte Klammern können Sie die Reihenfolge ändern.
Beispiel:
(a + b) * (a + b)
In diesem Beispiel wird zuerst a + b ausgewertet und dann die Multiplikation durchgeführt. Es dürfen auch geschachtelte Klammerungen verwendet werden. Dabei gilt: Die innerste Klammer wird immer zuerst ausgewertet. Sie dürfen Klammern auch dort verwenden, wo keine notwendig sind. Überflüssige Klammernpaare werden überlesen.
Beispiel:
((a - b)) * 3 * ((c + d) * (c - d))
Achtung: Ausdrücke, wie z. B. (a-b) oder (d**c) und auch (a) haben immer das Zugriffsrecht CONST. Einem Ausdruck kann also kein Wert zugewiesen werden.
Beispiel für die Abarbeitungsfolge einer Rechnung:
-2 + 3 * 2 ** 3 a) -2 b) 2 ** 3 c) 3 * (2 ** 3) d) (-2) + (3 * (2 ** 3))
Zuweisungen
Eine Zuweisung ist eine spezielle Operation, die einen Wert in eine Variable kopiert:
Variable := Wert
Diese Operation (Zuweisung) hat immer die geringste Priorität. Sie wird als letzte Operation einer Anweisung ausgeführt. Die Zuweisung wird verwendet, um einer Variablen einen neuen Wert zuzuweisen. Der Operator := liefert keinen Wert, sondern weist einem VAR-Datenobjekt den Wert des rechts vom Operator stehenden Operanden zu:
a := b;
Hier wird der Wert von b der Variablen a zugewiesen. Der vorher vorhandene Wert von a geht dabei verloren. Der Wert wird überschrieben.
Als rechter Operand des :=-Operators darf auch ein Ausdruck stehen:
a := b + c;
In diesem Beispiel wird das Resultat von b + c der Variablen a zugewiesen. Beachten Sie dabei die Prioritäten der Operatoren + (Priorität 6) und := (Priorität 1): die Addition wird vor der Zuweisung ausgeführt.
Es kann vorkommen, daß ein Objekt auf der linken und rechten Seite des Zuweisungsoperators erscheint, z. B. dann, wenn ein Wert erhöht werden soll.
a := a + 1;
Hier wird zunächst der alte (aktuelle) Wert von a genommen und um 1 erhöht. Dann wird der neue Wert der Variablen a zugewiesen.
Kontrollstrukturen
IF ... THEN ... END IF
IF ... THEN ... ELSE .... END IF
END IF kann als FI abgekürzt werden.
IF ... THEN ...
ELSE IF ... THEN ... ELSE .... END IF
SELECT ... OF CASE 1, 4: .... CASE 5 : .... CASE 12 : .... OTHERWISE .... END SELECT
REP ... END REPAuch die Kombination ist zulässig. END REP kann als PER abgekürzt werden. Die politischere Äußerung END REP sollte gerade derzeit jedoch bevorzugt werden.WHILE ... REP ... END REP
REP ... UNTIL ... END REP
FOR intvar FROM a UPTO (*DOWNTO*) b REP ... END REP
gesamtlösung: teil a; teil b; teil c. teil a: teil a1; teil a2. teil b: teil b1; ..
INT OP ** (INT CONST basis, exp): . . IF basis <> 0 AND exp = 0 THEN LEAVE ** WITH 1 END IF . . END OP **
Prozeduren und auch Operatoren sind prinzipiell generisch, d.h. Prozeduren dürfen gleiche Namen besitzen, wenn sie durch Anzahl und/oder Typ der Parameter unterscheidbar sind.
PROC prozedur (INT VAR par1, TEXT par2, par3):
PROC prozedur (TEXT VAR par 1, par2, par3):
Eine Prozedur kann Werte beliebigen Typs liefern.
INT PROC prozedur (TEXT par1):
STRUCT (TEXT name, vorname, INT gehalt) PROC liefere person:
Bei Werten liefernden Prozeduren ist zu beachten:
Man kann Prozeduren als Parameter übergeben, die (ggf. leere) Parameterliste muß angegeben werden.
PROC begin (TEXT name, PROC () startproc, TASK VAR t):
Auch monadische und dyadische Operatoren können selbst definiert werden. Der Operatortyp wird nur bei wertliefernden Operatoren angegeben.
Als Operatornamen sind erlaubt:
! $ % & ' * + - / < = > ? @ ' ä ö ü Ä Ü Ö ß
INT OP SIGN (REAL CONST argument): IF argument < 0.0 THEN -1 ELIF argument = 0.0 THEN 0 ELSE 1 FI END OP SIGN
Pakete
Voneinander abgegrenzte Programmteile (»Moduln«) heißen in ELAN Pakete (PACKET). Sie bestehen aus einer Zusammenfassung von
Der formale Aufbau eines Pakets sieht folgendermaßen aus:
PACKET paketname DEFINES schnittstelle : paketrumpf END PACKET paketname
Schnittstelle ist die Liste der herausgereichten Objekte. In ihr werden Prozeduren und Operatoren nur mit ihrem Namen, durch Kommata getrennt, angegeben. Weiterhin können Datentypen und mit CONST vereinbarte Datenobjekte in der Schnittstelle aufgeführt werden. VAR-Datenobjekte können nicht aufgeführt werden, da diese sonst über Paket-Grenzen hinweg verändert werden könnten.
Pakete werden zu folgenden Zwecken eingesetzt:
PACKET vertausche DEFINES swap: PROC swap (INT VAR a, b): INT CONST x :: a; b := a; a := x END PROC swap END PACKET vertausche
Das Beispiel-PACKET vertausche ist ein Paket, das eine Tausch-Prozedur für INT-Datenobjekte bereitstellt. Diese Prozedur heißt swap. Das Paket kann übersetzt und dem ELAN-Compiler bekannt gemacht werden. Dieser Vorgang wird Insertieren genannt. Ist das geschehen, kann man swap wie alle anderen Prozeduren (zum Beispiel put, get) in einem Programm verwenden. Der Quellcode kann gelöscht werden. 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.
Schutz vor fehlerhaftem Zugriff auf Datenobjekte
Beispiel:
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;
Dieses PACKET realisiert einen Stack. Den Stack können Sie über die Prozeduren initstack, push und pop benutzen.
Beispiel:
init stack; werte auf stack bringen; werte vom stack holen. werte auf stack bringen: INT VAR anzahl :: 0, wert; REP get (wert); push (wert); anzahl INCR 1 UNTIL ende kriterium END REP. werte vom stack holen: INT VAR i; FOR i FROM 1 UPTO anzahl REP pop (wert); put (wert) END REP.
Die Datenobjekte stack und stack pointer haben nur innerhalb des PACKETs stack handling Gültigkeit. Anweisungen wie
put (stack [3]);
stack [27] := 5
außerhalb des Paketes stack handling sind verboten und werden vom ELAN-Compiler zurückgewiesen. Ein Paket bietet also Schutz vor fehlerhafter Verwendung von Programmen und Datenobjekten. Wichtig ist außerdem: Wenn Sie die Schnittstelle nicht verändern, kann die Realisierung des Stacks ohne weiteres geändert werden. Dabei müssen Sie Benutzerprogramme nicht ändern. Beispielsweise könnten Sie sich entschließen, den Stack nicht durch eine Reihung, sondern durch eine Struktur zu realisieren. Alle Programme, die den Stack benutzen, können in diesem Fall unverändert bleiben.