Scriptsprache

In diesem Kapitel wird der Aufbau der Winguard-eigenen Scriptsprache erläutert. Seine Lektüre ist vor allem dann sinnvoll, wenn Sie den Winguard-Zeileneditor verwenden möchten. Im Gegensatz zu GUI-Modulen überprüft der Zeileneditor die Eingabe nicht auf Fehler. Die Informationen in diesem Kapitel können Ihnen helfen, Fehler zu vermeiden, oder einmal gemachte Fehler zu finden und zu beheben.

Ausdrücke

In den meisten GUI-Modulen können Sie statt konstanten Werten auch Ausdrücke angeben. Der Wert eines Ausdruckes wird von Winguard zur Laufzeit des Programmes ermittelt und kann damit beispielsweise aus bereits gemessenen Werten oder Benutzereingaben ermittelt werden. Damit wird eine weitaus höhere Flexibilität in der Programmentwicklung erreicht. Im folgenden Abschnitt finden Sie eine eingehende Erläuterung der von Winguard akzeptierten Ausdrücke.

Jeder Ausdruck hat einen Typ

Winguard unterscheidet Werte anhand ihres Typs. Der Typ eines Wertes bestimmt unter Anderem die Art der Berechnungen mit diesem Wert. So können zwei Zahlen a und b addiert werden, indem man den Ausdruck a+b schreibt, für zwei Zeichenketten a und b entspricht der Ausdruck a+b jedoch dem Aneinanderhängen (Konkatenation).

5 + 4       // entspricht dem Wert 9
"5" + "4"   // entspricht dem Wert "54"

Einfache Typen: Zahlen und Zeichenketten

Der Typ Number oder auch Real bezeichnet alle Werte, die Zahlen sind. Es findet keine Unterscheidung zwischen Integer- und Fliesspunktzahlen statt.

Der Typ String umfasst alle Zeichenketten.

Arraytypen

Arraytypen fassen mehrere Werte eines Typs zu einem neuen Wert zusammen. So speichert eine Variable vom Typ array of Real beliebig viele Zahlwerte unter einem einzigen Namen.

Auf die nte Stelle eines Arrays array kann mit array{n} zugegriffen werden.

Zu jedem Typ kann ein Arraytyp erzeugt werden. Winguard erkennt also den Typen array of String genauso wie den Typen array of array of String, auch wenn der letztere nicht von den Variablendialogen unterstützt wird.

Map-Typ

Der Typ Map speichert Werte anhand eines Strings. Beispielsweise ergibt m{"A"} den unter "A" gespeicherten Wert aus der Map m.

Bool’scher Typ

Der Typ Boolean kennt genau zwei Werte: True und False. Der Typ Boolean tritt nur als Ergebnis von Vergleichen auf und kann daher ebenfalls nicht im Variablendialog ausgewählt werden.

Konstante Werte

Die einfachste Art eines Ausdruckes ist ein konstanter Wert, also eine Zahl oder ein String. Die Art, wie Sie Werte angeben können hängt von dem Typ des Wertes ab.

Eingabe von Zahlenwerten

Winguard versteht unterschiedliche Zahlenformate. Einer Zahlenvariable x können Sie den Wert 120 einfach durch deren Angabe zuweisen:

x := 120

Enthält der Zahlenwert einen Nachkommaanteil so wird dieser durch einen Punkt vom Ganzzahlteil abgetrennt:

x := 120.5
x := -22.7

Besonders große Zahlen können in Exponentialschreibweise kürzer angegeben werden:

x := 1E9        // entspricht der Zahl 1000000000 (9 Nullen)
x := 1205E-1    // entspricht 120.5

Zahlen ohne Nachkommaanteil können in Hexadezimalschreibweise durch Voranstellen eines Dollarzeichens angegeben werden. Eine Schreibweise in Binärnotation wird durch Voranstellen eines Prozentzeichens erreicht:

x := $04ef          // entspricht der Zahl 1263 in Hexadezimalschreibweise ($04ef)
x := %10011101111   // entspricht der Zahl 1263 in Binärschreibweise

Eingabe von Strings

Strings müssen in Anführungszeichen angegeben werden:

y := "Foobar"

Sie können zwei Strings zu einem zusammenfassen, indem Sie sie konkatenieren:

y := "Foo" + "bar"  // ergibt den String "Foobar"

Anführungszeichen müssen verdoppelt werden:

Exec(ExePath:"C:\Windows\notepad.exe", Params:"""" + PROJEKTPFAD + "Datei mit Leerzeichen.txt""");

Soll der String Sonderzeichen enthalten, die nicht mit der Tastatur eingegeben werden können, können Sie deren ASCII-Code in eckigen Klammern verwenden.

y := "Foo" + [13] + "bar"  // fügt ein 'Newline' zwischen "Foo" und "bar" ein

Eingabe von Arrays

Zur direkten Eingabe von Arrays werden die einzelnen Werte in eckigen Klammern durch Komma getrennt geschrieben.

y := ["foo", "bar", "baz"]  // ein String-Array mit drei Elementen
z := [1, 2, 3, 4]           // ein Number-Array mit vier Elementen

Variablen und Funktionen

Variablen können in Ausdrücken anstelle eines Wertes verwendet werden. Sie werden während der Ausführung durch ihren Wert ersetzt. Das folgende Skript weist der Variablen x den Wert x + 1 zu, erhöht also ihren Wert um eins.

x := x + 1

Variablennamen beginnen mit einem Klein- oder Großbuchstaben oder einem Unterstrich (_), und können außerdem Zahlen enthalten.

Winguard definiert mehrere Funktionen, die in Ausdrücken verwendet werden können. Eine Funktion berechnet zu einem oder mehreren Parametern einen Ergebniswert. Parameter werden in Klammern hinter dem Funktionsnamen angegeben und können beliebige Ausdrücke enthalten. Einzelne Parameter werden durch Komma voneinander getrennt:

x := sin(90)                    // Berechne den Sinus von 90 Grad
y := ToNumber("Foo", x + 2);    // Konvertiere den String "Foo" in eine Zahl

Im „Übersicht der Funktionen“ finden Sie eine vollständige Liste aller unterstützten Funktionen. Die Funktionen sind nach ihrem Anwendungsbereich sortiert. Zu jeder Funktion ist der Typ angegeben. Betrachten wir als Beispiel die Funktion SubStr die einen Teilstring aus einem String extrahiert:

function SubStr(Str : String; Start : Real; Laenge : Real) : String;

Kopiere aus dem String Str die Zeichenkette die an Position Start beginnt und Laenge Zeichen lang ist. Das erste Zeichen des Strings besitzt den Index 0.

Die Funktion erhält die drei Parameter Str, Start und Laenge. Der erste Parameter ist vom Typ String, alle weiteren vom Typ Real. Der Typ hinter dem letzten Doppelpunkt gibt den Ergebnistypen der Funktion an.

Wenn wir die Funktion SubStr aufrufen möchten, müssen wir ihr also drei Parameter übergeben. Dabei muss der erste Parameter eine Zeichenkette sein, die letzten beiden eine Zahl:

x := SubStr("Foobar", 3, 3);

Obiger Aufruf kopiert von Position 3 des Strings "Foobar" drei Zeichen. Da das erste Zeichen des Strings mit 0 indiziert liefert der Aufruf als Ergebnis den String "bar". Der Typ der Variable muss mit dem Ergebnistypen der Funktion übereinstimmen. Ist dies nicht der Fall, versucht Winguard den Wert zu konvertieren. Wurde die Variable x als Stringvariable deklariert, wird der Ergebniswert einfach zugewiesen und die Variable erhält ebenfalls den Wert "bar". Ist die Variable vom Typ Number so wird versucht den String in eine Zahl umzuwandeln. Da dies nicht möglich ist, erhält die Variable den Wert 0. Die automatische Konvertierung wird im „Automatische Typanpassung“ beschrieben.

Im zweiten Beispiel ist für den dritten Parameter bereits ein Defaultwert vorgegeben. Wird bei Aufrufen der Funktion dieser Wert ausgelassen, wird stattdessen der Defaultwert verwendet.

function StrPos(HayStack : String; Needle : String; Offset : Number = 0) : Number

Sucht in einem String HayStack den String Needle, beginnend an Position Number. Wird der String gefunden, wird die Position des Strings zurückgegeben. Kommt Needle nicht in HayStack vor, gibt die Funktion 0 zurück.

Die folgenden beiden Aufrufe sind also äquivalent, da im ersten Fall der Defaultwert verwendet wird:

x := StrPos("Foobar", "bar");
x := StrPos("Foobar", "bar", 0);

Operatoren

Ähnlich zu Funktionen können Operatoren verwendet werden. Ein Operator wird in der Regel zwischen zwei Ausdrücken platziert und verknüpft beide Ausdrücke zu einem neuen Ausdruck. Daneben existieren auch Operatoren, die nur mit einem Ausdruck verknüpft werden. Als Beispiel für die erste Variante haben wir bereits den Operator + kennengelernt. Ein Operator der nur einen Parameter enthält ist beispielsweise der Operator not der zu einem Zahlwert das binäre Inverse berechnet:

x := y + 10
y := not x

Prioritäten von Operatoren

In dem Ausdruck 2 * x + y soll zuerst der Teilausdruck 2 * x berechnet werden um das Ergebnis dann zu y zu addieren (Punktrechnung geht vor Strichrechnung). Wir sagen der Operator * besitzt eine höhere Priorität als der Operator +. Operatoren mit einer höheren Priorität werden immer zuerst berechnet. Operatoren mit der gleichen Priorität werden von links nach rechts ausgewertet. Die Operatoren nach ihren Prioritäten absteigend sortiert:

  1. Präfix -, Präfix +, not, ^, #, ++
  2. *, /, div, mod, shl, shr, and
  3. -, +, or, xor
  4. <=, >=, =, <, >, <>, in

Operatortypen

Analog zu den Funktionen finden Sie im Anhang eine Auflistung der implementierten Operatoren. Die Operatoren sind nach ihrem Ergebnistyp sortiert. Im Unterschied zu den Funktionstypen werden hier keine Defaultwerte verwendet. Die Art der Operation hängt hier von den Typen der Parameter ab.

So führt beispielsweise die function +(X : Real; Y : Real) : Real; die Addition zweier Zahlen durch, während die function +(S : String; I : Real) : String; an den String S die zu einem String umgewandelte Zahl I anhängt. Der Wert des Ausdruckes x + 5 hängt also davon ab, ob x eine Zahl ist oder ein String:

x := "1" + 5;   // x = "15", da "1" ein String ist
y := 1 + 5;     // y = 6, da 1 eine Zahl ist

Automatische Typanpassung

Stimmt der Typ eines Parameters nicht mit dem erwarteten Typ überein, nimmt Winguard automatisch eine Anpassung des Wertes vor. Betrachten wir die Funktion ToArray:

function ToArray(Str : String): array of Number;

Wandle den String in ein Zahlenarray. Dabei erscheint der ASCII-Wert jedes Zeichens als Element im Array.

Der einzige Parameter ist vom Typ String. Übergeben wir statt des Strings eine Zahl, wird Winguard diese erst in einen String konvertieren und dann die Funktion ToArray aufrufen. Die Konvertierung einer Zahl in einen String liefert die textuelle Repräsentation der Zahl, also für die Zahl 123 den String "123". Für einen Aufruf ToArray(123) wird Winguard zuerst eine Konvertierung der Zahl durchführen, so dass wir einen Aufruf ToArray("123") erhalten und dann anschließend die Funktion anwenden, was in einem Array [49, 50, 51] (die ASCII-Werte der Zeichen "1", "2" und "3") resultiert.

array of Number nach String
Interpretiert die Zahlenwerte des Arrays als ASCII-Codes und erzeugt daraus einen String. Aus dem Array [49, 50, 51] wird der String "123".
String nach array of Number
Legt zu jedem Zeichen des Strings ein Arrayelement an, das den ASCII-Wert des Zeichens enthält. Aus "123" wird das Array [49, 50, 51].
String nach Number
Wandle den String in eine Zahl um. Es werden unterschiedliche Zahlrepräsentationen erkannt. Kann der String nicht konvertiert werden, wird 0 zurückgegeben. Beispiele: "123" wird zu 123, "$123" wird zu 291, "ABC" wird zu 0
Number nach String
Die Zahl wird in Dezimalschreibweise in einen String konvertiert, also 123 wird zu "123" und $123 zu "291". %$ otra vez
Boolean nach Number
Liefert 1 falls der bool’sche Wert True ist und sonst 0.
array of X nach array of Y
Es wird elementweise von X nach Y konvertiert. Beispiel: Die Konvertierung eines array of String in ein array of Number versucht aus allen Strings Zahlen zu erzeugen, aus ["12", "23", "34"] wird das Array [12, 23, 34].