2017-04-19 3 views
-1

Ich versuche, einen Parser für meine eigene Mini-Sprache zu bauen, die dann in C++ von YACC selbst übersetzt wird.LEX + YACC nimmt Token in der nächsten Zeile für eine Regel

Das Problem ist, YACC liest die erste Zeile der Eingabe sowie das erste Token aus der zweiten Zeile der Eingabe und vergleicht es mit der entsprechenden Regel, während es nur die Token in der ersten Zeile der Eingabe und gelesen hätte angepasst es

mit der entsprechenden Regel

Meine Eingabedatei:

print "hello" 
a = 10 
print a 

Lex-Datei:

%{ 
    #include <stdio.h> 
    #include "y.tab.h" 
%} 

alpha [a-zA-Z] 
digit [0-9] 

%% 
[ \t]       ; 
[ \n]       { yylineno = yylineno + 1;} 
print       {yylval = strdup(yytext); return PRINT;} 
{alpha}({alpha}|{digit})*  {yylval = strdup(yytext); return ID;} 
{digit}+      {yylval = strdup(yytext); return INTEGER;} 
\".*\"       {yylval = strdup(yytext); return STRING;} 
"="        return ASSIGN; 
%% 

YACC Datei ist:

%{ 
    #include <stdio.h> 
    #include <string.h> 
    #include <stdlib.h> 
    extern int yylineno; 
    extern FILE *yyin; 
    extern FILE *yyout; 
    extern char *yytext; 
%} 

%token PRINT INPUT INTO ASSIGN INTEGER DECIMAL BOOLVAL CHARACTER 

%nonassoc STRING 
%nonassoc ID 

%% 
entry: entry action {fprintf(yyout, "\t%s", $2); } 
    | action   {fprintf(yyout, "\t%s", $1); } 
    ; 

action : print   {$$ = $1;} 
    | assign   {$$ = $1;} 
    ; 

print : PRINT ID { 
      printf("rule: PRINT ID"); 
      char* id = strdup($2); 
      strcpy($$, ""); 
      strcat($$,"cout<<"); 
      strcat($$,id); 
      strcat($$,"<<endl;\n"); 
     } 
    | PRINT STRING { 
      printf("rule: PRINT STRING\n"); 
      char* str = strdup($2); 
      strcpy($$, ""); 
      strcat($$,"cout<<"); 
      strcat($$,str); 
      strcat($$,"<<endl;\n"); 
     } 
    | PRINT STRING ID { 
      printf("rule: PRINT STRING ID\n"); 
      char* str = strdup($2); 
      char* id = strdup($3); 
      strcpy($$, ""); 
      strcat($$,"cout<<"); 
      strcat($$,str); 
      strcat($$,"<<"); 
      strcat($$,id); 
      strcat($$,"<<endl;\n"); 
     } 
    ; 

assign: ID ASSIGN INTEGER { 
      char* id = strdup($1); 
      char* val = strdup($3); 
      strcpy($$,""); 
      strcat($$,"int "); 
      strcat($$,id); 
      strcat($$," = "); 
      strcat($$,val); 
      strcat($$,";\n"); 
     } 
    ; 
%% 

int main(int argc, char *argv[]) 
{ 

    yyin = fopen(argv[1], "r"); 
    yyout = fopen("out.txt","w"); 

    if(!yyparse()) 
     printf("\nParsing complete\n"); 
    else 
     printf("\nParsing failed\n"); 

    //fclose(yyin); 
    fclose(yyout); 
    return 0; 
} 

yyerror(char *s) { 
    printf("\n \nLine: %d, Message: %s, Cause: %s\n", yylineno, s, yytext); 
} 

yywrap() 
{ 
    return 1; 
} 

Erwartete Ausgabe lautet:

cout<<"hello"<<endl; 
int a = 10; 
cout<<a<<endl; 

Aber die Analyse fehlschlägt, mit Teilausgabe als:

cout<<"hello"<<a<<endl; 

Und Fehlermeldung:

Line: 2, Message: syntax error, Cause: = 

Die Regeln verwendet reduzieren sollen (in gleicher ord er):

PRINT STRING 
ID ASSIGN INTEGER 
PRINT ID 

aber die erste Regel verwendet wird, zu reduzieren, ist:

PRINT STRING ID 

und das Parsen nicht

ID in der nächsten Zeile ist, nach PRINT STRING, aber immer noch die Regel verwendet wird PRINT STRING ID.

ich eine geringere Priorität zu STRING über ID gegeben habe (ich denke, das ist das, was die folgenden Codemittel)

%nonassoc STRING 
%nonassoc ID 

Ist das das Problem?

Ich kann nicht verstehen, was passiert. Fehle ich etwas?

Antwort

2

Einer Ihrer gültigen Druckaktionen ist

PRINT STRING ID 

Ihre Eingabe dieser Aktion entspricht, sondern unmittelbar im Anschluss an diesen Eingang ist ein = Zeichen, die der Parser kann als Beginn andere Maßnahmen nicht überein.

Es scheint, als ob Sie Zeilenumbrüche benötigen, um Ihre Aktionen zu begrenzen. Daher müssen Sie explizit ein Aktionsende-Token erstellen, Ihre Grammatik aktualisieren, damit Ihre Aktionen mit diesem Token enden, und den Lexer veranlassen, das Token zu generieren, wenn es einen Zeilenumbruch sieht.

+0

Sie meinen, ein Token zurückgeben, NEWLINE für jeden \ n sagen und Regeln wie PRINT STRING NEWLINE und ID ASSIGN INTEGER NEWLINE verwenden? –

+0

@Abhilashk - ja, genau – antlersoft

Verwandte Themen