Created
December 5, 2018 05:21
-
-
Save howardlau1999/92c31f08f0d1829884e836f81c4ce8e8 to your computer and use it in GitHub Desktop.
Simple Calculator
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 <iostream> | |
#include <string> | |
#include <algorithm> | |
#include <vector> | |
#include <cmath> | |
#include <cctype> | |
#include <stdexcept> | |
using namespace std; | |
struct Node { | |
string content; | |
vector<Node*> children; | |
Node(string content) : content(content) {} | |
}; | |
struct BinaryNode { | |
string content; | |
BinaryNode *left, *right; | |
BinaryNode(string content, BinaryNode* left = nullptr, BinaryNode *right = nullptr) : content(content), left(left), right(right) {} | |
}; | |
string to_string(char c) { | |
string s; | |
s.push_back(c); | |
return s; | |
} | |
class Calculator { | |
int cur, preview; | |
string s; | |
public: | |
Node *root; | |
BinaryNode *exp_root; | |
int calculate(string s) { | |
size_t space; | |
root = new Node(""); | |
exp_root = new BinaryNode(""); | |
while ((space = s.find(" ")) != string::npos) { | |
s.erase(space, 1); | |
} | |
this->s = s; | |
cur = 0; | |
int val = expr(root, &exp_root); | |
if (cur != s.size()) throw runtime_error("expected +, - at " + to_string(cur) + " found " + to_string(s[cur])); | |
return val; | |
} | |
int expr(Node *parent, BinaryNode **exp_parent) { | |
Node *expression = new Node("E"); | |
parent->children.push_back(expression); | |
BinaryNode* middle = new BinaryNode(""); | |
int val = factor(expression, &middle); | |
while (cur < s.size() && (s[cur] == '+' || s[cur] == '-')) { | |
expression->children.push_back(new Node(to_string(s[cur]))); | |
middle = new BinaryNode(to_string(s[cur]), middle, new BinaryNode("")); | |
switch (s[cur++]) { | |
case '+': | |
val += factor(expression, &middle->right); | |
break; | |
case '-': | |
val -= factor(expression, &middle->right); | |
break; | |
} | |
} | |
*exp_parent = middle; | |
return val; | |
} | |
int factor(Node *parent, BinaryNode **exp_parent) { | |
Node *fact = new Node("F"); | |
parent->children.push_back(fact); | |
BinaryNode* middle = new BinaryNode(""); | |
int val = term(fact, &middle); | |
while (cur < s.size() && (s[cur] == '*' || s[cur] == '/' || s[cur] == '%')) { | |
fact->children.push_back(new Node(to_string(s[cur]))); | |
middle = new BinaryNode(to_string(s[cur]), middle, new BinaryNode("")); | |
switch (s[cur++]) { | |
case '*': | |
val *= term(fact, &middle->right); | |
break; | |
case '/': | |
val /= term(fact, &middle->right); | |
break; | |
case '%': | |
val %= term(fact, &middle->right); | |
break; | |
} | |
} | |
*exp_parent = middle; | |
return val; | |
} | |
int term(Node *parent, BinaryNode **exp_parent) { | |
bool neg = false; | |
Node *t = new Node("T"); | |
BinaryNode* middle = new BinaryNode(""); | |
bool unary = false; | |
parent->children.push_back(t); | |
if (s[cur] == '+') { | |
t->children.push_back(new Node(to_string(s[cur]))); | |
middle->content = to_string(s[cur]); | |
middle->left = new BinaryNode(""); | |
unary = true; | |
++cur; | |
} else if (s[cur] == '-') { | |
t->children.push_back(new Node(to_string(s[cur]))); | |
middle->content = to_string(s[cur]); | |
middle->left = new BinaryNode(""); | |
unary = true; | |
neg = true; | |
++cur; | |
} | |
int val = unary ? expo(t, &middle->left) : expo(t, &middle); | |
*exp_parent = middle; | |
return neg ? -val : val; | |
} | |
int expo(Node* parent, BinaryNode **exp_parent) { | |
Node* exp = new Node("Ep"); | |
parent->children.push_back(exp); | |
BinaryNode* middle = new BinaryNode(""); | |
int val = 0; | |
if (s[cur] == '(') { | |
exp->children.push_back(new Node(to_string(s[cur]))); | |
++cur; | |
val = expr(exp, &middle); | |
if (s[cur] != ')') throw runtime_error("expected ) at " + to_string(cur) + ", found " + to_string(s[cur])); | |
exp->children.push_back(new Node(to_string(s[cur]))); | |
++cur; | |
} | |
else { | |
if (!isdigit(s[cur])) throw runtime_error("expected number at " + to_string(cur) + ", found " + to_string(s[cur])); | |
while (std::isdigit(s[cur])) { | |
val *= 10; | |
val += (s[cur++] - '0'); | |
} | |
exp->children.push_back(new Node(to_string(val))); | |
middle->content = to_string(val); | |
} | |
while (cur < s.size() && s[cur] == '^') { | |
exp->children.push_back(new Node(to_string(s[cur]))); | |
middle = new BinaryNode(to_string(s[cur]), middle, new BinaryNode("")); | |
switch (s[cur++]) { | |
case '^': | |
val = pow(val, expo(exp, &middle->right)); | |
break; | |
} | |
} | |
*exp_parent = middle; | |
return val; | |
} | |
}; | |
int main() { | |
string expr; | |
getline(cin, expr); | |
Calculator cal; | |
try { | |
cout << cal.calculate(expr) << endl; | |
} catch (runtime_error& e) { | |
cout << e.what() << endl; | |
} | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment