-1

There is a task, to write calculator, which recieves strings cosisting of:

  • chars '0'-'9',
  • brackest '(', ')',
  • chars '+', '-', '*', '/', '^',

and performing following ops:

  • addition
  • substraction
  • multiplication
  • integer division
  • power.

Arcitecture of solution should include recursive descent

My code:

#include <stdio.h>
#include <setjmp.h>

jmp_buf begin;
char curlex;

void getlex(void);
int expr(void);
int add_sub(void);
int mult_div(void);
int power(void);
void error();

int main() {
    int result;
    setjmp(begin);
    printf("==>");
    getlex();
    result=expr();
    if ( curlex != '\n') error();
    printf("\n%d\n",result);
    return 0;
}

void getlex() {
    while ( ( curlex=getchar()) == ' ');
}

void error(void) {
    printf("\nERROR!\n");
    while(getchar()!='\n');
    longjmp(begin,1);
}

int expr() {
    int e=add_sub();
    while (curlex == '+' || curlex == '-')
        if (curlex == '+')
        {getlex(); e+=add_sub();}
        else if (curlex == '-')
        {getlex(); e-=add_sub();}
    return e;
}

int add_sub() {

    int a=mult_div();
    while (curlex == '*' || curlex == '/')
        if (curlex == '*')
        {getlex(); a*=mult_div();}
        else if (curlex == '/')
        {getlex(); a/=mult_div();}
    return a;
}

int mult_div() {
    int a=power();
    while (curlex == '^')
    {getlex(); for(int k=0;k<power(); k++, a*=power());}
    return a;
}

int power() {
    int m;
    switch(curlex){
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9': m= curlex-'0'; break;
        case '(': getlex(); m=expr();
                  if ( curlex == ')') break;
        default : error();
    }

    getlex();
    return m;
}

Code performs almost everything mentioned, except power-operation. I can't find a bug. There is also an issue with right association of power operation. That means expression 3^1^2 gives 9, but should give 3.

Please help!

Oka
  • 23,367
  • 6
  • 42
  • 53
Stepan Sokol
  • 111
  • 9
  • 2
    C and C++ are two very different languages, please don't spam irrelevant tags and only use the one for the language you're actually working with. – Some programmer dude Nov 14 '22 at 08:28
  • As for your problem, now might be a good time to learn how to use a [*debugger*](https://stackoverflow.com/questions/25385173/what-is-a-debugger-and-how-can-it-help-me-diagnose-problems) to step through your code line by line while monitoring variables and their values. – Some programmer dude Nov 14 '22 at 08:29
  • If you want others to read your code, then please adopt a conventional coding style. In addition, there are _lots_ of very bad practices in this code, so when you get it working I strongly recommend to post it on https://codereview.stackexchange.com/ – Lundin Nov 14 '22 at 08:51
  • 1
    @mch right associated power means 3^(1^2) = 3. – Stepan Sokol Nov 14 '22 at 08:57

2 Answers2

1

You are calling power() too often in mult_div(). Once you have a value returned by power() you should calculate the power and continue:

int mult_div() {
    int a=power();
    while (curlex == '^') 
    {
        getlex();
         a = calc_power(a, power());
    }
    return a;
}

To make it easier I used a helper function to calculate the power:

int calc_power(int a, int b)
{
    int res = 1;
    for (int i = 0; i < b; i++) res *= a;
    return res;
}

https://godbolt.org/z/n4KhWx6j1

curlex should be an int, because that's what getchar returns: https://en.cppreference.com/w/c/io/getchar

mch
  • 9,424
  • 2
  • 28
  • 42
0

Here is the full solution.

#include <stdio.h>
#include <setjmp.h>

jmp_buf begin;
char curlex;

void getlex(void); 
int expr(void); 
int add_sub(void); 
int mult_div(void); 
int power(void);
void error(); 

int main() {
    int result; 
    setjmp(begin); 
    printf("==>"); 
    getlex();      
    result=expr(); 
    if ( curlex != '\n') error(); 
    printf("\n%d\n",result);
    return 0;
}

void getlex() {
while ( ( curlex=getchar()) == ' '); 
}


void error(void) {
    printf("\nОШИБКА!\n");
    while(getchar()!='\n');
    longjmp(begin,1);
}


int expr() {
    int e=add_sub(); 
    while (curlex == '+' || curlex == '-') 
        if (curlex == '+')
        {getlex(); e+=add_sub();} 
        else if (curlex == '-')
        {getlex(); e-=add_sub();} 
    return e;
}

int add_sub() {
    while (curlex == '*' || curlex == '/') 
        if (curlex == '*')
        {getlex(); a*=mult_div();} 
        else if (curlex == '/')
        {getlex(); a/=mult_div();} 
    return a;
}


int mult_div() {

    int a=power(), res=1;
    while (curlex == '^') 
        {getlex(); 
        int m=mult_div();
        for(int k=0 ;k<m; k++, res*=a); 
        return res;} 
    return a;
}

int power() {
    int m; 

    switch(curlex){ 
    case '0': 
    case '1': 
    case '2': 
    case '3': 
    case '4': 
    case '5':
    case '6': 
    case '7': 
    case '8': 
    case '9': m= curlex-'0'; break;
    case '(': getlex(); m=expr(); 
        if ( curlex == ')') break; 
    default : error();
    }
    
getlex();
return m;
}

It works with right-assotiated power-operation.

Stepan Sokol
  • 111
  • 9
  • Solution of another user didn't help me, didn't even give me any idea, perhaps because of my own lack of programming intuition or feeleng. So, I wrote my own option of correct solution and published it. – Stepan Sokol Nov 20 '22 at 11:43
  • Moreover, the implementation of short concepts usually published is not easier than the understanding of concepts as part of complete programs. Both is not easy and useful to develop programming skills – Stepan Sokol Nov 20 '22 at 11:53