Up   This page in English.

Die Sprache SeL

Aufruf des SeL-Interpreters

Der SeL-Interpreter kann als Apache-Content-Handler oder aber direkt von der Kommandozeile aus gestartet werden. Er erkennt folgende Kommandozeilen-Optionen:

-h
Usage-Information
-c
Ausgeben des SeL-Objektcodes auf die Standardausgabe (Compile-Only-Modus)
-r <Dateiname>
Ausführen einer SeL-Objektcode-Datei (Runtime-Only-Modus)
-e
Ausgabe interner Konfigurationsoptionen
-f=<Feldname> <Datei>
Der Inhalt des Feldes Feldname (der SeL-Quelltext) in der Datei Datei wird zurückgegeben. Jede andere Ausgabe des Interpreters wird unterdrückt. Die Ausgabe enthält immer auch das abschließende Semikolon der Felddefinition.

Interpreter, Compile- und Runtime-Modus

Ab SeL Version 0.5 kann die Compilierung von SeL-Programmen von deren Ausführung getrennt werden. Mit dem Aufruf:


sel -c datei.sel
wird datei.sel nicht ausgeführt, wie das normalerweise der Fall wäre, sondern nur in ein Zwischenformat ("Objektcode") compiliert und dieser Objektcode wird auf die Standardausgabe geschrieben. Man kann ihn auch, etwa mit:

sel -c datei.sel > datei.sco
in eine zweite Datei speichern (.sco steht hier für "SeL compiled object", die Erweiterungen sind aber, wie immer in SeL, frei wählbar).

Compilierte SeL-Dateien haben einige interessante Eigenschaften:

Compilierte Objektdateien können mit dem Aufruf:


sel -r datei.sco
ausgeführt werden.

Zum Vergleich hier der Geschwindigkeitsgewinn bei Verwendung von compilierten Objektdateien gegenüber normalen SeL-Dateien. Die Messungen wurden mehrfach mit derselben Datei durchgeführt (der GhK-Homepage); das Ausgabeformat ist das des Unix-Kommandos "time".

Timings für SeL-Quelltext:
real	0m0.603s
user	0m0.430s
sys	0m0.100s

real	0m0.570s
user	0m0.440s
sys	0m0.060s

real	0m0.577s
user	0m0.450s
sys	0m0.060s

real	0m0.557s
user	0m0.420s
sys	0m0.090s

real	0m0.563s
user	0m0.450s
sys	0m0.070s

real	0m0.572s
user	0m0.450s
sys	0m0.080s

real	0m0.565s
user	0m0.430s
sys	0m0.080s

real	0m0.567s
user	0m0.440s
sys	0m0.060s

real	0m0.562s
user	0m0.430s
sys	0m0.080s

real	0m0.555s
user	0m0.430s
sys	0m0.070s
Timings für compilierte Objektdatei:
real	0m0.204s
user	0m0.100s
sys	0m0.030s

real	0m0.188s
user	0m0.090s
sys	0m0.050s

real	0m0.172s
user	0m0.090s
sys	0m0.040s

real	0m0.168s
user	0m0.090s
sys	0m0.050s

real	0m0.168s
user	0m0.100s
sys	0m0.040s

real	0m0.186s
user	0m0.090s
sys	0m0.060s

real	0m0.170s
user	0m0.100s
sys	0m0.040s

real	0m0.168s
user	0m0.100s
sys	0m0.050s

real	0m0.164s
user	0m0.090s
sys	0m0.050s

real	0m0.183s
user	0m0.090s
sys	0m0.040s

Variablen, Literale, Zuweisungen

Datentypen
SeL kennt zwei elementare Datentypen: Zeichenketten (strings) und ganzzahlige numerische Werte (integer). Eine Konvertierung zwischen diesen Datentypen findet bei Bedarf automatisch statt.

Variablen müssen vor der Verwendung nicht deklariert werden, aber sie müssen einen Wert zugewiesen bekommen, bevor man sie abfragen kann. Das Referenzieren einer nicht initialisierten Variable ergibt eine Fehlermeldung des Interpreters!

Strings können in SeL grundsätzlich beliebig lang sein und mehrere Zeilen umfassen.

Zuweisungen
Einer SeL-Variable wird mit dem Präfix-Operator "=" ein Wert zugewiesen:

=GRUSS "Hallo";
Hier weisen wir der Variable GRUSS den Wert "Hallo" zu. Groß- und Kleinschreibung bei Variablennamen wird unterschieden, d.h. "gruss", "Gruss", und "GRUSS" sind verschiedene Variablen. Alle drei Variablennamen sind in SeL zulässig, aber wir empfehlen (im Sinne der Benutzer) alle Variablen in einem Masterfile konsistent auf die eine oder andere Weise zu schreiben. Im WWW-Angebot der GhK werden alle Variablennamen großgeschrieben.

Jede Zuweisung endet mit einem Semikolon (";"). Das Semikolon ist für die korrekte Interpretation der Zuweisung erforderlich, weil man in SeL Zuweisungen schachteln kann (s.u.). Ein vergessenes Semikolon wird in vielen Fällen keinen Syntaxfehler hervorrufen, weil die Zuweisung aus der Sicht von SeL legal sein wird. Man wird allerdings dadurch eine unerwartete Schachtelung der Zuweisungen erhalten, die später zu Folgefehlern oder einem abenteuerlichen Verhalten der SeL-Datei führen wird. Achten Sie also bitte immer auf den korrekten Abschluß Ihrer Zuweisungen.

Einer Variable können mehrfach Werte zugewiesen werden. Die alten Werte werden dadurch überschrieben:

=GRUSS "Hallo";
=GRUSS "Guten Tag";
Die Variable GRUSS hat nach dieser Sequenz den Wert "Guten Tag".

Anführungsstriche und SQD
Folgende Zuweisung wäre falsch:

=GRUSS "Er sagte "Hallo"";
Das funktioniert nicht, weil die Anführungsstriche vor dem Wort "Hallo" von SeL als das Ende der Zeichenkette "Er sagte " interpretiert werden. Möchte man Anführungsstriche innerhalb einer Zeichenkette verwenden, so muß man die Zeichenkette mit der Sequenz <SQD> statt mit Anführungsstrichen begrenzen:

=GRUSS <SQD>Er sagte "Hallo"</SQD>;
SQD steht für "Sel Quoted Data" und funktioniert wie ein HTML-Tag. Der Beginn der Zeichenkette wird durch <SQD>, das Ende durch </SQD> angegeben. Innerhalb einer SQD-Sequenz können Anführungsstriche verwendet werden, ebenso wie innerhalb einer durch Anführungsstriche begrenzten Zeichenkette die Zeichenfolge "<SQD>" vorkommen kann:

=GRUSS "Zum Begrenzen von Zeichenketten kann man <SQD> benutzen!";
Innerhalb einer Zeichenkette können Zeilenumbrüche vorkommen. Sie werden als Teil der Zeichenkette übernommen:

=GRUSS "Erste Zeile
Zweite Zeile
Dritte Zeile"
;
Diese Zeichenkette umfasst also drei Zeilen. Das abschließende Semikolon sollte man in solchen Fällen am besten in eine eigene Zeile schreiben, damit es für den Leser der Datei besser sichtbar ist. Dem Interpreter ist es gleichgültig, wo das Semikolon plaziert wird, aber die Datei bleibt so besser lesbar.

Anführungsstriche und SQD sind in SeL fast immer gleichbedeutend. Der einzige Unterschied tritt bei der Verwendung von HTML-Triggern (s.u.) auf.

Kommentare
SeL-Dateien können Kommentare enthalten, die dem Bearbeiter helfen sollen zu verstehen, was da programmiert wurde. Kommentare werden vom SeL-Interpreter ignoriert und dienen nur der Information des Lesers.

Kommentare werden wie in der Sprache C geschrieben, und dürfen (wie dort) nicht geschachtelt werden. Sie werden eingeleitet durch die Zeichenfolge /* und durch */ abgeschlossen:

/* Hier machen wie eine dreizeilige Zuweisung. 
Das hier ist übrigens ein Kommentar. */

=GRUSS "Erste Zeile
Zweite Zeile
Dritte Zeile"
;
Kommentare können beliebig lang sein und mehrere Zeilen umfassen.

Eine weitere Form des Kommentars ist die "#if 0"-Anweisung. Da Kommentare nicht geschachtelt werden können, gibt es ein der Sprache C entlehntes Konstrukt, das in der Lage ist, ganze Blöcke von Anweisungen, einschließlich aller evtl. darin vorhandener Kommentare auszukommentieren. Das ist besonders praktisch, wenn während der Entwicklung eines SeL-Programms testweise ein Teil der Datei deaktiviert werden soll. So funktioniert es:

#if 0
/* Hier machen wie eine dreizeilige Zuweisung. 
Das hier ist übrigens ein Kommentar. */

=GRUSS "Erste Zeile
Zweite Zeile
Dritte Zeile"
;
#endif

=GRUSS "Hallo";
Alles zwischen "#if 0" und "#endif" wird einfach ignoriert. Der so auskommentierte Dateiabschnitt kann beliebig lang sein und seinerseits (wie im Beispiel) Kommentare enthalten (aber keine "#endif"-Sequenz!). Möchte man den auskommentierten Dateiabschnitt probeweise aktivieren, so muß man nur die "0" durch "1" ersetzen:

#if 1
/* Hier machen wie eine dreizeilige Zuweisung. 
Das hier ist übrigens ein Kommentar. */

=GRUSS "Erste Zeile
Zweite Zeile
Dritte Zeile"
;
#endif

=GRUSS "Hallo";
Jetzt ist die ganze Datei aktiv, gerade so als stünde das "#if"-Konstrukt übehaupt nicht da.

Im Gegensatz zur Sprache C werden keine weiteren Ausdrücke nach dem "#if" ausgewertet. Nur die Werte "0" und "1" sind zulässig.

Referenzieren von Variablen
Der Wert einer Variable kann mit dem Referenzierungsoperator "$" (Dollar) abgefragt werden:

$GRUSS
Dieser Ausdruck wird durch den gegenwärtigen Wert der Variable GRUSS ersetzt.

Implizite Verkettung von Werten
Mehrere Vriablenwerte können einfach hintereinander geschrieben werden. Sie werden von SeL stillschweigend aneinandergehängt und als ein einzelner Wert aufgefaßt:

=NAME "Andreas";
=GRUSS "Hallo, mein Name ist "$NAME;
Der Wert der Variable GRUSS wäre hier: "Hallo, mein Name ist Andreas".

Durch die implizite Verkettung von Werten können Zuweisungen sehr lang und komplex werden. Innerhalb der rechten Seite einer Zuweisung können Variablenwerte eingesetzt, Funktionen aufgerufen, Schleifen durchlaufen werden (diese Dinge werden im einzelnen weiter unten besprochen), und alle diese Konstrukte geben Werte zurück, die in die Zuweisung aufgenommen werden. Hier folgt ein Beispiel für eine komplexe Zuweisung. Das Beispiel ist im Detail mit dem bisher gesagten nicht verständlich, aber es soll einen Eindruck davon vermitteln, wie eine komplexe Zuweisung in SeL aussehen kann:

=c if ($a!=$b) then "Ungleich" else "Gleich" fi
        "
        "
        $_env("PATH")
        "
        "
        <SQD>Und jetzt ein substring von "Hallo", beginnend mit
Zeichen 1 und 3 Zeichen lang: </SQD>
        $_copy( "Hallo", 1, 3 )
        <SQD>
        Dasselbe nur mit einer Laenge von 99 Zeichen: </SQD>
        $_copy( "Hallo", 1, 99 )
        "
	Das Zeichen Nummer 4 (sollte o sein): "
        $_copy( "Hallo", 4, 1 )
        "
        Mal sehen, wo de in uni-kassel.de matcht: "
        $_match( "uni-kassel.de", "de" )
        "
        Mal sehen, wo com in uni-kassel.de matcht: "
        $_match( "uni-kassel.de", "com" )
        "
        Mal sehen, wo kassel in uni-kassel.de matcht: "
        $_match( "uni-kassel.de", "kassel" )
        "
        Und jetzt nochmal die vier letzten Zeichen von Hallo: "
        =startpos $_len("Hallo")-4;
        $_copy( "Hallo", $startpos, 999 )
;
Und noch ein letzter wichtiger Punkt: der Wert einer Zuweisung ist eine leere Zeichenkette:

=a "A";

=b 
   =b1 "B1";
   =b2 "B2";
   ;

=c $a$b;
Der Wert von c in diesem Beispiel wäre "A" (und sonst nichts), weil die Variable b selber nur die zwei leeren Zeichenketten der beiden Zuweisungen zugewiesen bekommt. b1 und b2 haben zwar jeweils eine nicht-leere Zeichenkette als Wert, b jedoch ist zwar deklariert, enthält jedoch nur einen leeren String ("").

Das SeL-Ablaufmodell

Startsymbole
Wir haben bisher Variablen, Zuweisungen und Literale (Textkonstanten, die einer Variable zugewiesen werden) kennengelernt. Wir werden jetzt sehen, wie ein vollständiges SeL-Programm abläuft. Dazu ist ein weiteres SeL-Konstrukt erforderlich: das Startsymbol. Ein Startsymbol ist ein Symbol, in der Regel eine Variable oder selbstdefinierte Funktion (s.u.), die als allererstes berechnet wird, und im Zuge dieser Berechnung wird das ganze SeL-Programm durchlaufen (eine Funktion als Startsymbol hätte somit ungefähr dieselbe Bedeutung wie die main()-Funktion eines C-Programms oder ein goal in Prolog).

Die genaue Ablaufsteuerung in einem SeL-Programm ist formal etwas unübersichtlich; sie ist so konzipiert worden, daß sie im konkreten Anwendungsbereich (der Erstellung hierarchisch designter WWW-Seiten) möglichst natürlich wirkt. Betrachten wir zum Anfang einen einfachen Fall. Später werden wir uns mit den Details der Ausführungsreihenfolge von Variablen und Funktionen mit und ohne Masterfiles befassen.

Ein Startsymbol ist syntaktisch dadurch gekennzeichnet, daß es eine mit einem Punkt abgeschlossene Variablenreferenz ist. Hier ein erstes Beispiel eines vollständigen SeL-Programms:

=a "Hallo ";

=b "Welt";

=c $a$b;

$c.
Das Startsymbol ist hier der Ausdruck "$c". Das SeL-Programm läuft zunächst durch bis zum Startsymbol, macht aber keinerlei Ausgabe. Die einzige Ausgabe eines jeden SeL-Programms ist der Wert seines Startsymbols.

Das Programm beginnt also seine sichtbare Ausführung beim Ausdruck "$c". Das "$c" wird evaluiert und expandiert zu "$a$b". $a wiederum ist "Hallo " und $b hat den Wert "Welt". Also ist $c gleich "Hallo Welt", und da $c der Startausdruck ist, wird dieser Wert auch als Ausgabe des SeL-Programms erscheinen.

Streng genommen muß ein SeL-Programm keinen Startausdruck haben. Folgendes Programm ist syntaktisch korrekt:

=a "Hallo ";

=b "Welt";

=c $a$b;
Dieses Programm gibt soviel aus wie ein C-Programm ohne main()-Funktion, nämlich gar nichts. SeL-Programme ohne Startsymbol sind also alleine nicht besonders hilfreich :) aber sie können in manchen Fällen sinnvoll sein: nämlich wenn das Startsymbol in einer Bibliothek verborgen ist (s.u.). Das wird in realen WWW-Server-Umgebungen in der Regel der Fall sein.

Ablaufmodell mit Variablen und Funktionen
Selbstdefinierte Funktionen werden weiter unten besprochen. Wir nehmen die Deklaration solcher Funktionen hier kurz vorweg, um einen wichtigen Unterschied zwischen Variablen und Funktionen bezüglich des Ablaufmodells zu verdeutlichen:

!a(void) "Hallo ";

!b(void) "Welt";

=c $a()$b();

$c.
Dieses Programm produziert dieselbe Ausgabe wie das entsprechende Programm mit Variablen, nämlich "Hallo Welt". Im Unterschied zu einer Variablenzuweisung (die mit dem Operator "=" eingeleitet wird) werden Funktionen mit dem Operator "!" deklariert. Aufgerufen werden sie mit einer Klammer hinter dem Funktionsnamen. Details zur Schreibweise folgen im Abschnitt über selbstdefinierte Funktionen weiter unten.

Was uns hier interessiert, ist der Programmablauf. Auch hier wird zuerst das Startsymbol "$c" evaluiert, und das ruft widerum die Funktionen "a" und "b" auf, die die Werte "Hallo " und "Welt" erzeugen. Soweit klingt alles sehr ähnlich dem Programm mit den Variablen, und die Ausgaben der beiden Programme sind auch gleich. Wo nun liegt der Unterschied?

In einem Satz: Variablenzuweisungen werden in dem Moment vollzogen, wo der Interpreter der Zuweisung begegnet; Funktionen werden erst dann ausgeführt, wenn sie aufgerufen werden. Hier noch einmal die beiden Programmversionen, diesmal mit Zeilennummern. Wir werden im folgenden den Ablauf der beiden Versionen anhand dieser Zeilennummern besprechen. Die Zeilennummern dienen nur dieser Diskussion und sind natürlich nicht Teil des jeweiligen Programms.

Variante A: Variablen
A1:     =a "Hallo ";
A2:	=b "Welt";
A3:	=c $a$b;
A4:	$c.

Variante B: Funktionen
B1:	!a(void) "Hallo ";
B2:	!b(void) "Welt";
B3:	=c $a()$b();
B4:	$c.
Das Programm A läuft so ab: A1,A2,A3,A4. In jedem Schritt stehen die jeweils zugewiesenen Variablenwerte für die folgenden Zeilen zur Verfügung. Variante B hingegen wird folgendermaßen ausgeführt: B3,B1,B2,B4. Die Funktionen werden also nicht sofort ausgeführt, sondern erst wenn sie aufgerufen werden. Die darin berechneten Werte stehen erst nach Aufruf der Funktion zur Verfügung. Dafür kann aber eine Funktion auch Werte verwenden, die erst "weiter unten" im Programm berechnet werden, solange sie nur zum Zeitpunkt ihres Aufrufs zur Verfügung stehen. Variablenzuweisungen können hingegen nur mit Werten arbeiten, die vorher im Programm ("weiter oben") festgelegt wurden, und die sich während des Ablaufs nicht mehr ändern.

Man kann das ganze so zusammenfassen: die sicherste Art ein SeL-Programm zu schreiben, ist mit Funktionen. Sie funktionieren unter allen Bedingungen eher so, wie man das erwartet. Allerdings sind sie etwas schwerfälliger zu formulieren und sie sind langsamer in der Ausführung als Variablenzuweisungen (weil sie bei mehrfachen Aufrufen auch mehrfach durchlaufen werden). Der Autor, der das oben gesagte verstanden hat, kann also gezielt seine Programme optimieren, indem er geeignete Funktionen durch Variablenzuweisungen ersetzt.

Das Startsymbol kann sowohl eine Variable als auch eine Funktion sein.

Einbinden von Bibliotheken

Richtig sinnvoll wird der Einsatz von SeL in der Praxis erst durch die Verwendung von Bibliotheken. Bibliotheken sind Teile von vorgefertigtem SeL-Code, die in ein SeL-Programm eingebunden werden und diesem bestimmte Funktionen zur Verfügung stellen. Sie entsprechen somit den Funktionsbibliotheken in C oder den "Units" in Pascal. Bibliotheken in SeL dürfen auch das Startsymbol enthalten, wodurch sie die Kontrolle über den Ablauf eines SeL-Programms behalten; das die Bibliothek einbindende SeL-Programm wird dann nur noch zum Liefern von Werten benutzt, die die Bibliothek für ihre internen Funktionen benötigt: so funktionieren die oben bereits beschriebenen Masterfiles, die nichts weiter als Bibliotheken mit einem Startsymbol sind.

Bibliotheken werden in ein SeL-Programm mit der Anweisung lib eingebunden, z.B.:

lib "ghk.mas";
Betrachten wir wieder ein einfaches Beispiel, das bereits das Zusammenspiel von Masterfile (Bibliothek) und Inhaltsdatei (aufrufendes SeL-Programm) verdeutlicht:

Bibliothek test.mas
fwd NAME;

!main(void)
	"Ihr Name ist: "$NAME
;

$main().

Inhaltsdatei test.sel
lib "test.mas";

=NAME "Andreas";
Die Ausgabe dieses SeL-Programms test.sel ist "Ihr Name ist: Andreas". Wir sehen, daß das SeL-Programm zwar kein Startsymbol hat, dafür ist aber eines in der Bibliothek: "main()". Dieses Symbol wird aufgrufen, die gleichnamige Funktion ausgeführt, und die oben genannte Zeichenkette als Ergebnis ausgegeben. Es ist wichtig, daß Sie verstehen, daß das Startsymbol in diesem Fall eine Funktion sein muß! Es hätte nicht funktioniert, wenn das Symbol "main" eine Variable gewesen wäre, weil sie sonst evaluiert worden wäre, bevor ein Wert für das Symbol "NAME" zur Verfügung gestanden hätte! Nur durch die Eigenschaft von Funktionen, erst dann ausgeführt zu werden, wenn sie aufgerufen werden, wird die Verwendung einer Variable, die erst später definiert wird, innerhalb einer Funktion möglich.

Außerdem benötigen wir in diesem Fall eine sogenannte Forward-Deklaraion des Symbols NAME (erste Zeile des Masterfiles). Die genaue Bedeutung einer solchen Forward-Deklaration wird im nächsten Abschnitt besprochen.

Es gibt weiterhin die Möglichkeit, ähnlich wie in C, Bibliotheken zu inkludieren, um bestimmte, in SeL selbst nicht enthaltene Funktionen zu nutzen. Ein Beispiel ist die mitgelieferte Datei percentbars.lib. Nachdem sie mit "lib" inkludiert wurde, steht im weiteren Programmablauf die Funktion $percentbar (da es sich nicht um eine eingebaute Funktion handelt, beginnt der Funktionsname nicht mit "$_") zur Verfügung. Diese Funktion gibt auf der Basis übergebender Argumente HTML-Code zurück, der im Browser als Prozent-Balken gerendert wird.

lib "percentbars.lib";

=BAR $percentbar("42","0","CENTER");

Ergebnis:
   42% 

Anhand des mitgelieferten Beispiels können leicht weitere Bibliotheken geschrieben und weitergegeben werden. Bitte dokumentieren Sie Syntax und Funktionalität Ihrer Funktionen in einem Kommentar im Kopf der Bibliothek und beachten Sie die im Beispiel eingehaltene Namenskonvention für Variablennamen in Bibliotheken: Variablennamen beginnen hier immer mit "lib.", es folgt der Name der Bibliothek, dann einem weiteren "." und schließlich einer frei wählbaren Zeichenkette (z.B. lib.percentbars.type). Wenn Sie nützliche Funktionen entwickelt haben, die Sie mit anderen SeL-Nutzern teilen wollen, können Sie sie an uns senden und wir werden sie in der SeL-Distribution veröffentlichen (eMail-Adressen am Anfang dieser Dokumentation).

Forward-Deklarationen
In SeL werden Variablen automatisch bei der ersten Zuweisung deklariert. Variablen, denen noch nichts zugewiesen wurde, sind unbekannt. Man darf sie nicht referenzieren (abfragen), weil der Interpreter dabei eine Meldung wie die folgende ausgeben würde:

File ./test.mas Line 3:
        Error: Reference to undefined symbol /main/NAME
 at `NAME'
In der Tat ist das die Meldung, die wir bekommen, wenn wir im zuletzt vorgstellten Masterfile die "fwd"-Zeile entfernen. Was ist passiert? Der Interpreter liest als erstes die SeL-Datei test.sel und findet darin die "lib"-Anweisung. Daraufhin sucht er nach der Bibliothek test.mas und fängt an, diese zu lesen. Dort stößt er irgendwann auf die Zeile:

"Ihr Name ist: "$NAME
und stellt fest, daß in dieser Zeile eine unbekannte Variable "NAME" auftritt. Das ist eigentlich kein Problem, weil die Variable jetzt ja noch nicht gebraucht wird. Das Startsymbol wird erst aufgerufen, wenn die ganze Datei gelesen wurde, und dann wird das Symbol "NAME" auch existieren. Unglücklicherweise braucht der Interpreter aber schon vorher, um das Programm übersetzen zu können, eine Speicheradresse für jede Variable. Diese Adresse wird angelegt, wenn die Variable einen ersten Wert zugewiesen bekommt. Da das nicht geschehen ist, kann hier die Abfrage nicht übersetzt werden, weil ja diese Variable zu diesem Zeitpunkt des Übersetzens dem Interpreter noch nie begegnet ist.

Jetzt sind wir bei der "fwd"-Anweisung angelangt. Mit

fwd NAME;
können wir SeL mitteilen, daß jetzt schon eine Adresse für eine Variable angelegt werden soll, die erst später zugewiesen wird. Es ist also sozusagen eine reine Deklaration ohne Wertzuweisung, oder, mit wieder anderen Worten, dieses Vorgehen ist immer erforderlich, wenn eine Variable abgefragt (referenziert) wird, bevor sie zum ersten Mal zugewiesen wird. Alternativ hätten wir auch schreiben können:

=NAME "";
in der ersten Zeile des Masterfiles. Auch das hätte eine gültige Variable erzeugt, und das Problem wäre nicht aufgetreten. Die "fwd"-Anweisung ist bloß praktischer, weil man damit eine beliebige Anzahl von Variablen vordeklarieren kann:

fwd LAYOUT INDEX URL KEYWORDS TITLE AUTHOR MAILTO DATE INSTITUTION
INSTLOGO ADDRESS WIDTH UPLINK HELP HELPURL SEARCH
SEARCHURL REMINDER SCRIPT CONTENT LANGUAGE LOCATION ADDTOBODY;
(das ist ein Ausschnitt aus dem Masterfile der GhK). Wir sehen, daß wir alle im Masterfile genutzten Variablen, die erst in der SeL-Datei des Benutzers zugewiesen werden, hier mit einem einzigen "fwd" deklariert haben. Auch das "fwd" wird, wie die meisten SeL-Anweisungen, mit einem Semikolon abgeschlossen.

Falls Sie Turbo-Pascal kennen, werden Sie die "fwd"-Anweisung, die in Pascal eine FORWARD-Deklaration ist, wiedererkennen. Auch C hat ein ähnliches Konstrukt: die extern-Deklaration von Variablen.

Bedingte Ausführung: if/then/else/fi

Kommen wir nun zu einem zentralen Konstrukt einer jeden imperativen Programmiersprache: der Selektionsanweisung. In SeL steht dafür eine "if"-Konstruktion zur Verfügung, die syntaktisch an die "if"-Anweisung der Bourne- und Korn-Shell unter Unix angelehnt ist:

=GRUSS
	if ($NAME=="Andreas") then
		"Hallo"
	else
		"Guten Tag"
	fi
;
Was passiert hier? Der Schlüssel zum Verständnis dieser Zeilen liegt darin, daß wir uns erinnern, daß jede SeL-Anweisung einen Ergebniswert hat. So auch die "if"-Anweisung. Der ganze "if"-Block evaluiert zu einem "Hallo", wenn die Variable "NAME" den Wert "Andreas" hat, und sonst zu "Guten Tag". Dieser Ergebniswert von "if" wird dann der Variable "GRUSS" zugewiesen (natürlich mußß die Variable NAME in diesem Fall irgendwo anders im Programm einen Wert zugewiesen bekommen). "if"-Konstrukte machen also (wie fast alle anderen Anweisungen von SeL auch) nur innerhalb einer Zuweisung Sinn.

Der else-Zweig ist optional und kann entfallen:

=GRUSS
	if ($NAME=="Andreas") then
		"Hallo"
	fi
;
In diesem Fall würde, wenn NAME gleich "Andreas" ist, GRUSS den Wert "Hallo" bekommen, sonst eine leere Zeichenkette. Im folgenden Abschnitt werden wir einige Operatoren kennelernen, die man in "if"-Anweisungen verwenden kann.

Vergleichsoperatoren

Die Vergleichsoperatoren orientieren sich an der Sprache C. Hier eine Übersicht:

VergleichsoperationSeL-Symbol
Gleich==
Ungleich!=
Kleiner<
Größer>
Kleiner oder gleich<=
Größer oder gleich>=

Arithmetische Operatoren

Die arithmetischen Operatoren orientieren sich an der Sprache C. Hier eine Übersicht:

OperationSeL-Symbol
Addition+
Subtraktion-
Multiplikation*
Division/
Modulo%

Schleifen: for/do/done

Die "for"-Schleife ermöglicht die wiederholte Ausführung eines Programmabschnitts. Die Syntax der "for"-Schleife ist etwas eigentümlich: der Gedanke dabei war, wie auch sonst in SeL, die Fehlermöglichkeiten für den Benutzer der Schleife zu minimieren. Die "for"-Schleife ist in SeL eine reine Zählschleife. Sie kann weder über Wertelisten iterieren, wie in der Bourne-Shell, noch eine beliebige logische Abbruchbedingung evaluieren, wie das in C der Fall ist. Sie entspricht somit in ihrer Funktionalität am ehesten den "for"-Schleifen von Basic oder Pascal. Hier ein Anwendungsbeispiel, das der Variable ZAHLEN die Zeichenkette "1 2 3 4 5 6 7 8 9 " zuweist:
=ZAHLEN
	for (i,1,9) do
	    $i" "
	done 
;
Die "for"-Schleife bekommt also in einer Klammer nacheinander folgende Angaben mitgeteilt: den Namen einer Variable (des "Zählers"), den Anfangs- und den Endwert dieser Variable. Die Zählervariable muß nicht (kann aber) vorher deklariert worden sein. Ist sie bisher nicht deklariert worden, dann wird sie automatisch durch die "for"-Schleife angelegt und bleibt bis zum Ende des "for"-Blocks (bis zum "done") bestehen. Existiert die Variable bereits, dann wird die bestehende Variable verwendet, und ihr Wert nach Beendigung der Schleife ist der angegebene Endwert des Zählers. Natürlich können die Anfangs- und Endwerte einer "for"-Schleife ihrerseits durch Variablen angegeben werden, die numerische Werte enthalten.

Manchmal möchte man eine "for"-Schleife in anderen Schritten als 1 zählen lassen. Dazu kann man das vierte (optionale) Argument der Schleife verwenden: die Schrittweite (step). Ein Beispiel:

=ZAHLEN
	for (i,9,1,"-2") do
	    $i" "
	done 
;
In diesem Fall würde der Variable ZAHLEN die Zeichenkette "9 7 5 3 1 " zugewiesen. Daß die "-2" in Anführungsstrichen eingeschlossen ist, hängt mit einem SeL-Fehler zusammen (vgl. Abschnitt über dokumentierte Fehler), der es erforderlich macht, negative numerische Literale in Anführungsstrichen anzugeben. Wird die Schrittweite überhaupt nicht angegeben, so wird (wie im ersten Beispiel) eine Schrittweite von +1 angenommen.

Simulation einer While-Schleife durch goto
In der gegenwärtigen Version verfügt SeL über keine echte Repeat- oder While-Schleife wie andere Programmiersprachen. Man kann jedoch diese Schleifen wie in Basic durch bedingte Sprünge mit der goto-Anweisung von SeL simulieren. Hier eine Schleife, die solange iteriert, bis eine benutzerdefinierte Funktion weiter() (die hier nicht gezeigt wird) den Wert "nein" zurückgibt:

=ERGEBNIS
	:nochmal
		"Schleifeninhalt..."
	if ($weiter()!="nein") then goto nochmal fi
;
Diese Schleife würde der Variable ERGEBNIS einen Wert der Art: "Schleifeninhalt...Schlefeninhalt...Schleifeninhalt..." so oft zuweisen, bis die Funktion weiter() den Wert "nein" zurückgibt.

Eine Positionsmarkierung (label) wird durch:

:Markierungsname
definiert. Mit:

goto Markierungsname
kann man später wieder dahin zurückspringen.

Vordefinierte Funktionen

Die Stärke einer jeden Programmiersprache liegt in der Funktionsbibliothek, die sie dem Benutzer zur Verfügung stellt. SeL bietet eine gezielt für den Aufbau von WWW-Seiten optimierte Auswahl an eingebauten Funktionen an, die ständig erweitert wird. Wenn Sie eine bestimmte Funktion vermissen, können Sie sie entweder mit Hilfe der vorhandenen Möglichkeiten von SeL als benutzerdefinierte Funktion nachbilden, oder aber eine e-Mail an uns schreiben (Adresse am Anfang dieses Handbuchs), sodaß wir diese Funktion in den Kern des Interpreters einbauen kann. Eingebaute Funktionen sind Teil des Interpreters und werden in Maschinencode ausgeführt; sie sind deshalb wesentlich schneller als in SeL nachgebildete Funktionen.

Um den Namensraum übersichtlich zu halten, beginnen die Namen aller vordefinierten Funktionen mit einem Unterstrich ("_"). Vermeiden Sie es also, Namen, die mit einem Unterstrich beginnen, an benutzerdefinierte Funktionen zu vergeben. Dadurch vermeiden Sie Namenskonflikte zwischen vor- und benutzerdefinierten Funktionen.

Arithmetische Funktionen
Aufruf:_hex( digits, decimal )
Beschreibung:Konvertiert dezimal nach hexadezimal
Beispiel:$_hex(2,15)
Ergebnis:0F
Parameter:digits: Anzahl der Stellen für das Ergebnis
decimal: Dezimaler Wert, der konvertiert werden soll
Aufruf:_dec( digits, hex )
Beschreibung:Konvertiert hexadezimal nach dezimal
Beispiel:$_dec(2,"A")
Ergebnis:10
Parameter:digits: Anzahl der Stellen für das Ergebnis
hex: Hexadezimaler Wert, der konvertiert werden soll
Stringfunktionen
Aufruf:_len( string )
Beschreibung:Gibt die Länge einer Zeichenkette zurück
Beispiel:$_len("Hallo")
Ergebnis:5
Parameter:string: Zeichenkette, deren Länge bestimmt werden soll
Aufruf:_copy( string, startpos, count )
Beschreibung:Gibt einen Teil einer Zeichenkette zurück
Beispiel:$_copy( "Hallo", 1, 3 )
Ergebnis:all
Parameter:string: Ursprüngliche Zeichenkette
startpos: Erstes Zeichen des Ergebnisses (Beginn mit 0!)
count: Anzahl der Zeichen, die extrahiert werden sollen
Aufruf:_match( string, substring )
Beschreibung:Sucht eine Teilzeichenkette in einer Zeichenkette. Gibt die Zeichenposition zurück, an der ein Treffer gefunden wurde, oder "-1" falls die Teilzeichenkette in der Zeichenkette nicht vorkommt.
Beispiel:$_match("uni-kassel.de", "de")
Ergebnis:11
Parameter:string: Ursprüngliche Zeichenkette
substring: Teilzeichenkette, die gesucht werden soll
Aufruf:_bstrip( text )
Beschreibung:Gibt den Teil von "text" zurück, der zwischen <BODY> und </BODY> steht.
Beispiel:$_bstrip($_include("http://www.uni-kassel.de"))
Ergebnis:Text zwischen <BODY> und </BODY> (exclusiv)
Parameter:text: Eine Textvariable, Konstante, oder ein Funktionswert, der sinnvollerweise HTML-Text enthalten sollte.
Anmerkung:Vgl. hierzu auch die Funktionen _include() und _frl().
Wenn in "text" kein <BODY> vorkommt, dann wird der ganze Inhalt von "text", ggf. inclusive eines abschließenden </BODY> zurückgegeben.
Wenn in "text" zwar ein <BODY> aber kein </BODY> vorkommt, dann wird "text" vom <BODY> beginnend bis zum Dateiende zurückgegeben.
Aufruf:_frl( text )
Beschreibung:Ersetzt relative HTTP-Links in HTML-Dokumenten durch absolute ("Fix Relative Links").
Beispiel:$bstrip($_frl($_include("http://www.uni-kassel.de")))
Ergebnis:Der BODY-Teil des Dokuments http://www.uni-kassel.de, in dem alle relativen Links durch absolute ersetzt wurden.
Parameter:text: Eine Textvariable, Konstante, oder ein Funktionswert, der sinnvollerweise HTML-Text (inclusive eines BASE-HREF-Tags) enthalten sollte.
Anmerkung:Vgl. hierzu auch die Funktionen _include() und _bstrip().
Zur Expansion relativer Links wird ein BASE-HREF-Tag in "text" benötigt ($_include() erzeugt eines mit Hilfe von Lynx). Wenn in "text" kein <BASE HREF> vorkommt, dann wird keine Konvertierung der Links durchgeführt.
Aufruf:_toupper( text )
Beschreibung:Konveriert Kleinbuchstaben in "text" in Großbuchstaben.
Beispiel:$_toupper("SeL")
Ergebnis:SEL
Parameter:text: Eine Variable, die Text enthält, eine Textkonstante oder ein Funktionsaufruf, der Text zurückgibt.
Anmerkung:Vgl. Funktion _tolower().
Aufruf:_tolower( text )
Beschreibung:Konvertiert Großbuchstaben in "text" in Kleinbuchstaben.
Beispiel:$_toupper("SeL")
Ergebnist:sel
Parameter:text: Eine Variable, die Text enthält, eine Textkonstante oder ein Funktionsaufruf, der Text zurückgibt.
Anmerkung:Vgl. Funktion _toupper().
System- und Dateifunktionen
Aufruf:_env( name )
Beschreibung:Gibt den Wert einer Umgebungsvariable zurück
Beispiel:$_env("REMOTE_HOST")
Ergebnis:hrz-ws48.hrz.uni-kassel.de
Parameter:name: Name der Umgebungsvariable
Aufruf:_date( format )
Beschreibung:Gibt die Systemzeit zurück
Beispiel:$_date("%d %h %Y: %H:%M:%S")
Ergebnis:26 May 1999: 17:17:23
Parameter:format: Ausgabeformatierung. Dieser Parameter wird wie der Format-Parameter der C-Funktion "strftime()" verarbeitet. Siehe dort für weitere Hinweise zur Ausgabeformatierung.
Aufruf:_dirname( pfad )
Beschreibung:Gibt den Verzeichnisanteil einer Unix-Pfadangabe zurück
Beispiel:$_dirname("/home/WWW/docs/Welcome.ghk")
Ergebnis:/home/WWW/docs
Parameter:pfad: Vollständiger Pfad. Der Verzeichnisanteil entspricht der Ausgabe des Unix-Kommandos "dirname". Der Pfad muß nicht existieren.
Aufruf:_include( pfad )
Beschreibung:Gibt den Inhalt einer Datei zurück
Beispiel:$_include("/etc/motd")
Ergebnis:[Inhalt der Datei]
Parameter:pfad: vollständiger Pfad zur einzufügenden Datei. Der Pfad wird auf Sicherheit geprüft und muß vom SeL-Administrator für diesen Zweck freigegeben worden sein. Im Fehlerfall wird eine Fehlermeldung anstelle des Dateiinhalts zurückgegeben. SeL-Kommandos, die sich ggf. in der Datei befinden, werden nicht ausgeführt, sondern nur als Text zitiert. Um Dateien mit SeL-Code (Bibliotheken) einzubinden, vgl. lib
Anmerkung:In früheren SeL-Versionen hieß diese Funktion (etwas unglücklich) _source(). Ab Version 0.4 wird _source() zwar noch erkannt, sollte aber in neuen Anwendungen nicht mehr benutzt werden.
Aufruf:_include( URL )
Beschreibung:Gibt den HTML-Code der WWW-Adresse "URL" zurück
Beispiel:$_include("http://www.uni-kassel.de")
Ergebnis:[HTML-Text]
Parameter:URL: vollständige URL. Damit dieser Aufruf funktioniert, muß der Administrator diese Funktion freigeschaltet haben; andernfalls erfolgt eine Fehlermeldung.
Zur Zeit wird nur das Protokoll "http" unterstützt.
Anmerkung:Vgl. hierzu auch die Funktionen _bstrip() und _frl().
HTTP-Funktionen
Aufruf:$_read()
Beschreibung:Liest CGI-Query von Standard Input.
Beispiel:=cgi.in $_read();
Ergebnis:CGI post query string
Parameter:keine
Anmerkung:Vgl. auch $_cgiparse() zum Parsen von CGI Variablen/Werten und $_cgival() zum Auslesen einzelner Werte.
Aufruf:$_cgiparse()
Beschreibung:Zerlegt Strings in CGI-Query-Syntax in Variablen/Werte-Paare und konvertiert enthaltene hexadezimale Query-Codierungen zurück in ASCII-Darstellung.
Beispiel:$_cgiparse($_read)
Ergebnis:Intern aufgelöste CGI-Variablen und deren Werte.
Parameter:text: einen String in der Syntax, in der CGI-Programme empfangene Formular-Inhalte vom WWW-Server übergeben bekommen.
Anmerkung:$_cgiparse() erfordert typischerweise zunächst die Ausführung von $_read(). Vgl. auch $_read() zum Einlesen des CGI-Query-Strings und $_cgival() zum extrahieren eines darin übergebenen Wertes. Diese eingebaute Funktion basiert u.a. auf Programmcode aus der C-Bibliothek "cgic" von Thomas Boutell.
Aufruf:$_cgival()
Beschreibung:Gibt den Wert einer CGI-Variablen zurück.
Beispiel:$_cgival("element")
Ergebnis:Der Wert, der in dem übermittelten Formular dem Element "element" zugewiesen wurde.
Parameter:text: Ein CGI-Variablenname (also der Name eines verschickten Formular-Elements).
Anmerkung:$_cgival() erfordert typischerweise zunächst die Ausführung von $_read() und dann die Ausführung von $_cgiparse(). Vgl. auch $_read() zum Einlesen des CGI-Query-Strings und $_cgiparse() zum Zerlegen von CGI-Query-Strings. Diese eingebaute Funktion basiert u.a. auf Programmcode aus der C-Bibliothek "cgic" von Thomas Boutell.
Aufruf:_setcookie( name, wert )
Beschreibung:Erzeugt HTML-Code für das Setzen eines Cookies mit dem Namen "name" und dem Wert "wert"
Beispiel:$_setcookie( "prinzen", "rolle" )
Ergebnis:<meta http-equiv="set-cookie" content="prinzen=rolle;path=/;">
Parameter:name: Der Name des Cookies
wert: der Wert, der dem Cookie zugewiesen werden soll.
Anmerkung:SeL erzeugt nur den HTML-Code für das Cookie und gibt ihn zurück. Es liegt in der Verantwortung des Masterfiles, eine Variable vorzusehen, die im HEAD der HTML-Ausgabe eingefügt wird, und die diesen Code aufnehmen kann (Cookies funktionieren nicht im BODY der Datei!)
Diese Funktion bietet zur Zeit keine Möglichkeit, das Expiration-Date eines Cookies zu setzen.
Aufruf:_getcookie( name )
Beschreibung:Gibt den Wert des Cookies mit dem Namen "name" zurück
Beispiel:$_getcookie( "prinzen" )
Ergebnis:rolle
Parameter:name: Der Name des Cookies
Anmerkung:Wenn das Cookie nicht gesetzt ist, gibt diese Funktion einen leeren String zurück.
Verschiedene Funktionen
Aufruf:_selversion
Beschreibung:Gibt die Versionsnummer des SeL-Interpreters zurück
Beispiel:$_selversion
Ergebnis:$Id: sprache.html,v 1.5 2000/03/24 23:29:39 andy Exp $
Parameter:Keine
Anmerkung:_selversion gehört eigentlich nicht hierher: es ist eine vordefinierte Variable und keine Funktion; wird deshalb auch ohne Parameterklammern aufgrufen.
Zusätzliche Präprozessor-Anweisungen
Name:#if
Beschreibung:Konditionale Compilierung von SeL-Code
Beispiel:#if 0
...
...
#endif
Ergebnis:Der zwischen "#if 0" und "#endif" stehende Code wird nicht ausgeführt. Mit "#if 1" statt "#if 0" kann er wieder aktiviert werden.
Parameter:0 oder 1
Anmerkung:Im Gegensatz zu C sind nur 0 und 1 als Parameter zulässig, nicht aber andere Ausdrücke.
Aufruf:lib "file"
Beschreibung:Bindet eine externe Datei mit SeL-Code (Bibliothek) in das Programm ein
Beispiel:lib "ghk.mas"
Ergebnis:[Dateiinhalt von ghk.mas]
Parameter:file: Dateiname. Der Name muß sich in einem vom Administrator für diesen Zweck freigegebenen Verzeichnis befinden. Er kann absolut oder relativ angegeben werden. Wenn er relativ ist, wird ein vom Administrator konfigurierter Suchpfad durchsucht.
Anmerkung:Im Gegensatz zu _include() wird hier der Inhalt der Datei ausgeführt und nicht bloß eingebunden. Diese Direktive hieß in früheren SeL-Versionen "#include". "#include" wird weiterhin unterstützt, sollte aber in neuen Anwendungen nicht mehr eingesetzt werden.

Arrays (Variablenfelder)

Referenzieren von ungültigen Array-Elementen

Benutzerdefinierte Funktionen

Referenzieren von Funktionen als Variablen

HTML-Trigger

Ab Version 05-11 unterstützt SeL das Konzept der Trigger: Damit kann man auf einfache Weise bestimmte Tags (im Moment nur HTML-artig formulierte Tags), die irgendwo in SQD-Konstanten vorkommen, durch einen Funktionsaufruf ersetzen und diese Tags, statt sie anzuzeigen, durch beliebigen SeL-Code ersetzen.

Trigger entsprechen in ihrer Funktionalität damit etwa den HTML-Style-Sheets, werden aber vollständig innerhalb von SeL (und damit serverseitig) behandelt, ohne daß der Browser des Benutzers damit in Berührung kommt.

Trigger werden durch die Anweisung html_trigger definiert:
html_trigger tag;
wobei tag zu ersetzen ist durch das HTML-Tag, das abgefangen werden soll. Das Tag muß dabei ohne die spitzen Klammern angegeben werden. Wollen wir das Tag <H1> abfangen, würden wir also schreiben:

html_trigger H1;
Mehrere Trigger können mit mehreren html_trigger-Anweisungen gesetzt werden:

html_trigger H1;
html_trigger H2;
html_trigger BODY;
Für jedes Tag, das abgefangen werden soll, müssen nun eine oder zwei SeL-Funktionen definiert werden. Diese haben immer festgelegte Namen:

html_start_tag( attributes )
und

html_end_tag( attributes )
wobei tag zu ersetzen ist durch das Tag, wie es in der html_trigger-Anweisung angegeben wurde; also z.B.:

!html_start_H1( attributes )
...
...
;
Die Start-Funktion wird vom Interpreter aufgerufen, wenn der Beginn des Trigger-Tags gefunden wird; die End-Funktion, wenn das Ende angetroffen wird. Bei Tags, die kein Ende haben (z.B. <LI>), würde es im Prinzip also genügen, eine Start-Funktion zu definieren. Da man aber nicht ausschließen kann, daß eine Benutzerdatei auch ein </LI> enthält (und da das auch normalerweise von den Browsern toleriert wird) sollte man zur Sicherheit immer auch eine leere End-Funktion mitdefinieren.

Die Trigger-Funktionen bekommen immer einen Parameter von SeL übergeben: die Attribute des Tags (z.B. BGCOLOR im BODY-Tag). Hat das Tag keine Attribute, so wird ein leerer String übergeben.

Der Rückgabewert der Trigger-Funktion wird statt des ursprünglichen Trigger-Tags in den Quelltext des SeL-Programms eingefügt und dann wird die Compilierung fortgesetzt. Trigger-Tags können also durch beliebig komplexe SeL-Anweisungsfolgen ersetzt werden.

Wichtig:
Der Triggermechanismus funktioniert nur innerhalb von <SQD>-Tags; wenn das HTML-Tag, das als Trigger definiert wurde, innerhalb von doppelten Anführungsstrichen steht (statt in SQD), dann wirkt es nicht als Trigger, d.h. es wird unverändert weitergegeben. Das ist nützlich, wenn eine Triggerfunktion ihr eigenes Triggertag als Teil ihres Rückgabewertes zurückgeben möchte: wenn sie es in SQD täte, entstünde eine Endlosschleife, weil der Rückgabewert der Funktion wiederum den Trigger auslösen würde. Es ist jedoch sicher, das Triggertag in doppelten Anführungsstrichen zurückzugeben, weil es dann nicht als Trigger betrachtet wird.

Beachten Sie bitte auch, daß SeL keine Kenntnis bestimmter HTML-Tags hat, d.h. die Trigger sprechen auch auf nicht standardgemäße Pseudotags an. Man kann also bei Bedarf eigene Tags erfinden und diese mittels Trigger in SeL behandeln.

Ein Beispiel für die Verwendung von Triggern liegt als test19.sel der Distribution bei.


Last modified: Mon May 08 18:08:44 MEZ 2000