2016-08-12 2 views
1

Ich lese gerade "Programmierung: Prinzipien und Praxis mit C++" von Bjarne Stroustrup und ich habe Probleme zu verstehen, wie diese bestimmte Grammatik implementiert ist. HierWie funktioniert dieser C++ Parser?

ist die Grammatik und seine Regeln:

Expression: 
    Term 
    Expression "+" Term 
    Expression "-" Term 
Term: 
    Primary 
    Term "*" Primary 
    Term "/" Primary 
    Term "%" Primary 
Primary: 
    Number 
    "(" Expression ")" 
Number: 
    floating-point literal 

Dies ist jedoch, wie Zeit implementiert:

double term() 
{ 
    double left = primary(); 
    Token t = ts.get();  // get the next token from token stream 

    while(true) { 
     switch (t.kind) { 
     case '*': 
      left *= primary(); 
      t = ts.get(); 
      break; 
     case '/': 
     { 
      double d = primary(); 
      if (d == 0) error("divide by zero"); 
      left /= d; 
      t = ts.get(); 
      break; 
     } 
     default: 
      ts.putback(t);  // put t back into the token stream 
      return left; 
    } 
    } 
} 

Warum wir in der switch-Anweisung, left *= primary(); nennen, wenn das Token gleich "*" anstelle von left *= term()?

Ich habe versucht, left *= primary(); durch left *= term() zu ersetzen (tat das gleiche für Division) und das Programm funktionierte immer noch gut. Ich verstehe jedoch nicht die Design-Entscheidung, die Bjarne im Sinn hatte, das heißt, warum er die Funktion so implementiert hat, wie er es getan hat. Vielleicht vermisse ich hier etwas?

Vielen Dank im Voraus!

+3

Dies ist keine "C++ Grammatik". Dies ist ein in C++ implementierter Parser. – EJP

+0

@BeyelerStudios: Das hat nichts mit der Reihenfolge der Auswertung zu tun. [Es ist wichtig, die Bewertungsreihenfolge nicht zu verwechseln.] (Http://programmers.stackexchange.com/a/300808/17853) –

Antwort

0

Warum wir in der switch-Anweisung, rufen left *= primary(); wenn das Token zu "*" gleich, statt left *= term()?

Da die Grammatik sagt:

Term: 
    Primary 
    Term "*" Primary 
    Term "/" Primary 
    Term "%" Primary 

Beachten Sie, dass, wenn C++ (und C) hatte einen Potenzierungsoperator, oder seine Beispielgrammatik hatte unäre Operatoren, was Sie gesehen hätten, ist das üblichere:

Expression: 
    Term 
    Expression "+" Term 
    Expression "-" Term 
Term: 
    Factor 
    Term "*" Factor 
    Term "/" Factor 
    Term "%" Factor 
Factor: 
    Primary 
    Primary "**" Factor /* note right-associativity */ 
Primary: 
    "+" Primary 
    "-" Primary 
    Number 
    "(" Expression ")" 
Number: 
    floating-point literal 
+0

Diese Grammatik erlaubt "+ - + - + - + 5". Ich denke, Sie brauchen '" + "Nummer (und ähnlich für minus. –

+0

@MartinBonner Korrekt. Es ist absichtlich.' - (- (- 5)) 'ist legal C zum Beispiel. Ihr Vorschlag würde es illegal machen. – EJP

+0

Oh I siehe Unary plus ist jedoch nicht für verallgemeinerte Ausdrücke legal: '+ (+ (+ 5))' ist nicht legal und wie gesagt "- - 5" ist auch nicht legal. Schlussfolgerung: Die Grammatik ist etwas komplexer! –

-1

Weil die Produktion nicht Term "*" Term ist.

Es ist Term "*" Primary.

Der Grund dafür in der Grammatik selbst ist so, dass, wenn Sie verschachtelte Term s im Ausdruck haben, sie gezwungen sind, auf der linken Seite aus einer Parsing-Perspektive "erscheinen". Die rechte Seite ist effektiv davon überzeugt, nur primäre Ausdrücke zu enthalten (die keine anderen Operatoren enthalten). Wenn dies angewendet wird, um Ihr "Programm" rekursiv zu analysieren, ist das Ergebnis, dass die Operatoren linksassoziativ sind, was zu ((a*b)*c) anstelle von (a*(b*c)) führt.

Eine solche Grammatik wird nur "nach unten" gehen, nicht "nach oben", sonst landen Sie in einer großen Unordnung oder zumindest einer unnatürlichen Assoziativität, die Menschen verwirrt, die versuchen, in Ihrer Sprache Arithmetik zu schreiben.

Natürlich ist das arithmetische Ergebnis für die Multiplikation theoretisch gleich. Wenn Sie jedoch verschiedene Operatoren verwenden, wird das Problem klar: ((a*b)/c) ist nicht dasselbe wie (a/(b*c)).

+0

Die Tatsache, dass 'primary' keine anderen Operatoren enthält, ist irrelevant. Was relevant ist, ist, dass es eine höhere Priorität hat als das nicht-terminale Symbol, in dem die Regel, in der es erscheint, ein Teil von ist. Betrachten Sie zum Beispiel "Ausdruck: Term" + "Term". – EJP

+0

@EJP: Die Tatsache, dass 'Primary' keine anderen Operatoren enthält, ist der Grund für diesen Unterschied, nein? Grammar-Produktionen haben keinen Vorrang; Betreiber tun. Tatsache ist, dass '*' linksassoziativ gemacht wird, indem die Grammatik kein anderes '*' auf der RHS eines 'Terms' zulässt (indem man nur eine' Primary' und eine 'Primary' keine Produktion zulässt) Äußerungen '*'). –

+0

Nein. Die Vorrangstellung des Operators ist fest in dieser Grammatik eingebettet, ohne dass weitere Notationen erforderlich sind. [Sie haben "Expression: Term" + "Term" nicht wie vorgeschlagen berücksichtigt. Es ist ein Beispiel für ein untergeordnetes Nicht-Terminal, das Operatoren enthält.] – EJP