使用Lex和Yacc正确打印令牌 [英] Print tokens properly using Lex and Yacc

查看:99
本文介绍了使用Lex和Yacc正确打印令牌的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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;
}

现在,Yacc上的代码:

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?

推荐答案

通常,通过自下而上的解析,我们使用左递归乘积,其结果是乘积从左向右递减.

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.

这篇关于使用Lex和Yacc正确打印令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆