/*! \file pievaluator.h * \brief Mathematic expressions calculator */ /* 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 "pistringlist.h" #include "pimathcomplex.h" typedef complexd (*FuncFunc)(void * , int, complexd * ); namespace PIEvaluatorTypes { 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 = 0;} Function(const PIString & name, short args, BaseFunctions ftype) {identifier = name; arguments = args; type = ftype; handler = 0;} Function(const PIString & name, short args, FuncFunc h) {identifier = name; arguments = args; type = bfCustom; handler = h;} PIString identifier; BaseFunctions type; FuncFunc handler; short arguments; }; struct PIP_EXPORT Variable { Variable() {value = 0.; index = -1;} Variable(const PIString & var_name, complexd val, int ind = -1) {name = var_name; value = val; index = ind;} int index; PIString name; complexd value; }; }; /* ≠ : ≥ } ≤ { ⋀ & ⋁ | */ class PIP_EXPORT PIEvaluatorContent { friend class PIEvaluator; friend inline PIByteArray & operator <<(PIByteArray & s, const PIEvaluatorContent & v); friend inline PIByteArray & operator >>(PIByteArray & s, PIEvaluatorContent & v); 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, FuncFunc 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 removeVariable(int index); void removeVariable(const PIString & var_name) {removeVariable(findVariable(var_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 variable with name "name" void removeVariable(const PIString & name) {content.removeVariable(name);} //! 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);} inline bool operator < (PIEvaluatorTypes::Variable e1, PIEvaluatorTypes::Variable e2) {return e1.name > e2.name;} inline bool operator ==(PIEvaluatorTypes::Variable e1, PIEvaluatorTypes::Variable e2) {return e1.name == e2.name;} inline PIByteArray & operator <<(PIByteArray & s, const PIEvaluatorTypes::Instruction & v) { s << PIByteArray::RawData(&v, sizeof(v) - sizeof(v.operators)) << v.operators; return s; } inline PIByteArray & operator >>(PIByteArray & s, PIEvaluatorTypes::Instruction & v) { s >> PIByteArray::RawData(&v, sizeof(v) - sizeof(v.operators)) >> v.operators; return s; } inline PIByteArray & operator <<(PIByteArray & s, const PIEvaluatorTypes::Element & v) { s << PIByteArray::RawData(&v, sizeof(v)); return s; } inline PIByteArray & operator >>(PIByteArray & s, PIEvaluatorTypes::Element & v) { s >> PIByteArray::RawData(&v, sizeof(v)); return s; } inline PIByteArray & operator <<(PIByteArray & s, const PIEvaluatorTypes::Variable & v) { s << v.name << v.value; return s; } inline PIByteArray & operator >>(PIByteArray & s, PIEvaluatorTypes::Variable & v) { s >> v.name >> v.value; return s; } inline PIByteArray & operator <<(PIByteArray & s, const PIEvaluatorContent & v) { s << v.variables << v.cv_count; return s; } inline PIByteArray & operator >>(PIByteArray & s, PIEvaluatorContent & v) { s >> v.variables >> v.cv_count; return s; } #endif // PIEVALUATOR_H