In diesem Abschnitt werden die in der
User Language verfügbaren Operatoren für Ausdrücke vorgestellt. Die Reihenfolge, in der dabei vorgegangen wird, entspricht dem abnehmenden Vorrang der Operatoren, wobei jeweils auch auf die Assoziativität d.h. die Verarbeitungsfolge der jeweiligen Operation eingegangen wird. Jeder Operator ist entweder links- oder rechts-assoziativ, je nachdem ob er von links oder rechts implizit geklammert wird. Der Vorrang gibt an, mit welcher Priorität ein Ausdruck bewertet wird. Abgesehen vom Vorrang ist die Reihenfolge der Bewertung undefiniert. Es ist der Implementierung freigestellt, Teilausdrücke auch dann, wenn diese Nebeneffekte verursachen, in möglichst effizienter Reihenfolge zu bewerten. Die Reihenfolge für die Evaluierung von Nebeneffekten ist dabei nicht definiert. Ausdrücke mit assoziativen und kommutativen Operatoren lassen sich beliebig umordnen. Eine bestimmte Reihenfolge in der Bewertung von Operanden kann nur durch Zuweisung an (temporäre) Variablen erzwungen werden.
2.4.1 Primäre Ausdrücke
Primäre Ausdrücke, auch bezeichnet als einfache Ausdrücke oder Primary, sind Konstanten, Verweise auf Objekte, Ausdrucks-Klammerungen, Funktionsaufrufe, sowie die Auswahl von Elementen aus einem Vektor, einer Struktur oder einem Index. Diese Operationen sind links-assoziativ.
Konstanten und Verweise auf Objekte
Jeder geeignet vereinbarte Identifier gilt als primärer Ausdruck, der auf ein Objekt verweist. Auch ganzzahlige, Gleitkomma-, Zeichen- und String-Konstanten sind primäre Ausdrücke; die Darstellungsformen für Konstanten wurden in
Kapitel 2.2.3 vorgestellt.
Ausdrucks-Klammerung
Ein geklammerter Ausdruck besteht aus einem in runde Klammern eingeschlossenen Ausdruck und stellt einen primären Ausdruck dar. Mit Hilfe dieses Operators können Ausdrücke explizit geklammert werden, wodurch eine definierte Änderung der Reihenfolge der Bewertung herbeigeführt werden kann. Da der Multiplikations-Operator z.B. höheren Vorrang hat als der Additions-Operator, ergibt sich der Wert des Ausdrucks
a + b * c
aus der Summe aus a und dem Produkt b*c, während er sich in
(a + b) * c
aus dem Produkt aus der Summe a+b und c ergibt.
Funktionsaufruf
Ein Funktionsaufruf besteht aus einem Identifier zur Bezeichnung der aufzurufenden Funktion gefolgt von einer in runde Klammern eingeschlossenen Liste von Ausdrücken, die durch Kommata getrennt sind. Die Werte der Ausdrücke innerhalb der runden Klammern repräsentieren die aktuellen Parameter für den Funktionsaufruf. Sofern eine Funktion per Definition einen Resultatwert liefert, kann der entsprechende Funktionsaufruf in einem beliebigen anderen Ausdruck verwendet werden. Die Liste der Ausdrücke innerhalb der runden Klammern kann leer sein. Typische Funktionsaufrufe sind z.B.
init_states(pass=1);
printf("This is a message!\n");
printf("Element %s\n",bae_planename());
xpos=nref_xcoord(ask_partname())-bae_planwsnx();
Zugriff auf Vektor-Element
Ein einfacher Ausdruck gefolgt von einem Ausdruck in eckigen Klammern ist wiederum ein einfacher Ausdruck. Mit dieser Operation erfolgt die Auswahl eines Elements aus einem Vektor oder
string -Wert. Der Ausdruck vor der eckigen Klammer referenziert dabei den Vektor, der Ausdruck innerhalb der eckigen Klammern wird als
int -Wert interpretiert und dient der Indizierung des Vektor-Elements. Der Indizierungs-Wert darf dabei nicht negativ sein; der Wert 0 (Null) verweist auf das erste Element des Vektors. Beim Speichern auf einen Vektor erfolgt ggf. eine dynamische Anpassung des Vektor-Feldbereichs durch den
User Language Interpreter. Der lesende Zugriff auf einen Vektor ist nur innerhalb des aktuell definierten Feldbereiches zulässig. Die folgende Funktion
strisoctal überprüft, ob der als Parameter übergebene
string -Wert nur oktale Ziffern
(0 bis
7 ) enthält und gibt für diesen Fall den Wert 1, in allen anderen Fällen den Wert 0 zurück:
int strisoctal(string str)
{
for (i=0;i<strlen(str);i++)
if (!isdigit(str[i]) || str[i]=='8' || str[i]=='9')
return(0);
return(1);
}
In obigem Beispiel wird die Feldlängen-Kontrolle für den Vektor-Lese-Zugriff mit Hilfe der auf
string -Werte anwendbaren Systemfunktion
strlen durchgeführt.
Im folgenden Programm-Konstrukt hingegen geschieht dies mit Hilfe einer speziellen
int -Variablen
(filecount ):
string curfilename="", filelist[];
int i, filecount=0;
while (scandirfnames(".",".ddb",curfilename)==1)
filelist[filecount++]=curfilename;
for (i=0;i<filecount;i++)
printf("File %s \n",filelist[i]);
In obigem Beispiel wird zunächst eine Liste aller im aktuellen Verzeichnis auffindbaren Dateinamen mit der Endung
.ddb erzeugt, und anschließend wird diese Liste ausgegeben.
Zugriff auf Struktur- oder Index-Element
Ein einfacher Ausdruck gefolgt von einem Punkt und einem Identifier ist wieder ein einfacher Ausdruck. Der erste Ausdruck referenziert dabei eine Struktur bzw. einen Index-Typ, und der Identifier nach dem Punkt-Operator muss ein definiertes Element aus dieser Struktur bzw. diesem Index-Typ bezeichnen. Der schreibende Zugriff auf Struktur-Elemente ist grundsätzlich immer möglich; auf die Elemente von Index-Typen hingegen darf nicht gespeichert werden (Fehlermeldung durch den Compiler). Umgekehrt ist der lesende Zugriff auf die Elemente einer aktuell gültigen
index -Variablen immer zulässig, während aus
struct -Variablen nur die zuvor initialisierten gelesen werden können (ansonsten Speicherzugriffs-Verletzung und entsprechende Fehlermeldung durch den Interpreter). Der folgende Programmteil definiert eine Liste bestehend aus Strukturen und erzeugt für jedes aktuell verfügbare Layout-Macro einen Listen-Eintrag mit dem Macro-Namen und der Macro-Klasse:
int macrocnt=0;
struct { string name; int class; } macrolist[];
index L_MACRO macro;
forall (macro) {
macrolist[macrocnt].name=macro.NAME;
macrolist[macrocnt++].class=macro.CLASS;
}
2.4.2 Unitäre Ausdrücke
Unitäre Ausdrücke, auch bezeichnet als Unary, sind rechts-assoziativ und umfassen alle Operatoren, die einen einzelnen Operanden bewerten.
Inkrement und Dekrement
Die Operatoren
++ bzw.
-- verändern ihre Operanden, indem sie den Wert 1 zum Wert ihres Operanden addieren bzw. subtrahieren. Sind diese Operatoren einem unitären Ausdruck vorangestellt, dann entspricht das Resultat dem Wert des Operanden nach dessen Inkrementierung bzw. Dekrementierung. Im anderen Fall, also wenn
++ bzw.
-- auf den Operanden folgt, dann wird zwar der Operand inkrementiert bzw. dekrementiert, das Resultat entspricht jedoch dem Wert des Operanden vor der Durchführung der Operation. Dies bedeutet, dass in einem Kontext, in dem der Resultatwert einer Inkrement- bzw. Dekrement-Operation weiter verwendet wird, die entsprechenden Ausdrücke unterschiedliche Bedeutung haben. Besitzt zum Beispiel die Variable
count den Wert 12 dann erhält die Variable
n durch die Zuweisung
n = count-- ;
den Wert 12, durch die Zuweisung
n = --count ;
jedoch den Wert 11 (der Wert von
count ergibt sich in beiden Fällen zu 11).
Arithmetische Negation
Der unitäre Operator
- liefert den Wert der arithmetischen Negation seines Operanden, das Resultat ist also der mit (-1) multiplizierte Wert des Operanden.
Logische Negation
Der unitäre Operator
! liefert den Wert der logischen Negation seines Operanden. Das Resultat ist dabei 1 für einen Operanden mit dem Null-Wert (0 oder Leerstring für
string -Operand), und 0 für alle anderen Operanden-Werte.
Bit-Komplement
Der Operator
~ komplementiert die einzelnen Bits in seinem Operanden, liefert also als Ergebnis das 1-Komplement seines Operanden.
2.4.3 Binäre Ausdrücke
Binäre Ausdrücke, auch bezeichnet als Binary, umfassen alle Operatoren, die zwei Operanden bewerten.
Produkt
Die Operatoren für Multiplikation und Division sind links-assoziativ und erzeugen jeweils einen Produkt-Ausdruck. Der binäre Operator
* ist kommutativ und assoziativ und bezeichnet die Multiplikation. Das Ergebnis dieser Operation ist der Wert des Produktes seiner beiden Operanden. Der binäre Operator
/ bezeichnet die Division. Das Ergebnis dieser Operation ist der Wert, der durch die Division des Wertes des ersten Operanden (Divident) geteilt durch den Wert des zweiten Operanden (Divisor) der Operation zustande kommt. Da eine Division durch Null nicht zulässig ist, ist der Wert 0 für den Divisor auch nicht erlaubt. Der binäre Operator
% liefert den Rest nach Division seiner beiden Operanden. Gleitkomma-Operanden sind hierbei nicht zulässig; ebenso ist der Wert 0 für den Divisor nicht erlaubt; ein Beispiel für die Verwendung des
% -Operators ist der Ausdruck
febdays = (year%4==0 && year%100!=0 || year%400==0) ? 29 : 28 ;
in dem zunächst überprüft wird, ob der Wert von
year der Jahreszahl eines Schaltjahres entspricht, und anschließend in Abhängigkeit vom Ergebnis dieser Überprüfung der Wert der Variablen
febdays gesetzt wird.
Summe
Die Operatoren für Addition und Subtraktion sind links-assoziativ und erzeugen jeweils einen Summen-Ausdruck. Der binäre Operator
+ bezeichnet die Addition. Für den Fall, dass dieser Operator auf numerische Werte angewendet wird, ist das Ergebnis dieser Operation die Summe der Operanden, und die Operation ist in diesem Fall assoziativ und kommutativ; wird diese Operation auf Zeichenketten angewendet, dann ergibt sich das Resultat zu dem
string -Wert, der sich durch Aneinanderfügen der
string -Werte der Operanden ergibt. Der binäre Operator
- bezeichnet die Subtraktion und liefert als Ergebnis den Wert der Differenz seiner Operanden.
Schiebe-Operation
Die Schiebe-Operatoren
<< und
>> sind links-assoziativ und können auf ganzzahlige Operanden angewendet werden. Der binäre Operator
<< bezeichnet die bitweise Links-Verschiebung. Das Ergebnis dieser Operation ist der Wert, der sich ergibt, wenn das Bitmuster des ersten Operanden um die Anzahl der durch den zweiten Operanden gegebenen Stellen nach links verschoben wird (von rechts her werden dabei Bits mit dem Wert 0 nachgeschoben; das Ergebnis ist undefiniert, wenn der zweite Operand negativ ist). Der binäre Operator
>> bezeichnet die bitweise Rechts-Verschiebung. Das Ergebnis dieser Operation ist der Wert, der sich ergibt, wenn das Bitmuster des ersten Operanden um die Anzahl der durch den zweiten Operanden gegebenen Stellen nach rechts verschoben wird (das Ergebnis ist undefiniert, wenn der zweite Operand negativ ist).
Vergleich
Die binären Operatoren
< (kleiner),
<= (kleiner oder gleich),
> (größer) und
>= (größer oder gleich) liefern den
int -Wert 0, wenn die angegebene Relation in Bezug auf die beiden Operanden falsch ist, und den Wert 1, wenn die Relation vorliegt. Diese Operatoren sind auch direkt auf
string -Typen anwendbar.
Äquivalenz-Vergleich
Die binären Operatoren
== (gleich) und
!= (ungleich) liefern den
int -Wert 0, wenn die angegebene Äquivalenz-Relation in Bezug auf die beiden Operanden falsch ist, und den Wert 1, wenn die Relation vorliegt. Die Äquivalenz-Vergleichs-Operatoren sind auch direkt auf
string -Typen anwendbar; sie verhalten sich analog zu den anderen Vergleichs-Operatoren, haben jedoch geringeren Vorrang.
Bitweise Und-Verknüpfung
Der binäre Operator
& bezeichnet die bitweise Und-Verknüpfung (AND) und ist assoziativ und kommutativ. Das Resultat dieser Operation ist der Wert, der sich ergibt, wenn die Bits der beiden Operanden in jeder Position der Und-Verknüpfung unterworfen werden.
Bitweise Exklusiv-Oder-Verknüpfung
Der binäre Operator
^ bezeichnet die bitweise Exklusiv-Oder-Verknüpfung (XOR) und ist assoziativ und kommutativ. Das Resultat dieser Operation ist der Wert, der sich ergibt, wenn die Bits der beiden Operanden in jeder Position der Exklusiv-Oder-Verknüpfung unterworfen werden.
Bitweise Oder-Verknüpfung
Der binäre Operator
| bezeichnet die bitweise Oder-Verknüpfung (OR) und ist assoziativ und kommutativ. Das Resultat dieser Operation ist der Wert, der sich ergibt, wenn die Bits der beiden Operanden in jeder Position der Oder-Verknüpfung unterworfen werden.
Logische Und-Verknüpfung
Der binäre Operator
&& bezeichnet die logische Und-Verknüpfung (AND) und ist links-assoziativ. Das Resultat dieser Operation ist der
int -Wert 1, wenn die Werte beider Operanden vom Null-Wert (0 oder Leerstring für
string -Operanden) verschieden sind; im anderen Fall ergibt sich das Resultat zum Wert 0. Die logische Und-Verknüpfung wird strikt von links nach rechts durchgeführt; der rechte Operand wird dabei nur bewertet, wenn der linke Operand kein Null-Wert ist. Im Ausdruck
x<100 && fct(x)
wird die Funktion
fct nur dann aufgerufen, wenn der Wert von
x kleiner als 100 ist.
Logische Oder-Verknüpfung
Der binäre Operator
|| bezeichnet die logische Oder-Verknüpfung (OR) und ist links-assoziativ. Das Resultat dieser Operation ist der
int -Wert 1, wenn einer der beiden Operanden-Wert vom Null-Wert (0 oder Leerstring für
string -Operanden) verschieden ist; im anderen Fall ergibt sich das Resultat zum Wert 0. Die logische Oder-Verknüpfung wird strikt von links nach rechts durchgeführt; der rechte Operand wird dabei nur bewertet, wenn der Wert des linken Operanden dem Null-Wert entspricht. Im Ausdruck
test1() || test2()
wird die Funktion
test2 also nur dann aufgerufen, wenn zuvor der Aufruf der Funktion
test1 das Resultat 0 geliefert hat.
Bedingte Bewertung
Der Operator
?: bezeichnet die bedingte Bewertung (conditional) und ist rechts-assoziativ. Vor dem
?: -Operator hat ein binärer Ausdruck zu stehen, der in jedem Fall bewertet wird. Ist der Wert dieses Ausdrucks vom Null-Wert (0 oder Leerstring für
string ) verschieden, dann ergibt sich das Resultat dieser Operation zum Wert des zweiten Ausdrucks (dieser befindet sich zwischen dem Fragezeichen und dem Doppelpunkt des Operators und kann wiederum eine bedingte Bewertung sein); im anderen Fall, also wenn der erste Operand dem Null-Wert entspricht, dann ergibt sich das Resultat zum Wert des dritten Ausdrucks (dieser folgt auf den Doppelpunkt Fragezeichen des Operators und kann ebenfalls eine bedingte Bewertung sein). Der allgemeine Ausdruck
result = logexpr ? trueexpr : falsexpr ;
für die Zuweisung einer bedingte Bewertung an ein Resultat entspricht also der folgenden Kontrollstruktur:
if (logexpr)
result = trueexpr ;
else
result = falseexpr ;
Beispiel für die Verwendung des
?: -Operators zur Berechnung des Maximums zweier Werte:
maxval = (val1>=val2) ? val1 : val2 ;
Zuweisungen
Der binäre Operator
= bezeichnet die einfache Zuweisung, die binären Operatoren
*= ,
/= ,
%= ,
+= ,
-= ,
>>= ,
<<= ,
&= ,
^= und
|= bezeichnen die zusammengesetzten Zuweisungen. Alle diese Operatoren sind rechts-assoziativ. Der linke Operand muss immer ein unitärer Ausdruck sein, der rechte Operand darf seinerseits ein Zuweisungs-Ausdruck sein. Bei der einfachen Zuweisung ersetzt der Wert des rechten Operanden den Wert des durch den linken Operanden referenzierten Objekts. Eine zusammengesetzte Zuweisung der allgemeinen Form
expr1 <operator>= expr2
entspricht dem Ausdruck
expr1 = expr1 <operator> (expr2)
wobei jedoch expr1 nur einmal bewertet wird (man beachte die Klammerung des Ausdrucks expr2). In der Zuweisungsfolge
a = 5 ;
b = 3-a ;
c = b+a ;
c -= a *= b += 4+2*a ;
ergeben sich die Werte der Variablen
a ,
b und
c zu 60, 12 und -57.
2.4.4 Liste von Ausdrücken
Jeder Ausdruck kann aus einer Liste von durch Kommata getrennten binären Ausdrücken bestehen. Zwei Ausdrücke, die durch Komma getrennt sind, werden dabei von links nach rechts bewertet; der Wert des linken Ausdrucks wird berechnet, aber nicht weiter verwendet. Typ und Wert des Resultats einer Liste von Ausdrücken entsprechen dem Typ und Wert des rechten Ausdrucks innerhalb der Ausdruck-Liste. Diese Operation ist links-assoziativ. In einem Kontext, in dem das Komma eine spezielle Bedeutung hat, wie etwa in der Liste von Argumenten für einen Funktionsaufruf, oder in einer Liste von Initialisierungen, kann der hier beschriebene Komma-Operator nur innerhalb von Klammern verwendet werden. Durch die Zuweisung
c -= (a=5, b=3-a, c=b+a, a*=b+=4+2*a) ;
ergeben sich die Werte der Variablen
a ,
b und
c zu 60, 12 und -57.
2.4.5 Vorrang und Reihenfolge der Bewertung
In
Tabelle 2-4 sind nochmals der Vorrang und die Assoziativität der Operatoren der
Bartels User Language zusammengefasst dargestellt.
Tabelle 2-4: Operator Vorrang und Assoziativität
Operation | Operator(en) | Verarbeitungsfolge |
Primary | () [] . | links nach rechts |
Unary | ! ~ ++ -- - | rechts nach links |
Product | * / % | links nach rechts |
Sum | + - | links nach rechts |
Shift | << >> | links nach rechts |
Comparison | < <= > >= | links nach rechts |
Equality | == != | links nach rechts |
Bit And | & | links nach rechts |
Bit Xor | ^ | links nach rechts |
Bit Or | | | links nach rechts |
Logical And | && | links nach rechts |
Logical Or | || | links nach rechts |
Conditional | ?: | rechts nach links |
Assignment | = += -= etc. | rechts nach links |
Expression List | , | links nach rechts |
Ausdrücke © 1985-2024 Oliver Bartels F+E • Aktualisiert: 05. December 2006, 16:54 [UTC]
|