Windows works

This commit is contained in:
2020-09-06 21:46:06 +03:00
parent 32707fbd4d
commit b1536eb16a
12 changed files with 81 additions and 63 deletions

View File

@@ -8,12 +8,14 @@
#include <QStyle>
#include <QStyleOptionSpinBox>
#include "qad_types.h"
#include "qpievaluator_p.h"
EvalSpinBox::EvalSpinBox(QWidget * parent): QAbstractSpinBox(parent) {
status = new QWidget(lineEdit());
cw = new QWidget(lineEdit());
label = new QLabel(lineEdit());
eval = new QPIEvaluator();
precision_ = -1;
// label->hide();
clear_im.load(":/icons/edit-clear-locationbar-rtl.png");
@@ -40,9 +42,10 @@ EvalSpinBox::EvalSpinBox(QWidget * parent): QAbstractSpinBox(parent) {
EvalSpinBox::~EvalSpinBox() {
delete eval;
delete label;
delete cw;
delete status;
delete label;
}
@@ -124,9 +127,9 @@ void EvalSpinBox::textChanged_(const QString & text) {
td = true;
t.chop(1);
}
bool ok = eval.check(t);
bool ok = eval->check(t);
if (ok) {
eval.evaluate();
eval->evaluate();
if (td) {
icon = icon_calc;
status->setToolTip("Enter to calc -> "+QString::number(value(), 'G', 10));
@@ -138,7 +141,7 @@ void EvalSpinBox::textChanged_(const QString & text) {
if (pv != value()) emit valueChanged(value());
} else {
icon = icon_fail;
status->setToolTip(eval.error());
status->setToolTip(eval->error());
}
resizeIcons();
}
@@ -152,16 +155,16 @@ void EvalSpinBox::setExpression_() {
td = true;
t.chop(1);
}
if (eval.check(t)) {
if (eval->check(t)) {
/*if (eval.expression() == "0") lineEdit()->clear();
else*/ lineEdit()->setText(eval.expression());
eval.evaluate();
else*/ lineEdit()->setText(eval->expression());
eval->evaluate();
if (td) lineEdit()->setText(QString::number(value(), 'G', precision_ > 0 ? precision_ : 16));
status->setToolTip("OK -> " + QString::number(value(), 'G', 10));
icon = icon_ok;
} else {
icon = icon_fail;
status->setToolTip(eval.error());
status->setToolTip(eval->error());
// qDebug() << eval.expression();
}
if (!label->isHidden()) {
@@ -169,12 +172,12 @@ void EvalSpinBox::setExpression_() {
// label->setText("<html><head/><body><p>" + eval.expression() + " <span style=\"color:#005500;\">-&gt; " + QString::number(value(), 'G', 10) + "</span></p></body></html>");
// else
// label->setText(eval.expression());
if (eval.expression() != QString::number(value(), 'G', 10) && eval.expression() != QString::number(value(), 'G', 11) && eval.isCorrect())
if (eval->expression() != QString::number(value(), 'G', 10) && eval->expression() != QString::number(value(), 'G', 11) && eval->isCorrect())
label->setText("<html><head/><body><p><span style=\"color:#005500;\">-&gt; " + QString::number(value(), 'G', 10) + "</span></p></body></html>");
else
label->setText("");
lineEdit()->blockSignals(true);
if (!eval.isCorrect()) {
if (!eval->isCorrect()) {
lineEdit()->setStyleSheet("color: darkred;");
status->show();
} else {
@@ -222,20 +225,20 @@ void EvalSpinBox::clear() {
double EvalSpinBox::value() const {
if (eval.isCorrect()) {
return eval.lastResult().real();
if (eval->isCorrect()) {
return eval->lastResult().real();
}
return 0.;
}
const QString & EvalSpinBox::expression() const {
return eval.expression();
return eval->expression();
}
bool EvalSpinBox::isCleared() const {
return (dt == eval.expression() || (value() == 0 && dt.isEmpty()));
return (dt == eval->expression() || (value() == 0 && dt.isEmpty()));
}
@@ -257,7 +260,7 @@ void EvalSpinBox::focusInEvent(QFocusEvent * event) {
status->show();
lineEdit()->blockSignals(true);
lineEdit()->setStyleSheet("");
if (eval.expression() == "0") lineEdit()->clear();
if (eval->expression() == "0") lineEdit()->clear();
lineEdit()->blockSignals(false);
QAbstractSpinBox::focusInEvent(event);
resizeIcons();
@@ -271,13 +274,13 @@ void EvalSpinBox::focusOutEvent(QFocusEvent * event) {
// label->setText("<html><head/><body><p>" + eval.expression() + " <span style=\"color:#005500;\">-&gt; " + QString::number(value(), 'G', 10) + "</span></p></body></html>");
// else
// label->setText(eval.expression());
if (eval.expression() != QString::number(value(), 'G', 10) && eval.expression() != QString::number(value(), 'G', 11) && eval.isCorrect())
if (eval->expression() != QString::number(value(), 'G', 10) && eval->expression() != QString::number(value(), 'G', 11) && eval->isCorrect())
label->setText("<html><head/><body><p><span style=\"color:#005500;\">-&gt; " + QString::number(value(), 'G', 10) + "</span></p></body></html>");
else
label->setText("");
label->show();
lineEdit()->blockSignals(true);
if (!eval.isCorrect()) lineEdit()->setStyleSheet("color: darkred;");
if (!eval->isCorrect()) lineEdit()->setStyleSheet("color: darkred;");
else status->hide();
// lineEdit()->setText(eval.expression() + " -> " + QString::number(value(), 'G', 10));
//lineEdit()->clear();
@@ -298,8 +301,8 @@ void EvalSpinBox::stepByDouble(double steps) {
//qDebug() << "step" << steps;
if (isReadOnly()) return;
QString t = text();
if (eval.check(t)) {
t = eval.expression();
if (eval->check(t)) {
t = eval->expression();
//QRegExp re("(\\-?\\d+)");
QRegExp re("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)");
int pos = 0;
@@ -312,8 +315,8 @@ void EvalSpinBox::stepByDouble(double steps) {
double v = steps;
t = QString::number(v) + t;
}
eval.check(t);
lineEdit()->setText(eval.expression());
eval->check(t);
lineEdit()->setText(eval->expression());
}
}
@@ -326,13 +329,13 @@ void EvalSpinBox::setDefaultText(const QString & t) {
// setExpression_();
// }
//if (t == eval.expression() || (value() == 0 && t.isEmpty())) clear();
cw->setVisible((eval.expression() != dt || (dt.isEmpty() && eval.expression() == "0")) && cw_visible);
cw->setVisible((eval->expression() != dt || (dt.isEmpty() && eval->expression() == "0")) && cw_visible);
resizeIcons();
}
void EvalSpinBox::setClearButtonVisible(bool visible) {
cw_visible = visible;
cw->setVisible((eval.expression() != dt || (dt.isEmpty() && eval.expression() == "0")) && cw_visible);
cw->setVisible((eval->expression() != dt || (dt.isEmpty() && eval->expression() == "0")) && cw_visible);
resizeIcons();
}

View File

@@ -22,9 +22,10 @@
#include <QAbstractSpinBox>
#include <QMouseEvent>
#include "qpievaluator.h"
#include "qad_widgets_export.h"
class QPIEvaluator;
class QLabel;
@@ -64,7 +65,7 @@ protected:
QWidget * status;
QWidget * cw;
QPIEvaluator eval;
QPIEvaluator * eval;
QLabel * label;
QImage icon_ok;
QImage icon_fail;

View File

@@ -1,5 +1,5 @@
#include "qpiconfigvaluewidget.h"
#include "qpievaluator.h"
#include "qpievaluator_p.h"
ConfigValueWidget::ConfigValueWidget(QWidget * parent): QWidget(parent), lay(QBoxLayout::Down, this) {

View File

@@ -0,0 +1,1050 @@
#include "qpievaluator_p.h"
QPIEvaluatorContent::QPIEvaluatorContent() {
addFunction("arcsin", 1);
addFunction("arccos", 1);
addFunction("arctg", 1);
addFunction("arcctg", 1);
addFunction("random", 2);
addFunction("sin", 1);
addFunction("cos", 1);
addFunction("ctg", 1);
addFunction("tg", 1);
addFunction("exp", 1);
addFunction("cth", 1);
addFunction("sh", 1);
addFunction("ch", 1);
addFunction("th", 1);
addFunction("sqrt", 1);
addFunction("sqr", 1);
addFunction("pow", 2);
addFunction("abs", 1);
addFunction("ln", 1);
addFunction("lg", 1);
addFunction("log", 2);
addFunction("im", 1);
addFunction("re", 1);
addFunction("arg", 1);
addFunction("len", 1);
addFunction("conj", 1);
addFunction("sign", 1);
addFunction("rad", 1);
addFunction("deg", 1);
clearCustomVariables();
//addVariable("n", 0.);
//addVariable("x1", 123);
}
bool QPIEvaluatorContent::setVariableValue(int index, complexd new_value) {
if (index < 0 || index >= variables.size()) return false;
variables[index].value = new_value;
return true;
}
bool QPIEvaluatorContent::setVariableName(int index, const QString & new_name) {
if (index < 0 || index >= variables.size()) return false;
variables[index].name = new_name;
return true;
}
void QPIEvaluatorContent::clearCustomVariables() {
var_index.clear();
func_index.clear();
variables.clear();
addVariable("i", complexd_i);
addVariable("pi", atan(1.) * 4.);
addVariable("e", exp(1.));
cv_count = variables.size();
}
void QPIEvaluatorContent::sortVariables() {
var_index.clear();
#if QT_VERSION < QT_VERSION_CHECK(5,13,0)
qSort
#else
std::sort
#endif
(variables.begin(), variables.end());
for (int i = 0; i < variables.size(); i++)
var_index[variables[i].name] = i;
/*
qDebug() << "---";
for (int i = 0; i < variables.size(); i++) {
qDebug() << variables[i].name;
}
*/
}
QPIEvaluatorTypes::BaseFunctions QPIEvaluatorContent::getBaseFunction(const QString & name) {
if (name == "sin") return QPIEvaluatorTypes::bfSin;
if (name == "cos") return QPIEvaluatorTypes::bfCos;
if (name == "tg") return QPIEvaluatorTypes::bfTg;
if (name == "ctg") return QPIEvaluatorTypes::bfCtg;
if (name == "arcsin") return QPIEvaluatorTypes::bfArcsin;
if (name == "arccos") return QPIEvaluatorTypes::bfArccos;
if (name == "arctg") return QPIEvaluatorTypes::bfArctg;
if (name == "arcctg") return QPIEvaluatorTypes::bfArcctg;
if (name == "exp") return QPIEvaluatorTypes::bfExp;
if (name == "random") return QPIEvaluatorTypes::bfRandom;
if (name == "sh") return QPIEvaluatorTypes::bfSh;
if (name == "ch") return QPIEvaluatorTypes::bfCh;
if (name == "th") return QPIEvaluatorTypes::bfTh;
if (name == "cth") return QPIEvaluatorTypes::bfCth;
if (name == "sqrt") return QPIEvaluatorTypes::bfSqrt;
if (name == "sqr") return QPIEvaluatorTypes::bfSqr;
if (name == "pow") return QPIEvaluatorTypes::bfPow;
if (name == "abs") return QPIEvaluatorTypes::bfAbs;
if (name == "ln") return QPIEvaluatorTypes::bfLn;
if (name == "lg") return QPIEvaluatorTypes::bfLg;
if (name == "log") return QPIEvaluatorTypes::bfLog;
if (name == "im") return QPIEvaluatorTypes::bfIm;
if (name == "re") return QPIEvaluatorTypes::bfRe;
if (name == "arg") return QPIEvaluatorTypes::bfArg;
if (name == "len") return QPIEvaluatorTypes::bfLen;
if (name == "conj") return QPIEvaluatorTypes::bfConj;
if (name == "sign") return QPIEvaluatorTypes::bfSign;
if (name == "rad") return QPIEvaluatorTypes::bfRad;
if (name == "deg") return QPIEvaluatorTypes::bfDeg;
return QPIEvaluatorTypes::bfUnknown;
}
const QString & QPIEvaluator::prepare(const QString & string) {
currentString = string.trimmed();
if (currentString.isEmpty()) currentString = "0";
replaceOperators();
removeSpaces();
checkBrackets();
while (fillElements()) checkBrackets();
while (setSignes()) fillElements();
removeJunk();
findUnknownVariables();
return currentString;
}
void QPIEvaluator::removeSpaces() {
QString tmps = currentString;
for (int i = 0; i < tmps.length(); i++) {
if (tmps[i] == ' ' || tmps[i] == '\t') {
tmps.remove(i, 1);
i--;
}
}
currentString = tmps;
}
void QPIEvaluator::removeJunk() {
QChar cc;
bool junk = true;
int bcnt;
while (junk) {
if (currentString.left(1) != "(" || currentString.right(1) != ")") return;
bcnt = 1;
junk = false;
for (int i = 1; i < currentString.length(); i++) {
cc = currentString[i];
if (cc == '(') bcnt++;
if (cc == ')') bcnt--;
if (bcnt == 0) {
if (i == currentString.length() - 1) {
currentString = currentString.mid(1, currentString.length() - 2);
elements.pop_front();
elements.pop_back();
junk = true;
break;
} else break;
}
}
}
}
void QPIEvaluator::replaceOperators() {
currentString.replace("==", "=");
currentString.replace("!=", ":");
currentString.replace(">=", "}");
currentString.replace("<=", "{");
currentString.replace("&&", "&");
currentString.replace("||", "|");
}
void QPIEvaluator::makeOutput(QString & string) {
string.replace(":", "");
string.replace("}", "");
string.replace("{", "");
string.replace("&", "");
string.replace("|", "");
}
void QPIEvaluator::findUnknownVariables() {
QString cvar;
unknownVars.clear();
for (int i = 0; i < currentString.length(); i++) {
if (elements[i].var_num == -666) cvar += currentString[i];
else {
if (cvar.length() == 0) continue;
unknownVars << cvar;
cvar = "";
}
}
if (cvar.length() > 0) unknownVars << cvar;
unknownVars.removeDuplicates();
}
bool QPIEvaluator::isSign(const QChar & ch) {
return ch == '+' || ch == '-' ||
ch == '*' || ch == '/' ||
ch == '%' || ch == '^' ||
ch == '=' || ch == ':' ||
ch == '>' || ch == '<' ||
ch == '}' || ch == '{' ||
ch == '&' || ch == '|';
}
void QPIEvaluator::checkBrackets() {
QString tmps = currentString;
QChar fc, sc;
int bcnt = 0, bpos = 0, inserted = 0;
currentString = tmps;
for (int i = 0; i < tmps.length(); i++) {
if (tmps[i] == '(') {
if (bcnt == 0) bpos = i;
bcnt++;
}
if (tmps[i] == ')') {
if (bcnt == 0) {
currentString.insert(bpos + inserted, "(");
inserted++;
} else bcnt--;
}
}
if (bcnt > 0) currentString += QString(bcnt, ')');
tmps = currentString;
for (int i = 0; i < tmps.length() - 1; i++) {
fc = tmps[i].toLower();
sc = tmps[i + 1].toLower();
if ((fc == ')' && sc == '(') ||
(fc == ')' && sc >= '0' && sc <= '9') ||
(fc == ')' && sc >= 'a' && sc <= 'z') ) tmps.insert(++i, '*');
}
currentString = tmps;
}
bool QPIEvaluator::fillElements() {
int fstart, flen, cnum = 0, cpart = 0, cfunc;
QChar cc, nc, pc, fc = '!';
bool numFound = false;
QString curfind, tmps = currentString;
elements.resize(tmps.length());
for (int i = 0; i < elements.size(); i++) {
elements[i].type = QPIEvaluatorTypes::etVariable;
elements[i].var_num = -666;
}
currentVariables.clear();
//qDebug().nospace() << "search for functions ...";
for (int i = 0; i < content.functionsCount(); i++) {
curfind = content.function(i).identifier;
cfunc = i; //(int)content.function(i).type;
flen = curfind.length();
fstart = 0;
while (fstart >= 0) {
fstart = tmps.indexOf(curfind, fstart);
if (fstart < 0) break;
if (tmps[fstart + flen] != '(') {
//currentString.insert(fstart + flen, "(");
fstart++;
continue;
}
for (int j = fstart; j < fstart + flen; j++) {
elements[j].set(QPIEvaluatorTypes::etFunction, cnum, cfunc);
tmps.replace(j, 1, fc);
}
cnum++;
}
}
cnum = 0;
//qDebug().nospace() << "search for variables ...";
for (int i = 0; i < content.variablesCount(); i++) {
curfind = content.variable(i).name;
flen = curfind.length();
fstart = 0;
while (fstart >= 0) {
fstart = tmps.indexOf(curfind, fstart);
if (fstart < 0) break;
for (int j = fstart; j < fstart + flen; j++) {
elements[j].set(QPIEvaluatorTypes::etVariable, cnum, i);
tmps.replace(j, 1, fc);
}
cnum++;
}
}
curfind = "";
cnum = 1;
//qDebug().nospace() << "search for numbers ...";
for (int i = 0; i < tmps.length(); i++) {
cc = tmps[i];
/*if (cc == " " || cc == "(" || cc == ")") {
curfind = "";
cpart = 0;
numFound = false;
continue;
}*/
switch (cpart) {
case 0:
if ((cc >= '0' && cc <= '9')) {// || cc == '-' || cc == '+') {
curfind += cc;
cpart = 1;
continue;
}
if (cc == '.') {
curfind += cc;
cpart = 2;
continue;
}
if (cc == 'E') {
curfind += cc;
cpart = 3;
continue;
}
break;
case 1:
if (cc >= '0' && cc <= '9') {
curfind += cc;
continue;
}
if (cc == '.') {
curfind += cc;
cpart = 2;
continue;
}
if (cc == 'E') {
curfind += cc;
cpart = 3;
continue;
}
numFound = true;
break;
case 2:
if (cc >= '0' && cc <= '9') {
curfind += cc;
continue;
}
if (cc == 'E') {
curfind += cc;
cpart = 3;
continue;
}
numFound = true;
break;
case 3:
if ((cc >= '0' && cc <= '9') || cc == '-' || cc == '+') {
curfind += cc;
cpart = 4;
continue;
}
numFound = true;
break;
case 4:
if (cc >= '0' && cc <= '9') {
curfind += cc;
continue;
}
numFound = true;
break;
}
if (numFound) {
//qDebug().nospace() << "add " << cnum << ": " << curfind << " = " << curfind.toDouble();
currentVariables.push_back(QPIEvaluatorTypes::Variable("tmp" + QString::number(cnum), curfind.toDouble()));
for (int j = i - curfind.length(); j < i; j++) {
elements[j].set(QPIEvaluatorTypes::etNumber, cnum, -cnum);
tmps.replace(j, 1, fc);
}
curfind = "";
cnum++;
cpart = 0;
numFound = false;
}
}
if (cpart > 0) {
//qDebug().nospace() << "add " << cnum << ": " << curfind << " = " << curfind.toDouble();
currentVariables.push_back(QPIEvaluatorTypes::Variable("tmp" + QString::number(cnum), curfind.toDouble()));
for (int j = tmps.length() - curfind.length(); j < tmps.length(); j++) {
elements[j].set(QPIEvaluatorTypes::etNumber, cnum, -cnum);
tmps.replace(j, 1, fc);
}
}
cc = nc = fc;
//qDebug().nospace() << "search for signes ...";
for (int i = 0; i < tmps.length(); i++) {
cc = tmps[i];
if (i > 0) pc = tmps[i - 1];
else pc = fc;
if (i < tmps.length() - 1) nc = tmps[i + 1];
else nc = fc;
if (cc == '(' || cc == ')' || cc == ',') {
elements[i].set(QPIEvaluatorTypes::etOperator, -1);
continue;
}
if (cc == '-' || cc == '+') {
elements[i].set(QPIEvaluatorTypes::etOperator, -1);
if (i < tmps.length() - 1) if (elements[i + 1].type == QPIEvaluatorTypes::etVariable ||
elements[i + 1].type == QPIEvaluatorTypes::etFunction) continue;
if ((pc == '(' || isSign(pc) || i == 0) && i < tmps.length() - 1) {
if (elements[i + 1].type != QPIEvaluatorTypes::etOperator) {
cnum = elements[i + 1].num;
elements[i].set(QPIEvaluatorTypes::etNumber, cnum);
tmps.replace(i, 1, fc);
///cout << "found sign " << cc << " :" << cnum - 1 << endl;
if (cc == '-' && currentVariables.size() >= cnum)
currentVariables[cnum - 1].value = -currentVariables[cnum - 1].value;
//i++;
continue;
}
}
}
if (isSign(cc)) {
elements[i].set(QPIEvaluatorTypes::etOperator, -1);
continue;
}
}
/*
qDebug().nospace() << tmps;
cout << " ";
for (int i = 0; i < elements.size(); i++) {
switch (elements[i].type) {
case etFunction: cout << "f"; break;
case etNumber: cout << "n"; break;
case etOperator: cout << "o"; break;
case etVariable: cout << "v"; break;
}
}
cout << endl;
*/
return false;
//for (int i = 0; i < currentVariables.size(); i++) qDebug() << "var " << i << ": " << currentVariables[i].value.real();
}
bool QPIEvaluator::setSignes() {
int inserted = 0, ni, pi = 0, needInsert = 0;
QChar fc, sc, pc;
QString tmps = currentString;
for (int i = 0; i < tmps.length() - 1; i++) {
needInsert = 0;
ni = i + 1;
if (i > 0) pi = i - 1;
fc = tmps[i].toLower();
sc = tmps[ni].toLower();
pc = tmps[pi].toLower();
//if (elements[i].type == etOperator || elements[ni].type == etVariable) continue;
if (fc == ',' || sc == ',') continue;
if (elements[i].type == QPIEvaluatorTypes::etOperator && elements[ni].type == QPIEvaluatorTypes::etOperator) continue;
if (fc == ')' && (elements[ni].type == QPIEvaluatorTypes::etNumber || elements[ni].type == QPIEvaluatorTypes::etVariable || elements[ni].type == QPIEvaluatorTypes::etFunction)) needInsert = 1;
if (sc == '(' && (elements[i].type == QPIEvaluatorTypes::etNumber || elements[i].type == QPIEvaluatorTypes::etVariable)) needInsert = 1;
if (elements[i].type == QPIEvaluatorTypes::etNumber && elements[ni].type == QPIEvaluatorTypes::etNumber && elements[i].num != elements[ni].num) needInsert = 1;
if (elements[i].type == QPIEvaluatorTypes::etVariable && elements[ni].type == QPIEvaluatorTypes::etVariable && elements[i].num != elements[ni].num) needInsert = 1;
if ((elements[i].type == QPIEvaluatorTypes::etNumber && elements[ni].type == QPIEvaluatorTypes::etVariable) || (elements[i].type == QPIEvaluatorTypes::etVariable && elements[ni].type == QPIEvaluatorTypes::etNumber)) needInsert = 1;
if ((elements[i].type == QPIEvaluatorTypes::etNumber || elements[i].type == QPIEvaluatorTypes::etVariable) && elements[ni].type == QPIEvaluatorTypes::etFunction) needInsert = 1;
if (elements[i].type == QPIEvaluatorTypes::etFunction && elements[ni].type == QPIEvaluatorTypes::etFunction && elements[i].num != elements[ni].num) needInsert = 2;
if (elements[i].type == QPIEvaluatorTypes::etFunction && elements[ni].type != QPIEvaluatorTypes::etFunction && sc != '(') needInsert = 2;
if (elements[pi].type == QPIEvaluatorTypes::etOperator && (elements[ni].type == QPIEvaluatorTypes::etFunction || elements[ni].type == QPIEvaluatorTypes::etVariable) && fc == '-') needInsert = 3;
switch (needInsert) {
case 1:
currentString.insert(ni + inserted, "*");
elements.insert(ni + inserted, QPIEvaluatorTypes::Element(QPIEvaluatorTypes::etOperator, -1));
//inserted++;
//i++;
return true;
/*case 2:
currentString.insert(ni + inserted, ")");
currentString.insert(ni + inserted, "(");
elements.insert(ni + inserted, Element(etOperator, -1));
elements.insert(ni + inserted, Element(etOperator, -1));
inserted++;
i++;
return true;*/
case 3:
currentString.insert(ni + inserted, "1*");
elements.insert(ni + inserted, QPIEvaluatorTypes::Element(QPIEvaluatorTypes::etOperator, -1));
//inserted;
//i++;
return true;
}
}
/*if (elements[tmps.length() - 1].type == etFunction) {
currentString.insert(tmps.length() + inserted, ")");
currentString.insert(tmps.length() + inserted, "(");
elements.insert(tmps.length() + inserted, Element(etOperator, -1));
elements.insert(tmps.length() + inserted, Element(etOperator, -1));
return true;
}*/
return false;
}
void QPIEvaluator::convert() {
int j;
QPIEvaluatorTypes::Element ce, pe;
for (int i = 0; i < currentString.length(); i++) {
pe = elements[i];
if (pe.type != QPIEvaluatorTypes::etFunction) continue;
j = i + 1;
while (j < currentString.length()) {
ce = elements[j];
if (ce != pe) break;
j++;
}
currentString.replace(i, j - i, " ");
for (int k = i + 1; k < j; k++) elements.remove(i);
//i++;
}
for (int i = 0; i < currentString.length(); i++) {
pe = elements[i];
if (pe.type != QPIEvaluatorTypes::etNumber) continue;
j = i + 1;
while (j < currentString.length()) {
ce = elements[j];
if (ce != pe) break;
j++;
}
currentString.replace(i, j - i, " ");
for (int k = i + 1; k < j; k++) elements.remove(i);
//i++;
}
for (int i = 0; i < currentString.length(); i++) {
pe = elements[i];
if (pe.type != QPIEvaluatorTypes::etVariable) continue;
j = i + 1;
while (j < currentString.length()) {
ce = elements[j];
if (ce != pe) break;
j++;
}
currentString.replace(i, j - i, " ");
for (int k = i + 1; k < j; k++) elements.remove(i);
//i++;
}
/*qDebug().nospace() << currentString;
cout << " ";
for (int i = 0; i < elements.size(); i++) {
switch (elements[i].type) {
case etFunction: cout << "f"; break;
case etNumber: cout << "n"; break;
case etOperator: cout << "o"; break;
case etVariable: cout << "v"; break;
}
}
cout << endl;*/
}
const QString & QPIEvaluator::preprocess(const QString & string) {
static QString ret;
int lind;
ret = prepare(string);
convert();
instructions.clear();
//qDebug() << preproc->currentString;
variables = currentVariables;
lind = parse(currentString);
if (instructions.size() == 0) {
variables.push_back(QPIEvaluatorTypes::Variable());
instructions.push_back(QPIEvaluatorTypes::Instruction(QPIEvaluatorTypes::oNone, QVector<int>(1, lind), -variables.size()));
}
kvars = &(content.variables);
/*
cout << endl << "variables:" << endl;
for (int i = 0; i < variables.size(); i++)
cout << i << " value = " << variables[i].value << endl;
cout << endl << "instructions:" << endl;
for (int i = 0; i < instructions.size(); i++) {
cout << i << endl;
cout << " operation " << instructions[i].operation << endl;
cout << " operators: ";
for (int j = 0; j < instructions[i].operators.size(); j++)
cout << instructions[i].operators[j] << "; ";
cout << endl << " function " << instructions[i].function << endl;
cout << " out " << instructions[i].out << endl;
}
*/
makeOutput(ret);
return ret;
}
QPIEvaluatorTypes::Operation QPIEvaluator::operationInOrder(const int & index) {
switch (index) {
case 0: return QPIEvaluatorTypes::oPower;
case 1: return QPIEvaluatorTypes::oMultiply;
case 2: return QPIEvaluatorTypes::oDivide;
case 3: return QPIEvaluatorTypes::oResidue;
case 4: return QPIEvaluatorTypes::oAdd;
case 5: return QPIEvaluatorTypes::oSubtract;
case 6: return QPIEvaluatorTypes::oEqual;
case 7: return QPIEvaluatorTypes::oNotEqual;
case 8: return QPIEvaluatorTypes::oGreaterEqual;
case 9: return QPIEvaluatorTypes::oSmallerEqual;
case 10: return QPIEvaluatorTypes::oGreater;
case 11: return QPIEvaluatorTypes::oSmaller;
case 12: return QPIEvaluatorTypes::oAnd;
case 13: return QPIEvaluatorTypes::oOr;
default: return QPIEvaluatorTypes::oNone;
}
}
int QPIEvaluator::parse(const QString & string, int offset) {
int slen = string.length(), /*facnt,*/ farg, bcnt, k;
QChar cc;
QPIEvaluatorTypes::Element ce;
QPIEvaluatorTypes::Function cfunc;
QPIEvaluatorTypes::Operation coper;
QString sbrackets, carg;
QVector<int> args, atmp;
QVector<QPIEvaluatorTypes::Operation> opers;
///qDebug() << "to parse :" + string;
///cout << " "; for (int i = 0; i < slen; i++) cout << preproc->elements[i + offset].type; cout << endl;
for (int i = 0; i < slen; i++) {
ce = elements[i + offset];
cc = string[i];
switch (ce.type) {
case QPIEvaluatorTypes::etNumber:
args.push_back(ce.var_num);
continue;
case QPIEvaluatorTypes::etVariable:
args.push_back(ce.var_num);
continue;
case QPIEvaluatorTypes::etFunction:
i++;
cfunc = content.function(ce.var_num);
//facnt = cfunc.arguments;
atmp.clear();
bcnt = farg = 1;
///qDebug() << "function: " + cfunc.identifier;
//for (int k = 0; k < facnt; k++) {
carg = "";
k = i + 1;
//if (string.size() <= k || k < 0) return -666;
while (bcnt > 0) {
//if (k < facnt - 1) fcomma = string.indexOf(',', j);
cc = string[k];
switch (cc.toLatin1()) {
case '(': bcnt++; break;
case ')':
bcnt--;
if (bcnt == 0) {
///qDebug() << "arument: " << carg;
atmp.push_back(parse(carg, k + offset - carg.length()));
k++;
carg = "";
if (atmp.size() > 0) if (atmp.back() < 0 && farg > 0) farg = atmp.back();
continue;
}
break;
case ',':
if (bcnt == 1) {
///qDebug() << "arument: " << carg;
atmp.push_back(parse(carg, k + offset - carg.length()));
k++;
carg = "";
if (atmp.size() > 0) if (atmp.back() < 0 && farg > 0) farg = atmp.back();
continue;
}
break;
}
carg += cc;
k++;
}
i = k - 1;
if (farg > 0) {
variables.push_back(QPIEvaluatorTypes::Variable());
farg = -variables.size();
}
instructions.push_back(QPIEvaluatorTypes::Instruction(QPIEvaluatorTypes::oFunction, atmp, farg, ce.var_num));
args.push_back(farg);
//for (int i = 0; i < args.size(); i++) cout << preproc->currentVariables[-args[i]].value << endl;
//i = j + 1;
continue;
case QPIEvaluatorTypes::etOperator:
//qDebug() << "operator: " << cc;
if (cc == '(') {
sbrackets = inBrackets(string.right(slen - i));
args.push_back(parse(sbrackets, i + offset + 1));
i += sbrackets.length() + 1;
continue;
}
if (cc == '+') {opers.push_back(QPIEvaluatorTypes::oAdd); continue;}
if (cc == '-') {opers.push_back(QPIEvaluatorTypes::oSubtract); continue;}
if (cc == '*') {opers.push_back(QPIEvaluatorTypes::oMultiply); continue;}
if (cc == '/') {opers.push_back(QPIEvaluatorTypes::oDivide); continue;}
if (cc == '%') {opers.push_back(QPIEvaluatorTypes::oResidue); continue;}
if (cc == '^') {opers.push_back(QPIEvaluatorTypes::oPower); continue;}
if (cc == '=') {opers.push_back(QPIEvaluatorTypes::oEqual); continue;}
if (cc == ':') {opers.push_back(QPIEvaluatorTypes::oNotEqual); continue;}
if (cc == '}') {opers.push_back(QPIEvaluatorTypes::oGreaterEqual); continue;}
if (cc == '{') {opers.push_back(QPIEvaluatorTypes::oSmallerEqual); continue;}
if (cc == '>') {opers.push_back(QPIEvaluatorTypes::oGreater); continue;}
if (cc == '<') {opers.push_back(QPIEvaluatorTypes::oSmaller); continue;}
if (cc == '&') {opers.push_back(QPIEvaluatorTypes::oAnd); continue;}
if (cc == '|') {opers.push_back(QPIEvaluatorTypes::oOr); continue;}
}
}
/*
cout << "stack: " << endl << "args: ";
for (int i = 0; i < args.size(); i++) cout << args[i] << ", ";
cout << endl << "opers: ";
for (int i = 0; i < opers.size(); i++) cout << opers[i] << ", ";
*/
if (opers.size() == 0) {
if (args.size() > 0) return args.back();
else return -666;
}
for (int i = 0; i < QPIEvaluatorTypes::operationCount; i++) {
coper = operationInOrder(i);
for (int j = 0; j < opers.size(); j++) {
if (coper == QPIEvaluatorTypes::oDivide || coper == QPIEvaluatorTypes::oMultiply) {
if (opers[j] != QPIEvaluatorTypes::oDivide && opers[j] != QPIEvaluatorTypes::oMultiply) continue;
} else {
if (opers[j] != coper) continue;
}
atmp.clear();
if (j < args.size() && j >= 0) atmp.push_back(args[j]);
else atmp.push_back(-666);
if (j + 1 < args.size() && j >= -1) atmp.push_back(args[j + 1]);
else atmp.push_back(-666);
farg = 1;
if (atmp[0] < 0) farg = atmp[0];
else {
if (atmp[1] < 0) farg = atmp[1];
else {
variables.push_back(QPIEvaluatorTypes::Variable());
farg = -variables.size();
}
}
instructions.push_back(QPIEvaluatorTypes::Instruction(opers[j], atmp, farg));
if (j >= 0 && j < args.size()) {
args.remove(j);
if (j < args.size()) args[j] = farg;
}
opers.remove(j);
j--;
}
}
return instructions.back().out;
///cout << endl;
}
bool QPIEvaluator::check() {
QPIEvaluatorTypes::Instruction ci;
bool error;
if (unknownVars.size() > 0) {
lastError = "Unknown variables: \"" + unknownVars.join("\", \"") + "\"";
return false;
}
for (int i = 0; i < instructions.size(); i++) {
error = false;
ci = instructions[i];
switch (ci.operation) {
case QPIEvaluatorTypes::oNone: break;
case QPIEvaluatorTypes::oFunction:
for (int j = 0; j < ci.operators.size(); j++) {
if (ci.operators[j] == -666) { //(ci.operators[j] < -variables.size() || ci.operators[j] >= kvars->size()) {
error = true;
break;
}
}
if (ci.operators.size() != content.function(ci.function).arguments || error) {
lastError = "Invalid arguments count for function \"" + content.function(ci.function).identifier + "\"";
return false;
}
break;
default:
if (ci.operators[0] == -666 || ci.operators[1] == -666) error = true;
if (ci.operators.size() != 2 || error) {
lastError = "Invalid arguments count for operation \" " + operationChar(ci.operation) + " \"";
return false;
}
break;
}
if (ci.out < -variables.size()) {
lastError = "Invalid variable index \"" + QString::number(ci.out) + "\"";
return false;
}
for (int j = 0; j < ci.operators.size(); j++) {
if (ci.operators[j] < -variables.size() || ci.operators[j] >= kvars->size()) {
lastError = "Invalid variable index \"" + QString::number(ci.operators[j]) + "\"";
return false;
}
}
}
return true;
}
QString QPIEvaluator::inBrackets(const QString & string) {
int slen = string.length(), bcnt = 0;
QChar cc;
for (int i = 0; i < slen; i++) {
cc = string[i];
if (cc == '(') bcnt++;
if (cc == ')') {
bcnt--;
if (bcnt == 0) return string.mid(1, i - 1);
}
}
return QString();
}
QString QPIEvaluator::operationChar(const QPIEvaluatorTypes::Operation & operation) {
switch (operation) {
case QPIEvaluatorTypes::oAdd: return "+";
case QPIEvaluatorTypes::oSubtract: return "-";
case QPIEvaluatorTypes::oMultiply: return "*";
case QPIEvaluatorTypes::oDivide: return "/";
case QPIEvaluatorTypes::oPower: return "^";
case QPIEvaluatorTypes::oResidue: return "%";
case QPIEvaluatorTypes::oEqual: return "=";
case QPIEvaluatorTypes::oNotEqual: return ("");
case QPIEvaluatorTypes::oGreaterEqual: return ("");
case QPIEvaluatorTypes::oSmallerEqual: return ("");
case QPIEvaluatorTypes::oGreater: return ">";
case QPIEvaluatorTypes::oSmaller: return "<";
case QPIEvaluatorTypes::oAnd: return ("");
case QPIEvaluatorTypes::oOr: return ("");
default: return "???";
}
}
inline complexd QPIEvaluator::residue(const complexd & f, const complexd & s) {
complexd ret;
if (s.real() != 0.) ret = complexd(f.real() - ((int)(f.real() / s.real())) * s.real(), 0.);
if (s.imag() != 0.) ret = complexd(ret.real(), f.imag() - ((int)(f.imag() / s.imag())) * s.imag());
return ret;
}
inline void QPIEvaluator::execFunction(const QPIEvaluatorTypes::Instruction & ci) {
QPIEvaluatorTypes::Function cfunc = content.function(ci.function);
int oi = -ci.out - 1;
complexd tmp, stmp;
double ldtmp;
//qDebug() << "function " << (int)cfunc.type;
switch (cfunc.type) {
case QPIEvaluatorTypes::bfSin:
tmpvars[oi].value = sin(value(ci.operators[0]));
break;
case QPIEvaluatorTypes::bfCos:
tmpvars[oi].value = cos(value(ci.operators[0]));
break;
case QPIEvaluatorTypes::bfTg:
tmpvars[oi].value = tan(value(ci.operators[0]));
break;
case QPIEvaluatorTypes::bfCtg:
tmp = tan(value(ci.operators[0]));
if (tmp == complexd_0) tmpvars[oi].value = 0.;
else tmpvars[oi].value = complexd_1 / tmp;
break;
case QPIEvaluatorTypes::bfArcsin:
tmpvars[oi].value = asinc_qpie(value(ci.operators[0]));
break;
case QPIEvaluatorTypes::bfArccos:
tmpvars[oi].value = acosc_qpie(value(ci.operators[0]));
break;
case QPIEvaluatorTypes::bfArctg:
tmpvars[oi].value = atanc_qpie(value(ci.operators[0]));
break;
case QPIEvaluatorTypes::bfArcctg:
tmpvars[oi].value = atanc_qpie(-value(ci.operators[0])) + M_PI_2;
break;
case QPIEvaluatorTypes::bfSh:
tmpvars[oi].value = sinh(value(ci.operators[0]));
break;
case QPIEvaluatorTypes::bfCh:
tmpvars[oi].value = cosh(value(ci.operators[0]));
break;
case QPIEvaluatorTypes::bfTh:
tmpvars[oi].value = tanh(value(ci.operators[0]));
break;
case QPIEvaluatorTypes::bfCth:
tmp = tanh(value(ci.operators[0]));
if (tmp == complexd_0) tmpvars[oi].value = 0.;
else tmpvars[oi].value = complexd_1 / tmp;
break;
case QPIEvaluatorTypes::bfAbs:
tmpvars[oi].value = abs(value(ci.operators[0]));
break;
case QPIEvaluatorTypes::bfSqrt:
tmpvars[oi].value = sqrt(value(ci.operators[0]));
break;
case QPIEvaluatorTypes::bfSqr:
tmpvars[oi].value = value(ci.operators[0]) * value(ci.operators[0]);
break;
case QPIEvaluatorTypes::bfExp:
tmpvars[oi].value = exp(value(ci.operators[0]));
break;
case QPIEvaluatorTypes::bfPow:
tmpvars[oi].value = pow(value(ci.operators[0]), value(ci.operators[1]));
break;
case QPIEvaluatorTypes::bfLn:
tmpvars[oi].value = log(value(ci.operators[0]));
break;
case QPIEvaluatorTypes::bfLg:
tmpvars[oi].value = log10(value(ci.operators[0]));
break;
case QPIEvaluatorTypes::bfLog:
tmp = log(value(ci.operators[1]));
if (tmp == complexd_0) tmpvars[oi].value = 0.;
else tmpvars[oi].value = log(value(ci.operators[0])) / tmp;
break;
case QPIEvaluatorTypes::bfRe:
tmpvars[oi].value = value(ci.operators[0]).real();
break;
case QPIEvaluatorTypes::bfIm:
tmpvars[oi].value = value(ci.operators[0]).imag();
break;
case QPIEvaluatorTypes::bfArg:
tmpvars[oi].value = arg(value(ci.operators[0]));
break;
case QPIEvaluatorTypes::bfLen:
tmpvars[oi].value = abs(value(ci.operators[0]));
break;
case QPIEvaluatorTypes::bfConj:
tmpvars[oi].value = conj(value(ci.operators[0]));
break;
case QPIEvaluatorTypes::bfSign:
ldtmp = value(ci.operators[0]).real();
tmpvars[oi].value = ldtmp >= 0. ? complexd_1 : -complexd_1;
break;
case QPIEvaluatorTypes::bfRad:
tmpvars[oi].value = value(ci.operators[0]) * complexd(deg2rad_qpie, 0.);
break;
case QPIEvaluatorTypes::bfDeg:
tmpvars[oi].value = value(ci.operators[0]) * complexd(rad2deg_qpie, 0.);
break;
case QPIEvaluatorTypes::bfRandom:
tmp = static_cast<double>(qrand()) / RAND_MAX;
stmp = value(ci.operators[1]) - value(ci.operators[0]);
tmpvars[oi].value = value(ci.operators[0]) + tmp * stmp;
break;
default: break;
}
}
inline bool QPIEvaluator::execInstructions() {
QPIEvaluatorTypes::Instruction ci;
int oi;
complexd tmp;
tmpvars = variables;
//cout << "var count " << tmpvars.size() << endl;
for (int i = 0; i < instructions.size(); i++) {
ci = instructions[i];
oi = -ci.out - 1;
//cout << value(ci.operators[0]) << operationChar(ci.operation) << value(ci.operators[1]) << ", " << oi << endl;
switch (ci.operation) {
case QPIEvaluatorTypes::oAdd:
tmpvars[oi].value = value(ci.operators[0]) + value(ci.operators[1]);
break;
case QPIEvaluatorTypes::oSubtract:
tmpvars[oi].value = value(ci.operators[0]) - value(ci.operators[1]);
break;
case QPIEvaluatorTypes::oMultiply:
tmpvars[oi].value = value(ci.operators[0]) * value(ci.operators[1]);
break;
case QPIEvaluatorTypes::oDivide:
tmp = value(ci.operators[1]);
if (tmp == complexd(0., 0.)) tmpvars[oi].value = 0.;
else tmpvars[oi].value = value(ci.operators[0]) / tmp;
break;
case QPIEvaluatorTypes::oResidue:
tmpvars[oi].value = residue(value(ci.operators[0]), value(ci.operators[1]));
break;
case QPIEvaluatorTypes::oPower:
tmpvars[oi].value = pow(value(ci.operators[0]), value(ci.operators[1]));
break;
case QPIEvaluatorTypes::oEqual:
tmpvars[oi].value = value(ci.operators[0]) == value(ci.operators[1]);
break;
case QPIEvaluatorTypes::oNotEqual:
tmpvars[oi].value = value(ci.operators[0]) != value(ci.operators[1]);
break;
case QPIEvaluatorTypes::oGreaterEqual:
tmpvars[oi].value = value(ci.operators[0]).real() >= value(ci.operators[1]).real();
break;
case QPIEvaluatorTypes::oSmallerEqual:
tmpvars[oi].value = value(ci.operators[0]).real() <= value(ci.operators[1]).real();
break;
case QPIEvaluatorTypes::oGreater:
tmpvars[oi].value = value(ci.operators[0]).real() > value(ci.operators[1]).real();
break;
case QPIEvaluatorTypes::oSmaller:
tmpvars[oi].value = value(ci.operators[0]).real() < value(ci.operators[1]).real();
break;
case QPIEvaluatorTypes::oAnd:
tmpvars[oi].value = value(ci.operators[0]).real() > 0. && value(ci.operators[1]).real() > 0.;
break;
case QPIEvaluatorTypes::oOr:
tmpvars[oi].value = value(ci.operators[0]).real() > 0. || value(ci.operators[1]).real() > 0.;
break;
case QPIEvaluatorTypes::oFunction:
execFunction(ci);
break;
case QPIEvaluatorTypes::oNone:
tmpvars[oi].value = value(ci.operators[0]);
break;
}
}
if (!instructions.isEmpty())
out = value(instructions.back().out);
return true;
}
bool QPIEvaluator::check(const QString & string) {
currentString = preprocess(string);
correct = check();
if (!correct)
return false;
lastError = "Correct";
return true;
}
int QPIEvaluator::setVariable(const QString & name, complexd value) {
int i = content.findVariable(name);
if (i < 0) {
content.addVariable(name, value);
return content.findVariable(name);
} else {
content.setVariableValue(i, value);
return i;
}
return -1;
}
complexd QPIEvaluator::evaluate() {
if (!execInstructions()) out = 0.;
if (fabs(out.real()) < 1E-300) out = complexd(0., out.imag());
if (fabs(out.imag()) < 1E-300) out = complexd(out.real(), 0.);
return out;
}

View File

@@ -0,0 +1,208 @@
/*
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 <QStringList>
#include <QVector>
#include <QMap>
#include <QDebug>
#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;
}
}
/*
≠ :
≥ }
≤ {
⋀ &
|
*/
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);
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