Als ich ursprünglich die Idee zu dieser Artikelreihe hatte, wollte ich die Anfänger erreichen - auch die REXX-Anfänger. Bis auf einige kleine Ausnahmen haben wir bisher aber nur Objekte und Methoden in DrDialog besprochen und REXX selbst eigentlich außer Acht gelassen. Heute werden wir daher den "GUI-Kram" einmal vergessen und eine Einführung in das "reine" REXX durchziehen. Wenn Sie also kein OS/2-REXX-Neuling sind, dürfen Sie diese Ausgabe gerne überspringen. ;-)
Wo anfangen?
Im heutigen Teil schauen wir uns an, was es an Besonderheiten hinsichtlich Variablen und
einigen grundlegenden Befehlen und Funktionen in REXX zu beachten gibt. Um das Erstellen von
Skripten zu vermeiden, die lediglich aus einer oder zwei Zeilen Code bestehen um REXX'
Verhalten zu testen, verwenden wir ein großartiges Hilfsprogramm zum "Spielen"
mit REXX: Es nennt sich REXXTRY
und eigentlich müßte es auch auf Ihrem
System direkt über Befehlszeileneingabe startbar sein. Probieren Sie's mal aus -
öffnen Sie eine Befehlszeilensitzung (ein OS/2-Fenster) und geben Sie rexxtry
ein. Falls Sie Ulrich Möllers XWorkplace zusammen mit dem XCenter verwenden, können Sie
natürlich auch den Menüpunkt Ausführen...
im XCenter-Button verwenden
und dort rexxtry
eingeben. In beiden Fällen sollten Sie danach etwas sehen, was
so aussieht wie...:
Abb.1: Das rexxtry-Fenster
Wenn rexxtry nicht startet, müssen Sie prüfen, ob es sich in einem
Verzeichnis befindet, das Teil der PATH-Variable Ihrer CONFIG.SYS ist. Oder -
um es anders zu formulieren - Sie müssen es dann aus dem Verzeichnis heraus starten, in dem
es sich befindet. Suchen Sie nach einer Datei namens rexxtry.cmd.
Standardmäßig sollte sie sich im Verzeichnis \OS2 auf dem
OS/2-Installationslaufwerk befinden.
Rexxtry
kann auf unterschiedliche Arten verwendet werden, je nach dem wie es
gestartet wurde. In unserem Beispiel verwenden wir beim Aufruf keinerlei Parameter und somit
startet es im "interaktiven Modus", in dem jede Eingabezeile einzeln verarbeitet
(interpretiert) wird.
Um rexxtry
zu beenden, geben Sie einfach exit
ein. Übrigens: Wie
immer bei Befehlszeilen werden auch hier die Eingaben jeweils durch Drücken der
Eingabetaste
abgeschlossen...
Sag' ich nun hallo oder "hallo"?
Um mit einer kleinen Besonderheit zu REXX zu beginnen, versuchen wir 'mal, unser Programm
"Hallo" sagen zu lassen, indem wir den say
-Befehl verwenden.
say
wird verwendet, um "einen Ausdruck in den Standard-Ausgabedatenstrom zu
schreiben". Da wir den interaktiven Modus von rexxtry verwenden und keine zusätzlichen
Tricks und Kniffe benutzen, ist der "Standard-Ausgabedatenstrom" in unserem Fall
schlichtweg der Bildschirm. Wir zeigen also etwas an. Was aber hat es nun mit
"Ausdruck" auf sich? Um es einfach zu halten, lassen Sie es mich so sagen: Das kann
entweder ein Literal sein (eine konstante Zeichenkette in Anführungszeichen), eine Variable
oder eine Funktion. In den beiden letzten Fällen wird also entweder der Inhalt der
Variable bzw. der Rückgabewert aus der Funktion ausgegeben.
Um endlich 'mal etwas zu tun, sagen wir Hallo, indem wir in rexxtry eingeben:
say "hallo"
Als Ergebnis erhalten wir eine einzelne Ausgabezeile mit dem Inhalt hallo
und
eine gepunktete Trennzeile, die rexxtry immer nach dem Abarbeiten einer Eingabe ausgibt (und die
wir im Folgenden ignorieren werden).
Was das Ganze nun so besonders macht, ist die Tatsache, daß REXX's Interpreter ein echt
hilfsbereiter Kerl ist. Würden wir statt des obigen Befehls eingeben...
say hallo
dann würde das bedeuten: Zeige den Inhalt der Variable hallo
an - da wir
nämlich keine Anführungszeichen verwenden. Eigentlich würde man nun eine Meldung
erwarten, die darüber informiert, daß es keine Variable dieses Namens gibt. Das stimmt
zwar, aber... REXX stellt diese Variable automatisch zur Verfügung und initialisiert sie
direkt noch mit ihrem Namen (in Großbuchstaben) als Inhalt und gibt daher aus:
HALLO
Ups! Das ist das Besondere an der Sache... natürlich sieht die Sache anders aus, wenn wir
selbst eine Variable namens hallo
definieren. Geben Sie zuerst ein:
hallo = "Tach!"
Und dann:
say hallo
...und Sie werden sehen, daß nun folgendes ausgegeben wird:
Tach!
Denn nun existiert bereits eine Variable namens hallo
zum Zeitpunkt des
say
-Befehls und REXX gibt deren Inhalt aus (welcher Tach!
lautet).
Vielleicht haben Sie schon mit anderen Programmiersprachen gearbeitet und wissen daher, daß
alle ein unterschiedliches Verhalten beim Formatieren relativ einfacher Ausgaben besitzen,
besonders wenn die Ausgaben aus einer Kombination von Literalen und Variablen bestehen. REXX
bildet da keine Ausnahme - allerdings ragt es aus der Masse hervor, weil es sich extrem
präzise verhält, wenn es um das geht, was "hinter" dem
say
-Schlüsselwort steht. Machen wir doch 'mal weiter und geben ein:
sdl = 42 say "Der Sinn des Lebens ist:" sdl
Daraus wird:
Der Sinn des Lebens ist: 42
Sie fragen sich jetzt wohl, was daran so besonders ist... nun, da steht doch eine Leerstelle zwischen dem Doppelpunkt und der 42. Haben wir gesagt, daß die da hin soll? Ich befürchte ja - um es zu verdeutlichen, geben Sie ein:
say "Der Sinn des Lebens ist:"sdl
Daraus wird nun:
Der Sinn des Lebens ist:42
Und nun - um ein letztes Beispiel anzugeben - geben Sie noch ein:
say "Der Sinn des Lebens ist:" sdl
(mit 7 Leerstellen zwischen dem Literal und dem Variablennamen) und ausgegeben wird entsprechend:
Der Sinn des Lebens ist: 42
Die Anzahl der Leerstellen in say
-Befehl entspricht genau der, die in der Ausgabe
verwendet wird, was nicht gerade typisch für Programmiersprachen ist, soweit ich weiß.
Normalerweise wird eine Anweisung untersucht und in Schlüsselwort und Parameter zerlegt,
wobei die Anzahl der Leerstellen unerheblich ist.
Da wir nun also schon eine Methode kennen, um Ausgaben in REXX zu erzeugen, schauen wir uns
doch noch einen Befehl an, um Eingaben zu verarbeiten. Wir verwenden dafür den Befehl
PULL
. Genau genommen dient PULL
dazu, eine Zeile aus dem
Standard-Eingabedatenstrom zu holen. Da wir in unserer rexxtry
-Sitzung weder mit
Warteschlangen noch mit Datenströmen herumgespielt haben, wird REXX dadurch veranlaßt,
auf die Eingabe einer Zeile (Eingabe wird abgeschlossen mittels Eingabetaste
)
durch den Anwender zu warten. Geben Sie 'mal ein:
pull eingabe
Ja. Da wartet rexxtry nun auf Ihre Eingabe. Tippen Sie ruhig irgendeinen Satz ein, der Ihnen gerade durch den Kopf geht - Hauptsache, er besteht (zumindest teilweise) aus Kleinbuchstaben, denn das wird gleich interessant... nach Ihrer Eingabe geben Sie folgenden Befehl ein:
say eingabe
Und nun sehen Sie sich das an! Da hat der doch tatsächlich alles in Großbuchstaben
umgewandelt! Aber so ist es nun mal - wenn Sie die Eingabe genau so benötigen, wie Sie
gemacht wurde, dann müssen Sie eine andere Funktion namens PARSE
in Kombination
mit PULL
verwenden, so wie in...
parse pull eingabe
Jetzt wird nach
say eingabe
genau das ausgegeben, was auch eingegeben wurde. Natürlich gibt es zu PARSE
noch einiges mehr zu erzählen, aber das werden wir uns in einer späteren Ausgabe
antun.
Nun kennen wir also schon das Grundgerüst, um Eingaben und Ausgaben in REXX zu erzeugen.
Leider nützt uns das aber innerhalb DrDialog nichts, denn dessen Umgebung ermöglicht
den Einsatz der oben beschrieben Funktionen für Ein-/Ausgabezwecke nicht - andererseits:
Wozu sollte das gut sein? In DrDialog werden Ausgaben gemacht, indem die Texteigenschaft eines
Objektes verändert wird und Eingaben werden durch das Auswerten eines Texteingabefelds
erreicht. Der say
-Befehl ist zwar in DrDialog sehr nützlich, um den
Programmablauf zu kontrollieren (da seine Ausgaben im Fenster des Laufzeit-Monitors landen), aber
sowohl say
als auch pull
ermöglichen Ihnen, auch außerhalb
DrDialog einfache Skripte zu erstellen.
Wie dem auch sei: Für's erste bleiben wir lieber bei REXX-Elementen, die Sie auch in
DrDialog einsetzen können. Schauen wir uns doch 'mal an, wie mathematische Berechnungen
in REXX gemacht werden.
Einmaleins in REXX
In REXX werden mathematische Berechnungen einfach durch Angabe der entsprechenden Formel gemacht, wobei die übliche Notation mit PLUS, MINUS, STERN (für Multiplikation) und SLASH (der "normale" Schrägstrich für Division) verwendet wird. Wie üblich gelten auch hierbei die Standardregeln der Algebra - das heißt, die Berechnung erfolgt von links nach rechts, wobei Klammerausdrücke Vorrang haben und die aus der Schulzeit bekannte Regel "Punktrechnung geht vor Strichrechnung" gilt. Ein paar Beispiele:
- Addition zweier Werte
ergebnis = 12 + 4
Die Variableergebnis
enthält danach den Wert 16 - Den Wert einer Variable um 1 erhöhen
ergebnis = ergebnis + 1
Der Wert vonergebnis
wird um1
erhöht - Subtraktion
ergebnis = a - 5
ergebnis
enthält den um5
verringerten Wert der Variablea
- Multiplikation
cents = euros * 100
cents
enthält danach den Wert der Variableeuros
multipliziert mit100
- Division
euros = cents / 100
Dasselbe rückwärts: Die Variableeuros
enthält danach den Wert der Variablecents
geteilt durch100
- "Komplexe" Funktionen:
say 100 + 17 * (3 - 1)
Angezeigt wird134
: Die Multiplikation wird vor der Addition durchgeführt wobei die Berechnung der Formel in Klammern zuerst geschieht...
Beachten Sie, daß einige der obigen Beispiele als Teil eines größeren Kontext
zu verstehen sind: Wenn Sie beispielsweise den Wert einer Variablen um 1 erhöhen wollen,
muß der Inhalt der Variablen numerisch sein, sonst erhalten Sie eine Fehlermeldung.
Dasselbe gilt auch für das Beispiel ergebnis = a - 5
: der Inhalt von
a
muß numerisch sein, bevor diese Anweisung erfolgt. In rexxtry
würden Sie zum Beispiel folgendes eingeben:
cents = 3456 euros = cents / 100 say euros
...was dann 34.56
ausgeben würde.
Für die Deutschen Leser muß hier noch darauf hingewiesen werden, daß
Nachkommastellen mittels eines Punkts vom ganzzahligen Teil getrennt werden, wie es in den
USA üblich ist... das gilt auch für eigene Angaben von Nachkommawerten im Programm. Sie
müssen einen Punkt verwenden.
Exponentialrechnung erfolgt durch Angabe eines doppelten Sterns, wie z.B. in:
say "Der maximale dezimale Wert eines Bytes ist" 2 ** 8 -1
Anführungszeichen und Kommentare
Schauen wir uns erst einmal die Kommentare an. Kommentare werden verwendet, um Informationen innerhalb eines Programms zu speichern, die keinen ausführbaren Code darstellen, also vom Interpreter oder Compiler nicht verarbeitet werden sollen. Damit werden einzelne Teile eines Programms dokumentiert, um ein besseres Verständnis für den Verarbeitungsablauf des Programms zu gewährleisten. Hinsichtlich der Kommentare gibt es eine Besonderheit in REXX - nämlich, daß ein REXX-Programm (oder Skript) mit einem Kommentar beginnen muß. Ich habe 'mal irgendwo gelesen, daß OS/2 diese Eigenschaft dazu verwendet, zwischen einem REXX-Skript und einer Batch-Datei (Stapeldatei) unterscheiden zu können, bin mir aber nicht sicher ob das stimmt.
Testüberschrift untere Ebene
Egal - nehmen Sie's einfach so hin: Ein REXX-Skript muß mit einem Kommentar
beginnen. (In DrDialog ist das übrigens anders, da alles, was Sie dort codieren, innerhalb
eines Code-Rahmens stattfindet, den die Entwicklungsumgebung zur Verfügung stellt.) Ein
Kommentar beginnt mit der Zeichenfolge /*
(normaler Schrägstrich und Stern) und
endet mit der umgekehrten Zeichenfolge */
(Stern Schrägstrich). Ein einfacher
Kommentar würde also beispielsweise so aussehen:
/* das ist ein Kommentar */
Kommentare können sich auch über mehrere Zeilen erstrecken - das könnte dann wie folgt aussehen:
/* Die folgende Routine wird für jede Zeile aufgerufen, die aus der Eingabedatei gelesen wird. Jede Zeichenkette innerhalb der Zeile, die zu dem angegebenen Suchbegriff paßt, wird entfernt und der Rest wird dann als eine Zeile in die Ausgabedatei geschrieben. Die Anzahl der gefundenen Zeichenketten in der Zeile wird als return code an die aufrufende Routine zurückgegeben. */
Wenn sich ein Kommentar über mehrere Zeilen erstreckt, kann es mühsam werden, auf den ersten Blick Code von Kommentar zu unterscheiden. Daher werden Sie - meistens - längere Kommentare in REXX-Skripten in einer anderen Form vorfinden. Programmierer bevorzugen meist eine Abfolge von einzelnen Kommentarzeilen wie...:
/* die folgende Routine wird für jede Zeile aufgerufen, */ /* die aus der Eingabedatei gelesen wird. Jede Zeichenkette */ /* innerhalb der Zeile die zu dem angegebenen Suchbegriff */ /* paßt wird entfernt und der Rest wird dann als eine */ /* Zeile in die Ausgabedatei geschrieben. Die Anzahl der */ /* gefundenen Zeichenketten in der Zeile wird als return */ /* code an die aufrufende Routine zurückgegeben. */
Der Grund hierfür liegt einfach in der besseren Lesbarkeit solcher Kommentare: Man erkennt diesen Block sofort als einen "Kommentar" verglichen mit einem mehrzeiligen Textblock, der lediglich eine einleitende Kommentarkennung hat und die unter Umständen erst nach Blättern im Code gefunden und erkannt werden kann. Kommentare müssen übrigens auch nicht alleine auf einer Zeile stehen. Sie werden es bei kurzen Kommentaren bestimmt bevorzugen, diese mit dem Code zusammen auf einer Zeile zu schreiben, wie in folgendem Beispiel:
euro = dm / 1.95583 /* konvertiere DM-Betrag in Euro */
Und nun kommen wir zu den Anführungszeichen. REXX unterstützt sowohl einfache als auch doppelte Anführungszeichen als gleichbedeutend. Die beiden folgenden Anweisungen sind daher auch gleichbedeutend:
say "hallo" say 'hallo'
Das einige, das Sie dabei beachten müssen ist, daß Sie für zusammengehörende Anführungszeichen auch denselben Typ (einfach/doppelt) verwenden, sonst erkennt REXX das nicht und beschwert sich mit der Meldung "unmatched quote or *". Das würde beispielsweise passieren bei einer Anweisung wie...:
say 'hallo"
REXX' Fähigkeit, beide Typen von Anführungszeichen zu unterstützen, ist dann sehr nützlich, wenn der zu verarbeitende (anzuzeigende) Text selbst Anführungszeichen enthält:
say "Die angegebene Datei gibt's nicht!"
oder
say 'Mein Chef sagt: "Wir müssen unsere Kernkompetenz stärker fokussieren." '
Doch selbst mit einem verständnisvollen Interpreter stößt man irgendwann auf eine Situation, in der im Text selbst dasselbe Anführungszeichen enthalten ist, das auch zur Eingrenzung des Textes selbst verwendet wird. Im Normalfall passiert das dann, wenn der Text beide Typen von Anführungszeichen verwendet. In REXX können Sie das dennoch bewerkstelligen, indem das Anführungszeichen im Text gedoppelt wird... Hmm.. es wird unübersichtlich. Hier ein Beispiel:
say 'Das Original von "That''s just the way it is." stammt aus Bruce Hornsby''s Feder und 2PAC hat''s gecovert.'
Ich schlage vor, Sie spielen ein wenig in rexxtry herum um selber ein Gespür für das Thema "Anführungszeichen" zu entwickeln.
Datum | Zeit | Beschreibung |
---|---|---|
Mai | ||
04. Mai 2003 | 3:00PM EDT (19:00 GMT) | Das Warp Doctor-Team trifft sich jeden Sonntag im Kanal #warpdoctor des WEBBnet. |
05. Mai 2003 | 8:00PM EDT (01:00 GMT) | Allgemeine VOICE Sitzung im IRC in #voice. Alle sind herzlich eingeladen. |
07. Mai 2003 | 10:00PM EDT (02:00 GMT) | Der SCOUG Help Desk trifft sich jeden Mittwoch im Kanal #SCOUG des WEBBnet. |
11. Mai 2003 | 3:00PM EDT (19:00 GMT) | Das Warp Doctor-Team trifft sich jeden Sonntag im Kanal #warpdoctor des WEBBnet. |
14. Mai 2003 | 10:00PM EDT (02:00 GMT) | Der SCOUG Help Desk trifft sich jeden Mittwoch im Kanal #SCOUG des WEBBnet. |
18. Mai 2003 | 3:00PM EDT (19:00 GMT) | Das Warp Doctor-Team trifft sich jeden Sonntag im Kanal #warpdoctor des WEBBnet. |
19. Mai 2003 | 8:00PM EDT (01:00 GMT) | Allgemeine VOICE Sitzung im IRC in #voice. Alle sind herzlich eingeladen. |
21. Mai 2003 | 10:00PM EDT (02:00 GMT) | Der SCOUG Help Desk trifft sich jeden Mittwoch im Kanal #SCOUG des WEBBnet. |
25. Mai 2003 | 3:00PM EDT (19:00 GMT) | Das Warp Doctor-Team trifft sich jeden Sonntag im Kanal #warpdoctor des WEBBnet. |
28. Mai 2003 | 10:00PM EDT (02:00 GMT) | Der SCOUG Help Desk trifft sich jeden Mittwoch im Kanal #SCOUG des WEBBnet. |
Juni | ||
01. Juni 2003 | 3:00PM EDT (19:00 GMT) | Das Warp Doctor-Team trifft sich jeden Sonntag im Kanal #warpdoctor des WEBBnet. |
02. Juni 2003 | 8:00PM EDT (00:00 GMT) | Allgemeine VOICE Sitzung im IRC in #voice. Alle sind herzlich eingeladen. |
04. Juni 2003 | 10:00PM EDT (02:00 GMT) | Der SCOUG Help Desk trifft sich jeden Mittwoch im Kanal #SCOUG des WEBBnet. |
08. Juni 2003 | 3:00PM EDT (19:00 GMT) | Das Warp Doctor-Team trifft sich jeden Sonntag im Kanal #warpdoctor des WEBBnet. |
11. Juni 2003 | 10:00PM EDT (02:00 GMT) | Der SCOUG Help Desk trifft sich jeden Mittwoch im Kanal #SCOUG des WEBBnet. |
15. Juni 2003 | 3:00PM EDT (19:00 GMT) | Das Warp Doctor-Team trifft sich jeden Sonntag im Kanal #warpdoctor des WEBBnet. |
16. Juni 2003 | 8:00PM EDT (00:00 GMT) | Allgemeine VOICE Sitzung im IRC in #voice. Alle sind herzlich eingeladen. |
18. Juni 2003 | 10:00PM EDT (02:00 GMT) | Der SCOUG Help Desk trifft sich jeden Mittwoch im Kanal #SCOUG des WEBBnet. |
22. Juni 2003 | 3:00PM EDT (19:00 GMT) | Das Warp Doctor-Team trifft sich jeden Sonntag im Kanal #warpdoctor des WEBBnet. |
25. Juni 2003 | 10:00PM EDT (02:00 GMT) | Der SCOUG Help Desk trifft sich jeden Mittwoch im Kanal #SCOUG des WEBBnet. |
29. Juni 2003 | 3:00PM EDT (19:00 GMT) | Das Warp Doctor-Team trifft sich jeden Sonntag im Kanal #warpdoctor des WEBBnet. |
Oktober | ||
18. Oktober 2003 | 8:00AM EDT (12:00 GMT) | Warpstock 2003 am Wochenende des 18./19. Oktober in San Francisco, Kalifornien. Weitere Informationen unter http://www.warpstock.org. |
Und was kommt dann?
Tja, für heute wär's das erst mal. In der nächsten Ausgabe schauen wir uns REXX' Konstrukte für bedingte Ausführung (if, select), Iterationen (Schleifen), Unterroutinen und Funktionen an. In Teil 10 kümmern wir uns um die Fülle von Funktionen, die REXX zur Zeichenkettenverarbeitung bietet, und nehmen uns auch einige der RexxUtils-Funktionen vor. Danach, in Teil 11 kommen wir zurück zu DrDialog und lernen, wie man mit mehreren Dialogen innerhalb eines Programms umgeht. Was danach kommt weiß ich noch nicht so genau - entweder beginnen wir dann mit unserer größeren Beispielapplikation oder wir schieben noch einen Teil mit "vergessenen" Punkten dazwischen... mal sehen. Bleiben Sie dran!