Search code examples
calculatoryacc

Yacc Calculator Parenthesis and Exponent problems


I've been trying to figure this problem out for a few hours now and I've finally decided to see if anyone could offer some input on this issue of mine.

I'm attempting to expand on a Yacc calculator that can do a variety of tasks. the two remaining ones are recognizing parenthesis as well as returning the exponent. I admit that I'm still very new to this process but as far as I can tell compared to many examples I find, I'm not doing anything horribly wrong so I'm hoping this is a fairly straight forward problem.

%{
#include <stdio.h>
#include <ctype.h>
%}
%token NUMBER

%%
command : expr {printf("Answer is: %d\n",$1);}
        ;


expr    : expr '-' term {$$=$1-$3;}
        | expr '+' term {$$=$1+$3;}
        | expr '*' term {$$=$1*$3;}
        | expr '/' term {$$=$1/$3;}
        | expr '%' term {$$=$1%$3;}
        | expr '^' term {$$=$1,$3;}
        | '(' term ')' term {$$=$2;}
        | term  {$$=$1;}
        ;

term    : factor        {$$=$1;}
        ;

factor  : NUMBER        {$$=$1;}

%%

main(){
    return yyparse();
}

int yylex(void){
    int character;
    while((character=getchar())==' ');
    if(isdigit(character)){
        ungetc(character,stdin);
        scanf("%d",&yylval);
        return(NUMBER);
    }
    if(character=='\n'){
        return(0);
    }
    return(character);
}

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

The calculator is fairly simple but I don't see my problem. The code compiles with no issues and the other functions work perfectly fine.

I'd appreciate any help at all!

EDIT/Addition

I accidentally used the wrong code I fixed it and I added updated code from advice provided by @rici.

This code is the new and properly function code.

%{
int yylex (void);
#include <stdio.h>
#include <ctype.h>
#include <math.h>
%}
%token NUMBER

%left '+' '-'
%left '*' '/'
%precedence NEG
%right '^'

%%

command : expr {printf("Answer is: %d\n",$1);}
        ;


expr    : expr '-' term {$$=$1-$3;}
        | expr '+' term {$$=$1+$3;}
        | expr '*' term {$$=$1*$3;}
        | expr '/' term {$$=$1/$3;}
        | expr '%' term {$$=$1%$3;}
        | '-' term %prec NEG {$$=-$2;}
        | expr '^' term {$$=pow($1,$3);}
        | '(' expr ')'  {$$=$2;}
        | term  {$$=$1;}
        ;

term    : factor        {$$=$1;}
        ;

factor  : NUMBER        {$$=$1;}

%%

main(){
    return yyparse();
}

int yylex(void){
    int character;
    while((character=getchar())==' ');
    if(isdigit(character)){
        ungetc(character,stdin);
        scanf("%d",&yylval);
        return(NUMBER);
    }
    if(character=='\n'){
        return(0);
    }
    return(character);
}

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

Solution

  • I don't know what your issue with exponentiation is (and you don't describe the problem at all) except that you need to

    #include <math.h>
    

    if you're going to use pow. You also need to add -lm to your compilation command. Since you don't include the math header, the compiler will assume that pow takes int arguments and produces an int result, which is certainly not the case. Unless your compiler does something like automatically include math functions (which seems unlikely to me), that will cause the return value from pow to be meaningless. So that's a possible problem with pow.

    The issue with parentheses seems a bit more clear. Your grammar says:

    expr: ... | '(' term ')' term | ...
    

    What that means is "One possible way of writing an expr is to write an open parenthesis, followed by a term, followed by a close parenthesis, followed by another term. (In other words, grammars are just what they seem to be. No magic or subtleties.)

    Since term is just factor and factor is just NUMBER, a term can only be a number, and your parenthesis rule allows expr to be, for example,

    ( 42 ) 63
    

    But it doesn't allow (42), much less (42+63). So that's unlikely to be what you wanted.

    Your calculator also doesn't seem to have any operator precedence, so it will evaluate 2+4*3 as 18, not 14. Maybe you're OK with that, but it's a bit unconventional.

    There's a series of example calculators in the Bison manual. The example code itself is part of the bison distribution, and the manual text attempts to explain how the bison input is interpreted. The second example is a standard calculators with parentheses and exponentiation -- basically what you're trying to implement.