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.
Each token and grammar rule can use only one value from the union and not the whole union as a struct.