Last active
August 29, 2015 14:07
-
-
Save Yepoleb/4916601b08f48ea478b7 to your computer and use it in GitHub Desktop.
Calculator for https://gist.github.com/vladdeSV/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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