'C program data structure stack calculator [closed]

I'm studying about data structure coding. I built a calculator using a stack. infix to postfix and result However, I want to get the result after all completing the input. And I want to "out" the input with an end. the last line is example when it debug.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_STACK_SIZE 100
#define MAX_EXPR_SIZE 100

enum {
    lparen = -9,
    rparen,
    plus,
    minus,
    times,
    divide,
    mod,
    eos,
    operand
};

int stack[MAX_STACK_SIZE];
char expr[MAX_EXPR_SIZE], postexpr[MAX_EXPR_SIZE];
int pos = 0;
static int isp[] = { 0, 19, 12, 12, 13, 13, 13, 0 };
static int icp[] = { 20, 19, 12, 12, 13, 13, 13, 0 };

void add_stack(int *top, int item) {
    if (*top >= MAX_STACK_SIZE - 1)
        printf("Error: Stack is full\n");
    stack[++*top] = item;
}

int delete_stack(int *top) {
    if (*top == -1)
        printf("Error: Stack is empty\n");
    return stack[(*top)--];
}

int get_token(char *symbol, int *n) {
    *symbol = expr[(*n)++];
    switch (*symbol) {
        case '(': return lparen;
        case ')': return rparen;
        case '+': return plus;
        case '-': return minus;
        case '*': return times;
        case '/': return divide;
        case '%': return mod;
        case 0:
        case '\n': return eos;
        default: return operand;
    }
}

void print_token(int p) {
    switch (p) {
        case plus:
            printf("+");
            postexpr[pos++] = '+';
            break;
        case minus:
            printf("-");
            postexpr[pos++] = '-';
            break;
        case times:
            printf("*");
            postexpr[pos++] = '*';
            break;
        case divide:
            printf("/");
            postexpr[pos++] = '/';
            break;
        case mod:
            printf("%");
            postexpr[pos++] = '%';
            break;
        case eos: 
            printf(" ");
            break;
    }
}

void postfix(void) {
    char symbol;
    int token;
    int n = 0;
    int top = 0;
    stack[0] = eos;
    token = get_token(&symbol, &n);
    for(; token != eos; token = get_token(&symbol, &n)) {
        if (token == operand) {
            printf("%c", symbol);
            postexpr[pos++] = symbol;
        }
        else if (token == rparen) {
            while (stack[top] != lparen)
                print_token(delete_stack(&top));
            delete_stack(&top);
        } else {
            while (isp[stack[top] + 9] >= icp[token + 9])
                print_token(delete_stack(&top));
                add_stack(&top, token);
        }
    }

    while ((token = delete_stack(&top)) != eos)
        print_token(token);
    printf("\n");
}

int eval(void) {
    int token;
    char symbol;
    int op1, op2;
    int n = 0;
    int top = 0;
    stack[0] = eos;
    token = get_token(&symbol, &n);
    for(; token != eos; token = get_token(&symbol, &n)) {
        if (token == operand)
            add_stack(&top, symbol - '0');
        else {
            op2 = delete_stack(&top);
            op1 = delete_stack(&top);
            switch (token) {
                case plus: add_stack(&top, op1 + op2); break;
                case minus: add_stack(&top, op1 - op2); break;
                case times: add_stack(&top, op1 * op2); break;
                case divide: add_stack(&top, op1 / op2); break;
                case mod: add_stack(&top, op1 % op2); break;
            }
        }
    }
    return delete_stack(&top);
}

int main(void) {
    printf("Input expression : ");
    scanf("%s", expr);
    printf("Postfix expression: ");
    postfix();

    strcpy(expr, postexpr);
    printf("Evaluation of the expression : %d", eval());
}

this is example when it done

input //
(8*6)+2/4
(8*6)+4/2
out // 

print//
postfix (8*6)+2/4
result (8*6)+2/4
postfix (8*6)+4/2
result (8*6)+4/2
//
c


Solution 1:[1]

Here are some problems and possible improvements to your code:

  • printf("%") has undefined behavior. You should write printf("%%") or simply putchar('%')
  • you should parse numbers with multiple digits
  • you should skip spaces and TABs
  • you should detect invalid characters
  • you should detect invalid expressions
  • you should not use global variables

Here is a modified version:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_STACK_SIZE 100

enum {
    error = -10,
    lparen = -9,
    rparen,
    plus,
    minus,
    times,
    divide,
    mod,
    eos,
    operand,  /* 0 and above are operand values */
};

static int const isp[] = {  0, 19, 12, 12, 13, 13, 13, 0 };

void add_stack(int *stack, int *top, int item) {
    if (*top >= MAX_STACK_SIZE - 1) {
        printf("Error: Stack is full\n");
        return;
    }
    stack[++*top] = item;
}

int delete_stack(int *stack, int *top) {
    if (*top < 0) {
        printf("Error: Stack is empty\n");
        return eos;
    }
    return stack[(*top)--];
}

int get_token(const char *expr, int *pos) {
    for (;;) {
        int c = expr[*pos];
        if (c == '\0' || c == '\n')
            return eos;
        *pos += 1;
        if (c == ' ' || c == '\t')
            continue;
        if (c >= '0' && c <= '9') {
            int value = c - '0';
            while ((c = expr[*pos]) >= '0' && c <= '9') {
                *pos += 1;
                value = value * 10 + (c - '0');
            }
            return value;
        }
        switch (c) {
        case '(': return lparen;
        case ')': return rparen;
        case '+': return plus;
        case '-': return minus;
        case '*': return times;
        case '/': return divide;
        case '%': return mod;
        default:  *pos -= 1; return error;
        }
    }
}

void print_token(char *postexpr, int *ppos, int token) {
    int pos = *ppos;
    switch (token) {
    case error:  postexpr[pos++] = '?'; break;
    case lparen: postexpr[pos++] = '('; break;
    case rparen: postexpr[pos++] = ')'; break;
    case plus:   postexpr[pos++] = '+'; break;
    case minus:  postexpr[pos++] = '-'; break;
    case times:  postexpr[pos++] = '*'; break;
    case divide: postexpr[pos++] = '/'; break;
    case mod:    postexpr[pos++] = '%'; break;
    case eos:    break;
    default:
        /* insert a space between numbers */
        if (pos > 0 && postexpr[pos - 1] >= '0' && postexpr[pos - 1] <= '9')
            postexpr[pos++] = ' ';
        pos += sprintf(postexpr + pos, "%d", token);
        break;
    }
    *ppos = pos;
    postexpr[pos] = '\0';
}

int put_error(const char *message, const char *expr, int col) {
    if (col < 0) {
        printf("%s\n", message);
    } else {
        printf("%s at column %d\n", message, col + 1);
        printf("%s\n%*s\n", expr, col + 1, "^");
    }
    return -1;
}

int postfix(const char *expr, char *postexpr) {
    int stack[MAX_STACK_SIZE];
    int token, n = 0, top = 0, pos = 0, last = eos;
    stack[0] = eos;
    while ((token = get_token(expr, &n)) != eos) {
        if (token == error) {
            return put_error("syntax error", expr, n);
        }
        if (token >= operand) {
            if (last >= operand) {
                return put_error("missing operator", expr, n - 1);
            }
            print_token(postexpr, &pos, token);
        } else
        if (token == rparen) {
            if (last < operand && last != rparen) {
                return put_error("missing operand", expr, n - 1);
            }
            while (stack[top] != lparen) {
                if (stack[top] == eos) {
                    return put_error("invalid parenthesis", expr, n - 1);
                }
                print_token(postexpr, &pos, delete_stack(stack, &top));
            }
            delete_stack(stack, &top);
        } else {
            if (token == lparen) {
                if (last >= operand || last == rparen) {
                    return put_error("missing operator", expr, n - 1);
                }
            } else {
                if (last < operand && last != rparen) {
                    return put_error("missing operand", expr, n - 1);
                }
                while (isp[stack[top] - lparen] >= isp[token - lparen]) {
                    print_token(postexpr, &pos, delete_stack(stack, &top));
                }
            }
            add_stack(stack, &top, token);
        }
        last = token;
    }
    if (last < operand && last != rparen) {
        return put_error("missing operand", expr, n);
    }
    while ((token = delete_stack(stack, &top)) != eos) {
        if (token == lparen) {
            return put_error("unmatched parenthesis", expr, -1);
        }
        print_token(postexpr, &pos, token);
    }
    return 0;
}

int eval(const char *expr) {
    int stack[MAX_STACK_SIZE];
    int token, n = 0, top = 0;
    stack[0] = eos;
    while ((token = get_token(expr, &n)) != eos) {
        if (token >= operand) {
            add_stack(stack, &top, token);
        } else {
            int op2 = delete_stack(stack, &top);
            int op1 = delete_stack(stack, &top);
            switch (token) {
              case plus:   add_stack(stack, &top, op1 + op2); break;
              case minus:  add_stack(stack, &top, op1 - op2); break;
              case times:  add_stack(stack, &top, op1 * op2); break;
              case divide: add_stack(stack, &top, op1 / op2); break;
              case mod:    add_stack(stack, &top, op1 % op2); break;
            }
        }
    }
    return delete_stack(stack, &top);
}

int main() {
    char expr[100], postexpr[200];

    for (;;) {
        printf("Input expression: ");
        if (scanf("%99s", expr) != 1)
            break;
        if (!postfix(expr, postexpr)) {
            printf("Postfix expression: %s\n", postexpr);
            printf("Evaluation of the expression: %d\n", eval(postexpr));
        }
    }
    printf("Done.\n");
    return 0;
}

Sample run:

Input expression: 1
Postfix expression: 1
Evaluation of the expression: 1
Input expression: 1+
missing operand at column 3
1+
  ^
Input expression: 1+1
Postfix expression: 1 1+
Evaluation of the expression: 2
Input expression: (1+2*3)
Postfix expression: 1 2 3*+
Evaluation of the expression: 7
Input expression: (1+2*3)*(3+4*5/6)
Postfix expression: 1 2 3*+3 4 5*6/+*
Evaluation of the expression: 42
Input expression: Done.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1