// ************************************************************************** // // (C) Copyright 2009 Swiss SIMTEC AG // // ************************************************************************** // // $HeadURL$ // $LastChangedBy$ // $LastChangedDate$ // $LastChangedRevision$ // // ************************************************************************** #pragma once #include #include namespace N_SST { /** * This class calculates algebraic texts with integer values and returns its * result as a signed value. It handles the operations - +, -, *, /, %, <<, >>. It * understands the paranthesis and priorities of operations, like * before -. It * also computes with variables, which names are case-sensitive. The values can be * decimal, hexadecimal (0x) or binary (0b). The variable-system implemented * virtual, so you can implement your own variable system (see getVariableValue()). * * * @author alois.wismer * @version 1.0 * @created 12-Mai-2010 16:26:43 */ class IntegerCalculator { public: /** * Describes the error happend while calculation of an expression * * @author alois.wismer * @version 1.0 * @created 17-Mai-2010 16:38:24 */ enum E_Error { /** * No error happend */ e_Ok, /** * The divisor is 0 */ e_DivisionByZero, /** * The operation/variable is not known. a_addErrorText will contain the unknown * operation/variable. */ e_UnknownOperationOrVariable, /** * Between to operators no variable/operand exists. a_addErrorText contains the 2 * operations. */ e_NoOperandBetweenOperators, /** * The operand contains invalid characters. a_addErrorText contains the invalid * operand. */ e_InvalidOperand, /** * There are more ) than ( */ e_MissingLeftParanthesis, /** * There are more ) than ( */ e_MissingRightParanthesis, /** * Something else went wrong */ e_UnknownError }; IntegerCalculator(); virtual ~IntegerCalculator() = default; /** * Converts the expressen in a_calcText into a signed value. Returns whether an * error happend in the variable a_error. If an error happend, the variable * a_addErrorText can contain more informaition about the error (see E_Error for * more information about errors). * * @param a_calcText * @param a_error * @param a_addErrorText */ int64_t calc(const std::string& a_calcText, E_Error& a_error, std::string* a_addErrorText = nullptr); /** * Adds or changes a case-sensitive variable to the calculator. * * @param a_name * @param a_value */ void addVariable(const std::string& a_name, const int64_t a_value); /** * Removes a case-sensitive variable from the calculator. * * @param a_name */ void removeVariable(const std::string& a_name); protected: /** * Contains all supported operations */ const std::map m_OperationList; /** * Contains all variables */ std::map m_VariableList; /** * The additional text for errors */ std::string m_AdditionalErrorText; /** * The number of open paranthesis */ int32_t m_ParanthesisCount; E_Error m_Error; /** * Calculates the expression (recursive) * * @param a_calcText * @param a_pos * @param a_IsEndParanthesis * @param a_prevOp * @param a_prevValue * @param a_initOp */ int64_t calc(const std::string& a_calcText, size_t& a_pos, bool& a_IsEndParanthesis, const std::string& a_prevOp = std::string(), const int64_t a_prevValue = 0, const std::string& a_initOp = std::string()); /** * Calculates an operation with respecting the priority of operations. This will * be done with recursion. * * @param a_calcText * @param a_pos * @param a_value1 * @param a_operation * @param a_value2 * @param a_prevOp */ bool 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); /** * Returns the inverted a_value if a_isNegative is true. a_isNegative will be * false after calling this function. * If a_isNegative is true, the NOT inverted a_value will be returned. * * @param a_value * @param a_isNegative */ static int64_t calcSign(const int64_t a_value, bool& a_isNegative); /** * Converts the value in form of text to a number. The Text can be decimal, hex * (0x) or binary (0b). * * @param a_valueText * @param a_pos */ int64_t convertValue(const std::string& a_valueText, size_t& a_pos); /** * Returns the next token (with space as separator). Heading spaces will be * ignored. * * @param a_calcText * @param a_pos */ static std::string getToken(const std::string& a_calcText, size_t& a_pos); /** * returns true if a_operation is a known operation. * * @param a_operation */ bool isOperation(const std::string& a_operation) const; /** * Calculates the opeation a_operations with a_value1 as first and a_value2 as * second operand. * * @param a_value1 * @param a_operation * @param a_value2 */ int64_t doOperation(const int64_t a_value1, const std::string& a_operation, const int64_t a_value2); /** * returns true if priority of a_opeation1 is higher than priority of a_operation2. * * * @param a_operation1 * @param a_operation2 */ bool isOperationPriorityHigher(const std::string& a_operation1, const std::string& a_operation2) const; /** * Returns true if the variable named a_variableName is known and a_value will be * filled with its value. If the variable is not found false will be returned. * Overload this virtual function if you want to implement your own variable-list. * * @param a_variableName * @param a_value */ virtual bool getVariableValue(const std::string& a_variableName, int64_t& a_value) const; /** * Returns true if a_char is a digit. When a_isHex is true, also the charactes a-f * will be accepted as digits. When a_isBin is true, only 0 and 1 will be treated * as digit. * * @param a_char * @param a_isHex * @param a_isBin */ static bool isDigit(const char a_char, const bool a_isHex = false, const bool a_isBin = false); /** * Returns the priority of the operation. A higher value means more priority. * * @param a_operation */ int16_t getPriority(const std::string& a_operation) const; /** * replaces in a_haystack all a_searchText with a_replaceText (not greedy). * * @param a_haystack * @param a_searchText * @param a_replaceText */ static void replace(std::string& a_haystack, const std::string& a_searchText, const std::string& a_replaceText); }; }