Search code examples
compiler-constructionyacc

Yacc prints a different union variable than the one specified


I am trying to implement a calculator in flex/yacc that will also support real numbers ( i have not implemented them yet). But for some reason instead of printing the value of the expression my code only prints the type of the expression which is 1 for integers. Here's the flex file

%{

#include <stdio.h>
#include "y.tab.h"
int c;
%}
%%
" "       ;
[a-z]     {
            c = yytext[0];
            yylval.a = c - 'a';
            return(LETTER);
          }
[0-9]     {
            c = yytext[0];
            yylval.a = c - '0';
            return(DIGIT);
          }
[^a-z0-9\b]    {
                 c = yytext[0];
                 return(c);
              }
%%

And here's the yacc file

%{
#include <stdio.h>
#include <math.h>

int iregs[26];
double dregs[26];
char type[26];
int base = 10;

void yyerror(char*);
int yywrap();
int yyparse();
int yylex();
%}

%start list

%union 
{ 
  int a; 
  double b;
  char type; /* 0 for double , 1 for integer */
}


%token DIGIT LETTER

%left '|'
%left '&'
%left '+' '-'
%left '*' '/' '%'
%left UMINUS  /*supplies precedence for unary minus */

%%                   /* beginning of rules section */

list:                       /*empty */
         |
        list stat '\n'
         |
        list error '\n'
         {
           yyerrok;
         }
         ;
stat:    expr
         {
           if($1.type) {
             printf("%d\n",$1.a);
           }
           else {
             printf("%f\n",$1.b);
           }
         }
         |
         LETTER '=' expr
         {
           if($3.type) {
             iregs[$1.a] = $3.a;
             type[$1.a] = 1;
           }
           else {
             dregs[$1.a] = $3.b;
             type[$1.a] = 0;
           }
         }
         ;
expr:    '(' expr ')'
         {
           $$ = $2;
         }
         |
         expr '*' expr
         {
           if($1.type && $3.type) { /* both integers */
             $$.a = $1.a * $3.a;
             $$.type = 1;
           }
           else if (!$1.type && !$1.type) { /* both doubles */
             $$.b = $1.b * $3.b;
             $$.type = 0;
           }
           else if ($1.type && !$3.type) { /* first integer second double */
             $$.b = $1.a * $3.b;
             $$.type = 0;
           }
           else { /* first double second integer */
             $$.b = $1.b * $3.a;
             $$.type = 0;
           }
         }
         |
         expr '/' expr
         {
           if($1.type && $3.type) { /* both integers */
             $$.a = $1.a / $3.a;
             $$.type = 1;
           }
           else if (!$1.type && !$1.type) { /* both doubles */
             $$.b = $1.b / $3.b;
             $$.type = 0;
           }
           else if ($1.type && !$3.type) { /* first integer second double */
             $$.b = $1.a / $3.b;
             $$.type = 0;
           }
           else { /* first double second integer */
             $$.b = $1.b / $3.a;
             $$.type = 0;
           }
         }
         |
         expr '%' expr
         {
           if($1.type && $3.type) { /* both integers */
             $$.a = $1.a % $3.a;
             $$.type = 1;
           }
           else { /* at least one double */
             yyerror("% is applied to integers only");
           }
         }
         |
         expr '+' expr
         {
           if($1.type && $3.type) { /* both integers */
             $$.a = $1.a + $3.a;
             $$.type = 1;
           }
           else if (!$1.type && !$1.type) { /* both doubles */
             $$.b = $1.b + $3.b;
             $$.type = 0;
           }
           else if ($1.type && !$3.type) { /* first integer second double */
             $$.b = $1.a + $3.b;
             $$.type = 0;
           }
           else { /* first double second integer */
             $$.b = $1.b + $3.a;
             $$.type = 0;
           }
         }
         |
         expr '-' expr
         {
           if($1.type && $3.type) { /* both integers */
             $$.a = $1.a - $3.a;
             $$.type = 1;
           }
           else if (!$1.type && !$1.type) { /* both doubles */
             $$.b = $1.b - $3.b;
             $$.type = 0;
           }
           else if ($1.type && !$3.type) { /* first integer second double */
             $$.b = $1.a - $3.b;
             $$.type = 0;
           }
           else { /* first double second integer */
             $$.b = $1.b - $3.a;
             $$.type = 0;
           }
         }
         |
         expr '&' expr
         {
           if($1.type && $3.type) { /* both integers */
             $$.a = $1.a & $3.a;
             $$.type = 1;
           }
           else { /* at least one double */
             yyerror("& is applied to integers only");
           }
         }
         |
         expr '|' expr
         {
           if($1.type && $3.type) { /* both integers */
             $$.a = $1.a | $3.a;
             $$.type = 1;
           }
           else { /* at least one double */
             yyerror("| is applied to integers only");
           }
         }
         |

        '-' expr %prec UMINUS
         {
           if($2.type) {
             $$.a = -$2.a;
             $$.type = 1;
           }
           else {
             $$.b = -$2.b;
             $$.type = 0;
           }
         }
         |
         LETTER
         {
           if(type[$1.a]) {
             $$.a = iregs[$1.a];
             $$.type = 1;
           }
           else {
             $$.b = dregs[$1.a];
             $$.type = 0;
           }
         }
         |
         integer
         {
           $$.a = $1.a;
           $$.type = 1;
         }
         ;

integer:  DIGIT
         {
           $$.a = $1.a;
         }       
         |
         integer DIGIT
         {
           $$.a = base * $1.a + $2.a;
         }
         ;

%%
int main()
{
 return(yyparse());
}

void yyerror(s)
char *s;
{
  fprintf(stderr, "%s\n",s);
}

int yywrap()
{
  return(1);
}

Because i am using integers in my test file this code only prints 1 no matter what expression i use and i cant figure out why.


Solution

  • Each token and grammar rule can use only one value from the union and not the whole union as a struct.