Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Implementing Infix Expression Evaluation Using a Stack Data Structure

Tech 1

Simple arithmetic expressions like 1 + 2 are straightforward to compute. However, evaluating more complex infix expressions such as 1 + (2 ^ 2) / 3 * 4 requires a systematic approach accounting for operator precedence and parentheses. A standard solution uses two stacks: one for numeric operands and another for operators.

The algorithm processes the expression string sequentially. When a number is encountered, it's pushed onto the operand stack. For operators, the system checks the operator stack. If empty, the new operator is pushed. If not empty, the precedence of the new operator is compared to the top of the operator stack. Based on precedence and associativity rules, operators are popped from the stack and applied to operands before pushing the new operator. Parentheses are handled specially: left parentheses are pushed onto the operator stack, and a right parenthesis triggers popping and calculation until a matching left parenthesis is found.

The following C++ implementation demonstrates this two-stack method.

#include <iostream>
#include <stack>
#include <cmath>
#include <cstring>
#include <cctype>
using namespace std;

stack<int> valueStack;    // Holds numeric values
stack<char> symbolStack;  // Holds operators and parentheses

// Executes an operation using the top operator from symbolStack
void evaluateOperator(char op) {
    int rightOperand = valueStack.top();
    valueStack.pop();
    int leftOperand = valueStack.top();
    valueStack.pop();
    int computationResult = 0;

    switch(op) {
        case '+': computationResult = leftOperand + rightOperand; break;
        case '-': computationResult = leftOperand - rightOperand; break;
        case '*': computationResult = leftOperand * rightOperand; break;
        case '/': computationResult = leftOperand / rightOperand; break;
        case '^': computationResult = pow(leftOperand, rightOperand); break;
    }
    valueStack.push(computationResult);
}

int main() {
    char expression[100];
    cin.getline(expression, 100);

    for (int pos = 0; pos < strlen(expression); ++pos) {
        if (isdigit(expression[pos])) { // Handle multi-digit numbers
            int currentNumber = 0;
            while (pos < strlen(expression) && isdigit(expression[pos])) {
                currentNumber = currentNumber * 10 + (expression[pos] - '0');
                ++pos;
            }
            --pos; // Adjust position after number parsing
            valueStack.push(currentNumber);
        }
        else if (expression[pos] == '(') {
            symbolStack.push('(');
        }
        else if (expression[pos] == ')') { // Evaluate until '(' is found
            while (!symbolStack.empty() && symbolStack.top() != '(') {
                evaluateOperator(symbolStack.top());
                symbolStack.pop();
            }
            symbolStack.pop(); // Remove the '('
        }
        else if (strchr("+-*/^", expression[pos])) { // Handle operators
            char currentOp = expression[pos];
            // Determine precedence and evaluate higher/equal precedence ops
            while (!symbolStack.empty() && symbolStack.top() != '(') {
                char topOp = symbolStack.top();
                bool shouldEvaluate = false;
                // Define precedence: '^' > '/*' > '+-'
                if ((currentOp == '+' || currentOp == '-') && 
                    (topOp == '+' || topOp == '-' || topOp == '*' || topOp == '/' || topOp == '^')) {
                    shouldEvaluate = true;
                }
                else if ((currentOp == '*' || currentOp == '/') && 
                         (topOp == '*' || topOp == '/' || topOp == '^')) {
                    shouldEvaluate = true;
                }
                else if (currentOp == '^' && topOp == '^') {
                    shouldEvaluate = true; // Right associativity for '^'
                }
                if (!shouldEvaluate) break;
                evaluateOperator(topOp);
                symbolStack.pop();
            }
            symbolStack.push(currentOp);
        }
    }
    // Process any remaining operators
    while (!symbolStack.empty()) {
        evaluateOperator(symbolStack.top());
        symbolStack.pop();
    }
    cout << valueStack.top() << endl;
    return 0;
}

Python's eval() function offers a concise alternative by leveraging its built-in expression parser. The input string requires modification to use Python's exponent (**) and integer division (//) operators.

user_input = input()
modified_input = user_input.replace('^', '**').replace('/', '//')
print(eval(modified_input))

While Python porvides a succinct one-line solution, understanding the underlying stack-based algorithm is crucial for foundational computer science knowledge and implementing evaluators in environments without such built-in functions.

Related Articles

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

SBUS Signal Analysis and Communication Implementation Using STM32 with Fus Remote Controller

Overview In a recent project, I utilized the SBUS protocol with the Fus remote controller to control a vehicle's basic operations, including movement, lights, and mode switching. This article is aimed...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.