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:
- Präfix
-
, Präfix+
,not
,^
,#
,++
-
*
,/
,div
,mod
,shl
,shr
,and
-
-
,+
,or
,xor
-
<=
,>=
,=
,<
,>
,<>
,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
nachString
- Interpretiert die Zahlenwerte des Arrays als ASCII-Codes und erzeugt daraus einen String. Aus dem Array
[49, 50, 51]
wird der String"123"
. -
String
nacharray 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
nachNumber
- 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 zu123
,"$123"
wird zu291
,"ABC"
wird zu0
-
Number
nachString
- Die Zahl wird in Dezimalschreibweise in einen String konvertiert, also
123
wird zu"123"
und$123
zu"291"
. %$ otra vez -
Boolean
nachNumber
- Liefert
1
falls der bool’sche WertTrue
ist und sonst0
. -
array of X
nacharray of Y
- Es wird elementweise von X nach Y konvertiert. Beispiel: Die Konvertierung eines
array of String
in einarray of Number
versucht aus allen Strings Zahlen zu erzeugen, aus["12", "23", "34"]
wird das Array[12, 23, 34]
.