I recently started to learn C++ and came across this problem in a book "Object Oriented Programming in C++" by Robert Lafore.
The author has a program in the book which creates a Parser. I found a problem with the original program in the book which breaks at one of the input expressions I am providing. Therefore I tried to make changes and made it recursive. It works fine with the inputs I am providing.
I am more concerned about correctness and programming style of the program I have written. I believe I have made many mistakes. Any comments would be very helpful.
#include <iostream>
using namespace std;
const char SIZE = 40;
class Stack
{
private:
char array[SIZE];
char top;
public:
Stack():top(-1)
{
}
void push(char v)
{
if (!is_full())
{
array[++top] = v;
}
}
char pop()
{
if (!is_empty())
{
return array[top--];
}
throw "Stack is empty. Pop failed";
}
bool is_full()
{
return top >= SIZE ? true : false;
}
bool is_empty()
{
return top == -1;
}
char get_top()
{
return top;
}
};
bool is_operator(char c)
{
return (c == '*' || c == '/' || c == '+' || c == '-');
}
bool is_dm_operator(char c)
{
return (c == '*' || c == '/');
}
bool is_value(char c)
{
return (c >= '0' && c <= '9');
}
void resolve_op_recursively(Stack& e_stack, char in)
{
if (e_stack.get_top() == 0) //stack has only 1 operand
{
e_stack.push(in);
}
else
{
char last_val = e_stack.pop();
char last_op = e_stack.pop();
if (is_dm_operator(in) && !is_dm_operator(last_op)) // 2 + 3 * 5 case only
{
e_stack.push(last_op);
e_stack.push(last_val);
e_stack.push(in);
}
else
{
char first_val = e_stack.pop();
switch (last_op)
{
case '/':
e_stack.push(first_val / last_val);
break;
case '*':
e_stack.push(first_val * last_val);
break;
case '+':
e_stack.push(first_val + last_val);
break;
case '-':
e_stack.push(first_val - last_val);
break;
default:
break;
}
resolve_op_recursively(e_stack, in);
}
}
}
void parse_expression_using_stack(Stack& e_stack, const char * input)
{
while (*input)
{
char in = *input;
if (in != ' ')
{
if (is_value(in))
{
e_stack.push(in - '0');
}
else if (is_operator(in))
{
resolve_op_recursively(e_stack, in);
}
else
{
cout << "unknow expression" << endl;
}
}
input++;
}
}
void solve_expression_using_stack(Stack& e_stack)
{
while(e_stack.get_top())
{
char second_operand = e_stack.pop();
char operator_ = e_stack.pop();
switch (operator_)
{
case '+':
e_stack.push(e_stack.pop() + second_operand);
break;
case '-':
e_stack.push(e_stack.pop() - second_operand);
break;
case '*':
e_stack.push(e_stack.pop() * second_operand);
break;
case '/':
e_stack.push(e_stack.pop() / second_operand);
break;
default:
cout << "unkown operand " << operator_ << endl;
}
}
}
void solve_expression_and_match_result(const char * input, char expected_result)
{
Stack e_stack;
char result;
cout << "Expression: " << input;
parse_expression_using_stack(e_stack, input);
solve_expression_using_stack(e_stack);
result = e_stack.pop();
cout << " Got solution: " << static_cast<int>(result) << " Expected Solution: " << static_cast<int>(expected_result) << " Test: ";
if (result == expected_result)
{
cout << "\nPASSED" << endl;
}
else
{
cout << "\nFAILED" << endl;
}
}
int main(int argc, const char * argv[])
{
const char * expressions[20] =
{
static_cast<const char *>("5 / 5 + 3 - 6 * 2"), // why static_cast here? what is const_cast
static_cast<const char *>("3 * 7 - 1 + 5 / 3"),
static_cast<const char *>("3 * 5 - 4"),
static_cast<const char *>("3 + 5 - 4"),
static_cast<const char *>("2 / 6 * 3 / 2"),
static_cast<const char *>("3 + 6 * 9 / 3 - 7"),
static_cast<const char *>("9 - 5 / 5 * 2 + 6"),
static_cast<const char *>("7 + 3 * 4 / 2 - 5 * 6"),
static_cast<const char *>("4 * 5 + 3 - 4 / 2"),
static_cast<const char *>("4 / 2 * 5 + 3 - 4"),
static_cast<const char *>("5 + 3 * 4 / 2 - 3"),
static_cast<const char *>("5 - 3 + 4 / 2"),
static_cast<const char *>("5 * 3 / 2 - 2"),
static_cast<const char *>("5 * 2 / 4 + 9 - 2")
};
char solutions[20] =
{
5 / 5 + 3 - 6 * 2,
3 * 7 - 1 + 5 / 3,
3 * 5 - 4,
3 + 5 - 4,
2 / 6 * 3 / 2,
3 + 6 * 9 / 3 - 7,
9 - 5 / 5 * 2 + 6,
7 + 3 * 4 / 2 - 5 * 6,
4 * 5 + 3 - 4 / 2,
4 / 2 * 5 + 3 - 4,
5 + 3 * 4 / 2 - 3,
5 - 3 + 4 / 2,
5 * 3 / 2 - 2,
5 * 2 / 4 + 9 - 2
};
for (int i = 0; i < 20; ++i)
{
if (expressions[i])
{
solve_expression_and_match_result(expressions[i], solutions[i]);
}
}
return 0;
}
std::stack
instead of rolling your own? \$\endgroup\$