//! \~\file pievaluator.h //! \~\ingroup Math //! \~\brief //! \~english Mathematical expression evaluator //! \~russian Вычислитель математических выражений //! \~\details //! \~english //! Declares evaluator types, expression storage, and the evaluator that //! prepares an expression once and then reuses compiled instructions. //! \~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 = std::move(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; }; //! \~\ingroup Math //! \~\brief //! \~english Expression evaluator with reusable compiled instructions. //! \~russian Вычислитель выражений с повторно используемыми скомпилированными инструкциями. //! //! \~\details //! \~english //! The evaluator prepares an expression with \a check(), keeps the processed //! form and instruction list, and then reevaluates it after variable updates. //! Built-in constants include \c i, \c pi, and \c e. //! \~russian //! Вычислитель подготавливает выражение через \a check(), сохраняет //! обработанную форму и список инструкций, а затем повторно вычисляет его //! после обновления переменных. Встроенные константы: \c i, \c pi и \c e. class PIP_EXPORT PIEvaluator { public: //! \~english Constructs an empty evaluator. //! \~russian Создает пустой вычислитель. PIEvaluator() { correct = false; data_ = 0; } //! \~english Destroys the evaluator. //! \~russian Уничтожает вычислитель. ~PIEvaluator() { ; } //! \~english Returns custom user data passed to callback functions. //! \~russian Возвращает пользовательские данные, передаваемые в callback-функции. void * data() { return data_; } //! \~english Sets custom user data for callback functions. //! \~russian Устанавливает пользовательские данные для callback-функций. void setData(void * _data) { data_ = _data; } //! \~english Checks and compiles an expression. //! \~russian Проверяет и компилирует выражение. bool check(const PIString & string); //! \~english Returns true if the last \a check() succeeded. //! \~russian Возвращает true, если последний вызов \a check() завершился успешно. bool isCorrect() const { return correct; } //! \~english Sets a named variable and creates it if needed. //! \~russian Устанавливает именованную переменную и создает ее при необходимости. int setVariable(const PIString & name, complexd value = complexd(0.)); //! \~english Sets a variable by index. //! \~russian Устанавливает переменную по индексу. void setVariable(int index, complexd value = 0.); //! \~english Evaluates the last successfully compiled expression. //! \~russian Вычисляет последнее успешно скомпилированное выражение. complexd evaluate(); //! \~english Removes user-added variables and keeps built-in constants. //! \~russian Удаляет добавленные пользователем переменные и сохраняет встроенные константы. void clearCustomVariables() { content.clearCustomVariables(); } //! \~english Returns variable index by name, or -1. //! \~russian Возвращает индекс переменной по имени или -1. int variableIndex(const PIString & name) const { return content.findVariable(name); } //! \~english Returns unknown variables found during the last \a check(). //! \~russian Возвращает неизвестные переменные, найденные при последнем \a check(). const PIStringList & unknownVariables() const { return unknownVars; } //! \~english Returns variables used in the last checked expression. //! \~russian Возвращает переменные, использованные в последнем проверенном выражении. const PIStringList & usedVariables() const { return usedVars; } //! \~english Returns the normalized form of the last checked expression. //! \~russian Возвращает нормализованную форму последнего проверенного выражения. const PIString & expression() const { return currentString; } //! \~english Returns the last status or error text from \a check(). //! \~russian Возвращает последний статус или текст ошибки из \a check(). const PIString & error() const { return lastError; } //! \~english Returns the last evaluation result. //! \~russian Возвращает последний результат вычисления. const complexd & lastResult() const { return out; } //! \~english Serializes evaluator state. //! \~russian Сериализует состояние вычислителя. PIByteArray save() const; //! \~english Restores evaluator state from serialized data. //! \~russian Восстанавливает состояние вычислителя из сериализованных данных. 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