Woher weiß der Compiler, dass das Komma in einem Funktionsaufruf kein Kommaoperator ist?

Lesezeit: 9 Minuten

Benutzeravatar von hackks
hackt

Betrachten Sie den Funktionsaufruf (calling int sum(int, int))

printf("%d", sum(a,b));

Wie entscheidet der Compiler, dass die , im Funktionsaufruf verwendet sum(int, int) ist kein Kommaoperator?

HINWEIS: Ich wollte den Kommaoperator eigentlich nicht im Funktionsaufruf verwenden. Ich wollte nur wissen, woher der Compiler weiß, dass es sich nicht um einen Kommaoperator handelt.

  • Sie sprechen davon, welches der beiden Kommas …

    – Sazzadur Rahaman

    29. Juni 2013 um 18:39 Uhr

  • Warum die Leute dafür stimmen, dies zu schließen !!!!!!!!

    – Hacken

    29. Juni 2013 um 19:14 Uhr

  • Stimmen Sie nicht zu, dass diese Frage nicht zum Thema gehört. Die Frage fragt nach einem subtilen Detail, wie eine bestimmte Syntax von Implementierungen interpretiert werden kann, und kann durch Zitieren der relevanten Standardzitate abschließend beantwortet werden. Versuche, das Problem zu lösen trifft hier nicht zu. Standard-Zitate zu verstehen oder aufzuspüren ist keine triviale Aufgabe.

    – Alok Speichern

    29. Juni 2013 um 19:38 Uhr

  • Es gibt zwei Funktionsaufrufe, einen bis sum und eins zu printf.

    – Keith Thompson

    29. Juni 2013 um 19:55 Uhr

  • Ich hatte einmal ein seltsames Verhalten von C-Code, weil ich über einen Zeiger eine Division durch eine ganze Zahl durchführte. dh der Ausdruck war a/*b. Es wurde behoben, indem einige Leerzeichen hinzugefügt wurden: a / *b

    – Steward

    29. Juni 2013 um 21:10 Uhr

Benutzeravatar von ams
ams

Sehen Sie sich die Grammatik für die C-Sprache an. Es ist vollständig in Anhang A des aufgeführt Standard. Es funktioniert so, dass Sie jedes Token in einem C-Programm schrittweise durchgehen und es mit dem nächsten Element in der Grammatik abgleichen können. Bei jedem Schritt haben Sie nur eine begrenzte Anzahl von Optionen, sodass die Interpretation eines bestimmten Zeichens davon abhängt Kontext, in dem es erscheint. Innerhalb jeder Regel in der Grammatik gibt jede Zeile eine gültige Alternative für das entsprechende Programm an.

Insbesondere, wenn Sie suchen parameter-list, werden Sie sehen, dass es ein explizites Komma enthält. Immer wenn sich der C-Parser des Compilers im “Parameterlisten”-Modus befindet, werden Kommas, die er findet, als verstanden Parametertrennzeichennicht so wie Komma-Operatoren. Dasselbe gilt für Klammern (die auch in Ausdrücken vorkommen können).

Das funktioniert, weil die parameter-list Regel ist vorsichtig zu verwenden assignment-expression Regeln, anstatt nur die Ebene expression Regel. Ein expression kann Kommas enthalten, während an assignment-expression kann nicht. Wenn dies nicht der Fall wäre, wäre die Grammatik mehrdeutig, und der Compiler wüsste nicht, was er tun soll, wenn er in einer Parameterliste auf ein Komma trifft.

Allerdings eine öffnende Klammer, das heißt zum Beispiel nicht Teil einer Funktionsdefinition/eines Aufrufs, oder ein if, whileoder for -Anweisung, wird als Teil eines Ausdrucks interpretiert (weil es keine andere Option gibt, sondern nur, wenn der Beginn eines Ausdrucks an diesem Punkt eine gültige Wahl ist), und dann innerhalb der Klammern die expression Es gelten Syntaxregeln, und das erlaubt Kommaoperatoren.

  • Ich hatte vergessen, dass es einen Fachbegriff mit diesem Namen gibt. Ich meine lediglich, dass ein gegebenes Token nur in dem Kontext verstanden werden kann, in dem es erscheint. Mit anderen Worten, ich verwende “kontextsensitiv” als Adjektiv und nicht als Substantiv. Ich vermute jedoch, dass die einzigen Leute, die davon verwirrt waren, Leute waren, die die Antwort bereits kannten!

    – ams

    2. Juli 2013 um 8:35 Uhr

  • Dies ist eine gute Antwort, aber Sie sollten auch erwähnen, dass die Dinge zwischen den Kommas sind assignment-expression Nichtterminale statt expression Nonterminals (wie in Jens ‘Antwort besprochen), also nicht zulassen , auf höchstem Niveau a parameter-list davon ab, der Kommaoperator zu sein. Wenn der Standard das tun würde, was Sie beschreiben, ohne dies ebenfalls zu tun, wäre die gesamte Grammatik mehrdeutig.

    – zol

    10. Februar 2014 um 15:47 Uhr

  • @Zack, ganz so. Ich habe die Antwort mit diesen Informationen erweitert.

    – ams

    11. Februar 2014 um 17:06 Uhr

  • @EricLippert: Ich halte es nicht für sinnvoll zu sagen, dass C eine kontextfreie Grammatik hat. Wenn Sie in diese Richtung gehen, könnten Sie auch behaupten, dass C++ eine CFG hat (da sie, genau wie im Fall von C, mehrdeutig ist und einen semantischen Pass erfordert, um ungültige Programme zurückzuweisen). Wenn Sie wirklich streng sein wollen, können Sie auch behaupten, dass die meisten Programmiersprachen dies tun nicht haben CFGs, weil sie alle Deklarationen vor Definitionen erfordern, bevor das Programm als gültig erachtet wird, was nicht kontextfrei ist. Beides ist keine sehr nützliche Definition, da es die meisten Sprachen in dieselbe Kategorie einordnet. (Fortsetzung)

    – Benutzer541686

    15. Juni 2014 um 22:19 Uhr


  • @EricLippert: (Fortsetzung) … aus praktischer Sicht (vielleicht nicht so sehr auf der theoretischen Seite) wäre meiner Meinung nach eine nützliche Definition, dass C kontextfrei ist, wenn es eine CFG hat, die alle gültigen C-Programme eindeutig analysiert vorausgesetzt, es gibt keine nicht deklarierten Identifikatoren. Aber in diesem Fall ist C wegen des Klassikers nicht kontextfrei (und hat daher kein CFG). T * T; Mehrdeutigkeit, die erfordert, was zu wissen T ist (und nicht nur, ob es deklariert ist). Daher halte ich es nicht für sinnvoll zu sagen, dass C kontextfrei ist.

    – Benutzer541686

    15. Juni 2014 um 22:26 Uhr


Benutzeravatar von Yu Hao
Yu Hao

Ab C99 6.5.17:

Wie aus der Syntax hervorgeht, darf der Kommaoperator (wie in diesem Unterabschnitt beschrieben) nicht in Kontexten erscheinen, in denen ein Komma verwendet wird, um Elemente in einer Liste zu trennen (z. B. Argumente für Funktionen oder Listen von Initialisierern). Andererseits kann es in solchen Kontexten innerhalb eines eingeklammerten Ausdrucks oder innerhalb des zweiten Ausdrucks eines Bedingungsoperators verwendet werden. Im Funktionsaufruf

f(a, (t=3, t+2), c)

Die Funktion hat drei Argumente, von denen das zweite den Wert 5 hat.

Ein weiteres ähnliches Beispiel ist die Initialisierungsliste von Arrays oder Strukturen:

int array[5] = {1, 2};
struct Foo bar = {1, 2};

Wenn ein Komma-Operator als Funktionsparameter verwendet werden soll, verwenden Sie ihn wie folgt:

sum((a,b))

Das wird natürlich nicht kompiliert.

  • Richtig, aber keine Antwort auf die Frage.

    – bmargulies

    29. Juni 2013 um 18:38 Uhr

  • @Yu: Ich wollte keinen Kommaoperator verwenden. Ich möchte nur wissen, woher der Compiler weiß, dass es sich nicht um einen Kommaoperator handelt!

    – Hacken

    29. Juni 2013 um 18:51 Uhr

  • @sasha.sochka Siehe den Kommentar des OP. Er möchte wissen, wie Parser funktionieren, nicht, wie man ein Komma in einem Funktionsaufruf verwendet.

    – bmargulies

    29. Juni 2013 um 18:56 Uhr

  • @hackks Verstanden, meine Worte bearbeitet. Die Verwendung eines Komma-Operators als Funktionsparameter ist praktisch nicht nützlich, aber zu wissen, wie man ihn verwendet, ist immer noch interessant, also werde ich diesen Teil behalten.

    – Yu Hao

    29. Juni 2013 um 19:01 Uhr

  • @YuHao; Danke Alter! wenigstens. Und danke auch für die Bearbeitung meines Beitrags.

    – Hacken

    29. Juni 2013 um 19:07 Uhr


Benutzeravatar von Jens
Jens

Der Grund ist die C-Grammatik. Während alle anderen das Beispiel gerne zitieren, ist das eigentliche Geschäft die Phrasenstrukturgrammatik für Funktionsaufrufe im Standard (C99). Ja, ein Funktionsaufruf besteht aus der () Operator, der auf einen Postfix-Ausdruck angewendet wird (wie zum Beispiel ein Bezeichner):

 6.5.2 postfix-expression:
       ...
       postfix-expression ( argument-expression-list_opt )

zusammen mit

argument-expression-list:
       assignment-expression
       argument-expression-list , assignment-expression    <-- arglist comma

expression:
       assignment-expression
       expression , assignment-expression                  <-- comma operator

Der Kommaoperator kann nur in an vorkommen Ausdruck, also weiter unten in der Grammatik. Der Compiler behandelt also ein Komma in einer Funktionsargumentliste als Trennzeichen Zuweisungsausdrückenicht als eine Trennung Ausdrücke.

  • @hackks: ein bedingter Ausdruck oder ein unärer Ausdruck, gefolgt von einem Zuweisungsoperator, gefolgt von einem Zuweisungsausdruck.

    – Jens

    29. Juni 2013 um 19:28 Uhr

  • Ich habe Ihren Punkt nicht verstanden, bitte erläutern Sie es. Es sollte geschätzt werden

    – Hacken

    29. Juni 2013 um 20:31 Uhr

  • Um die Antwort von @Jen ein wenig zu erweitern: Ändern wir das Problem und vereinfachen es. Anstelle von “Ausdrücken” haben wir Golfbälle (gelb gestrichen) und auch große durchsichtige Plastikbälle, die geöffnet werden können und in denen Sachen stecken: ( Sachen ). Die Grammatik besagt, dass Sie gelbe Golfbälle haben können, die automatisch getrennt werden. Oder Sie können einen klaren Ball liefern solange Sie beide Hälften verwendet haben. Die durchsichtige Kugel funktioniert als Einheit, sie kann nicht geöffnet und getrennt werden. Also: f( (a,b), g ) hat einen “klaren Ball” (a,b) und einen “gelben Ball” g und damit genau zwei Bälle, äh, Argumente.

    – Torek

    30. Juni 2013 um 1:54 Uhr

  • Mir ist der Kommentarraum ausgegangen, also fuhr ich fort und zurück zur echten C-Grammatik: Die Klammern ermöglichen es Ihnen, zu einem “ausgewachsenen” Ausdruck zu gelangen, bei dem Kommas Komma-Ausdrucksteile sind. Bis Sie jedoch eine “zusätzliche” offene Klammer haben, befinden Sie sich in dieser eingeschränkteren Untergrammatik “Zuweisungsausdruck” (wie die Idee “gelbe Golfbälle”), wo Kommas einfach nicht erlaubt sind. Wenn der Parser in diesem Zusammenhang auf ein Komma stößt, muss er anhalten und den Zuweisungsausdruck beenden. Das funktioniert, weil ( “beendet” mit ): Die Klammerung beendet den vollständigen Ausdruckskontext.

    – Torek

    30. Juni 2013 um 2:00 Uhr

  • Hm, ich habe keine andere natürliche Sprache, um das auszudrücken. In Betracht ziehen {}, []und (). Sie “passen zusammen”: wenn Sie schreiben a[3} it’s obviously wrong. If you write a[(3] es ist immer noch offensichtlich falsch. ( wird erst durch das Matching beendet ). Das “schließt” die ganze Sequenz ab und macht klar, was zu was gehört.

    – Torek

    30. Juni 2013 um 23:59 Uhr


Roddys Benutzeravatar
Roddy

Vorhandene Antworten sagen “weil die C-Sprachspezifikation besagt, dass es sich um ein Listentrennzeichen und nicht um einen Operator handelt”.

Ihre Frage lautet jedoch: “Woher weiß der Compiler …”, und das ist ganz anders: Es unterscheidet sich wirklich nicht davon, wie der Compiler weiß, dass das Komma eingegeben wird printf("Hello, world\n"); ist kein Komma-Operator: Der Compiler ‘weiß’ aufgrund des Kontexts, wo das Komma erscheint – im Grunde, was vorher passiert ist.

Die C-‘Sprache’ kann in beschrieben werden Backus-Naur-Form (BNF) – im Wesentlichen eine Reihe von Regeln, die die des Compilers Parser verwendet, um Ihre Eingabedatei zu scannen. Die BNF für C wird zwischen diesen verschiedenen möglichen Vorkommen von Kommas in der Sprache unterscheiden.

Es gibt viele gute Ressourcen darüber, wie Compiler funktionieren und wie man einen schreibt.

Der Entwurf des C99-Standards sagt:

Wie aus der Syntax hervorgeht, darf der Kommaoperator (wie in diesem Unterabschnitt beschrieben) nicht in Kontexten erscheinen, in denen ein Komma verwendet wird, um Elemente in einer Liste zu trennen (z. B. Argumente für Funktionen oder Listen von Initialisierern). Andererseits kann es in solchen Kontexten innerhalb eines eingeklammerten Ausdrucks oder innerhalb des zweiten Ausdrucks eines Bedingungsoperators verwendet werden. Im Funktionsaufruf f(a, (t=3, t+2), c) Die Funktion hat drei Argumente, von denen das zweite den Wert 5 hat.

Mit anderen Worten „weil“.

  • Meine Kinder nehmen das nicht als Antwort, warum sollte das OP … aber das ist der Grund, weil der mehrdeutige Fall verboten ist.

    – Grady-Spieler

    29. Juni 2013 um 20:28 Uhr

Benutzeravatar von John Tseng
John Tseng

Diese Frage hat mehrere Facetten. Ein Par ist, dass die Definition dies sagt. Nun, woher weiß der Compiler, in welchem ​​Kontext dieses Komma steht? Das ist die Aufgabe des Parsers. Insbesondere für C kann die Sprache von einem LR(1)-Parser geparst werden (http://en.wikipedia.org/wiki/Canonical_LR_parser).

Dies funktioniert so, dass der Parser eine Reihe von Tabellen generiert, die die möglichen Zustände des Parsers darstellen. Nur ein bestimmter Satz von Symbolen ist in bestimmten Zuständen gültig, und die Symbole können in verschiedenen Zuständen unterschiedliche Bedeutung haben. Der Parser weiß aufgrund der vorangehenden Symbole, dass er eine Funktion parst. Daher weiß es, dass die möglichen Zustände den Komma-Operator nicht enthalten.

Ich bin hier sehr allgemein, aber Sie können alle Details im Wiki nachlesen.

  • Meine Kinder nehmen das nicht als Antwort, warum sollte das OP … aber das ist der Grund, weil der mehrdeutige Fall verboten ist.

    – Grady-Spieler

    29. Juni 2013 um 20:28 Uhr

1394190cookie-checkWoher weiß der Compiler, dass das Komma in einem Funktionsaufruf kein Kommaoperator ist?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy