2017-04-19 4 views
-1

J'essaye de construire un analyseur pour mon propre mini-langage, qui est ensuite traduit en C++ par YACC lui-même. Le problème est que YACC lit la première ligne d'entrée ainsi que le premier jeton de la deuxième ligne de l'entrée et l'associe à la règle correspondante, alors qu'il aurait dû lire uniquement les jetons dans la première ligne d'entrée et identifié avec la règle correspondanteLEX + YACC prenant un jeton dans la ligne suivante pour une règle

Mon fichier d'entrée est:

print "hello" 
a = 10 
print a 

fichier Lex:

%{ 
    #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; 
%% 

fichier YACC est:

%{ 
    #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; 
} 

sortie prévue est:

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

Mais ne analyse syntaxique, avec une sortie partielle:

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

Et message d'erreur:

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

Les règles utilisées pour réduire sont censés être (dans le même er):

PRINT STRING 
ID ASSIGN INTEGER 
PRINT ID 

mais, la première règle étant utilisée pour réduire est:

PRINT STRING ID 

et l'analyse syntaxique échoue

ID est dans la ligne suivante, après PRINT STRING, mais toujours la règle utilisé est PRINT STRING ID.

J'ai donné une priorité moindre à STRING sur ID (je suppose que c'est ce que le code ci-dessous signifie)

%nonassoc STRING 
%nonassoc ID 

Est-ce le problème?

Je n'arrive pas à comprendre ce qui se passe. Est-ce que je manque quelque chose?

Répondre

2

Un de vos actions d'impression valides est

PRINT STRING ID 

Votre entrée correspond à cette action, mais immédiatement après cette entrée est un signe =, que l'analyseur ne peut pas correspondre comme le début d'une autre action.

Il semble que vous vouliez que les nouvelles lignes délimitent vos actions. Par conséquent, vous devez créer explicitement un jeton de fin d'action, mettre à jour votre grammaire afin que vos actions se terminent avec ce jeton et que le lexeur génère le jeton lorsqu'il voit un saut de ligne.

+0

Vous voulez dire, renvoyez un jeton, dites NEWLINE pour chaque \ n et utilisez les règles telles que PRINT STRING NEWLINE et ID ASSIGN INTEGER NEWLINE? –

+0

@Abhilashk - oui, exactement – antlersoft