使用Lex和Yacc正确打印令牌

时间:2016-03-10 16:13:57

标签: yacc lex

我在打印一系列递归行为的令牌时遇到困难。为了更好地解释,我将展示相应代码的部分:首先,Lex上的代码:

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

现在,Yacc上的代码:

leia: LEIA ABREPARENTESE entradas ids FECHAPARENTESE PONTOEVIRGULA
  {

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


  }
;

我相信我已经在代码中复制了我的问题的所有相关部分(有些事情我可能忘记复制和粘贴),但是我的问题是这部分代码:

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

在输入文件中,我有以下一行:

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

期望是输出文件:

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

但实际上这是输出文件中的结果:

Sheet1.Cells.Clear

Dim i As Integer
Dim rng as Range
Set rng = Range("A1:E8")
For i = 1 To 40
    rng
Next    
你可以帮我解决这个问题吗?如何在正确的位置打印令牌?

1 个答案:

答案 0 :(得分:0)

通常情况下,使用自下而上的解析,我们使用左递归制作,结果是制作从左到右缩小。

当你使用正确的递归时,生产会堆积到最后,然后从堆栈中弹出,因此从右到左执行缩减。

因此,例如,更常见的是写:

 ids: id
    | ids ',' id

然后语义规则将按预期顺序执行。