2016-05-17 9 views
0

Dies ist keine Hausaufgaben, obwohl es aus einem Buch ist.kann nicht herausfinden, warum Yacc/Bison Grammatik nicht funktioniert

Ich habe eine YACC/Bison Spec-Datei. Die Aufgabe ist eine neue Produktions

number -> number digit 
digit -> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 

hinzuzufügen, um den Wert einer Zahl zu berechnen und tun, weg mit einem NUMBER Token. Die Grammatik ist unten angegeben.

%{ 
#include <stdio.h> 
#include <ctype.h> 

int yylex(); 
int yyerror(); 
%} 

%token NUMBER 

%% 

command : exp { printf("%d\n", $1); } 
     ; /* allows printing of the result */ 

exp : exp '+' term { $$ = $1 + $3; } 
    | exp '-' term { $$ = $1 - $3; } 
    | term { $$ = $1; } 
    ; 

term : term '*' factor { $$ = $1 * $3; } 
    | factor { $$ = $1; } 
    ; 

factor : NUMBER { $$ = $1; } 
     | '(' exp ')' { $$ = $2; } 
     ; 

%% 

int main() { 
    return yyparse(); 
} 

int yylex() { 
    int c; 
    while((c = getchar()) == ' '); 
    /* eliminate blanks*/ 
    if (isdigit(c)) { 
    ungetc(c, stdin); 
    scanf("%d", &yylval); 
    return (NUMBER); 
    } 
    if (c == '\n') return 0; 
    /* makes the parse stop */ 
    return (c); 
} 

int yyerror(char * s) { 
    fprintf(stderr, "%s\n", s); 
    return 0; 
} /* allows for printing of an error message */ 

Als ein Experiment, um sicherzustellen, dass ich alles tue, richtig beseitigt ich die Nummer Token hinzugefügt, um die folgende Produktion:

number : '1' {$$ = $1;} 

die factor Produktion

geändert
factor : number {$$ = $1;} 

und eliminiert

if (isdigit(c)) { 
    ungetc(c, stdin); 
    scanf("%d", &yylval); 
    return (NUMBER); 
} 

von der yylex() Funktion. Mit anderen Worten sieht die Spec-Datei wie folgt aus:

%{ 
#include <stdio.h> 
#include <ctype.h> 

int yylex(); 
int yyerror(); 
%} 


%% 

command : exp { printf("%d\n", $1); } 
     ; /* allows printing of the result */ 

exp : exp '+' term { $$ = $1 + $3; } 
    | exp '-' term { $$ = $1 - $3; } 
    | term { $$ = $1; } 
    ; 

term : term '*' factor { $$ = $1 * $3; } 
    | factor { $$ = $1; } 
    ; 

factor : number { $$ = $1; } 
     | '(' exp ')' { $$ = $2; } 
     ; 

number : '1' { $$ = $1; } 
     ; 

%% 

int main() { 
    return yyparse(); 
} 

int yylex() { 
    int c; 
    while((c = getchar()) == ' '); 
    /* eliminate blanks*/ 

    if (c == '\n') return 0; 
    /* makes the parse stop */ 
    return (c); 
} 

int yyerror(char * s) { 
    fprintf(stderr, "%s\n", s); 
    return 0; 
} /* allows for printing of an error message */ 

aber nachdem ich den Code auf dem folgenden Ausdruck aus: 1 + 1, erhalte ich eine Antwort von 0.

mir jemand Kommt helfen? Was mache ich falsch?

+0

oh nein, ich von 1 Stimme herabgestuft wurde . Warum ist diese Frage falsch? – flashburn

+1

Wahrscheinlich, weil Debugging-Fragen hier nicht behandelt werden. Sie suchen nach StackOverflow. – Ixrec

+0

@lxrec ich sehe. Ich hatte Angst, dass, wenn ich es auf Überlauf frage, sie mir sagen, es hier zu verschieben. Ich wäre mir passiert. – flashburn

Antwort

3
number : '1' { $$ = $1; } 

Diese besagt, dass der Parser das Terminal '1' (ein einzelnes Zeichen Token) reduzieren kann zu einem number und dass, wenn es so tut, sollte sie den semantischen Wert kopieren.

Sehr gut. Aber was ist der semantische Wert von '1'? Wie bei jedem anderen Token ist es der Wert yylval von yylex, wenn es den Tokentyp zurückgibt. Im ursprünglichen Code, z. B. yylex, wurde scanf("%d", &yylval) verwendet, um den semantischen Wert des Tokens NUMBER festzulegen. Aber in dem neuen Code wird yylex seinen Vertrag nicht erfüllen. Es setzt nie yylval auf irgendetwas, so dass der semantische Wert eines Token, das zurückgegeben wird, nicht definiert ist. (Das ist vollkommen in Ordnung, solange der Parser nie den semantischen Wert des Tokens verwendet. '+' wird keine semantischen Wert entweder gegeben, aber der Parser erwartet nicht ein.)

Im Fall des Tokens '1', der Parser wirklich die Hilfe der Scanner nicht braucht: es ist klar, was der semantische Wert sein sollte:

number : '1' { $$ = 1; } 

Alternativ könnte der Scanner helfen:

if (isdigit(c)) yylval = c - '0'; 
return c; 
+0

Danke für die Eingabe. Eine andere Frage. Angenommen, eine Zahlenproduktion ist definiert als "Zahl: '0' |" '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | 9 ''. Wie würde ich den semantischen Wert in diesem Fall ohne die Verwendung von "if (isidgit (c))" extrahieren? ist es überhaupt möglich? – flashburn

+0

@flashburn: In yacc/bison können Sie keine einzelne Aktion an mehr als eine Produktion anhängen, so dass Sie in diesem Fall zehn Aktionen benötigen. Das sollte Ihnen einen guten Hinweis auf die Lösung geben :) (Und natürlich, wenn der Parser eines dieser Terminals sieht, muss er isdigit nicht aufrufen.) – rici

+0

Worüber ich nicht weiß ist, wo der erkannte Wert ist wird gelagert? Ich habe Schwierigkeiten, die Bedeutung von '$$', '$ 1',' $ 2' und ihre Beziehung zu 'yylval' sowie zu '% union' zu verstehen. Ich würde mich über Hilfe sehr freuen. Vielleicht könnten wir hier ein neues Thema erstellen, um Diskussionen in den Kommentaren zu vermeiden. – flashburn

Verwandte Themen