borncrusader
borncrusader

Reputation: 263

flex/bison interpreting numbers as floats

I'm trying a implement a flex/bison calculator which can do floating point arithmetic. My flex code looks like this

%{
#include "calc.tab.h"
#include <stdlib.h>

void yyerror(char *s);
%}

digit [0-9]
integer {digit}+
real ({digit}+[.]{digit}*)|({digit}*[.]{digit}+)
exp ({integer}|{real})[eE]-?{integer}

%%

({integer}|{real}|{exp}) { yylval = atof(yytext); return NUMBER; }
[-+*/\n]                 { return *yytext; }
[ \t\v\f\r]              { }
.                        { yyerror("Unknown Character"); }

%%

int yywrap(void)
{
  return 1;
}

And my bison code looks like this

%{
#include <stdio.h>

typedef double YYSTYPE;
#define YYSTYPE_IS_DECLARED

void yyerror(char *s);
extern char *yytext;
extern int yylineno;
%} 

%token NUMBER

%left '+' '-'
%left '*' '/'

%%

program: program expr '\n' { printf("%g\n", $2); }
       | program '\n'
       |
       ;
expr: expr '+' expr { $$ = $1 + $3; }
    | expr '-' expr { $$ = $1 - $3; }
    | expr '*' expr { $$ = $1 * $3; }
    | expr '/' expr { $$ = $1 / $3; }
    | NUMBER { $$ = $1; }
    ;

%%

void yyerror(char *s)
{
  fprintf(stderr, "error: %s at %s, line %d\n", s, yytext, yylineno);
}

int main(int argc, char *argv[])
{
  yyparse();

  return 0;
}

This doesn't produce the right output. Even though the lexer interprets the strings as doubles and stores them properly in the yylval variable, when the parser adds up the numbers, it spits out only 0.0000. However, if I declare yylval as a union through the %union directive consisting of only one double lf_val; variable, and store the atof output in this field of yylval in the lexer and also declare %token <lf_val> NUMBER and %type <lf_val> expr in the parser, things seem to work.

But, why doesn't the straightforward method of typedefing YYSTYPE work? I also tried #define YYSTYPE double. That didn't work either.

Upvotes: 4

Views: 7774

Answers (1)

yroeht
yroeht

Reputation: 121

Concerning %code, Bison's documentation states:

%code requires [...] is the best place to override Bison's default YYSTYPE
and YYLTYPE definitions.

So juste add the following at the top of you bison file:

%code requires
  {
    #define YYSTYPE double
  }

You will also want to remove these two lines:

typedef double YYSTYPE;
#define YYSTYPE_IS_DECLARED

Note that YYSTYPE_IS_DECLARED is, as far as I know, not documented anywhere and is thus for Bison's internal use only.

If you are not familiar with the use of Bison's %code directives over simple %{ prologues, you might find this section of the documentation interesting to read.

Upvotes: 5

Related Questions