aboutsummaryrefslogtreecommitdiff
path: root/src/parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser.cpp')
-rw-r--r--src/parser.cpp190
1 files changed, 190 insertions, 0 deletions
diff --git a/src/parser.cpp b/src/parser.cpp
new file mode 100644
index 0000000..3aaf7e2
--- /dev/null
+++ b/src/parser.cpp
@@ -0,0 +1,190 @@
+#include "parser.h"
+
+#include <sstream>
+
+namespace SimpleParser {
+
+int8_t Parser::getPriority(char tmp)
+{
+ switch ( tmp ) {
+ case '-':
+ return 10;
+ case '+':
+ return 10;
+ case '/':
+ return 20;
+ case '*':
+ return 20;
+ case '^':
+ return 30;
+ case '(':
+ return 90;
+ case ')':
+ return 90;
+ case ',':
+ return -1;
+ default:
+ return -1;
+ }
+}
+
+std::vector<std::string> Parser::lexer(std::string term)
+{
+ std::string tmp;
+ std::string tmpNum;
+ std::string::iterator termIter;
+ std::vector<std::string> output;
+
+ int8_t priority = 0;
+ int8_t lastPriority = 0;
+ uint32_t level = 0;
+
+ for ( termIter = term.begin(); termIter != term.end(); termIter++ ) {
+ priority = this->getPriority(*termIter);
+
+ if ( priority == -1 || ( termIter == term.begin() && priority == 10 ) ) {
+ if ( level > 0 ) {
+ tmp += *termIter;
+ } else {
+ tmpNum += *termIter;
+ }
+ } else {
+ if ( lastPriority == -1 && level == 0 ) {
+ output.push_back(tmpNum);
+ tmpNum.clear();
+ }
+
+ switch ( *termIter ) {
+ case '(': {
+ if ( level > 0 ) {
+ tmp += *termIter;
+ }
+
+ level++;
+ break;
+ }
+ case ')': {
+ level--;
+
+ if ( level == 0 ) {
+ output.push_back(tmp);
+ tmp.clear();
+ }
+ else {
+ tmp += *termIter;
+ }
+ break;
+ }
+ default: {
+ if ( level == 0 ) {
+ std::string helper;
+ helper = *termIter;
+
+ output.push_back(helper);
+ }
+ else {
+ tmp += *termIter;
+ }
+ break;
+ }
+ }
+ }
+
+ lastPriority = priority;
+ }
+
+ if ( lastPriority == -1 ) {
+ output.push_back(tmpNum);
+ } else if ( lastPriority != 90 ) {
+ throw operator_exception();
+ }
+
+ if (level != 0) {
+ throw parenthese_exception();
+ }
+
+ if ( lastPriority == 90 && output.size() == 1 ) {
+ output = lexer(output[0]);
+ }
+
+ return output;
+}
+
+Node* Parser::buildTree(Tree *tree, std::string term) {
+ std::stack<Node*> operandStack;
+ std::stack<Node*> operatorStack;
+
+ std::vector<std::string> tmpLexer;
+ std::vector<std::string> lexerOutput = this->lexer(term);
+
+ int8_t priority;
+
+ for ( auto termIter = lexerOutput.begin(); termIter != lexerOutput.end(); termIter++ ) {
+ std::string& currTerm = (*termIter);
+ priority = this->getPriority(currTerm[0]);
+
+ if ( priority != -1 && (*termIter).size() == 1 ) {
+ if ( !operatorStack.empty() ) {
+ OperatorNode *lastNode = static_cast<OperatorNode*>(operatorStack.top());
+
+ if ( this->getPriority(lastNode->getFunction()) < priority ) {
+ operatorStack.push(
+ tree->addOperator(nullptr, currTerm[0])
+ );
+ } else {
+ Node *currOperator = operatorStack.top();
+ operatorStack.pop();
+
+ currOperator->rightChild = operandStack.top();
+ operandStack.pop();
+
+ currOperator->leftChild = operandStack.top();
+ operandStack.pop();
+
+ operandStack.push( currOperator );
+
+ termIter--;
+ }
+ } else {
+ operatorStack.push(tree->addOperator(nullptr, currTerm[0]));
+ }
+ } else {
+ tmpLexer = this->lexer(*termIter);
+
+ if ( tmpLexer.size() == 1 ) {
+ double value;
+ std::istringstream convertStream(tmpLexer[0]);
+ convertStream >> value;
+
+ operandStack.push(tree->addOperand(nullptr,value));
+ }
+ else if ( tmpLexer.size() > 1 ) {
+ operandStack.push(buildTree(tree, *termIter));
+ }
+ }
+ }
+
+ while ( !operatorStack.empty() ) {
+ OperatorNode *currOperator = static_cast<OperatorNode*>(operatorStack.top());
+ operatorStack.pop();
+
+ currOperator->rightChild = operandStack.top();
+ operandStack.pop();
+
+ currOperator->leftChild = operandStack.top();
+ operandStack.pop();
+
+ operandStack.push(currOperator);
+ }
+
+ return operandStack.top();
+}
+
+double Parser::calculate(std::string term) {
+ Tree termTree;
+ termTree.setRoot(this->buildTree(&termTree, term));
+
+ return termTree.solve();
+}
+
+}