Print tokens properly using Lex and Yacc

2019-09-10 07:17发布

问题:

I'm having difficulties printing a sequence of tokens that behaves recursively. To better explain, I will show the sections of the corresponding codes: First, the code on Lex:

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

   installID(){
   }

%}

abreparentese           "("
fechaparentese          ")"
pontoevirgula           ";"
virgula                 ","
id                      {letra}(({letra}|{digito})|({letra}|{digito}|{underline}))*
digito                  [0-9]
letra                   [a-z|A-Z]
porreal                 "%real"
portexto                "%texto"
porinteiro              "%inteiro"
leia                    "leia"

%%

{abreparentese}     { return ABREPARENTESE; }
{fechaparentese}    { return FECHAPARENTESE; }
{pontoevirgula}     { return PONTOEVIRGULA; }
{virgula}           { return VIRGULA; }
{id}                { installID();
                      return ID; }
{porinteiro}        { return PORINTEIRO; }
{porreal}           { return PORREAL; }
{portexto}          { return PORTEXTO; }
{leia}              { return LEIA;}

%%

int yywrap() {
   return 1;
}

Now, the code on Yacc:

%{
   #include <stdio.h>
   #include <stdlib.h>
   #include <string.h>
   #include <stdbool.h>
   #define YYSTYPE char*
   int yylex(void);
   void yyerror(char *);
   extern FILE *yyin, *yyout;
   extern char* yytext;
%}

%token ABREPARENTESE FECHAPARENTESE PONTOEVIRGULA VIRGULA ID PORREAL PORTEXTO PORINTEIRO LEIA
%%
programs : programs program
      | program
      | ABREPARENTESE {fprintf(yyout,"%s",yytext);}
      | FECHAPARENTESE {fprintf(yyout,"%s",yytext);}
      ;

program:
     leia
;

leia: 
    LEIA ABREPARENTESE entradas ids FECHAPARENTESE PONTOEVIRGULA
  {
    fprintf(yyout,"scanf(\"%s\",%s);",$3,$4);
  }
;

 entradas:
      tipo_entrada VIRGULA entradas {fprintf(yyout,"%s,",$1);}
      | tipo_entrada VIRGULA {fprintf(yyout,"%s", $1); }
 ;

 tipo_entrada:   
            | PORREAL {$$ = "%f";}
            | PORTEXTO {$$ = "%c";}
            | PORINTEIRO {$$ = "%d";}
 ;

 ids:    
       id VIRGULA ids {fprintf(yyout,"&%s,",$1);} 
       | id {fprintf(yyout,"&%s",$1);}
 ;

 id:
    ID {$$ = strdup(yytext);}
 ;

 %%
 void yyerror(char *s) {
fprintf(stderr, "%s\n", s);
}

int main(int argc, char *argv[]){
   yyout = fopen(argv[2],"w");
   yyin = fopen(argv[1], "r");
   yyparse();
   return 0;
}

I believe I have copied all the relevant part of my problem on the code (some things maybe I forgot to copy and paste), however my problem is this part of the code:

leia: LEIA ABREPARENTESE entradas ids FECHAPARENTESE PONTOEVIRGULA
  {

    fprintf(yyout,"scanf(\"%s\",%s);",$3,$4);


  }
;

In the input file, I have the following line:

leia (%real, %inteiro, id1, id2);

The expectation was this on the output file:

scanf("%f,%d",&id1,&id2);

But actually this is the result in the output file:

%d%f,&id2&id1,scanf("%f",id1);

Can you help me solve this problem? How do I print the tokens in the right place?

回答1:

Normally, with bottom-up parsing, we use left-recursive productions, which has the result that the productions are reduced from left to right.

When you use right recursion, then productions are stacked up until the end, and then popped off the stack and therefore reductions are executed right-to-left.

So for example, it would be more usual to write:

 ids: id
    | ids ',' id

and then the semantic rules will execute in the expected order.



标签: yacc lex