c++treebinary-treearithmetic-expressionsparse-tree

(C++) Parse tree for evaluating simple arithmetic expressions returning incorrect value


I attempted to write a function that takes a simple arithmetic equation, converts it into a parse tree, and returns the evaluated value. For some reason, the value being returned is not correct at all. (Not that it helps, but the same function coded in Python works correctly). I've rechecked multiple times but I'm not able to locate the problem. I've tested the BinaryTree class and the build_parse_tree() function and they seem to work as intended. I'm pretty sure it's an issue with the eval_parse_tree() function. Please let me know what the issue is with this implementation.

And yes, I know that this implementation only works for single-digit numbers, but that shouldn't be a problem here.

#include <iostream>
#include <vector>
using namespace std;

class BinaryTree{
private:
    char root;
    BinaryTree * left = NULL;
    BinaryTree * right = NULL;
public:
    BinaryTree(char root_val){
        // constructor
        root = root_val;
    }
    void insert_right(char value){
        BinaryTree * new_node = new BinaryTree(value);
        if(right == NULL)
            right = new_node;
        else{
            new_node -> right = right;
            right = new_node;
        }
    }
    void insert_left(char value){
        BinaryTree * new_node = new BinaryTree(value);
        if(left == NULL)
            left = new_node;
        else{
            new_node -> left = left;
            left = new_node;
        }
    }
    BinaryTree * get_right(){
        return right;
    }
    BinaryTree * get_left(){
        return left;
    }
    char get_root(){
        return root;
    }
    void set_root(char value){
        root = value;
    }
};

bool is_operator(char token){
    string ops = "+-/*";
    for(unsigned long long int i = 0; i < ops.length(); i++)
        if(ops[i] == token)
            return true;
    return false;
}

BinaryTree * build_parse_tree(string expr){
    vector <BinaryTree *> stack;
    BinaryTree * tree = new BinaryTree(' ');
    stack.push_back(tree);
    for(long long unsigned int i = 0; i < expr.length(); i++){
        if(expr[i] == '('){
            tree -> insert_left(' ');
            stack.push_back(tree);
            tree = tree -> get_left();
        }
        else if(isdigit(expr[i])){
            tree -> set_root(expr[i]);
            tree = stack.back();
            stack.pop_back();
        }
        else if(is_operator(expr[i])){
            tree -> set_root(expr[i]);
            tree -> insert_right(' ');
            stack.push_back(tree);
            tree = tree -> get_right();
        }
        else{
            tree = stack.back();
            stack.pop_back();
        }
    }
    return tree;
}

int eval_parse_tree(BinaryTree * tree){
    //cout << "Root: " << tree -> get_root() << endl;
    char op;
    int left, right;
    BinaryTree * left_child = tree -> get_left();
    BinaryTree * right_child = tree -> get_right();
    if(left_child && right_child){
        op = tree -> get_root();
        left = eval_parse_tree(left_child);
        right = eval_parse_tree(right_child);
        switch(op){
            case '+': return (int)left + (int)right;
            case '-': return (int)left - (int)right;
            case '*': return (int)left * (int)right;
            case '/': return (int)left / (int)right;
        }
    }
    else
        return tree -> get_root();
}

int main(void){
    cout << eval_parse_tree(build_parse_tree("(5+(2*7))")) << endl; //returns 2803, instead of 19
}


Solution

  • The problem is that you are doing calculations with characters and not with integers. As you might know each character has a Ascii-code, a numerical representation of this character, which is used for calculations. Ascii codes for '5', '2' and '7' are 53, 50 and 55.

    Thus '5' + '2' * '7' is indeed 2083, because it's actually 53 + 50 * 55.

    A simple fix would be to replace

    return tree -> get_root();
    

    in eval_parse_tree with

    return tree -> get_root() - '0';