0
votes

I am implementing calculator using flex and bison, but double values are interpreted as integers, then I was looking for answers on the internet and I realized the mistake was probably that bison interprets numbers as integers, so if I have input "1.2" in *yylval = atof(yytext) is 1 instead of 1.2. So I tried adding #define YYSTYPE double in parser.ypp but I'm getting compiling errors. I know there are several similar questions, but none of them really helped me. Here are my lex and ypp files and compiling errors I get.
Thanks in advance.

lexer.lex:

%option noyywrap
%option noinput
%option nounput

%{
    #include <iostream>
    #include <cstdlib>
    #include <string>
    #include <fstream>

    #include "parser.tab.hpp"

%}

%%

[0-9]+([.][0-9]+)? {
    *yylval = atof(yytext);
        return NUMBER;
}



sin {
    return SIN;
}

cos {
    return COS;
}

tan {
    return TG;
}

tg {
    return TG;
}

ctan {
    return CTG;
}

ctg {
    return CTG;
}

asin {
    return ASIN;
}

acos {
    return ACOS;
}

atan {
    return ATG;
}

actan {
    return ACTG;
}

ln {
    return LN;
}

log {
    return LOG;
}

exp {
    return EXP;
}

sqrt {
    return SQRT;
}

abs {
    return ABS;
}

mod {
    return MOD;
}

[a-z] {
    return VARIABLE;
}

[-+*/^()%!,] {
    return *yytext;
}


[ \t\n] ;

. {

}

parser.ypp:


%{

#define YYSTYPE double


#include <iostream>
#include <cstdlib>
#include <string>
#include <cmath>

 bool indicator_calculating_value ;

extern int yylex();

void yyerror(double *return_value, std::string s);

%}




%parse-param  { double *return_value}

%left '+' '-'
%left '*' '/' '%'
%left SIN COS TG CTG ASIN ACOS ATG ACTG LN LOG MOD
%left UMINUS
%left '^' EXP SQRT
%left ABS
%left '!'


%type <double> E
%token <double> NUMBER
%token <char> VARIABLE;
%start pocetak

%%
pocetak
    : E {
       *return_value = $1;

    };

E   
    : E '+' E {
        if (indicator_calculating_value) {
            $$ = $1 + $3;
        }
    } 
    | E '*' E {

        if (indicator_calculating_value) {
            $$ = $1 * $3;
        }
    }
    | E '-' E {
        if (indicator_calculating_value) {
            $$ = $1 - $3;
        }
    }
    | E '/' E {

        if(indicator_calculating_value) {
            if ($3 == 0) {
                yyerror(0, "divide by zero");
            }
            $$ = $1 / $3;
        }
    }
    | MOD '(' E ',' E ')' {
        if(indicator_calculating_value) {
            if ($5 == 0) {
                yyerror(0, "divide by zero");
            }
            $$ = static_cast<int>($3) % static_cast<int>($5);
        }
    }
    | SIN '(' E ')' {
        if(indicator_calculating_value) {
            $$ = sin($3);
        }
    }
    | COS '(' E ')' {
        if(indicator_calculating_value) {
            $$ = cos($3);
        }
    }
    | TG '(' E ')' {
        if(indicator_calculating_value) {
            $$ = tan($3);
        }
    }
    | CTG '(' E ')' {
        if(indicator_calculating_value) {
            $$ = 1 / tan($3);
        }
    }
    | ASIN '(' E ')' {
        if(indicator_calculating_value) {
            $$ = asin($3);
        }
    }
    | ACOS '(' E ')' {
        if(indicator_calculating_value) {
            $$ = acos($3);
        }
    }       
    | ATG '(' E ')' {
        if(indicator_calculating_value) {
            $$ = atan($3);
        }
    }
    | ACTG '(' E ')' {
        if(indicator_calculating_value) {
            $$ = 1 / atan($3);
        }
    }
    | LN '(' E ')' {
        if(indicator_calculating_value) {
            $$ = log($3);
        }
    }
    | LOG '(' E ',' E ')' {
        if(indicator_calculating_value) {
            $$ = log($5) / log($3);
        }
    }
    | EXP '(' E ')' {
        if(indicator_calculating_value) {
            $$ = exp($3);
        }
    }
    | SQRT '(' E ')' {
        if(indicator_calculating_value) {
            $$ = sqrt($3);
        }
    }
    | E '^' E {
        if(indicator_calculating_value) {
            $$ = pow($1, $3);
        }
    }
    | '-' E %prec UMINUS {
        if(indicator_calculating_value) {
            $$ = -$2;
        }
    } 
    | ABS '(' E ')' {
        if(indicator_calculating_value) {
            $$ = fabs($3);
        }
    }
    | E '!' {
        if(indicator_calculating_value) {
            $$ = 1;
            for (int i = 1; i <= static_cast<int>($1); i++) {
                $$ = $$ * i;
            }
        }
    }
    | '(' E ')' {
        if(indicator_calculating_value) {
            $$ = $2;
        }
    }
    | NUMBER {
        if(indicator_calculating_value) {
            $$ = $1;
        }
    }
    | VARIABLE {

    }
    ;
%%

void yyerror(double *return_value, std::string s)
{
   std::cout << s << std::endl;

}

int main() {

    indicator_calculating_value = true;

    double value = 0.0;
    yyparse(&value);

    std::cout << value << std::endl;



    return 0;
}








errors:

make
bison -d -v parser.ypp
g++ -Wall -L/usr/local/lib -lmgl-qt5 -lmgl -lm  -c -o parser.tab.o parser.tab.cpp
parser.ypp: In function ‘int yyparse(double*)’:
parser.ypp:42:34: error: expected unqualified-id before ‘double’
        *return_value = $1;
                                  ^     
parser.ypp:42:34: error: expected ‘)’ before ‘double’
parser.ypp:49:20: error: expected unqualified-id before ‘double’
             $$ = $1 + $3;
                    ^~~~~~
parser.ypp:49:20: error: expected ‘)’ before ‘double’
parser.ypp:55:20: error: expected unqualified-id before ‘double’
             $$ = $1 * $3;
                    ^~~~~~
parser.ypp:55:20: error: expected ‘)’ before ‘double’
parser.ypp:60:20: error: expected unqualified-id before ‘double’
             $$ = $1 - $3;
                    ^~~~~~
parser.ypp:60:20: error: expected ‘)’ before ‘double’
parser.ypp:66:27: error: expected unqualified-id before ‘double’
             if ($3 == 0) {
                           ^     
parser.ypp:66:27: error: expected ‘)’ before ‘double’
parser.ypp:69:20: error: expected unqualified-id before ‘double’
             $$ = $1 / $3;
                    ^~~~~~
parser.ypp:69:41: error: expected unqualified-id before ‘double’
             $$ = $1 / $3;
                                         ^     
parser.ypp:69:41: error: expected ‘)’ before ‘double’
parser.ypp:69:68: error: expected ‘)’ before ‘;’ token
             $$ = $1 / $3;
                                                                    ^
parser.ypp:74:28: error: expected unqualified-id before ‘double’
             if ($5 == 0) {
                            ^     
parser.ypp:74:28: error: expected ‘)’ before ‘double’
parser.ypp:77:20: error: expected unqualified-id before ‘double’
             $$ = static_cast<int>($3) % static_cast<int>($5);
                    ^~~~~~
parser.ypp:77:58: error: expected unqualified-id before ‘double’
             $$ = static_cast<int>($3) % static_cast<int>($5);
                                                          ^~~~  
parser.ypp:77:58: error: expected ‘)’ before ‘double’
parser.ypp:77:105: error: expected ‘)’ before ‘;’ token
             $$ = static_cast<int>($3) % static_cast<int>($5);
                                                                                                         ^
parser.ypp:77:105: error: expected ‘)’ before ‘;’ token
parser.ypp:82:20: error: expected unqualified-id before ‘double’
             $$ = sin($3);
                    ^~~~~~
parser.ypp:82:20: error: expected ‘)’ before ‘double’
parser.ypp:87:20: error: expected unqualified-id before ‘double’
             $$ = cos($3);
                    ^~~~~~
parser.ypp:87:20: error: expected ‘)’ before ‘double’
parser.ypp:92:20: error: expected unqualified-id before ‘double’
             $$ = tan($3);
                    ^~~~~~
parser.ypp:92:20: error: expected ‘)’ before ‘double’
parser.ypp:97:20: error: expected unqualified-id before ‘double’
             $$ = 1 / tan($3);
                    ^~~~~~
parser.ypp:97:20: error: expected ‘)’ before ‘double’
parser.ypp:102:20: error: expected unqualified-id before ‘double’
             $$ = asin($3);
                    ^~~~~~
parser.ypp:102:20: error: expected ‘)’ before ‘double’
parser.ypp:107:20: error: expected unqualified-id before ‘double’
             $$ = acos($3);
                    ^~~~~~
parser.ypp:107:20: error: expected ‘)’ before ‘double’
parser.ypp:112:20: error: expected unqualified-id before ‘double’
             $$ = atan($3);
                    ^~~~~~
parser.ypp:112:20: error: expected ‘)’ before ‘double’
parser.ypp:117:20: error: expected unqualified-id before ‘double’
             $$ = 1 / atan($3);
                    ^~~~~~
parser.ypp:117:20: error: expected ‘)’ before ‘double’
parser.ypp:122:20: error: expected unqualified-id before ‘double’
             $$ = log($3);
                    ^~~~~~
parser.ypp:122:20: error: expected ‘)’ before ‘double’
parser.ypp:127:20: error: expected unqualified-id before ‘double’
             $$ = log($5) / log($3);
                    ^~~~~~
parser.ypp:127:20: error: expected ‘)’ before ‘double’
parser.ypp:132:20: error: expected unqualified-id before ‘double’
             $$ = exp($3);
                    ^~~~~~
parser.ypp:132:20: error: expected ‘)’ before ‘double’
parser.ypp:137:20: error: expected unqualified-id before ‘double’
             $$ = sqrt($3);
                    ^~~~~~
parser.ypp:137:20: error: expected ‘)’ before ‘double’
parser.ypp:142:20: error: expected unqualified-id before ‘double’
             $$ = pow($1, $3);
                    ^~~~~~
parser.ypp:142:20: error: expected ‘)’ before ‘double’
parser.ypp:147:20: error: expected unqualified-id before ‘double’
             $$ = -$2;
                    ^~    
parser.ypp:147:20: error: expected ‘)’ before ‘double’
parser.ypp:152:20: error: expected unqualified-id before ‘double’
             $$ = fabs($3);
                    ^~~~~~
parser.ypp:152:20: error: expected ‘)’ before ‘double’
parser.ypp:157:20: error: expected unqualified-id before ‘double’
             $$ = 1;
                    ^     
parser.ypp:157:20: error: expected ‘)’ before ‘double’
parser.ypp:158:62: error: expected unqualified-id before ‘double’
             for (int i = 1; i <= static_cast<int>($1); i++) {
                                                              ^     
parser.ypp:158:62: error: expected ‘)’ before ‘double’
parser.ypp:158:70: error: expected ‘)’ before ‘;’ token
             for (int i = 1; i <= static_cast<int>($1); i++) {
                                                                      ^
parser.ypp:159:24: error: expected unqualified-id before ‘double’
                 $$ = $$ * i;
                        ^~~~~ 
parser.ypp:159:24: error: expected ‘)’ before ‘double’
parser.ypp:165:20: error: expected unqualified-id before ‘double’
             $$ = $2;
                    ^     
parser.ypp:165:20: error: expected ‘)’ before ‘double’
parser.ypp:170:20: error: expected unqualified-id before ‘double’
             $$ = $1;
                    ^     
parser.ypp:170:20: error: expected ‘)’ before ‘double’
Makefile:15: recipe for target 'parser.tab.o' failed
make: *** [parser.tab.o] Error 1
1
On a couple of notes unrelated to the errors you get, I suggest you read the generated header file "parser.tab.hpp", because then you will see that yylval isn't a pointer. Also the libraries you link with should be last on the command-line when you build (or at least after all source and object files), and you don't need to add linker-libraries when generating object files.Some programmer dude

1 Answers

2
votes

Your bison file defines symbols wirh two different types:

%type <double> E
%token <double> NUMBER
%token <char> VARIABLE;

(The semicolon at the end of the third line there is incorrect, although I think bison will just ignore it.)

As discussed in the bison manual, the most common way of accomplishing that is with a %union bison declaration, which will declare YYSTYPE to be a C union. That's not compatible with using the preprocessor to #define YYSTYPE as a single type.

If you use a %union declaration, you specify a C type and a tag for each variant of YYSTYPE. What you then place between the angle brackets is the tag, not the type. For example,

%union {
     double number;
     char id;
}
%token <number> NUMBER

With that declaration, bison will declare a union type with two members named number and id. And it will automatically make $n refer to the correct member (if the symbol $n refers to has a known type) by appending a member selector. In other words, if $1 refers to a NUMBER, bison will replace it in the generated code with something like stack[top - 2 + 1].number. (Without the %union and type declaration, the replacement would have been something like stack[top - 2 + 1].)

Bison doesn't require you to use a %union. If you don't and you still declare types for your tokens and non-terminals, bison will assume you know what you're doing and that you have somehow declared YYSTYPE as a composite type. It will do exactly the same replacement, adding a member selector to the references to stack values with known types.

So in your case, you've declared %type <double> E, so bison will replace a $1 in an action where the $1 refers to the symbol E with something like stack[top - 4 + 1].double.

Of course, that will cause the compiler to choke. double is a reserved word and cannot be used as a composite member name, and anyway YYSTYPE is a scalar (a double) because that's the way you defined it.

You haven't yet tried to compile your scanner, but you will encounter similar problems there. Obviously, YYSTYPE must be the same type in both the scanner and the parser, which are separate C translation units. If you had used a %union declaration, bison would have put the C union into tje generated header, which you #include in the generated scanner. That guarantees consistency. If you don't use %union, then you have to make sure that the scanner has the right definition.

Since you don't do anything in your flex file to declare YYSTYPE, the generated code will fallback to int. It does this by including a block like this:

#ifndef YYSTYPE
#define YYSTYPE int
#endif

The bison manual contains lots of simple examples. There are a lot more options than I have presented here, and you would be well-advised to spend a bit of time reading the manual.