Skip to content

Instantly share code, notes, and snippets.

@Yepoleb
Last active August 29, 2015 14:07
Show Gist options
  • Save Yepoleb/4916601b08f48ea478b7 to your computer and use it in GitHub Desktop.
Save Yepoleb/4916601b08f48ea478b7 to your computer and use it in GitHub Desktop.
#include <exception>
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
using namespace std;
const string operators1 = "+-";
const string operators2 = "*/%";
const string operators3 = "^";
const string operators4 = "()";
double eval(string exp);
vector<size_t> splitops(const string& exp, const string& ops);
int main()
{
string inp;
while (true) {
cout << "Enter Expression: ";
getline(cin, inp);
// End the loop if the input is exit or quit
if (inp == "exit" or inp == "quit") {
break;
}
// Catch all exceptions so the loop keeps running
try {
cout << "Result: " << eval(inp) << endl << endl;
}
catch (std::exception ex) {
cerr << "An error occured while processing the input\n";
}
}
return 0;
}
double eval(string exp)
{
cout << "Evaluating \"" << exp << "\"\n";
vector<string> modes {operators1, operators2, operators3, operators4};
int mode = 0;
// Iterate over all modes and check if there's something to do
for (size_t modenum = 0; modenum < modes.size(); modenum++) {
// Check if we can split the expression at the operators
if (splitops(exp, modes[modenum]).size() > 0) {
// Set mode to 1 higher than the actual index because 0 is reserved
mode = modenum + 1;
break;
}
}
double result = 0;
switch (mode) {
case 0: // No Operators
{
// If there are no known operaters in the expression any more, parse it to double
result = stod(exp);
break;
}
case 1: // + -
{
// Add a + at the beginning of the expression, if there is no operator
if (operators1.find(exp[0]) == string::npos) {
exp = "+" + exp;
}
// Find all occurences of the operators in the expression
vector<size_t> splits = splitops(exp, operators1);
// Add the string end to the split points
splits.push_back(exp.size()+1);
for (size_t i = 0; i < splits.size()-1; i++) {
// Get the split operator
char op = exp[splits[i]];
// The number starts 1 character after the split
int start = splits[i]+1;
// Length is the next split minus the start
int len = splits[i+1]-start;
string part = exp.substr(start, len);
if (op == '+') {
result += eval(part);
}
else if (op == '-') {
result -= eval(part);
}
}
break;
}
case 2: // * / %
{
// Find all occurences of the operators in the expression
vector<size_t> splits = splitops(exp, operators2);
// Add the string end to the split points
splits.push_back(exp.size()+1);
// Use the first number as base
result = eval(exp.substr(0,splits[0]));
for (size_t i = 0; i < splits.size()-1; i++) {
// Get the split operator
char op = exp[splits[i]];
// The number starts 1 character after the split
int start = splits[i]+1;
// Length is the next split minus the start
int len = splits[i+1]-start;
string part = exp.substr(start, len);
if (op == '*') {
result *= eval(part);
}
else if (op == '/') {
result /= eval(part);
}
else if (op == '%') {
result = (int)result % (int)eval(part);
}
}
break;
}
case 3: // ^
{
// Find all occurences of the operators in the expression
vector<size_t> splits = splitops(exp, operators3);
// Add the string end to the split points
splits.push_back(exp.size()+1);
// Use the first number as base
result = eval(exp.substr(0,splits[0]));
for (size_t i = 0; i < splits.size()-1; i++) {
// The number starts 1 character after the split
int start = splits[i]+1;
// Length is the next split minus the start
int len = splits[i+1]-start;
string part = exp.substr(start, len);
result = pow(result, eval(part));
}
break;
}
case 4: // ( )
{
// Just remove the parentheses and evaluate again
result = eval(exp.substr(1, exp.size()-2));
break;
}
}
return result;
}
vector<size_t> splitops(const string& exp, const string& ops)
{
vector<size_t> splits;
// Number for tracking the parentheses
int level = 0;
for (size_t i = 0; i < exp.size(); i++) {
char c = exp[i];
// Check if the current character is an operator and on level 0
if (ops.find(c) != string::npos and level < 1) {
// Add the current location to splits
splits.push_back(i);
}
// Increase and decrease the level if the current character is a parenthesis
else if (c == '(') {
level++;
}
else if (c == ')') {
level--;
}
}
if (level != 0) {
cerr << "Error: Unmatching parentheses!\n";
throw;
}
return splits;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment