Following your suggestions, I updated my expression evaluator with a Shunting-Yard algorithm.
I've created two classes, a Shunting-yard class and a RPNsolver class.
The first I mentioned converts from infix to postfix notation and the other solves the postfix expression.
I'm open to suggestions of any type.
Shunting_yard.h
#pragma once
#include <string>
#include <stack>
#include <map>
#include <iostream>
#include <sstream>
class Shunting_yard
{
private:
std::string infix;
std::map<char, std::pair<int, bool>> op //Operators features(precedence, right associative)
{
{ '+', std::make_pair(2, 0) },
{ '-', std::make_pair(2, 0) },
{ '*', std::make_pair(3, 0) },
{ '/', std::make_pair(3, 0) },
{ '^', std::make_pair(4, 1) }
};
bool isoperator(char);
public:
Shunting_yard(std::string );
void convert();
std::string postfix;
};
Shunting_yard.cpp
#include "Shunting_yard.h"
Shunting_yard::Shunting_yard(std::string str)
{
this->infix = str;
}
bool Shunting_yard::isoperator(char c)
{
return c == '+' || c == '-' || c == '*' || c == '/' || c == '^';
}
void Shunting_yard::convert()
{
std::stack<char> operators;
std::istringstream iss(infix);
char tmp;
double num;
while ((int)iss.tellg() != EOF)
{
char token = iss.peek();
if (isdigit(token))
{
iss >> num;
std::stringstream ss;
ss << num;
postfix += ss.str();
postfix += " ";
}
else if (isoperator(token))
{
char o1 = token;
bool offset = 0;
if (!op[o1].second)
offset = 1;
if (!operators.empty())
{
char top = operators.top();
while (isoperator(top))
{
if (op[o1].first < op[top].first+offset)
{
postfix += top;
postfix += " ";
operators.pop();
}
else break;
if (operators.empty())
break;
else top = operators.top();
}
}
operators.push(o1);
iss >> tmp;
}
else if (token == '(')
{
operators.push(token);
iss >> tmp;
}
else if (token == ')')
{
while (operators.top() != '(')
{
postfix += operators.top();
postfix += " ";
operators.pop();
}
operators.pop();
iss >> tmp;
}
else iss.get(tmp);
}
if (!operators.empty())
{
int size = operators.size();
for (int i = 0; i < size; i++)
{
postfix += operators.top();
postfix += " ";
operators.pop();
}
}
}
RPNSolver.h
#include "Shunting_yard.h"
#include <string>
#include <stack>
#include <map>
#include <iostream>
#include <sstream>
class RPNSolver
{
private:
std::string postfix;
bool isOperator(char);
public:
double result;
RPNSolver(std::string str);
void solve();
};
RPNSolver.cpp
#include "Solver.h"
RPNSolver::RPNSolver(std::string str)
{
Shunting_yard exp(str);
exp.convert();
this->postfix = exp.postfix;
}
bool RPNSolver::isOperator(char c)
{
return c == '+' || c == '-' || c == '*' || c == '/' || c == '^';
}
void RPNSolver::solve()
{
std::istringstream iss(postfix);
std::stack<double> nums;
double num;
char tmp;
double res;
while ((int)iss.tellg() != EOF)
{
char token = iss.peek();
if (isdigit(token))
{
iss >> num;
nums.push(num);
}
else if (isOperator(token))
{
double num2 = nums.top();
nums.pop();
double num1 = 0;
if (!nums.empty())
{
num1 = nums.top();
nums.pop();
}
if (token == '+' || token == '-')
{
if (token == '-')
num2 *= -1;
res = num1 + num2;
}
else if (token == '*' || token == '/')
{
if (token == '/')
num2 = 1/num2;
res = num1 * num2;
}
else if (token == '^')
{
res = pow(num1, num2);
}
nums.push(res);
iss >> tmp;
}
else iss.get(tmp);
}
result = nums.top();
}