2

I am currently writing a shunting yard algorithm implementation. I am having trouble with handling parentheses. My current method trying to check if it's seen a token with lexeme ")" in it's iteration through the operator stack, and if it has, it won't add it to the output stack. My current code:

#include <iostream>
#include <vector>
#include <map>
#include <string>

enum Type { Operator, Terminal, Blank };

std::map<std::string, int> precedence_lookup;

class Token {
    public:
        std::string lexeme;
        Type type;
        int precedence;
        Token(std::string init_lexeme, Type init_type) {
            precedence_lookup.insert(std::pair<std::string, int>("+", 2));
            precedence_lookup.insert(std::pair<std::string, int>("-", 2));
            precedence_lookup.insert(std::pair<std::string, int>("/", 3));
            precedence_lookup.insert(std::pair<std::string, int>("*", 3));
            precedence_lookup.insert(std::pair<std::string, int>("^", 4));
            precedence_lookup.insert(std::pair<std::string, int>("(", 0));
            precedence_lookup.insert(std::pair<std::string, int>(")", 0));
            lexeme = init_lexeme;
            type = init_type;
            precedence = precedence_lookup[lexeme];
        }
};

std::string print(std::vector<Token> tokens) {
    std::string p = "";
    for (std::vector<Token>::iterator iter = tokens.begin(); iter < tokens.end(); iter++) {
        Token token = *iter;
        p += token.lexeme;
    }
    return p;
}

std::vector<Token> shunting_yard_algorithm(std::vector<Token> input_stack) {
    std::vector<Token> output_stack;
    std::vector<Token> operator_stack;
    for (std::vector<Token>::iterator input = input_stack.begin(); input < input_stack.end(); input++) {
        Token current_input = *input;
        std::cout << current_input.lexeme << " -> ";
        if (current_input.type == Terminal) {
            output_stack.push_back(current_input);
            std::cout << "sent to output   " << print(operator_stack) << " | " << print(output_stack) << "\n";
        } else {
            if (current_input.lexeme == ")") {
                std::vector<int> get_rid_of;
                bool add = true;
                for (int i = 0; i < operator_stack.size(); i++) {
                    Token top = operator_stack[i];
                    if (top.lexeme == "(") {
                        add = false;
                        operator_stack.erase(operator_stack.begin()+i);
                    }
                    if (add) {
                        get_rid_of.push_back(i);
                    }
                }
                for (std::vector<int>::iterator it = get_rid_of.begin(); it < get_rid_of.end(); it++) {
                    output_stack.push_back(operator_stack[*it]);
                    operator_stack.erase(operator_stack.begin()+*it);
                }
                std::cout << "sent all operators from ) to ( to output   " << print(operator_stack) << " | " << print(output_stack) << "\n";
            } else if (current_input.lexeme == "(") {
                operator_stack.push_back(current_input);
                std::cout << "sent to operator   " << print(operator_stack) << " | " << print(output_stack) << "\n";
            } else {
                if (operator_stack.empty()) {
                    operator_stack.push_back(current_input);
                    std::cout << "sent to operator   " << print(operator_stack) << " | " << print(output_stack) << "\n";
                } else {
                    Token top_operator = operator_stack.back();
                    if (top_operator.precedence > current_input.precedence) {
                        int bigness = operator_stack.size();
                        for (std::vector<Token>::iterator it = operator_stack.begin(); it < operator_stack.end(); it++) {
                            output_stack.push_back(*it);
                        }
                        for (int i = 0; i < bigness; i++) {
                            operator_stack.pop_back();
                        }
                        operator_stack.push_back(current_input);
                        std::cout << "dumping operator stack to output   " << print(operator_stack) << " | " << print(output_stack) << "\n";
                    } else {
                        operator_stack.push_back(current_input);
                        std::cout << "sent to operator   " << print(operator_stack) << " | " << print(output_stack) << "\n";
                    }
                }
            }
        }
    }
    int bigness = operator_stack.size();
    for (std::vector<Token>::iterator it = operator_stack.begin(); it < operator_stack.end(); it++) {
        output_stack.push_back(*it);
    }
    for (int i = 0; i < bigness; i++) {
        operator_stack.pop_back();
    }
    std::cout << "operator stack -> sent to output\n";
    return output_stack;
}
int main() {
    Token a("3", Terminal);
    Token b("+", Operator);
    Token c("4", Terminal);
    Token d("*", Operator);
    Token e("2", Terminal);
    Token f("/", Operator);
    Token g("(", Operator);
    Token h("1", Terminal);
    Token i("-", Operator);
    Token j("5", Terminal);
    Token k(")", Operator);
    Token l("^", Operator);
    Token m("2", Terminal);
    Token n("^", Operator);
    Token o("3", Terminal);
    std::vector<Token> input = { a, b, c, d, e, f, g, h, i, j, k, l, m, n, o };
    std::vector<Token> postfix = shunting_yard_algorithm(input);
    std::cout << "Infix: ";
    for (std::vector<Token>::iterator token = input.begin(); token != input.end(); token++) {
        Token tok = *token;
        std::cout << tok.lexeme;
    }
    std::cout << "\nPostfix: ";
    for (std::vector<Token>::iterator token = postfix.begin(); token != postfix.end(); token++) {
        Token tok = *token;
        std::cout << tok.lexeme;
    }
}

The output of that code is:

3 -> sent to output    | 3
+ -> sent to operator   + | 3
4 -> sent to output   + | 34
* -> sent to operator   +* | 34
2 -> sent to output   +* | 342
/ -> sent to operator   +*/ | 342
( -> sent to operator   +*/( | 342
1 -> sent to output   +*/( | 3421
- -> sent to operator   +*/(- | 3421
5 -> sent to output   +*/(- | 34215
) -> sent all operators from ) to ( to output   * | 34215+/
^ -> sent to operator   *^ | 34215+/
2 -> sent to output   *^ | 34215+/2
^ -> sent to operator   *^^ | 34215+/2
3 -> sent to output   *^^ | 34215+/23
operator stack -> sent to output
Infix: 3+4*2/(1-5)^2^3
Postfix: 34215+/23*^^

The RPN is 34215+/23^^, when it should be 342*15-23^^/+. I've looked at the output, and I've come to the conclusion that the error is in how it handles parentheses. This is also made clear by the fact that it handles expressions without parentheses just fine.

can house
  • 41
  • 2
  • Now is a good time to use the debugger that comes with your compiler toolset. – PaulMcKenzie May 15 '20 at 20:27
  • 2
    A simpler example might be easier to debug. How many of those operations can you remove before the example no longer misbehaves? Go there, then back up *one* step to something slightly more complicated. (Personally, I'd be inclined to jump to `2/(1-5)`, theorizing that that makes real use of parentheses, so might still exhibit the problem.) – JaMiT May 15 '20 at 20:33
  • @JaMiT I kept the rest, as I wanted to see how it would handle operations before and after the parentheses, just in case something went awry. – can house May 15 '20 at 20:44
  • 2
    @canhouse If you want to make the task harder for yourself, that is fine with me. However, if you want others to *voluntarily* help you out, you might want to reconsider. (You can -- and should -- go back to the more complicated expression to see if anything else goes awry **after** getting the simpler case working.) – JaMiT May 15 '20 at 20:54

0 Answers0