Sunday, April 10, 2005

Tough Day, lex and yacc code dissected

today was a tough day. Had to submit record, finished it; but had to skip lunch to finish. After finishing found an easy way with yacc for the intermediate code generator for assignment statement, with just a few lines. Hmmm...
This is the code and explanation
/* calc.lex */
%{
#include
#include
#include "y.tab.h" //needed to obtain represented values for tokens (for example INTEGER is given a number 257 by yacc) and need to be used here
extern int yylval; // this enables to pass values to yacc

%}

DIGIT [0-9]
ID [a-z]
OPR [+-\\*/()]
//guess no problem here
%%
= { return *yytext;;} //returns the char '='
{DIGIT}+ {yylval=atoi(yytext);
return INTEGER; } //sets the value of digit in yylval. When yacc resolves those $x's in case the $x is INTEGER, it reads the value from here.
{ID} { yylval=*yytext-'a'; return IDS;} //same case here. Since my yylval is integer i have to convert char to int this way (by subtracting ascii(a) )
{OPR} {return *yytext;}
[ \n] {return *yytext;}
[ \t] ;
. { fprintf(stderr,"Illegal char %c\n",*yytext); }
%%

/****************************************************************/

/* calc.yacc */

%token INTEGER IDS EQUALS //meaning these are the possible user def tokens
%left '+' '-'
%left '*' '/'
//operator precedence + and - have equal and less precedence than * and / (which have equal precedence)
%{
#include
#include
int tcount=1; //this is same as mktemp function. returns a running var for temp variable(as in dragon book)
%}

%%
program:
IDS '=' expr '\n' { printf("%c=t%d\n",$1+'a',tcount-1);} //assignment statement will always be a=expr\n form.
|
;
expr:
IDS {$$=$1; } //if i have an ID resolved for expression set value of expression to be the value of ID
|expr '+' expr { printf("t%d=",tcount++);
if($1>=50) printf("t%d+",$1-50); else
printf("%c+",$1+'a');
if($3>=50) printf("t%d\n",$3-50); else
printf("%c\n",$3+'a');
$$=50+tcount-1;fflush(stdout);
}
//here if i have a both expr1 and expr2 to be IDS then i have to print tx=a+b where a and b are the IDs resolved.
//in case the expr1 or expr2 are states (i use a convention that if the value of expr1 is >=50, i mean a tempvar rather than ID)
//then print tx instead of some character(i mean ID).
|expr '-' expr {
printf("t%d=",tcount++);
if($1>=50) printf("t%d-",$1-50); else
printf("%c-",$1+'a');
if($3>=50) printf("t%d\n",$3-50); else
printf("%c\n",$3+'a');
$$=50+tcount-1;fflush(stdout);
}
|expr '*' expr {
printf("t%d=",tcount++);
if($1>=50) printf("t%d*",$1-50); else
printf("%c*",$1+'a');
if($3>=50) printf("t%d\n",$3-50); else
printf("%c\n",$3+'a');
$$=50+tcount-1;fflush(stdout);
}
|expr '/' expr {
printf("t%d=",tcount++);
if($1>=50) printf("t%d/",$1-50); else
printf("%c/",$1+'a');
if($3>=50) printf("t%d\n",$3-50); else
printf("%c\n",$3+'a');
$$=50+tcount-1;fflush(stdout);
}
| '('expr')' { $$=$2;}; //if i have a open brackt and close bracket dont worry, the value only is required.
%%
int main(int argc, char **argv)
{
yyparse();
return 0;
}
//////*****************************************************************////////////////////

/* makefile */
//this is the order of compilation
//compile yacc, then lex , then the binary code with gcc
all:yacc lex code
yacc:calc.yacc
yacc -d calc.yacc
lex:calc.lex
lex calc.lex
code: y.tab.c lex.yy.c
gcc -g -o code y.tab.c lex.yy.c -lfl -L /home/cs2k23749/lib -ly
Thats it . If you have any problems, tell me. I guess this should be useful for atleast one soul.

1 comment:

Anonymous said...

hey thats cool.
i was cracking my head until i found your method. i have reduce your code to just 10 lines and it works fine. i got the same thing in my end-sem lab exam and guess what....i finished in 3 mins and 20 seconds :)
thanks
--balaji

Search this site

Google