[Split von 'Eigene Klassenbibliothek'] Diskussionen um Parser
-
volkard schrieb:
Xin schrieb:
wobei einige hier schreiben, als hätten sie die Wahrheit für sich gepachtet.
*meld*
Bei Dir weiß ich nie genau, ob Du gerade ironisch bist oder das ernst meinst...*

volkard schrieb:
Xin schrieb:
Ich habe ein Buch von Jürgen Wolf. Ich finde es inspirierend.
Es gibt nicht viele Ledernacken wie uns. Die meisten gehen davon einfach kaputt.
Ich höre mir hier immer an, wie schlecht Jürgen Wolf schreibt. Ich habe mir das C von A bis Z mal zur Hand genommen und fand, man kann es durchaus kaufen. Steht was zu C drin und auch wie es dann weitergeht. Fand ich gut.
Ich lese aber keine C-Bücher mehr. Ich lese keine Listings mehr. Ich suche Überschriften, Inspiration. Ich muss dafür ein Buch aber nicht mehr durcharbeiten und auf die Details achten.
Und wenn doch: Wenn ich feststellte, dass ein Buch falsch ist, dann habe ich verstanden, was man falsch machen kann - damit habe ich mehr gelernt, als hätte ich nur gelernt, wie man es richtig machen kann.
Vielleicht verstehe ich ein Buch eher als Wegweiser, nicht als Navigationssystem: Man muss auch noch selbst überlegen, an welcher Kreuzung man in welche Richtung abbiegen sollte, statt sich alles vorkauen zu lassen.volkard schrieb:
Xin schrieb:
Genauso kann ich mir eine alte Lib angucken und darin Dinge finden, die vom ersten Eindruck heute vielleicht altmodisch aussehen. Und morgen vielleicht State of Art sind.
Jo, kommt vor. Hier wohl nicht.
Ich habe den Quelltext nicht gesehen. Vielleicht ist da was Cooles unter einer fragwürdigen Architektur versteckt.
volkard schrieb:
es fühlt sich für mich so unglaublich flutschig an, der Code sprudelt in die Tastatur und bis auf gelegentliche Tippfrhler ist er fertig.
*...wobei ich Deinen Humor gelegentlich durchaus schätze. ^^
volkard schrieb:
Wie man Yacc/Bison benutzt, habe ich immer gelesen, denn keine Compilerbau-Vorlesung macht es anders.
Ich schreibe einen Compiler, ich hatte Compilerbau in der Vorlesung, ich glaube, etwas Yacc/Bison-mäßiges schreiben zu können, aber weiß es nicht, weil ich Yacc und Bison noch nie benutzt habe.
volkard schrieb:
Habe aber auch WernerSolomons mathematische Parser gelesen
Gibt's da was wirklich suchbares? Google lieferte mir dazu nix.
Ich lese Ausdrücke nach Priorität ein. Dafür gibt es einen Mini-Stack, so dass ich keine Funktionsaufrufe brauche:
Die Werte haben bei mir auch Priorität und zwar die höchste, da sie keine Kinder haben können: Es sind also grundsätzlich die Blätter.
1+2*3+2^4*5 91929193929Ich lese 1, mein Einstieg in den AST: 1. Dann +, die Zahl hat eine höhere Prio als +, also schiebt das + sich vor die Zahl und es wird eine weiterer Ausdruck erwartet: +(1,?) und lese 2: +(1, 2). Ich halte mich an der soeben gelesenen 2 fest und lese . Es entsteht ein neuer Knoten, der das Blatt, an dem ich mich festhalte als linkes Kind erhält: +(1,(2,?)). * hat aber eine höhere Prio als +, also schiebt es sich nicht vor das +, es passiert also nix: +(1,(2,?)) und ich lese die 3: +(1,(2,3)). 3 hat eine höhere Prio als das , es bleibt also dabei, ich halte mich an der soeben gelesen 3 fest und lese +:
+(1,(2,+(3,?)). + hat eine niedriger Prio als , schiebt sich also vor das , mein Linkes Kind wird das Rechte Kind von , * wird mein linkes Kind: +(1,+((2,3),?)). Das neue + hat die gleiche Prio wie das erste: Passt. Ich lese die 2: +(1,+((2,3),2)) und halte mich an ihr fest. Ich lese ^: +(1,+((2,3),^(2,?))), ^ hat eine höhere Prio als das darüber liegende + - passt - und ich lese die 4: +(1,+((2,3),^(2,4))) und halte mich an der 4 fest. Es folgt : +(1,+((2,3),^(2,(4,?)))). * hat eine niedriger Prio als ^, schiebt sich also nach oben, mein linkes Kind, wird das rechte Kind von ^, ^ wird mein linkes Kind: +(1,+((2,3),(^(2,4),?))). * hat eine höhere Prio als +, bleibt also da, ich lese die nächsten Ausdruck ein: 5. +(1,+((2,3),(^(2,4),5))).
Ich halte mich an der 5 fest und lese das nächste Token: Ende. Mein Ausdruck ist fertig: +(1,+((2,3),(^(2,4),5)))Das Ganze läuft in einem Durchgang, der Operator ist egal, die Prio kann direkt aus einer Tabelle ausgelesen werden: Prio[Token::Plus], fertig. Die Klammerungs-Methode haben wir in Compiler-Construction im Studium gelernt und damit den Compiler aufgebaut. Das war mir zu umständlich und zu statisch, zumal ich die Anforderung habe, die Prioritäten zur Laufzeit modifizieren zu können. Um den Ausdruck anders aufzubauen, muss ich nur meine Prioritäten-Tabelle überarbeiten.
Da ich inzwischen mehr Operatortypen habe, bin ich trotzdem zu einem rekursiven Einlesen zurückgekehrt. Das waren rund 10 Zeilen in einer Schleife und lief mit den einfachen Priority-Operatoren problemlos.
-
Xin schrieb:
volkard schrieb:
Habe aber auch WernerSolomons mathematische Parser gelesen
Gibt's da was wirklich suchbares? Google lieferte mir dazu nix.
Dann haste bestimmt auch "Salomon" falsch geschrieben.
http://www.c-plusplus.net/forum/p1642138
-
Bashar schrieb:
Das stimmt halt nicht ganz. …
Danke für die Richtigstellung. Mächtigeres Werkzeug ist eigentlich immer gut, vielleicht kicke ich die rekursiven Ideen.
-
Wenn ich mir andere Parsertypen ansehe, gewinnt RecDesc einfach immer in Einfachheit und Lesbarkeit. Fehlerbehandlung funktioniert genauso gut wie mit anderen Parsern, wenn nicht sogar besser.
@Xin
Dynamische Operatoren hab ich bei meinem Parser mittels Hack implementiert. Zunaechst werden Ausdruecke mit Operatoren im Syntaxbaum als "operator sequence" repraesentiert. Diese OpSeqs sind im Wesentlichen nur eine Liste an Ausdruecken mit Operatoren dazwischen. Sobald alles geparsed wurde, sind Benutzerdefinierte Operatoren samt Prioritaeten bekannt und die Operator Sequence wird in einem zweiten Parserschritt nach Prioritaet und Assiziativitaet korrekt zerlegt. Danach gehts ganz normal weiter mit semantischer Analyse. Was haeltst du von diesem Ansatz?
-
Kellerautomat schrieb:
Dynamische Operatoren hab ich bei meinem Parser mittels Hack implementiert.
Da wäre erstmal die Frage, was eigentlich dynamische Operatoren sind. Ich vermute selbstdefinierte, wobei sich dann die Frage stellt, wie dynamische Operatoren in Deiner Sprache aussehen, so dass sie sich von einer Funktion merklich unterscheiden.
Selbst definierbare Operatoren habe ich (noch) nicht.
Kellerautomat schrieb:
Zunaechst werden Ausdruecke mit Operatoren im Syntaxbaum als "operator sequence" repraesentiert. Diese OpSeqs sind im Wesentlichen nur eine Liste an Ausdruecken mit Operatoren dazwischen. Sobald alles geparsed wurde, sind Benutzerdefinierte Operatoren samt Prioritaeten bekannt und die Operator Sequence wird in einem zweiten Parserschritt nach Prioritaet und Assiziativitaet korrekt zerlegt. Danach gehts ganz normal weiter mit semantischer Analyse. Was haeltst du von diesem Ansatz?

Interessant, vorrangig deswegen, weil ich diesen Ansatz bisher nicht im entferntesten mit selbstdefinierten Operatoren gesehen habe...!? Wenngleich das ganze einen zweiten Durchlauf für die semantische Analyse fordert... sofern Du eine typsichere Sprache hast...?!
Ich denke gerade an einen Ausdruck wie
int a = <"selbstdefinierter Operator"> + 1;Wie erkennst Du, dass es sich um einen selbstdefinierten Operator handelt, wenn dieser noch nicht deklariert wurde? An der Stelle weiß ich ja nicht, ob ["selbstdefinierter Operator"] überhaupt ein Integer addiert werden kann und wenn ja, ob da ein einem Integer zuweisbares Objekt rauskommt.
Merkst Du Dir diese Stellen, um sie nachträglich zu prüfen?---
@Moderator mit Rechten: ggfs. abtrennen
-
Mit dynamischen Operatoren meinte ich selbstdefinierte, richtig. Zunaechst einmal ist es so, dass man zwischen selbst definierten Operatoren und selbst definierten Overloads unterscheiden muss. Bevor ein Operator ueberladen werden kann, muss er erstmal definiert sein. Da gibt es natuerlich die built-in Definitionen, aber man kann sich auch seine eigenen bauen (Syntax aendert sich gefuehlt jede Woche mal):
// neuer Operator $$ // Symbol $$, binaer mit Prioritaet 42, links-assoziativ operator $$ binary(42, left);Sobald man den definiert hat, kann man diesen ganz normal ueberladen, wie man es in C++ auch tun wuerde.
Eine symantische Analyse ist damit nicht wirklich erforderlich, da es keine semantisch "falschen" Operator Definitionen gibt. Die beiden Parserschritte koennen daher direkt hintereinander ausgefuehrt werden. Das einige, was geprueft werden muss, ist dass es nicht mehrere wiederspruechige Definitionen gibt. Man kann einen Operator durchaus als binaer und unaeren prefix/postfix gleichzeitig definieren, allerdings niemals alle 3, da es dann zu Mehrdeutigkeiten kommen koennte.Zu deinem Beispiel: Es wird beim aufbauen des ASTs zunaechst angenommen, dass es ein gueltiger Operator ist und der OpSeq Knoten erstellt. Sobald alles geparsed wurde, habe ich eine Liste aller definierten Operatoren sowie eine Liste aller OpSeqs vorliegen und kann im zweiten Parseschritt - dem Zerlegen aller OpSeqs - nachsehen, ob der Operator tatsaechlich existiert. Ob dieser Operator-Overload dann fuer die gegebenen Argument-Typen existiert, ist eine ganz andere Frage und wird erst bei der semantischen Analyse geprueft.
-
Kellerautomat schrieb:
Zunaechst einmal ist es so, dass man zwischen selbst definierten Operatoren und selbst definierten Overloads unterscheiden muss.
Finde ich gut.
Kellerautomat schrieb:
// neuer Operator $$ // Symbol $$, binaer mit Prioritaet 42, links-assoziativ operator $$ binary(42, left);Sobald man den definiert hat, kann man diesen ganz normal ueberladen, wie man es in C++ auch tun wuerde.
Ich habe noch keine dynamischen Operatoren, ich tue mich derzeit an zwei Dingen schwer: der Magic-Number "42" - wobei mir auch noch nichts besseres eingefallen ist - und "left". Ich bin sowieso schon leicht inflationär was Schlüsselwörter angeht. Selbiges mit binary.
Wie sieht's mit ternärer Operatoren aus?Kellerautomat schrieb:
Die beiden Parserschritte koennen daher direkt hintereinander ausgefuehrt werden. Das einige, was geprueft werden muss, ist dass es nicht mehrere wiederspruechige Definitionen gibt. Man kann einen Operator durchaus als binaer und unaeren prefix/postfix gleichzeitig definieren, allerdings niemals alle 3, da es dann zu Mehrdeutigkeiten kommen koennte.
Präfix-Operatoren gibt's bei mir nicht mehr - mit Ausnahme von 'negativ'. Ich hoffe, das bleibt auch so.

Kellerautomat schrieb:
Zu deinem Beispiel: Es wird beim aufbauen des ASTs zunaechst angenommen, dass es ein gueltiger Operator ist und der OpSeq Knoten erstellt. Sobald alles geparsed wurde, habe ich eine Liste aller definierten Operatoren sowie eine Liste aller OpSeqs vorliegen und kann im zweiten Parseschritt - dem Zerlegen aller OpSeqs - nachsehen, ob der Operator tatsaechlich existiert. Ob dieser Operator-Overload dann fuer die gegebenen Argument-Typen existiert, ist eine ganz andere Frage und wird erst bei der semantischen Analyse geprueft.
Aber bringt das einen erwähnenswerten Vorteil? Du musst den Operator ja sowieso deklarieren, da könnte man die Overloads ja als Deklaration auch gleich verlangen und sich einen Durchgang sparen.
Grundsätzlich finde ich die Idee das Parsen so aufzuteilen aber sehr interessant. Ich denke da aber mehr an Präprozessing.
-
Xin schrieb:
Kellerautomat schrieb:
// neuer Operator $$ // Symbol $$, binaer mit Prioritaet 42, links-assoziativ operator $$ binary(42, left);Sobald man den definiert hat, kann man diesen ganz normal ueberladen, wie man es in C++ auch tun wuerde.
Ich habe noch keine dynamischen Operatoren, ich tue mich derzeit an zwei Dingen schwer: der Magic-Number "42" - wobei mir auch noch nichts besseres eingefallen ist - und "left". Ich bin sowieso schon leicht inflationär was Schlüsselwörter angeht. Selbiges mit binary.
Ich gebe dir Recht. Ein Grund, warum ich meine Syntax dafuer dauernd aendere, ist weil ich immer versuche die perfekte Syntax zu bekommen. Ich habe sie noch nicht gefunden.
Xin schrieb:
Wie sieht's mit ternärer Operatoren aus?
Ich habe darueber nachgedacht, aber ich halte den praktischen Nutzen fuer zu gering. Wenn, dann wuerde ich Operatoren so generalisieren, dass man eine beliebige Aritaet haben kann, aber ich bin mir nicht mal sicher, wie man das machen koennte. Das Potential fuer Mehrdeutigkeiten ist riesig, und ich koennte mir vorstellen, dass die Regeln ziemlich kompliziert werden. Falls du irgendwo Literatur dazu hast, immer her damit, das Thema interessiert mich.
Und was ist eigentlich mit einer variablen Anzahl an Argumenten?
Xin schrieb:
Kellerautomat schrieb:
Die beiden Parserschritte koennen daher direkt hintereinander ausgefuehrt werden. Das einige, was geprueft werden muss, ist dass es nicht mehrere wiederspruechige Definitionen gibt. Man kann einen Operator durchaus als binaer und unaeren prefix/postfix gleichzeitig definieren, allerdings niemals alle 3, da es dann zu Mehrdeutigkeiten kommen koennte.
Präfix-Operatoren gibt's bei mir nicht mehr - mit Ausnahme von 'negativ'. Ich hoffe, das bleibt auch so.

Was hast du gegen Praefix-Operatoren? Sollten diese nicht sogar einfacher zu parsen sein als Postfix?
Xin schrieb:
Kellerautomat schrieb:
Zu deinem Beispiel: Es wird beim aufbauen des ASTs zunaechst angenommen, dass es ein gueltiger Operator ist und der OpSeq Knoten erstellt. Sobald alles geparsed wurde, habe ich eine Liste aller definierten Operatoren sowie eine Liste aller OpSeqs vorliegen und kann im zweiten Parseschritt - dem Zerlegen aller OpSeqs - nachsehen, ob der Operator tatsaechlich existiert. Ob dieser Operator-Overload dann fuer die gegebenen Argument-Typen existiert, ist eine ganz andere Frage und wird erst bei der semantischen Analyse geprueft.
Aber bringt das einen erwähnenswerten Vorteil? Du musst den Operator ja sowieso deklarieren, da könnte man die Overloads ja als Deklaration auch gleich verlangen und sich einen Durchgang sparen.
Ich finde es sauberer abzutrennen, aber es sollte kein Problem darstellen, einen syntaktischen Shortcut einzufuehren. Ist ja nur Syntaxzucker.
Xin schrieb:
Grundsätzlich finde ich die Idee das Parsen so aufzuteilen aber sehr interessant. Ich denke da aber mehr an Präprozessing.
Danke, ich hab mir den Ansatz selbst ausgedacht.

Aber was meinst du mit Praeprozessing?
-
[quote="Kellerautomat"]Wenn, dann wuerde ich Operatoren so generalisieren, dass man eine beliebige Aritaet haben kann, aber ich bin mir nicht mal sicher, wie man das machen koennte.quote]
Meinst du sowas?
($$ a b c d)
-
@Moderator mit Rechten: ggfs. abtrennen
Hihi, mein erster Split! Hoffe ich habe nicht zu viel Verwirrung gestiftet.
Was hast du gegen Praefix-Operatoren? Sollten diese nicht sogar einfacher zu parsen sein als Postfix?
Vielleicht meint er sowas wie
a+++b. Entspricht es(a++)+bodera+(++b)? Wenn du aber lediglich den Postfix-Operator definierst verschwindet auch die Ambiguität.
-
Mechanics schrieb:
Kellerautomat schrieb:
Wenn, dann wuerde ich Operatoren so generalisieren, dass man eine beliebige Aritaet haben kann, aber ich bin mir nicht mal sicher, wie man das machen koennte.
Meinst du sowas?
($$ a b c d)
int operator $$ ## ?? (int a, int b, int c, int d) { return a + b + c + d; } int x = 42 $$ 666 ## 1337 ?? 9001;Arcoth schrieb:
Kellerautomat schrieb:
Was hast du gegen Praefix-Operatoren? Sollten diese nicht sogar einfacher zu parsen sein als Postfix?
Vielleicht meint er sowas wie
a+++b. Entspricht es(a++)+bodera+(++b)? Wenn du aber lediglich den Postfix-Operator definierst verschwindet auch die Ambiguität.Das habe ich ja beretis gesagt: Es darf nur maximal 2 aus {unary prefix, unary postfix, binary} geben, damit es eindeutig ist.
Auf die Regel bin ich selbst draufgekommen, aber aehnliche regeln fuer n-ary Operatoren aufstellen kann ich schwer.Von formalen Beweisen und der ganzen Theorie hinter Parsing halte ich eh nix, ich bin da praxisorientiert. Wenn ich fuer etwas nicht sinnvolle Regeln aufstellen kann, wie sollen dann erst die Benutzer meine Sprache das Feature einsetzen koennen?
Edit: @Arcoth: Im uebrigen waere die Bedeutung deines Codes in meiner Sprache a +++ b, wobei +++ ein einziger Operator ist. Wer das getrennt haben will, muss Whitespace einfuegen.
-
Kellerautomat schrieb:
int operator $$ ## ?? (int a, int b, int c, int d) { return a + b + c + d; } int x = 42 $$ 666 ## 1337 ?? 9001;Mir ist jetzt nicht wirklich klar, was das ausdrücken soll.
-
Ein Quartaerer Operator halt.
-
Gibt es sowas in freier Wildbahn? Es ist ja schon schwer, sinnvolle Beispiele für ternäre Operatoren, die Funktionen sind (also nicht ?: ) zu finden.
-
Koennte man z.B. statt Expression Templates zur Optimierung verwenden.
-
Bashar schrieb:
Gibt es sowas in freier Wildbahn? Es ist ja schon schwer, sinnvolle Beispiele für ternäre Operatoren, die Funktionen sind (also nicht ?: ) zu finden.
Pythons slice operator wäre ein quartärer Operator:
a[start:end:step]
-
Kellerautomat schrieb:
Ich gebe dir Recht. Ein Grund, warum ich meine Syntax dafuer dauernd aendere, ist weil ich immer versuche die perfekte Syntax zu bekommen. Ich habe sie noch nicht gefunden.
Ich frickel jetzt seit 10 Jahren an der Syntax, es kommen laufend neue Ideen, aber der Kern ist inzwischen eigentlich recht fix.
Wichtig ist nur, dass man nicht in vorgegebenen Mustern denkt.Kellerautomat schrieb:
Was hast du gegen Praefix-Operatoren? Sollten diese nicht sogar einfacher zu parsen sein als Postfix?
Weil es - für mich logischer ist - ein Objekt zu nehmen und dann etwas damit zu machen. Es heißt ja auch nicht method.member<-this(arg1, arg2). oder (arg1, arg2)func. Warum sollte ein Operator also vorne stehen?
Kellerautomat schrieb:
Ist ja nur Syntaxzucker.
Alles ist nur Syntax-Zucker, wenn man nicht in Assembler programmiert. (Und gefälligst ohne Makro-Assembler - wir haben mal eine Grafik-Adventure-Engine in Assembler geschrieben, nur sah man gar nicht, dass es Assembler war... ein guter Assembler kann auch zuckersüß sein)
Xin schrieb:
Aber was meinst du mit Praeprozessing?
#if, #else, #endif
Und den Text dazwischen muss man sich ja auch irgendwie merken.
Arcoth schrieb:
@Moderator mit Rechten: ggfs. abtrennen
Hihi, mein erster Split! Hoffe ich habe nicht zu viel Verwirrung gestiftet.
Klappt doch wunderbar.

Arcoth schrieb:
Was hast du gegen Praefix-Operatoren? Sollten diese nicht sogar einfacher zu parsen sein als Postfix?
Vielleicht meint er sowas wie
a+++b. Entspricht es(a++)+bodera+(++b)? Wenn du aber lediglich den Postfix-Operator definierst verschwindet auch die Ambiguität.
Ich habe deutlich mehr Postfix-Operatoren. Ich würde mir mit quasi allem in die Quere kommen.
Kellerautomat schrieb:
Mechanics schrieb:
Meinst du sowas?
($$ a b c d)
int operator $$ ## ?? (int a, int b, int c, int d) { return a + b + c + d; } int x = 42 $$ 666 ## 1337 ?? 9001;Denkmuster aufbrechen... eine Möglichkeit:
int operator (int a, "$$", int b, "##", int c, "??", int d );Ein String in einer Argumentenliste kann kein Argument sein. Also muss er irgendwas anderes bedeuten.
Kellerautomat schrieb:
Von formalen Beweisen und der ganzen Theorie hinter Parsing halte ich eh nix, ich bin da praxisorientiert.
Grundsätzlich unterschreibe ich das auch so... Top-Down, Bottom-Up, Single-Pass, alles gut und schön: Die Sprache muss gut zu programmieren sein, der Rest ist heute das Problem des Parser-Herstellers.
Trotzdem kann es nicht schaden, sich mit der Theorie ein wenig auseinander zu setzen.Bashar schrieb:
Kellerautomat schrieb:
Ein Quartaerer Operator halt.
Gibt es sowas in freier Wildbahn? Es ist ja schon schwer, sinnvolle Beispiele für ternäre Operatoren, die Funktionen sind (also nicht ?: ) zu finden.
Ich habe vor 10 Jahren eine Umfrage gestartet, was in aktuellen Programmiersprachen fehlt. Die wichtigste Erkenntnis ist, dass Software-Entwickler es sehr schwer haben, Dinge zu vereinfachen, weil sie es gewohnt sind, Probleme mit den Mitteln zu lösen, die sie haben.
Mathematiker, Ingenieure oder Anfänger interessieren sich nicht dafür, dass die Mittel begrenzt sind. Die Sachen sich, da muss es bestimmt ein Werkzeug für geben und wenn nicht, beschwere ich mich. Der Informatiker weiß, es gibt kein Werkzeug und löst sein Problem so.
Die Leute, die Compiler bauen, machen das meistens aus Spaß. Manche bauen auch das Werkzeug, dass ihnen fehlt.
Dass manche Dinge nicht in freier Wildbahn auftauchen liegt oftmals einfach nur daran, dass sich kein Sprachdesigner gefunden hat, der sich fragte, ob es Leute geben könnte, die sowas brauchen könnten, bzw. die sowas praktisch finden. Wer braucht schon ternäre Operatoren? Man kann einen Bruch wie 1 1/2 ja auch in 3/2 schreiben. Oder muss halt den passenden Konstruktor der Klasse Fraction( 1, 1, 2 ) aufrufen. Oder man definiert sich einen Operator 1_1_2, wenn man viel mit Brüchen rechnet, der Fraction( 1, 1, 2 ) aufruft.
-
Arcoth schrieb:
Vielleicht meint er sowas wie
a+++b. Entspricht es(a++)+bodera+(++b)? Wenn du aber lediglich den Postfix-Operator definierst verschwindet auch die Ambiguität.Wo ist da eine Ambiguität?
a+++bist genauso wiea+++++++++bin C++ genau definiert. In K11ts Sprache leicht anders, aber auch wohldefiniert.Xin schrieb:
Kellerautomat schrieb:
Was hast du gegen Praefix-Operatoren? Sollten diese nicht sogar einfacher zu parsen sein als Postfix?
Weil es - für mich logischer ist - ein Objekt zu nehmen und dann etwas damit zu machen. Es heißt ja auch nicht method.member<-this(arg1, arg2). oder (arg1, arg2)func. Warum sollte ein Operator also vorne stehen?
Verstehe ich nicht. In C++ hast du sowas perverses* wie
next(begin(v)), aber was eigentlich gemeint ist ist "nimm v, nehme davon den Startiterator und inkrementiere diesen". Eine sprechendere Schreibweise wäre z.B.v:begin():next().Also nein,
func(arg1, arg2)ist Präfix-Notation. Sogar das meiste aus C++ ist Präfix-Notation. Aber Postfix-Notation wäre lesbarer.*im wahrsten Wortsinn
-
Max Munch schrieb:
Xin schrieb:
Warum sollte ein Operator also vorne stehen?
Verstehe ich nicht. In C++ hast du sowas perverses* wie
next(begin(v)), aber was eigentlich gemeint ist ist "nimm v, nehme davon den Startiterator und inkrementiere diesen". Eine sprechendere Schreibweise wäre z.B.v:begin():next().Wie steht's mit v.begin()++?
(Ich weiß, dass es in C++ korrekt ++v.begin() heißen würde, aber wie ich schon sagte: Ich habe keine Präfixe)Das klassenbasierte Programmieren ist doch am Ende nichts anderes, als das Objekt nach vorne zu ziehen und die Handlung - die Methode - als Postfix-Operation dahinter zu setzen.
Schwierig wird's teils bei der STL, wo sich generische und objektorientierte Programmierung in die Quere kommen:
std::next( v.begin(), 1);
-
Xin schrieb:
Bashar schrieb:
Kellerautomat schrieb:
Ein Quartaerer Operator halt.
Gibt es sowas in freier Wildbahn? Es ist ja schon schwer, sinnvolle Beispiele für ternäre Operatoren, die Funktionen sind (also nicht ?: ) zu finden.
Ich habe vor 10 Jahren eine Umfrage gestartet, was in aktuellen Programmiersprachen fehlt. Die wichtigste Erkenntnis ist, dass Software-Entwickler es sehr schwer haben, Dinge zu vereinfachen, weil sie es gewohnt sind, Probleme mit den Mitteln zu lösen, die sie haben.
Ich fürchte, du hast die Frage bzw. ihren Hintergrund anders verstanden, als ich sie gemeint habe. Prinzipiell braucht man Funktionen und Formen (Lisp-Jargon für Ausdrücke, deren Argumente nicht unbedingt ausgewertet werden, z.B. if oder while). Man könnte also z.B. while(less(x,10), assign(x, plus(x,1))) schreiben und damit über die Runden kommen. Operatoren gibt es in erster Linie, um mathematische Operatoren in der Programmiersprache abzubilden, darüber hinaus natürlich aus Bequemlichkeitsgründen. Manche Operatoren sind im Prinzip Funktionen (wie arithmetische Operatoren), manche sind Formen (wie Komma, &&, ||, ?: ). Beim Operatorüberladen (und wie mir scheint, bei euren selbstdefinierten Operatoren) gibt es nur Funktionen. Der einzige ternäre Operator in C++ ist eine Form. Es stellt sich daher die Frage, ob es überhaupt Bedarf dafür gibt, n-äre Operatoren, die Funktionen sind, einzuführen. Was ist das Vorbild in der Mathematik oder sonstwo? Das ist die "freie Wildbahn", die ich meine. Nicht andere Programmiersprachen.
Außerdem ist die Frage nicht als Kritik gemeint (auch wenn sie so klingt, mea culpa), sondern rein interessehalber.
Wer braucht schon ternäre Operatoren? Man kann einen Bruch wie 1 1/2 ja auch in 3/2 schreiben.
1 1/2 ist kein ternärer Ausdruck, sondern ein spezielles Literal. Man kann jedenfalls (in der Mathematik) nicht (1+1) 1/2 oder 2 3/x schreiben.
Mathematiker, Ingenieure oder Anfänger interessieren sich nicht dafür, dass die Mittel begrenzt sind. Die Sachen sich, da muss es bestimmt ein Werkzeug für geben und wenn nicht, beschwere ich mich. Der Informatiker weiß, es gibt kein Werkzeug und löst sein Problem so.
Kannst du dir solche Pauschalaussagen nicht einfach mal abgewöhnen?
oenone schrieb:
Bashar schrieb:
Gibt es sowas in freier Wildbahn? Es ist ja schon schwer, sinnvolle Beispiele für ternäre Operatoren, die Funktionen sind (also nicht ?: ) zu finden.
Pythons slice operator wäre ein quartärer Operator:
a[start:end:step]Nicht schlecht, aber ich würde das wohl anders designen. Das innere ist ein Range-Ausdruck (immerhin ternär), das [] ist ein binärer Operator. Dadurch werden a[i], a[i:j], a[i:j:k] alle einheitlich behandelt, während das bei dir verschiedene Operatoren sind. (Sorry, zu faul in der Python-Doku nachzulesen, wie es wirklich ist.)