/*! \file pievaluator.h * \ingroup Math * \~\brief * \~english Mathematic expressions calculator * \~russian Вычислитель математических выражений */ /* PIP - Platform Independent Primitives Evaluator designed for stream calculations Ivan Pelipenko peri4ko@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef PIEVALUATOR_H #define PIEVALUATOR_H #include "pimathcomplex.h" #include "pistringlist.h" namespace PIEvaluatorTypes { typedef std::function FuncHanlder; enum eType { etNumber, etOperator, etVariable, etFunction }; enum Operation { oNone, oAdd, oSubtract, oMultiply, oDivide, oResidue, oPower, oEqual, oNotEqual, oGreater, oSmaller, oGreaterEqual, oSmallerEqual, oAnd, oOr, oFunction }; enum BaseFunctions { bfUnknown, bfSin, bfCos, bfTg, bfCtg, bfArcsin, bfArccos, bfArctg, bfArcctg, bfExp, bfRandom, bfRandomn, bfSh, bfCh, bfTh, bfCth, bfSqrt, bfSqr, bfPow, bfAbs, bfLn, bfLg, bfLog, bfSign, bfIm, bfRe, bfArg, bfLen, bfConj, bfRad, bfDeg, bfJ0, bfJ1, bfJN, bfY0, bfY1, bfYN, bfMin, bfMax, bfClamp, bfStep, bfMix, bfDefined, bfRound, bfCustom = 0xFFFF }; struct PIP_EXPORT Instruction { Instruction() { out = -1; function = -1; operation = oNone; } Instruction(Operation oper, PIVector opers, short out_ind, short func = -1) { operation = oper; operators = opers; out = out_ind; function = func; } Operation operation; short out; short function; PIVector operators; }; struct PIP_EXPORT Element { Element() { num = 0; var_num = -1; type = etNumber; } Element(eType new_type, short new_num, short new_var_num = -1) { set(new_type, new_num, new_var_num); } void set(eType new_type, short new_num, short new_var_num = -1) { type = new_type; num = new_num; var_num = new_var_num; } eType type; short num; short var_num; }; struct PIP_EXPORT Function { Function() { arguments = 0; type = bfUnknown; handler = nullptr; } Function(const PIString & name, short args, BaseFunctions ftype) { identifier = name; arguments = args; type = ftype; handler = nullptr; } Function(const PIString & name, short args, FuncHanlder h) { identifier = name; arguments = args; type = bfCustom; handler = h; } PIString identifier; BaseFunctions type; FuncHanlder handler; short arguments; }; struct PIP_EXPORT Variable { Variable() { value = 0.; } Variable(const PIString & var_name, complexd val) { name = var_name; value = val; } PIString name; complexd value; }; } // namespace PIEvaluatorTypes /* ≠ : ≥ } ≤ { ⋀ & ⋁ | */ class PIP_EXPORT PIEvaluatorContent { friend class PIEvaluator; BINARY_STREAM_FRIEND(PIEvaluatorContent); public: PIEvaluatorContent(); ~PIEvaluatorContent() { ; } void addFunction(const PIString & name, int args = 1); int addVariable(const PIString & name, const complexd & val = 0.); void addCustomFunction(const PIString & name, int args_count, PIEvaluatorTypes::FuncHanlder func); int functionsCount() const { return functions.size(); } int variablesCount() const { return variables.size(); } int customVariablesCount() const; int findFunction(const PIString & name) const; int findVariable(const PIString & var_name) const; PIEvaluatorTypes::Function function(int index); PIEvaluatorTypes::Variable variable(int index); PIEvaluatorTypes::Function function(const PIString & name) { return function(findFunction(name)); } PIEvaluatorTypes::Variable variable(const PIString & name) { return variable(findVariable(name)); } PIEvaluatorTypes::Variable customVariable(int index); bool setVariableValue(int index, complexd new_value); bool setVariableValue(const PIString & var_name, const complexd & new_value) { return setVariableValue(findVariable(var_name), new_value); } bool setVariableName(int index, const PIString & new_name); bool setVariableName(const PIString & var_name, const PIString & new_name) { return setVariableName(findVariable(var_name), new_name); } void clearCustomVariables(); PIEvaluatorTypes::BaseFunctions getBaseFunction(const PIString & name); void dump(); private: PIVector functions; PIVector variables; int cv_count; }; class PIP_EXPORT PIEvaluator { public: //! Constructs an empty evaluator PIEvaluator() { correct = false; data_ = 0; } ~PIEvaluator() { ; } //! Returns custom data void * data() { return data_; } //! Set custom data to "_data" void setData(void * _data) { data_ = _data; } //! Check mathematical expression and parse it to list of instructions bool check(const PIString & string); //! Returns true if expression was checked succesfully bool isCorrect() const { return correct; } //! Set variable value with name "name" to value "value". Add variable if it doesn`t exists int setVariable(const PIString & name, complexd value = complexd(0.)); //! Set variable value with index "index" to value "value". Don`t add variable if it doesn`t exists void setVariable(int index, complexd value = 0.); //! Evaluate last successfully checked with function \a check() expression and returns result complexd evaluate(); //! Remove all manually added variables void clearCustomVariables() { content.clearCustomVariables(); } //! Returns index of variable with name "name" int variableIndex(const PIString & name) const { return content.findVariable(name); } //! Returns all unknown variables founded in last expression passed to \a check() function const PIStringList & unknownVariables() const { return unknownVars; } //! Returns all used variables founded in last expression passed to \a check() function const PIStringList & usedVariables() const { return usedVars; } //! Returns processed last expression passed to \a check() function const PIString & expression() const { return currentString; } //! Returns last error description occured in \a check() function const PIString & error() const { return lastError; } //! Returns last result of \a evaluate() const complexd & lastResult() const { return out; } //! Save to %PIByteArray evaluator state (expression, variables, errors, compiled instructions) PIByteArray save() const; //! Restore from %PIByteArray evaluator state (expression, variables, errors, compiled instructions) void load(PIByteArray ba); private: const PIString & prepare(const PIString & string); PIString preprocess(const PIString & string); int parse(const PIString & string, int offset = 0); void convert(); void checkBrackets(); void removeSpaces(); void findUnknownVariables(); void removeJunk(); void replaceOperators(); void makeOutput(PIString & string); bool fillElements(); bool setSignes(); bool isSign(const PIChar & ch); PIString inverse(const PIString & string) { int len = string.length(); PIString s; for (int i = 0; i < len; i++) s += string[len - i - 1]; return s; } bool check(); bool execInstructions(); PIString inBrackets(const PIString & string); PIString operationChar(const PIEvaluatorTypes::Operation & operation); void operationsByPriority(int p, PIVector & ret); complexd value(const int & index) { if (index < 0) return tmpvars[-index - 1].value; else return content.variables[index].value; } inline complexd residue(const complexd & f, const complexd & s); inline void execFunction(const PIEvaluatorTypes::Instruction & ci); PIEvaluatorContent content; PIDeque elements; PIVector currentVariables, variables, tmpvars; PIVector instructions; PIStringList unknownVars, usedVars; PIString currentString, lastError; complexd out; bool correct; void * data_; }; inline bool operator==(PIEvaluatorTypes::Element e1, PIEvaluatorTypes::Element e2) { return (e1.type == e2.type && e1.num == e2.num); } inline bool operator!=(PIEvaluatorTypes::Element e1, PIEvaluatorTypes::Element e2) { return (e1.type != e2.type || e1.num != e2.num); } BINARY_STREAM_WRITE(PIEvaluatorTypes::Instruction) { s << PIMemoryBlock(&v, sizeof(v) - sizeof(v.operators)) << v.operators; return s; } BINARY_STREAM_READ(PIEvaluatorTypes::Instruction) { s >> PIMemoryBlock(&v, sizeof(v) - sizeof(v.operators)) >> v.operators; return s; } BINARY_STREAM_WRITE(PIEvaluatorTypes::Element) { s << createMemoryBlock(&v); return s; } BINARY_STREAM_READ(PIEvaluatorTypes::Element) { s >> createMemoryBlock(&v); return s; } BINARY_STREAM_WRITE(PIEvaluatorTypes::Variable) { s << v.name << v.value; return s; } BINARY_STREAM_READ(PIEvaluatorTypes::Variable) { s >> v.name >> v.value; return s; } BINARY_STREAM_WRITE(PIEvaluatorContent) { s << v.variables << v.cv_count; return s; } BINARY_STREAM_READ(PIEvaluatorContent) { s >> v.variables >> v.cv_count; return s; } #endif // PIEVALUATOR_H