Die Ausdruckklammern »(« und »)« in C++
Einführendes Beispiel
Das folgende Programm enthält ein Beispiel eines Ausdrucks, der mit den Ausdruckklammern »(« und »)« geschrieben wurde.
main.cpp
#include <iostream>
#include <ostream>
#include <string>using namespace ::std::literals;
int main() { ::std::cout <<( 24 )<< "\n"s; }
transcript
24
Morphologie
Das Zeichen »(« wird „runde Klammer auf “ genannt.
Das Zeichen »)« wird „runde Klammer zu “ genannt.
Zusammenfassend werden die beiden Zeichen »(« und »)« als runde Klammern bezeichnet.
Es gibt in C++ keine lexikalische Einheit mit mehreren Zeichen, die runde Klammern enthält (außer Zeichenfolgenliteralen). Daher können runden Klammern nie Teil einer längeren lexikalischen Einheit werden. Runde Klammern müssen also nie von anderen Zeichen mit Leerraum abgetrennt werden. Wir nennen solche Zeichen, die nie mit Leerraum abgetrennt werden müssen, auch volltrennende Zeichen, weil sie sich selbst von allen anderen Zeichen trennen, ohne daß Leerraum benötigt wird. Jede runde Klammer ist stets eine lexikalische Einheit für sich.
Syntax
Wird ein Ausdruck in runde Klammern eingeschlossen, so gilt dies wieder als ein Ausdruck, den wir auch Klammerausdruck nennen. Während »-« ein Präfixoperator ist, ist »( … )« ein Zirkumfixoperator : Das heißt, »-« steht vor seinem Operandenausdruck, aber »(…)« umgibt seinen Operandenausdruck.
- Produktion
Klammerausdruck
.-. .----------. .-.
--->( ( )--->| Ausdruck |--->( ) )--->
'-' '----------' '-'
Wir können unser Syntaxdiagramm für das Symbol 〈Ausdruck 〉 nun um den Klammerausdruck erweitern. Darin kommt die Bezeichnung „Klammerausdruck“ nicht vor, da der Klammerausdruck in der Produktionsregel für Primärausdrücke enthalten ist.
Ein Primärausdruck ist ein Ausdruck, dessen einzelne Teile so fest zusammengehören, daß er niemals eingeklammert werden muß, egal wo er eingesetzt wird. Ein Literal wie »123.45« ist ohnehin nicht weiter zerlegbar, und ein Klammerausdruck wie »(23.45)« ist schon eingeklammert und muß nicht erneut eingeklammert werden.
Syntaktisch betrachtet verwandelt der Klammeroperator einen beliebigen Ausdruck in einen Primärausdruck.
- Neue, erweiterte Syntax
Primaerausdruck
.----------.
---.------------>| Literal |------------.--->
| '----------' |
| .-. .----------. .-. |
'--->( ( )--->| Ausdruck |--->( ) )---'
'-' '----------' '-'Vorzeichenausdruck
.-----------------.
---.------------>| Primaerausdruck |------------.--->
| '-----------------' |
| .------------. .-----------------. |
'--->| Vorzeichen |--->| Primaerausdruck |---'
'------------' '-----------------'Vorzeichen
.-.
---.--->( + )---.--->
| '-' |
| .-. |
'--->( - )---'
'-'Ausdruck
.--------------------.
--->| Vorzeichenausdruck |--->
'--------------------'
Aufgrund der Zirkumfixstellung braucht der Klammeroperator nicht in das Prioritätssystem integriert werden, da Fälle, in denen eine Priorität zum Finden der Operanden des Klammeroperators benötigt wird, nie vorkommen – alleine durch die Position der Klammern ist der Operand immer eindeutig bestimmt: der Operand umfaßt immer alles zwischen den Klammern befindlich. Um dies anzudeuten, erfassen wir den Klammeroperator als Operator mit höchster Priorität in unserer Tabelle der Prioritäten.
- Priorität der bisher behandelten Operatoren
() Eingeklammerter Ausdruck
+ - Unaere vorangestellte Operatoren
Typanforderungen
Ein Ausdruck eines beliebigen Typs darf eingeklammert werden.
Typregeln
Der Typ eines Klammerausdrucks ist der Typ des eingeklammerten Ausdrucks.
Die folgenden Typregeln bringen dies symbolisch zum Ausdruck. Sie sind nicht als C++ -Quelltext zu verstehen.
- Typregel für Ausdruckklammern
- (int ) = int
(double ) = double
(::std::string ) = ::std::string - (char * ) = char *
Wert
Bei der Auswertung eines Klammerausdrucks wird der eingeklammerte Ausdruck ausgewertet. Der Wert des Klammerausdrucks ist der Wert des eingeklammerten Ausdrucks. (Das Einklammern ändert den Wert nicht.)
main.cpp
#include <iostream>
#include <ostream>
#include <string>using namespace ::std::literals;
int main() { ::std::cout <<( 35 )<< "\n"s; }
transcript
35
main.cpp
#include <iostream>
#include <ostream>
#include <string>using namespace ::std::literals;
int main() { ::std::cout <<( "Text"s )<< "\n"s; }
transcript
Text
Syntaktische Rekursion
Da ein eingeklammerter Ausdruck wieder ein Ausdruck ist, kann dieser selber auch wieder eingeklammert werden.
main.cpp
#include <iostream>
#include <ostream>
#include <string>using namespace ::std::literals;
int main() { ::std::cout <<( ( 50 ))<< "\n"s; }
transcript
50
Eine schließende Klammer gehört immer zur letzten vorangehenden öffnenden Klammer, die bis zu der Stelle der schließenden Klammer noch nicht geschlossen wurde. Im Ausdruck »( ( 50 ))« gehört die erste schließende Klammer daher zu zweiten öffnenden Klammer und die letzte schließende Klammer zur ersten öffnenden Klammer.
- Zuordnung der Klammern
( ( 50 ))
^ ^ ^^
| | ||
| '----'|
'-------'
Übungsfragen
Eine lexikalische Einheit ist ein Literal oder ein Operator. Der Klammeroperator besteht ausnahmsweise aus zwei lexikalischen Einheiten.
? Übungsfrage ⃗
Welcher der folgenden Texte ist nach dem darunter wiedergegebenem Syntaxdiagramm ein Klammerausdruck?
- Text
- A »(-)«
- B »(2)«
- C »()«
- D »(int)«
- E »(2«
- F »(2)2«
- Produktion
Klammerausdruck
.-. .----------. .-.
--->( ( )--->| Ausdruck |--->( ) )--->
'-' '----------' '-'
? Übungsfrage ⃗
Wie viele lexikalische Einheiten hat der folgende Ausdruck?
- Ausdruck
-(-2)
Anmerkungen *
Die runden Klammern werden nicht von jedem als Operatoren angesehen, da der eingeklammerte Wert nicht verändert wird, und manchmal erwartet wird, daß ein Operator den Wert seines Operanden irgendwie verändert. Allerdings kann man den Klammern als Operation auf systematische Weise die identische Funktion zuordnen. Außerdem wird das positive Vorzeichen »+« als Operator angesehen, aber verändert seinen Argumentwert auch nicht.