【问题标题】:3 Address Code Generation using lex and yacc3 使用 lex 和 yacc 生成地址代码
【发布时间】:2016-03-09 12:12:45
【问题描述】:

我正在尝试生成与基本算术表达式相对应的 3 个地址代码。我以前没有使用过 lex 和 yacc 工具(新手),我无法理解两者之间的控制/命令流,即两个程序如何交互。

lex.l

%{
    #include<stdio.h>
    #include"y.tab.h"
    int k=1;
%}

%%
[0-9]+ {
yylval.dval=yytext[0];
return NUM;
}

\n {return 0;}
. {return yytext[0];}
%%

void yyerror(char* str)
{
        printf("\n%s",str);
}
char *gencode(char word[],char first,char op,char second)
{
    char temp[10];
    sprintf(temp,"%d",k);
    strcat(word,temp);
    k++;
    printf("%s = %c %c %c\n",word,first,op,second);

    return word; //Returns variable name like t1,t2,t3... properly
}
int yywrap()
{
    return 1;
}

main()
{
        yyparse();
        return 0;
}

yacc.y

%{
#include<stdio.h>
int aaa;
%}

%union{
    char dval;
}

%token <dval> NUM
%type <dval> E
%left '+' '-'
%left '*' '/' '%'

%%
statement : E {printf("\nt = %c \n",$1);}
          ;

E : E '+' E 
    {   
        char word[]="t";
        char *test=gencode(word,$1,'+',$3);
        $$=test;

    }
  | E '-' E 
    {
        char word[]="t";
        char *test=gencode(word,$1,'-',$3);
        $$=test;
    }
  | E '%' E 
    {
        char word[]="t";
        char *test=gencode(word,$1,'%',$3);
        $$=test;
    }
  | E '*' E 
    {
        char word[]="t";
        char *test=gencode(word,$1,'*',$3);
        $$=test;
    }
  | E '/' E 
    {
        char word[]="t";
        char *test=gencode(word,$1,'/',$3);
        $$=test;
    }
  | '(' E ')' 
    {
        $$=$2;
    }
  | NUM 
    {
        $$=$1;
    }
  ;
%%

问题getting garbage value in output

表达式 (2+3)*5 的预期输出应类似于:

t1= 2 + 3
t2= t1 * 5

得到的输出:

t1= 2 + 3
t2= garbage value * 5

我无法弄清楚如何纠正这个问题。 lex.l 中的 gencode() 方法正确返回了变量名称(例如 t1,t2,t3 )

char *test=gencode(word,$1,'%',$3);

但我完全不知道在那之后出了什么问题。我相信我没有正确处理$$,$1,$3 条款。


请帮助我了解出了什么问题、需要做什么以及如何去做。 一点帮助和一些解释将非常有帮助。谢谢。

【问题讨论】:

    标签: yacc lex


    【解决方案1】:

    这里的问题不在于使用 flex 或 bison;相反,它是 C 代码中的未定义行为。

    您的gencode 函数返回它的第一个参数。然后你大致这样称呼它:

    {
      char word[] = ...
      ... = gencode(word, ...);
    }
    

    word 的生命周期在块完成时结束,即在调用 gencode 之后。实际上,这与经典的悬空指针生成器没有什么不同:

    char* dangle(void) {
      char temporary[] = "some string";
      return temporary;
    }
    

    这显然是不正确的,因为局部变量在其地址被返回之前就已经不存在了。

    此外,您实际上将word 创建为两个字符的数组:

    char word[] = "t";
    

    因为省略大小告诉 C 为初始字符串(一个字符加上空终止符)留出足够的空间。这很好,但是你不能追加更多字符到字符串(strcat),因为没有剩余空间,你最终会覆盖一些其他变量(或更糟)。

    【讨论】:

    • 我认为stackoverflow.com/a/25799033/3728336 讨论了您所指的问题。它建议在将字符串传递给函数之前在调用方的堆栈上分配字符串。通过这样做,即使函数返回,char 数组的生命周期也不会结束。这就是我在调用函数之前声明 char word[] 的原因。这个ideone.com/RBz0y2 是我单独编写的代码,也在这里使用过。不对吗?
    • @novice:如果 caller 在堆栈上分配并传递给被调用函数,那很好。 调用者 仍然有内存。但是一旦调用者返回到 its 调用者,内存就消失了。您不能将持久变量设置为地址。所以,不,这是不对的。如果您需要保留该值以备将来使用,则需要使用malloc 进行分配;堆栈分配的存储将不起作用。
    【解决方案2】:

    即使函数返回,mentall 也不会结束。这就是我在调用函数之前声明 char word[] 的原因。这个 ideone.com/RBz0y2 是我单独编写并在这里使用的代码。不对吗? – Swagnik Dutta 2016 年 3 月 9 日在 16:38 @novice:如果调用者在堆栈上分配并传递给被调用的函数,那很好。调用者仍然有记忆。但是一旦调用者返回到它的调用者,内存就消失了。您不能将持久变量设置为地址。所以,不,这是不对的。如果您需要为将来保留该值,则需要使用 malloc 进行分配;堆栈分配存储

    【讨论】:

      猜你喜欢
      • 2013-11-27
      • 2012-05-21
      • 2015-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-25
      • 2011-11-05
      相关资源
      最近更新 更多