1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
5 #include "simple_math.h"
13 // Using the algorithm from: https://en.wikipedia.org/wiki/Shunting-yard_algorithm
15 const std::set<char> SimpleMathExpression::whitespaces = {
19 const std::map<char, SimpleMathExpression::Operator> SimpleMathExpression::operators = {
20 { '+', { 0, std::plus<int>() } },
21 { '-', { 0, std::minus<int>() } },
22 { '*', { 1, std::multiplies<int>() } },
23 { '/', { 1, std::divides<int>() } },
24 { '%', { 1, std::modulus<int>() } },
27 void SimpleMathExpression::SetVariables(const std::map<char, int>& vars) {
31 bool SimpleMathExpression::SetExpression(const std::string & expression) {
32 m_expression = expression;
37 int SimpleMathExpression::Evaluate() const {
39 throw std::runtime_error("Evaluation error: not parsed yet");
42 std::stack<int> values;
43 for (Token t : m_parsedTokens) {
48 case Token::Operator: {
49 if (values.size() < 2) {
50 throw std::runtime_error("Illegal expression: not enough values for operator evaluation");
52 // pop last 2 values and apply operand
53 int val2 = values.top();
55 int val1 = values.top();
57 values.push(operators.at(t.op).second(val1, val2));
61 throw std::runtime_error("Illegal expression: unhandled token");
64 if (values.size() != 1) {
65 throw std::runtime_error("Illegal expression: not enough operators");
70 bool SimpleMathExpression::Parse() {
71 std::stack<char> operatorStack;
72 m_parsedTokens.clear();
74 // while there are tokens to be read:
75 for (size_t i = 0; i != m_expression.length(); i++) {
77 while (whitespaces.find(m_expression.at(i)) != whitespaces.end()) i++; // ignore whitespaces
78 char curr = m_expression.at(i);
80 // if the token is a number, then push it to the output queue.
83 int value = std::stoi(m_expression.substr(i), &len);
84 m_parsedTokens.push_back(Token(Token::Value, value, 0));
89 // if the token is a variable, then push it's value to the output queue.
90 if (m_variables.find(curr) != m_variables.end()) {
91 m_parsedTokens.push_back(Token(Token::Value, m_variables.at(curr), 0));
95 // if the token is an operator, then:
96 if (operators.find(curr) != operators.end()) {
97 // while there is an operator at the top of the operator stack with
98 // greater than or equal to precedence:
99 // pop operators from the operator stack, onto the output queue;
100 while ( !operatorStack.empty() &&
101 (operators.find(operatorStack.top()) != operators.end()) &&
102 (operators.at(operatorStack.top()).first >= operators.at(curr).first)) {
103 char op = operatorStack.top();
105 m_parsedTokens.push_back(Token(Token::Operator, 0, op));
107 // push the read operator onto the operator stack.
108 operatorStack.push(curr);
112 // if the token is a left bracket (i.e. "("), then:
113 // push it onto the operator stack.
115 operatorStack.push(curr);
119 // if the token is a right bracket (i.e. ")"), then:
121 // while the operator at the top of the operator stack is not a left bracket:
122 // pop operators from the operator stack onto the output queue.
123 while (!operatorStack.empty() && operatorStack.top() != '(') {
124 m_parsedTokens.push_back(Token(Token::Operator, 0, operatorStack.top()));
127 // pop the left bracket from the stack.
128 // /* if the stack runs out without finding a left bracket, then there are
129 // mismatched parentheses. */
130 if (!operatorStack.empty() && operatorStack.top() == '(') {
141 // if there are no more tokens to read:
142 // while there are still operator tokens on the stack:
143 // /* if the operator token on the top of the stack is a bracket, then
144 // there are mismatched parentheses. */
145 // pop the operator onto the output queue.
146 while (!operatorStack.empty()) {
147 if (operatorStack.top() == '(') {
150 m_parsedTokens.push_back(Token(Token::Operator, 0, operatorStack.top()));