318 lines
8.9 KiB
C++
318 lines
8.9 KiB
C++
/*
|
||
QAD - Qt ADvanced
|
||
|
||
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@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 <http://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
#ifndef QPIEVALUATOR_P_H
|
||
#define QPIEVALUATOR_P_H
|
||
|
||
#include <QDebug>
|
||
#include <QMap>
|
||
#include <QStringList>
|
||
#include <QVector>
|
||
#include <cmath>
|
||
#include <complex>
|
||
|
||
|
||
#ifndef PIP_MATH_COMPLEX
|
||
# define QPIEVALUATOR_COMPLEX
|
||
typedef std::complex<double> complexd;
|
||
const complexd complexd_i(0., 1.);
|
||
const complexd complexd_0(0.);
|
||
const complexd complexd_1(1.);
|
||
#endif
|
||
const double deg2rad_qpie = atan(1.) / 45.;
|
||
const double rad2deg_qpie = 45. / atan(1.);
|
||
|
||
inline complexd round_qpie(const complexd & c) {
|
||
return complexd(round(c.real()), round(c.imag()));
|
||
}
|
||
inline complexd floor_qpie(const complexd & c) {
|
||
return complexd(floor(c.real()), floor(c.imag()));
|
||
}
|
||
inline complexd ceil_qpie(const complexd & c) {
|
||
return complexd(ceil(c.real()), ceil(c.imag()));
|
||
}
|
||
#if (__cplusplus >= 201103L) // стандарт C++ 11 или выше
|
||
# define acosc_qpie acos
|
||
# define asinc_qpie asin
|
||
# define atanc_qpie atan
|
||
#else
|
||
inline complexd atanc_qpie(const complexd & c) {
|
||
return complexd(0., 0.5) * log((complexd_1 - complexd_i * c) / (complexd_1 + complexd_i * c));
|
||
}
|
||
inline complexd asinc_qpie(const complexd & c) {
|
||
return -complexd_i * log(complexd_i * c + sqrt(complexd_1 - c * c));
|
||
}
|
||
inline complexd acosc_qpie(const complexd & c) {
|
||
return -complexd_i * log(c + complexd_i * sqrt(complexd_1 - c * c));
|
||
}
|
||
#endif
|
||
|
||
namespace QPIEvaluatorTypes {
|
||
static const int operationCount = 14;
|
||
|
||
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,
|
||
bfSh,
|
||
bfCh,
|
||
bfTh,
|
||
bfCth,
|
||
bfSqrt,
|
||
bfSqr,
|
||
bfPow,
|
||
bfAbs,
|
||
bfLn,
|
||
bfLg,
|
||
bfLog,
|
||
bfSign,
|
||
bfIm,
|
||
bfRe,
|
||
bfArg,
|
||
bfLen,
|
||
bfConj,
|
||
bfRad,
|
||
bfDeg
|
||
};
|
||
|
||
struct Instruction {
|
||
Instruction() { ; }
|
||
Instruction(Operation oper, QVector<int> opers, int out_ind, int func = -1) {
|
||
operation = oper;
|
||
operators = opers;
|
||
out = out_ind;
|
||
function = func;
|
||
}
|
||
Operation operation;
|
||
QVector<int> operators;
|
||
int out;
|
||
int function;
|
||
};
|
||
struct Element {
|
||
Element() { ; }
|
||
Element(eType new_type, int new_num, int new_var_num = -1) { set(new_type, new_num, new_var_num); }
|
||
void set(eType new_type, int new_num, int new_var_num = -1) {
|
||
type = new_type;
|
||
num = new_num;
|
||
var_num = new_var_num;
|
||
}
|
||
eType type;
|
||
int num;
|
||
int var_num;
|
||
};
|
||
struct Function {
|
||
Function() {
|
||
arguments = 0;
|
||
type = bfUnknown;
|
||
}
|
||
Function(const QString & name, int args, BaseFunctions ftype) {
|
||
identifier = name;
|
||
arguments = args;
|
||
type = ftype;
|
||
}
|
||
QString identifier;
|
||
BaseFunctions type;
|
||
int arguments;
|
||
};
|
||
struct Variable {
|
||
Variable() { value = 0.; }
|
||
Variable(const QString & var_name, complexd val) {
|
||
name = var_name;
|
||
value = val;
|
||
}
|
||
QString name;
|
||
complexd value;
|
||
};
|
||
inline bool operator<(const Variable & s1, const Variable & s2) {
|
||
if (s1.name.size() != s2.name.size()) return s1.name.size() > s2.name.size();
|
||
return s1.name > s2.name;
|
||
}
|
||
} // namespace QPIEvaluatorTypes
|
||
|
||
|
||
/*
|
||
≠ :
|
||
≥ }
|
||
≤ {
|
||
⋀ &
|
||
⋁ |
|
||
*/
|
||
class QPIEvaluatorContent {
|
||
friend class QPIEvaluator;
|
||
|
||
public:
|
||
QPIEvaluatorContent();
|
||
~QPIEvaluatorContent() { ; }
|
||
|
||
void addFunction(const QString & name, int args = 1) {
|
||
functions.push_back(QPIEvaluatorTypes::Function(name, args, getBaseFunction(name)));
|
||
}
|
||
void addVariable(const QString & name, const complexd & val = 0., bool sort = true) {
|
||
variables.push_back(QPIEvaluatorTypes::Variable(name, val));
|
||
if (sort) sortVariables();
|
||
}
|
||
int functionsCount() const { return functions.size(); }
|
||
int variablesCount() const { return variables.size(); }
|
||
int customVariablesCount() const { return variables.size() - cv_count; }
|
||
int findFunction(const QString & name) const { return func_index.value(name, -1); }
|
||
int findVariable(const QString & name) const { return var_index.value(name, -1); }
|
||
QPIEvaluatorTypes::Function function(int index) {
|
||
if (index < 0 || index >= functions.size()) return QPIEvaluatorTypes::Function();
|
||
return functions[index];
|
||
}
|
||
QPIEvaluatorTypes::Variable variable(int index) {
|
||
if (index < 0 || index >= variables.size()) return QPIEvaluatorTypes::Variable();
|
||
return variables[index];
|
||
}
|
||
QPIEvaluatorTypes::Function function(const QString & name) { return function(findFunction(name)); }
|
||
QPIEvaluatorTypes::Variable variable(const QString & name) { return variable(findVariable(name)); }
|
||
QPIEvaluatorTypes::Variable customVariable(int index) {
|
||
if (index < cv_count || index >= variables.size() + cv_count) return QPIEvaluatorTypes::Variable();
|
||
return variables[index + cv_count];
|
||
}
|
||
bool setVariableValue(int index, complexd new_value);
|
||
bool setVariableName(int index, const QString & new_name);
|
||
bool setVariableValue(const QString & var_name, const complexd & new_value) {
|
||
return setVariableValue(findVariable(var_name), new_value);
|
||
}
|
||
bool setVariableName(const QString & var_name, const QString & new_name) { return setVariableName(findVariable(var_name), new_name); }
|
||
void removeVariable(int index) { variables.remove(index); }
|
||
void removeVariable(const QString & var_name) { removeVariable(findVariable(var_name)); }
|
||
void clearCustomVariables();
|
||
void sortVariables();
|
||
QPIEvaluatorTypes::BaseFunctions getBaseFunction(const QString & name);
|
||
|
||
private:
|
||
QVector<QPIEvaluatorTypes::Function> functions;
|
||
QVector<QPIEvaluatorTypes::Variable> variables;
|
||
QMap<QString, int> var_index, func_index;
|
||
int cv_count;
|
||
};
|
||
|
||
|
||
class QPIEvaluator {
|
||
public:
|
||
QPIEvaluator() { correct = false; }
|
||
~QPIEvaluator() { ; }
|
||
|
||
bool check(const QString & string);
|
||
bool isCorrect() const { return correct; }
|
||
int setVariable(const QString & name, complexd value = 0.);
|
||
void setVariable(int index, complexd value = 0.) {
|
||
if (index >= 0 && index < content.variablesCount()) content.setVariableValue(index, value);
|
||
}
|
||
void setCustomVariableValue(int index, complexd value = 0.) { content.variables[index + content.cv_count].value = value; }
|
||
complexd evaluate();
|
||
void removeVariable(const QString & name) { content.removeVariable(name); }
|
||
void clearCustomVariables() { content.clearCustomVariables(); }
|
||
int variableIndex(const QString & name) const { return content.findVariable(name); }
|
||
const QStringList & unknownVariables() const { return unknownVars; }
|
||
const QString & expression() const { return currentString; }
|
||
const QString & error() const { return lastError; }
|
||
const complexd & lastResult() const { return out; }
|
||
static QString inBrackets(const QString & string);
|
||
|
||
QPIEvaluatorContent content;
|
||
|
||
private:
|
||
const QString & prepare(const QString & string);
|
||
const QString & preprocess(const QString & string);
|
||
int parse(const QString & string, int offset = 0);
|
||
void convert();
|
||
void checkBrackets();
|
||
void removeSpaces();
|
||
void findUnknownVariables();
|
||
void removeJunk();
|
||
void replaceOperators();
|
||
void makeOutput(QString & string);
|
||
bool fillElements();
|
||
bool setSignes();
|
||
bool isSign(const QChar & ch);
|
||
QString inverse(const QString & string) {
|
||
int len = string.length();
|
||
QString s;
|
||
for (int i = 0; i < len; i++)
|
||
s += string[len - i - 1];
|
||
return s;
|
||
}
|
||
bool check();
|
||
bool execInstructions();
|
||
QString operationChar(const QPIEvaluatorTypes::Operation & operation);
|
||
void operationsByPriority(int p, QVector<QPIEvaluatorTypes::Operation> & ret);
|
||
QPIEvaluatorTypes::Operation operationInOrder(const int & index);
|
||
complexd value(const int & index) {
|
||
if (index < 0)
|
||
return tmpvars[-index - 1].value;
|
||
else
|
||
return kvars->at(index).value;
|
||
}
|
||
inline complexd residue(const complexd & f, const complexd & s);
|
||
inline void execFunction(const QPIEvaluatorTypes::Instruction & ci);
|
||
|
||
QVector<QPIEvaluatorTypes::Element> elements;
|
||
QVector<QPIEvaluatorTypes::Variable> currentVariables, variables, tmpvars, *kvars;
|
||
QVector<QPIEvaluatorTypes::Instruction> instructions;
|
||
QStringList unknownVars;
|
||
QString currentString, lastError;
|
||
complexd out;
|
||
bool correct;
|
||
};
|
||
|
||
|
||
inline bool operator==(QPIEvaluatorTypes::Element e1, QPIEvaluatorTypes::Element e2) {
|
||
return (e1.type == e2.type && e1.num == e2.num);
|
||
}
|
||
inline bool operator!=(QPIEvaluatorTypes::Element e1, QPIEvaluatorTypes::Element e2) {
|
||
return (e1.type != e2.type || e1.num != e2.num);
|
||
}
|
||
|
||
#endif // QPIEVALUATOR_P_H
|