#include "IntegerCalculator.hpp" #include #include namespace N_SST { IntegerCalculator::IntegerCalculator() : m_OperationList({{"*", 6},{"/", 6},{"%", 6},{"+", 5},{"-", 5},{"<<", 4},{">>", 4}}) , m_AdditionalErrorText() , m_ParanthesisCount(0) , m_Error(IntegerCalculator::e_Ok) { } int64_t IntegerCalculator::calc(const std::string& a_calcText, E_Error& a_error, std::string* a_addErrorText) { std::string calcText = a_calcText; for (auto iter = m_OperationList.begin(); iter != m_OperationList.end(); ++iter) replace(calcText, iter->first, " "+iter->first+" "); replace(calcText, "(", " ( "); replace(calcText, ")", " ) "); m_ParanthesisCount = 0; m_Error = e_Ok; m_AdditionalErrorText = ""; size_t pos = 0; bool dummy; int64_t value = calc(calcText, pos, dummy, "", 0, "+"); if (m_Error == e_Ok) { if (m_ParanthesisCount > 0) { m_Error = e_MissingRightParanthesis; } else if (m_ParanthesisCount < 0) { m_Error = e_MissingLeftParanthesis; } else if (pos != calcText.length()) { m_Error = e_UnknownError; } } a_error = m_Error; if (a_error != e_Ok) { value = 0; if (a_addErrorText) { *a_addErrorText = m_AdditionalErrorText; } } return value; } void IntegerCalculator::addVariable(const std::string& a_name, const int64_t a_value) { std::map::iterator iter = m_VariableList.find(a_name); if (iter != m_VariableList.end()) removeVariable(a_name); m_VariableList.insert(std::make_pair(a_name, a_value)); } void IntegerCalculator::removeVariable(const std::string& a_name) { std::map::iterator iter = m_VariableList.find(a_name); if (iter != m_VariableList.end()) m_VariableList.erase(iter); } int64_t IntegerCalculator::calc(const std::string& a_calcText, size_t& a_pos, bool& a_IsEndParanthesis, const std::string& a_prevOp, const int64_t a_prevValue, const std::string& a_initOp) { std::string operation = a_initOp; int64_t value1 = a_prevValue; bool isNegative = false; std::string calcText = a_calcText; a_IsEndParanthesis = false; while (a_pos < calcText.length()) { if (' ' == calcText[a_pos]) { a_pos++; } else if ('(' == calcText[a_pos]) { m_ParanthesisCount++; bool dummy; int64_t value2 = calcSign(calc(calcText, ++a_pos, dummy), isNegative); value1 = doOperation(value1, operation, value2); size_t tmpPos = a_pos; std::string nextOp = getToken(a_calcText, tmpPos); if (isOperation(nextOp) && isOperation(a_prevOp) && !isOperationPriorityHigher(nextOp, a_prevOp)) { return value1; } operation = ""; } else if (')' == calcText[a_pos]) { m_ParanthesisCount--; a_pos++; a_IsEndParanthesis = true; return value1; } else if (isDigit(calcText[a_pos])) { int64_t value2 = calcSign(convertValue(calcText, a_pos), isNegative); if (calcWithPriority(calcText, a_pos, value1, operation, value2, a_prevOp)) return value1; } else { std::string oldOperation = operation; operation = getToken(calcText, a_pos); if (!isOperation(operation)) { int64_t value2 = 0; if (getVariableValue(operation, value2)) { value2 = calcSign(value2, isNegative); if (calcWithPriority(calcText, a_pos, value1, oldOperation, value2, a_prevOp)) return value1; operation = ""; } else { m_Error = e_UnknownOperationOrVariable; m_AdditionalErrorText = operation; } } else { if (oldOperation != "") { if (operation == "+") { operation = oldOperation; } else if (operation == "-") { isNegative = !isNegative; operation = oldOperation; } else { m_Error = e_NoOperandBetweenOperators; m_AdditionalErrorText = oldOperation + " " + operation; return 0; } } } } } return value1; } bool IntegerCalculator::calcWithPriority(const std::string& a_calcText, size_t& a_pos, int64_t& a_value1, std::string& a_operation, int64_t a_value2, const std::string& a_prevOp) { bool isParaEnd = false; size_t tmpPos = a_pos; std::string nextOp = getToken(a_calcText, tmpPos); if (isOperation(a_operation) && isOperation(nextOp) && isOperationPriorityHigher(nextOp, a_operation)) { a_value2 = calc(a_calcText, a_pos, isParaEnd, a_operation, a_value2); } a_value1 = doOperation(a_value1, a_operation, a_value2); if (isParaEnd || (isOperation(nextOp) && isOperation(a_prevOp) && !isOperationPriorityHigher(nextOp, a_prevOp))) { return true; } a_operation = ""; return false; } int64_t IntegerCalculator::calcSign(const int64_t a_value, bool& a_isNegative) { if (a_isNegative) { a_isNegative = false; return -a_value; } return a_value; } int64_t IntegerCalculator::convertValue(const std::string &a_valueText, size_t& a_pos) { std::string valueText = a_valueText.substr(a_pos); int base = 10; size_t startpos = 0; bool isHex = (0 == valueText.find("0X")) || (0 == valueText.find("0x")); bool isBin = (0 == valueText.find("0B")) || (0 == valueText.find("0b")); if (isHex) { base = 16; startpos = 2; } else if (isBin) { base = 2; startpos = 2; } size_t i; for (i=startpos; i i && valueText[i] != ' ') { m_Error = e_InvalidOperand; int spacePos = valueText.find(' '); m_AdditionalErrorText = valueText.substr(0, spacePos); } a_pos += i; int64_t value = 0; std::stringstream stream; stream.str(valueText.substr(startpos, i-startpos)); if (2 == base) { const std::string binValueAsText = stream.str(); for (const char c : binValueAsText) { value = value << 1; if (c == '1') value += 1; } } else { stream << std::setbase(base); stream >> value; } return value; } std::string IntegerCalculator::getToken(const std::string &a_calcText, size_t& a_pos) { while (a_pos < a_calcText.length()) { if (a_calcText[a_pos] == ' ') a_pos++; else break; } size_t startPos = a_pos; while (a_pos < a_calcText.length()) { if (' ' == a_calcText[a_pos]) break; a_pos++; } return a_calcText.substr(startPos, a_pos-startPos); } bool IntegerCalculator::isOperation(const std::string& a_operation) const { std::map::const_iterator iter = m_OperationList.find(a_operation); return (iter != m_OperationList.end()); } int64_t IntegerCalculator::doOperation(const int64_t a_value1, const std::string& a_operation, const int64_t a_value2) { if (("+" == a_operation) || a_operation.empty()) { return a_value1 + a_value2; } else if ("-" == a_operation) { return a_value1 - a_value2; } else if ("*" == a_operation) { return a_value1 * a_value2; } else if ("/" == a_operation) { if (0 == a_value2) { m_Error = e_DivisionByZero; } else { return a_value1 / a_value2; } } else if ("%" == a_operation) { if (0 == a_value2) { m_Error = e_DivisionByZero; } else { return a_value1 % a_value2; } } else if ("<<" == a_operation) { return a_value1 << a_value2; } else if (">>" == a_operation) { return a_value1 >> a_value2; } else { m_Error = e_UnknownOperationOrVariable; m_AdditionalErrorText = a_operation; } return 0; } bool IntegerCalculator::isOperationPriorityHigher(const std::string& a_operation1, const std::string& a_operation2) const { return (getPriority(a_operation1) > getPriority(a_operation2)); } bool IntegerCalculator::getVariableValue(const std::string& a_variableName, int64_t& a_value) const { auto iter = m_VariableList.find(a_variableName); if (iter != m_VariableList.end()) { a_value = iter->second; return true; } return false; } bool IntegerCalculator::isDigit(const char a_char, const bool a_isHex, const bool a_isBin) { if (a_isHex) { return (a_char >= '0' && a_char <= '9') || (a_char >= 'A' && a_char <= 'F') || (a_char >= 'a' && a_char <= 'f'); } else if (a_isBin) { return (a_char >= '0' && a_char <= '1'); } return (a_char >= '0' && a_char <= '9'); } int16_t IntegerCalculator::getPriority(const std::string& a_operation) const { std::map::const_iterator iter = m_OperationList.find(a_operation); if (iter != m_OperationList.end()) return iter->second; return -1; } void IntegerCalculator::replace(std::string& a_haystack, const std::string &a_searchText, const std::string &a_replaceText) { std::string::size_type searchSize = a_searchText.length(); std::string::size_type replaceSize = a_replaceText.length(); std::string::size_type pos = a_haystack.find(a_searchText, 0); while (std::string::npos != pos) { a_haystack.replace(pos, searchSize, a_replaceText); pos += replaceSize; pos = a_haystack.find(a_searchText, pos); } } }