0

I'm trying to generate 3 address code corresponding to basic arithmetic expressions. I haven't worked with lex and yacc tools before much (Newbie) and I'm having trouble understanding the flow of control/command among the two i.e how the two programs are interacting.

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

Problem: getting garbage value in output

Expected output for expression (2+3)*5 should be like:

t1= 2 + 3
t2= t1 * 5

Obtained output:

t1= 2 + 3
t2= garbage value * 5

I'm unable to figure out how to correct this. The variable names (eg t1,t2,t3 ) are being properly returned from gencode() method in lex.l

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

But I'm completely clueless about what is going wrong after that. I believe I'm not handling the $$,$1,$3 terms correctly.


Please help me understand what is going wrong, what needs to be done and how to do it. A little help and some explanation would be very helpful. Thank you.

Swagnik Dutta
  • 129
  • 1
  • 15

2 Answers2

1

The problem here is not in the use of flex or bison; rather, it is an Undefined Behaviour in your C code.

Your gencode function returns its first argument. Then you call it like this, roughly:

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

The lifetime of word ends when the block finishes, which is right after the call to gencode. In effect, that is no different from the classic dangling pointer generator:

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

which is obviously incorrect, since the local variable ceases to exist before its address is returned.

In addition, you actually create word as a two-character array:

char word[] = "t";

since leaving out the size tells C to leave exactly enough space for the initial string (one character plus null terminator). That's fine, but you cannot then append more characters to the string (with strcat) because there is no space left and you will end up overwriting some other variable (or worse).

rici
  • 234,347
  • 28
  • 237
  • 341
  • I think this http://stackoverflow.com/a/25799033/3728336 discusses the problem you are referring to. It advises to allocate the string on the stack on the caller side before passing it to the function. By doing so lifecycle of the char array won't end even after the function returns. That's why I declared char word[] before calling the function. This http://ideone.com/RBz0y2 is a code I wrote seperately and used it in here too. Is it not right? – Swagnik Dutta Mar 09 '16 at 16:38
  • @novice: If the *caller* allocates on the stack and passes to the called function, that is fine. The *caller* still has the memory. But as soon as the caller returns to *its* caller, the memory is gone. You cannot set a persistent variable to the address. So, no, it is not right. If you need keep the value around for the future, you need to allocate with `malloc`; stack-allocated storage just will not work. – rici Mar 09 '16 at 19:58
-1

mentall n't end even after the function returns. That's why I declared char word[] before calling the function. This ideone.com/RBz0y2 is a code I wrote seperately and used it in here too. Is it not right? – Swagnik Dutta Mar 9 '16 at 16:38 @novice: If the caller allocates on the stack and passes to the called function, that is fine. The caller still has the memory. But as soon as the caller returns to its caller, the memory is gone. You cannot set a persistent variable to the address. So, no, it is not right. If you need keep the value around for the future, you need to allocate with malloc; stack-allocated storage