yacc: Distinguish Integers from Floating Point Numbers

compiler-theory, yacc

Solution

Basically you can do something like this:

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

struct number
{
  union
  {
    int ival;
    float fval;
  }
  char type;
}

char INT_TYPE = 1;
char FLOAT_TYPE = 2;

%}

%union
{
   struct number value;
}

%token <value> FLOAT INTEGER command exp term factor

int yylex()
{
   ...
   if(f1 == 0)
   {
     yylval.value.type = INT_TYPE;
     yylval.value.ival = 0
   }
   ...
}

and so on..

in this way you can check operands when reducing rules being sure to generate new correct types.. for example:

exp : exp '+' term {
   if ($1.type == INT_TYPE && $3.type == INT_TYPE)
   {
      $$.type = INT_TYPE;
      $$.ival = $1.ival + $3.ival;
   }
   else if ($1.type == INT_TYPE && $3.type == FLOAT_TYPE)
   {
      // this is a sort of implicit conversion to float
      $$.type = FLOAT_TYPE; 
      $$.fval = $1.ival + $3.fval;
   }
   // and so on

}

PS. I did something similar with Flex+Bison, I don't know if everything is supported as well as in Lex+Yacc but I think so..

Problem

I'm supposed to write a program that does 2 + 2 = 4 and 2.2 + 2 = 4.2. I've already done it so that it treats everything as a floating point, but that's "wrong". I have to distinguish them. Here's what I have so far: ``` %{ #include <stdio.h> #include <ctype.h> %} %token <dval> FLOAT %token <ival> INTEGER %union { float dval; int ival; } %type <dval> command exp term factor %% command : exp {printf("%f\n",$1);} ; exp : exp '+' term {$$ = $1 + $3;} | exp '-' term {$$ = $1 - $3;} | term {$$ = $1;} ; term : term '*' factor {$$ = $1 * $3;} | factor {$$ = $1;} ; factor : '(' exp ')' {$$ = $2;} | FLOAT {$$ = $1;} | INTEGER {$$ = $1;} ; %% int main() { return yyparse(); } int yylex() { int c; while( (c=getchar()) == ' '); if( isdigit(c) ) { ungetc(c, stdin); float f1; scanf("%f", &f1); int i1 = (int) f1; if(f1 == 0) { yylval.ival = 0; return INTEGER; } else if( (((float) i1) / f1 ) == 1) { yylval.ival = i1; return INTEGER; } else { yylval.dval = f1; return FLOAT; } //scanf("%f",&yylval.dval); //return(NUMBER); } if(c == '\n') return 0; return c; } int yyerror(char *s) { fprintf(stderr,"%s\n",s); return 0; } ``` The problem I have is that each expression can only have 1 type. Right now everything is basically float, so while the operations are right, this isn't the right solution. I thought about defining more expressions, basically having factor_int and factor_float, and then replacing everything in it, but that seems really wrong. I have no idea how to get this done though, and the tutorials I've seen haven't really helped me.

Original source