.. highlightlang:: us .. _elemente-von-uniscript: Elemente von UniScript ====================== .. index:: Kommentare .. _kommentare: Kommentare ---------- Kommentare haben den Zweck, ein Programm besser lesbar zu machen. Die Sprache ignoriert alle Zeichen, die innerhalb von Kommentaren stehen. In UniScript gibt es Kommentare im C-Stil, die mit den Zeichen ``/*`` anfangen und mit den Zeichen ``*/`` enden, sowie Kommentare im C++-Stil, die mit den Zeichen ``//`` beginnen und bis zum Ende der Zeile reichen. Die Kommentare im C-Stil können über mehrere Zeilen gehen. Beispiele: :: /* Dies ist ein Kommentar im C-Stil. */ // Dies ist ein Kommentar // im C++-Stil Kommentare im C-Stil können überall dort stehen, wo auch ein Leerzeichen stehen kann, z. B.:: rvSignal = [1.4, 1.45, 133254.4 /* Messfehler ? */, 1.53]; Kommentare im C-Stil dürfen nicht geschachtelt werden. Die Zeichenfolge ``*/`` ist also innerhalb eines ``/* */``-Kommentars verboten. Treffende Namen zu vergeben ist besser als ungünstige Namen zu kommentieren:: ssFilename = GetOpenFileName(); ist auch ohne Kommentar besser zu lesen als die Zeilen :: // Dateinamen holen f = getname(); Auch Selbstverständlichkeiten zu kommentieren ist kein guter Stil :: // Minimum des Signals ermitteln rsMin = min(rvSignal); Kommentare werden häufig dazu verwendet, Quellcode-Zeilen auszublenden wie im folgenden Beispiel:: // Berechnung einer n mal n Hilbert-Matrix def hilb(n) { /* h = zeros(n, n); for (i in 1:n) { for (j in 1:n) { h[i;j] = 1/(i+j-1); } } return h; */ // so geht es schneller als // mit zwei geschachtelten for-Schleifen x = 1:n; x = x[ones(1,n); /* alle Spalten */ ]; return 1./(x+x.'-1); } .. index:: Fortsetzungszeilen .. _fortsetzungszeilen: .. _continuation-line: Fortsetzungszeilen ------------------ In UniScript dürfen Anweisungen nicht über mehrere Zeilen gehen. Wird eine Anweisung zu lang, kann man mit zwei Punkten eine Fortsetzungszeile einleiten. UniScript ignoriert alle Zeichen hinter den beiden Punkten bis zum Ende der Zeile:: return (ones(1,m) .* 10) .^ .. [s1+(0:m-2) * (S2-s1) ./ (m-1), S2]; Fortsetzungszeilen können nur dort beginnen, wo auch ein Leerzeichen erlaubt ist, also nicht innerhalb von Namen oder Konstanten. Eine Zeichenkette kann folgendermaßen in mehreren Zeilen geschrieben werden:: "Dies ist eine lange konstante Zeichenkette," + .. " die über zwei Zeilen geschrieben wird" Ab UniPlot R2013.11 brauchen hinter einem Komma, einem Semikolon und binären Operatoren keine ``..`` mehr angegeben werden. D. h. die ``..`` in den beiden Beipielen oben sind redundant. .. index:: Konstanten .. _konstanten: Konstanten ---------- Die einfachste Form eines Ausdrucks ist eine Konstante. In UniScript gibt es drei konstante Typen: Reelle Konstanten, komplexe Konstanten (diese beiden Typen bezeichnet man als numerische Konstanten) und Zeichenketten-Konstanten oder String-Konstanten. .. _define: .. _numerische-konstanten: Numerische Konstanten --------------------- Eine numerische Konstante steht für eine Zahl. In UniScript werden Zahlen als doppelt genaue Fließkomma-Zahlen gespeichert. Beispiele für gültige Zahlen sind:: 123 12.8 +13.01e-3 12E3 Nicht zulässig sind folgende Darstellungen :: .03 // Punkt am Anfang nicht erlaubt 12. // Punkt am Ende nicht erlaubt 13.9D8 // Buchstabe D als Exponentkennzeichen // nicht erlaubt 3,82 // Dezimaltrennzeichen ist der Punkt, // nicht das Komma Es gelten genau die gleichen Regeln wie bei der Programmiersprache C. Normalerweise wird man Konstanten einen Namen geben. Dazu wird wie in C die ``#define``-Anweisung verwendet. Die ``#define``-Anweisung hat folgende Form:: #define konstanten-name ersatztext Anmerkung für C-Programmierer: Die :keyword:`define`-Anweisung ist die einzige Präprozessor-Anweisung, die UniScript kennt. Parameter sind nicht zulässig. Immer dort, wo der UniScript-Interpreter auf ``konstanten-name`` trifft (außer in Zeichenketten und Kommentaren), wird er durch den Ersatztext ausgetauscht. Der Konstanten-Name muss den Regeln für UniScript-Namen gehorchen, der Ersatztext kann eine beliebige Zeichenfolge sein. Wird beispielsweise die Konstante PI wie folgt definiert:: #define PI 3.1415926535897931 kann der Name ``PI`` in Ausdrücken wie ``u = 2 * PI * r`` verwendet werden. Die Namen von Konstanten werden üblicherweise in Großbuchstaben geschrieben, um sie leichter von Variablennamen zu unterscheiden. Nach der Definition des Namens ``PI`` ist der Name in allen Dateien bekannt, nicht nur in der Datei, in der er definiert wurde wie in der Programmiersprache C. .. index:: Hexadezimale Konstanten, Oktale Konstanten .. _hexadezimale-und-oktale-konstanten: Hexadezimale und oktale Konstanten ---------------------------------- Ganzzahlige Konstanten können wie in C auch in hexadezimaler oder oktaler Schreibweise geschrieben werden. Besteht eine Zeichenkette aus den Zahlen ``0 ... 9`` und ``a ... f`` (oder ``A ... F``) und beginnt sie mit den Zeichen ``0x`` oder ``0X``, wird sie als hexadezimale Zahl (Basis 16) interpretiert. Beispiel:: 0x10 ist 16 0xFF ist 255 0x0d ist 13 0x5 ist 5 Besteht eine Zeichenkette nur aus den Ziffern ``0 ... 7``, und sie beginnt mit der Ziffer ``0`` (null) wird sie als oktal, also zur Basis 8, interpretiert. :: 034 ist 28 0377 ist 255 .. index:: Komplexe Konstanten .. _komplexe-konstanten: Komplexe Konstanten ------------------- Komplexe Konstanten werden eingegeben, indem man den Kleinbuchstaben ``i`` direkt hinter die Zahl schreibt, z. B. ``3i``, ``1.23e-8i``, ``0xFFi``. .. index:: String Konstanten .. index:: Steuerzeichen .. index:: Escape Sequenzen .. _string-konstanten: String Konstanten ----------------- String-Konstanten sind in Anführungszeichen stehende Zeichenketten:: "Dies ist eine String-Konstante" Ein String kann Steuerzeichen (Escape Sequenzen) für die Ausgabe enthalten. Will man z. B. bei der Ausgabe das Wort ``"String-Konstante"`` in eine neue Zeile schreiben, muss man vor das Wort den String ``\n`` einfügen:: "Dies ist eine\nString-Konstante" UniScript kennt folgende Escape-Sequenzen: .. list-table:: :header-rows: 1 * - Code - Bedeutung * - ``\`` - Repräsentiert ein einzelnes ``\``-Zeichen (den Backslash) * - ``\n`` - Repräsentiert einen Zeilenwechsel (newline) * - ``\r`` - Repräsentiert einen Wagen-Rücklauf (carriage return) * - ``\b`` - Repräsentiert ein backspace * - ``\f`` - Repräsentiert ein formfeed * - ``\t`` - Repräsentiert ein Tabulator-Zeichen * - ``\a`` - Repräsentiert einen Warn-Ton (allert) * - ``\"`` - Repräsentiert das Zeichen ``\"`` * - ``\zzz`` - zzz steht für eine ganze Zahl in hexadezimaler, oktaler oder dezimaler Schreibweise (siehe Anmerkung). * - ``\uXXXX`` - XXXX steht für eine hexadezimale Zahl mit genau 4 Ziffern, die den Code eines Unicode-Zeichens enthalten (ab UniPlot 5.0). Anmerkung: Die Zahl ``zzz`` kann in dezimaler, hexadezimaler oder oktaler Schreibweise im Bereich ``0 ... 255`` (dezimal) sein. Es wird der ASCII-Code für die entsprechende Zahl ausgegeben. Beispielsweise sind die Zeichenketten ``"Hallo\n"``, ``"Hallo\10"`` (dezimal), ``"Hallo\012"`` (oktal) und ``"Hallo\x0a"`` oder ``"Hallo\0x0a"`` identisch. Bei der hexadezimalen Schreibweise, müssen den Zeichen ``\x`` oder ``\0x`` exakt zwei hexadezimale Zeichen (0 .. f) folgen. Bei der dezimalen oder oktalen Schreibweise werden alle dezimalen (0 .. 9) oder oktalen (0 .. 7) Ziffern gelesen. Falls die Zahl größer als 255 (dezimal) ist, wird sie durch Abschneiden auf ein Byte gekürzt. Beispielsweise ist ``"\300a"`` nicht das selbe wie ``"\30" + "0a"``. Die hexadezimale Schreibweise ist der dezimalen und oktalen Schreibweise vorzuziehen, da sie nicht zu solchen Missverständnissen führen kann. .. index:: r-Prefix (Strings) Falls eine Zeichenkette den Präfix ``r`` hat, z. B. ``r"Hallo\10"`` werden alle Backslashe in der Zeichenkette belassen, ``r"Hallo\10"`` liefert die selbe Zeichenkette wie ``"Hallo\\10"``. Innerhalb einer einfachen Zeichenkette mit r-Präfix kann kein ``"``-Zeichen definiert werden. .. index: Zeichenketten; lange Zeichenketten "Lange" Zeichenketten --------------------- Ab UniScript 4.0 gibt es sogenannte "lange Zeichenketten". Diese Zeichenketten beginnen mit der Zeichenfolge ``"[[`` und enden mit der Zeichenfolge ``]]"``. Beispiel:: a = "[[ Dies ist eine String-Konstante ]]" ist die selbe Zeichenkette wie:: a = "\nDies ist eine\nString-Konstante\n" In langen Zeichenketten können ``"``-Zeichen mit oder ohne führendem Backslash verwendet werden. Wenn ``r`` als prefix benutzt wird verliert der Backslash seine Spezialbedeutung und wird zu einem normalen Zeichen. Das kann zum Beispiel für Dateinamen nützlich sein. :: b = r"[[ c:\foo \t ]]" // b == "\nc:\\foo\n\\t\\n" .. _null-zeichen-in-strings: .. index:: Null-Zeichen in Strings Null-Zeichen in Strings ----------------------- Ab UniScript 4.2.0 können Zeichenketten Null-Zeichen enthalten (eight-bit clean Strings). Dadurch können UniScript-Strings beliebige binäre Daten enthalten. Der ``+``-Operator kann auch für Zeichenketten mit 0-Zeichen verwendet werden. Die Vergleichsoperatoren verwenden nur den String bis zum ersten 0-Zeichen. :: "Hello\x00Hello" == "Hello" liefert TRUE (1). Um die Zeichenketten komplett zu vergleichen, kann die Funktion :ref:`mem_compare` verwendet werden. Viele String-Funktionen verwenden nur den Teil des Strings bis zum ersten 0-Zeichen. Beispiel:: strlen("Hello\x00Hello") liefert 5, d. h. die Anzahl an Zeichen bis zum ersten Null-Zeichen. Der Funktionsaufruf ``mem_len("Hello\x00Hello")`` liefert in UniPlot 4.x den Wert 11 in UniPlot 5.x oder höher den Wert 22, da UniPlot 5 Unicode verwendet und ein Unicode-Zeichen 2 Bytes enthält. .. index:: Variablen .. index:: Schlüsselwörter .. _variablen: Variablen --------- Eine Variable ist eine benannte Speicheradresse. In UniScript braucht eine Variable nicht deklariert werden, man kann sie einfach bei Bedarf definieren:: a = 1 Falls ``a`` bisher noch nicht existierte, wird sie durch diese Anweisung erzeugt, das heißt, es wird Speicherplatz für die 1 bereitgestellt und die 1 wird in den Speicher kopiert. Falls die Variable ``a`` bereits vorher existierte, wird zunächst der alte Wert der Variablen gelöscht. Der alte Wert kann z. B. ein ``"String"`` gewesen sein, die Variable kann also ihren Typ ändern. Der Name einer Variablen kann aus Buchstaben, Ziffern und Unterstrichen bestehen. Er muss aber mit einem Buchstaben oder einem Unterstrich anfangen. Länderspezifische Buchstaben (z. B. Umlaute) sind nicht erlaubt. Namen können beliebig lang sein. Es werden jedoch nur die ersten 80 Zeichen unterschieden. Groß- und Kleinbuchstaben werden unterschieden: ``var`` und ``Var`` sind also zwei unterschiedliche Namen. Namen dürfen nicht identisch mit den UniScript Schlüsselwörtern sein. In UniScript sind folgende Wörter reservierte Namen: :: break continue def else except for global if in print return try while Variablennamen dürfen auch nicht mit Funktionsnamen identisch sein: ``sin = sin(1)`` ist **nicht** zulässig, wohl aber ``Sin = sin(1)``. Gültige Variablennamen sind :: _test var1 Dies_Ist_Ein_Langer_Name __ a1 Return während die Namen .. code-block:: none 1a Dies ist kein Name a?3 ungültig sind. Bei größeren Programmen ist es empfehlenswert, die Namen so zu wählen, daß die Bedeutung und der Typ der Variablen erkennbar sind. Bei den Funktionen, die mit UniScript mitgeliefert werden, bestehen die meisten Namen deshalb aus einem Typpräfix und dem eigentlichen Namen, der mit einem Großbuchstaben anfängt. **Beispiele**: .. list-table:: :header-rows: 1 * - Name - Bedeutung * - ssFilename - ss steht für skalarer String. ssFilename wird also einen einzelnen Dateinamen enthalten. * - svFilename - sv steht für String-Vektor. svFilename wird also vermutlich mehrere Dateinamen enthalten. * - smSorted - sm steht für String-Matrix. * - rsXValue - rs steht für reeller Skalar. * - rvMin - rv steht für reeller Vektor. * - rmSize - rm steht für reelle Matrix. * - bVisible - b steht für Bool. Eine solche Variable sollte den Wert wahr oder falsch (TRUE (1) oder FALSE (0)) haben. * - hLayer - h steht für Zugriffsnummer (handle). * - hvLayer - hv steht für einen Vektor von Zugriffsnummern. * - nLayer - n steht für Anzahl und sollte eine ganze Zahl sein, z. B. 123. .. _vektoren-und-matrizen: Vektoren und Matrizen --------------------- Die folgende Anweisung erzeugt einen Zeilenvektor mit den Elementen 6, 4 und 13 und weist ihn der Variablen ``a`` zu:: a = [6, 4, 13] Falls die Variable ``a`` vorher bereits einen Wert hatte, wird dieser Wert durch diese Anweisung überschrieben. ``a`` ist nun ein reeller Vektor mit drei Elementen. Man kann die Variable ``a`` in Ausdrücken verwenden. Die Anweisung:: b = a + 5 addiert den Wert 5 zu allen Elementen von ``a`` und weist das Ergebnis der Variablen ``b`` zu. ``b`` hat dann den Wert ``[11, 9, 18]``. Es werden häufig Vektoren der Form ``[1, 2, 3, 4, 5, ..., n]`` oder ``[1.0, 1.5, 2.0, ...]`` benötigt. Zur Erzeugung solcher Vektoren steht der ``:``-Operator zur Verfügung. Es gibt zwei Formen: :: start:end und :: start:step:end Die erste Form entspricht ``start:1.0:end``. ``step`` wird zu ``start`` addiert, solange der Wert kleiner oder gleich ``end`` ist. **Beispiel**: :: 1:5 ist [1, 2, 3, 4, 5] 1.3:4 ist [1.3, 2.3, 3.3] 1:0.5:2 ist [1, 1.5, 2.0] ``start`` kann größer als ``end`` sein :: 5:1 ist [5, 4, 3, 2, 1] Ein Vektor ist in UniScript der Spezialfall einer Matrix; ``[6, 4, 13]`` ist eine 1 * 3 Matrix, d.h. sie besteht aus einer Zeile und drei Spalten. Matrizen, die nur Elemente in einer Zeile enthalten, bezeichnet man auch als Zeilenvektoren. Spaltenvektoren werden ähnlich eingegeben wie Zeilenvektoren, die Elemente werden jedoch durch ein Semikolon getrennt:: a = [1;2;3] Spaltenvektoren können mit dem Transponierungsoperator ``'`` in Zeilenvektoren umgewandelt werden (und umgekehrt). :: b = a' Die Matrix .. math:: \begin{pmatrix} 1 & 2 & 3\\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{pmatrix} kann man sich als Kombination der Zeilenvektoren ``[1,2,3]``, ``[4,5,6]`` und ``[7,8,9]`` vorstellen. Sie kann in UniScript folgendermaßen eingegeben werden: :: m = [1,2,3; 4,5,6; 7,8,9] Eine Matrix kann auch aus vorhandenen Vektoren und Matrizen aufgebaut werden, z. B. .. math:: \left( \begin{array}{ccc|cc|c} 1 & 2 & 3 & 10 & 11 & 16 \\ 4 & 5 & 6 & 12 & 13 & 17 \\ \cline{4-5} 7 & 8 & 9 & 14 & 15 & 18 \end{array} \right) :: m1 = [1,2,3; 4,5,6; 7,8,9] m2 = [10,11; 12,13] v1 = [14,15] v2 = [16;17;18] m = [m1, [m2;v1], v2] .. _index-ausdrucke: Index-Ausdrücke --------------- Auf einzelne Elemente eines Vektors kann über seine Indizes zugegriffen werden. Hat die Variable ``a`` den Wert ``[1.5, 3.8, 6.3]``, dann hat ``a[1]`` den Wert 1.5, ``a[2]`` den Wert 3.8 und ``a[3]`` den Wert 6.3. Indizes sind ganzzahlige Werte und beginnen bei 1. Statt eines einzelnen Index kann auch ein Index-Vektor angegeben werden. So hat ``a[1, 3]`` den Wert ``[1.5, 6.3]`` und ``a[1, 3, 1]`` den Wert ``[1.5, 6.3, 1.5]``. Einzelne Indizes können also mehr als einmal angegeben werden. Eine Vektor-Variable mit einem Index-Vektor kann auch auf der linken Seite des Zuweisungs-Operators stehen. :: a = [1, 2, 3, 4, 5] a[1, 4] = [-1, 66] ``a[1]`` wird der Wert -1 zugewiesen und ``a[4]`` der Wert 66. Der Index-Vektor muss in diesem Fall genauso viele Elemente haben wie der Vektor auf der rechten Seite des Zuweisungs-Operators. Um zwei Werte auf Gleichheit zu testen, wird in UniScript der ``==``-Operator verwendet. Die Variable ``a`` hat nun den Wert ``[-1, 2, 3, 66, 5]``. Die Anweisung :: a[1, 4] = a[4, 1] vertauscht das erste Element mit dem vierten Element des Vektors, ohne die anderen Elemente zu verändern. Die Anweisung :: a[6] = 100 führt zu einem Laufzeitfehler, da der Vektor ``a`` nur 5 Elemente hat. Um an den Vektor ein sechstes Element anzuhängen, muss geschrieben werden :: a = [a, 100] Auf eine Matrix kann mit zwei Indexvektoren die durch ein Semikolon getrennt sind zugegriffen werden. Der erste Indexvektor ist der Zeilen-Index-Vektor und der zweite der Spalten-Index-Vektor. Ist die Matrix ``a`` gleich ``[5,6;7,8]`` dann ist z. B. ``a[1;1]`` gleich 5 und ``a[1;2]`` gleich 6. Entsprechend ist ``a[1,2;1]`` gleich ``[5,6]`` die erste Zeile der Matrix ``a``. Falls ein Zeilen- oder Spalten-Index-Vektor vollständig ist, kann er auch weggelassen werden. Anstatt ``a[1,2;1]`` kann man also schreiben ``a[;1]``, um auf die erste Zeile der Matrix ``a`` zuzugreifen. Eine Matrix wird in UniScript intern als eindimensionaler Vektor spaltenweise gespeichert. Die Elemente der Matrix werden also in UniScript intern in der Reihenfolge ``[1, 4, 7, 2, 5, 8, 3, 6, 9]`` gespeichert. Auf diese interne Darstellung kann zugegriffen werden, indem bei Matrizen ein eindimensionaler Indexvektor angegeben wird. Anstatt ``a[2;3]`` (zweite Zeile, dritte Spalte) kann auch ``a[8]`` geschrieben werden. Um auf alle Elemente der Matrix als Vektor zuzugreifen, kann ``a[1:9]`` geschrieben werden, dies entspricht der Schreibweise ``a[:]``. **Zusammenfassung** ``var = start:step:end`` erzeugt einen Zeilenvektor. ``var = start:end`` erzeugt einen Zeilenvektor mit der Schrittweite 1.0. ``var = [e1, e2, e3]`` erzeugt einen Zeilenvektor. ``var = [e1; e2; e3]`` erzeugt einen Spaltenvektor. ``var = [e1, e2; e3, e4]`` erzeugt eine Matrix. ``var[index-vektor]`` greift auf Elemente eines Vektors zu. ``var[zeilen-index-vektor; spalten-index-vektor]`` greift auf Elemente einer Matrix zu. ``var[zeilen-index-vektor ; ]`` greift auf die Zeilenvektoren einer Matrix zu. ``var[ ; spalten-index-vektor]`` greift auf die Spaltenvektoren einer Matrix zu. ``var[:]`` wandelt eine Matrix in einen Zeilenvektor um. :sub:`id-1040188`