2016-04-23 10 views
0

Edit # 1: Ich denke, das Problem ist in meiner .l-Datei. Ich glaube nicht, dass die Regeln als Regeln behandelt werden, und ich bin mir nicht sicher, wie man die Terminals der Regeln als Strings behandeln soll.Flex und Yacc Grammatik Ausgabe

Mein letztes Projekt für eine Compiler-Klasse ist das Schreiben einer .l- und einer .y-Datei für eine einfache SQL-Grammatik. Ich habe keine Erfahrung mit Flex oder Yacc, also habe ich alles, was ich geschrieben habe, zusammengefügt. Ich habe nur ein grundlegendes Verständnis davon, wie diese Dateien funktionieren. Wenn Sie also mein Problem erkennen, können Sie auch erklären, was dieser Teil der Datei tun soll? Ich bin mir nicht einmal sicher, was die '%' Symbole tun.

Grundsätzlich funktionieren einige Regeln einfach nicht, wenn ich versuche, etwas zu analysieren. Einige Regeln hängen und andere lehnen ab, wenn sie akzeptieren sollten. Ich brauche die folgende Grammatik implementieren:

start 
    ::= expression 

expression 
    ::= one-relation-expression | two-relation-expression 

one-relation-expression 
    ::= renaming | restriction | projection 

renaming 
    ::= term RENAME attribute AS attribute 

term 
    ::= relation | (expression) 

restriction 
    ::= term WHERE comparison 

projection 
    ::= term | term [ attribute-commalist ] 

attribute-commalist 
    ::= attribute | attribute , attribute-commalist 

two-relation-expression 
    ::= projection binary-operation expression 

binary-operation 
    ::= UNION | INTERSECT | MINUS | TIMES | JOIN | DIVIDEBY 

comparison 
    ::= attribute compare number 

compare 
    ::= < | > | <= | >= | = | <> 

number 
    ::= val | val number 

val 
    ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 

attribute 
    ::= CNO | CITY | CNAME | SNO | PNO | TQTY | 
      SNAME | QUOTA | PNAME | COST | AVQTY | 
      S# | STATUS | P# | COLOR | WEIGHT | QTY 

relation 
    ::= S | P | SP | PRDCT | CUST | ORDERS 

Hier meine .l Datei ist:

%{ 
#include <stdio.h> 
#include "p5.tab.h" 
%} 
binaryOperation  UINION|INTERSECT|MINUS|TIMES|JOIN|DIVIDEBY 
compare   <|>|<=|>=|=|<> 
attribute  CNO|CITY|CNAME|SNO|PNO|TQTY|SNAME|QUOTA|PNAME|COST|AVQTY|S#|STATUS|P#|COLOR|WEIGHT|QTY 
relation  S|P|SP|PRDCT|CUST|ORDERS 
%% 
[ \t\n]+  ; 
{binaryOperation} return binaryOperation; 
{compare}  return compare; 
[0-9]+   return val; 
{attribute}  return attribute; 
{relation}  return relation; 
"RENAME"  return RENAME; 
"AS"   return AS; 
"WHERE"   return WHERE; 
"("   return '('; 
")"   return ')'; 
"["   return '['; 
"]"   return ']'; 
","   return ','; 
.   {printf("REJECT\n"); 
       exit(0);} 
%% 

Hier meine .y-Datei ist:

%{ 
#include <stdio.h> 
#include <stdlib.h> 
%} 
%token RENAME attribute AS relation WHERE binaryOperation compare val 
%% 

start: 
    expression   {printf("ACCEPT\n");} 
    ; 

expression: 
    oneRelationExpression 
    | twoRelationExpression 
    ; 

oneRelationExpression: 
    renaming 
    | restriction 
    | projection 
    ; 

renaming: 
    term RENAME attribute AS attribute 
    ; 

term: 
    relation 
    | '(' expression ')' 
    ; 

restriction: 
    term WHERE comparison 
    ; 

projection: 
    term 
    | term '[' attributeCommalist ']' 
    ; 

attributeCommalist: 
    attribute 
    | attribute ',' attributeCommalist 
    ; 

twoRelationExpression: 
    projection binaryOperation expression 
    ; 

comparison: 
    attribute compare number 
    ; 

number: 
    val 
    | val number 
    ; 

%% 

yyerror() { 
    printf("REJECT\n"); 
    exit(0); 
} 

main() { 
    yyparse(); 
} 

yywrap() {} 

Hier ist mein Make-Datei:

p5: p5.tab.c lex.yy.c 
    cc -o p5 p5.tab.c lex.yy.c 

p5.tab.c: p5.y 
    bison -d p5.y 

lex.yy.c: p5.l 
    flex p5.l 

Dies funktioniert:

S RENAME CNO AS CITY

Diese nicht:

S

S WHERE CNO = 5

ich alles nicht getestet haben, aber Ich denke, dass es ein gemeinsames Problem für diese Probleme gibt.

Antwort

1

Ihre Grammatik ist korrekt, das Problem ist, dass Sie interaktiv laufen. Wenn Sie yyparse() aufrufen, versucht es alle Eingaben zu lesen. Da der Eingang

S

könnte entweder durch RENAME oder WHERE folgen wird es nicht akzeptieren. In ähnlicher Weise

S WHERE CNO = 5

könnte durch eine oder mehr Zahlen folgen, so yyparse wird nicht akzeptieren, bis sie ein EOF oder ein unerwartetes Token erhält.

Was möchten Sie tun, befolgen Sie die Ratschläge here und p5.l diese Zeilen zu haben, ändern:

[ \t]+  ; 
\n   if (yyin==stdin) return 0; 

Auf diese Weise, wenn Sie ausführen, interaktiv wird es dauern, die ENTER-Taste das Ende der Eingabe zu sein .

Außerdem möchten Sie left recursion für Nummer verwenden:

number: 
    val 
    | number val 
    ; 
+0

Danke, es funktioniert viel besser. Ich habe allerdings ein paar Fragen. Was ist die Überprüfung der if-Anweisung? Ich bin mir nicht sicher, was 'yyin == stdin' bedeutet. Auch jetzt geht das Programm nach einem ab, was wenn ich mehr Befehle eingeben möchte? – Pareod

+0

'yyin == stdin' überprüft, ob die Eingabe von der Standardeingabe kommt, was wir (vielleicht fälschlicherweise) annehmen, dass sie eingegeben wird. In diesem Fall nehmen wir an, dass es das Ende der Eingabe ist. Wenn Sie mehr als eine Zeile akzeptieren möchten, sollten Sie 'yyparse' in eine Schleife einfügen. Alternativ könnten Sie ein ';' nach einem Ausdruck, nur aus Dateien lesen, oder eine Phantasie [repl so] (http://stackoverflow.com/questions/6636808/repl-for-interpreter-using-flex-bison). –