1034 lines
32 KiB
C++
1034 lines
32 KiB
C++
#include "pievaluator.h"
|
||
|
||
|
||
PIEvaluatorContent::PIEvaluatorContent() {
|
||
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 PIEvaluatorContent::setVariableValue(int index, complexd new_value) {
|
||
if (index < 0 || index >= variables.size_s()) return false;
|
||
variables[index].value = new_value;
|
||
return true;
|
||
}
|
||
|
||
|
||
bool PIEvaluatorContent::setVariableName(int index, const PIString & new_name) {
|
||
if (index < 0 || index >= variables.size_s()) return false;
|
||
variables[index].name = new_name;
|
||
return true;
|
||
}
|
||
|
||
|
||
void PIEvaluatorContent::clearCustomVariables() {
|
||
variables.clear();
|
||
addVariable("i", complexd_1);
|
||
addVariable("pi", atan(1.) * 4.);
|
||
addVariable("e", exp(1.));
|
||
cv_count = variables.size();
|
||
}
|
||
|
||
|
||
void PIEvaluatorContent::sortVariables() {
|
||
PIEvaluatorTypes::Variable tv;
|
||
for (uint i = 0; i < variables.size(); i++) {
|
||
for (uint j = variables.size() - 1; j > i; j--) {
|
||
if (variables[j].name.length() <= variables[i].name.length()) continue;
|
||
piSwap<PIEvaluatorTypes::Variable>(variables[i], variables[j]);
|
||
}
|
||
}
|
||
/*
|
||
* qDebug() << "---";
|
||
* for (int i = 0; i < variables.size(); i++) {
|
||
* qDebug() << variables[i].name;
|
||
}
|
||
*/
|
||
}
|
||
|
||
|
||
PIEvaluatorTypes::BaseFunctions PIEvaluatorContent::getBaseFunction(const PIString & name) {
|
||
if (name == "sin") return PIEvaluatorTypes::bfSin;
|
||
if (name == "cos") return PIEvaluatorTypes::bfCos;
|
||
if (name == "tg") return PIEvaluatorTypes::bfTg;
|
||
if (name == "ctg") return PIEvaluatorTypes::bfCtg;
|
||
if (name == "arcsin") return PIEvaluatorTypes::bfArcsin;
|
||
if (name == "arccos") return PIEvaluatorTypes::bfArccos;
|
||
if (name == "arctg") return PIEvaluatorTypes::bfArctg;
|
||
if (name == "arcctg") return PIEvaluatorTypes::bfArcctg;
|
||
if (name == "exp") return PIEvaluatorTypes::bfExp;
|
||
if (name == "random") return PIEvaluatorTypes::bfRandom;
|
||
if (name == "sh") return PIEvaluatorTypes::bfSh;
|
||
if (name == "ch") return PIEvaluatorTypes::bfCh;
|
||
if (name == "th") return PIEvaluatorTypes::bfTh;
|
||
if (name == "cth") return PIEvaluatorTypes::bfCth;
|
||
if (name == "sqrt") return PIEvaluatorTypes::bfSqrt;
|
||
if (name == "sqr") return PIEvaluatorTypes::bfSqr;
|
||
if (name == "pow") return PIEvaluatorTypes::bfPow;
|
||
if (name == "abs") return PIEvaluatorTypes::bfAbs;
|
||
if (name == "ln") return PIEvaluatorTypes::bfLn;
|
||
if (name == "lg") return PIEvaluatorTypes::bfLg;
|
||
if (name == "log") return PIEvaluatorTypes::bfLog;
|
||
if (name == "im") return PIEvaluatorTypes::bfIm;
|
||
if (name == "re") return PIEvaluatorTypes::bfRe;
|
||
if (name == "arg") return PIEvaluatorTypes::bfArg;
|
||
if (name == "len") return PIEvaluatorTypes::bfLen;
|
||
if (name == "conj") return PIEvaluatorTypes::bfConj;
|
||
if (name == "sign") return PIEvaluatorTypes::bfSign;
|
||
if (name == "rad") return PIEvaluatorTypes::bfRad;
|
||
if (name == "deg") return PIEvaluatorTypes::bfDeg;
|
||
return PIEvaluatorTypes::bfUnknown;
|
||
}
|
||
|
||
const PIString & PIEvaluator::prepare(const PIString & string) {
|
||
currentString = string.trimmed();
|
||
if (currentString.isEmpty()) currentString = "0";
|
||
replaceOperators();
|
||
removeSpaces();
|
||
checkBrackets();
|
||
while (fillElements()) checkBrackets();
|
||
while (setSignes()) fillElements();
|
||
removeJunk();
|
||
findUnknownVariables();
|
||
return currentString;
|
||
}
|
||
|
||
|
||
void PIEvaluator::removeSpaces() {
|
||
PIString tmps = currentString;
|
||
for (int i = 0; i < tmps.length(); i++) {
|
||
if (tmps[i] == ' ' || tmps[i] == '\t') {
|
||
tmps.remove(i, 1);
|
||
i--;
|
||
}
|
||
}
|
||
currentString = tmps;
|
||
}
|
||
|
||
|
||
void PIEvaluator::removeJunk() {
|
||
PIChar 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 PIEvaluator::replaceOperators() {
|
||
currentString.replaceAll("==", "=");
|
||
currentString.replaceAll("!=", ":");
|
||
currentString.replaceAll(">=", "}");
|
||
currentString.replaceAll("<=", "{");
|
||
currentString.replaceAll("&&", "&");
|
||
currentString.replaceAll("||", "|");
|
||
}
|
||
|
||
|
||
void PIEvaluator::makeOutput(PIString & string) {
|
||
string.replaceAll(":", "≠");
|
||
string.replaceAll("}", "≥");
|
||
string.replaceAll("{", "≤");
|
||
string.replaceAll("&", "⋀");
|
||
string.replaceAll("|", "⋁");
|
||
}
|
||
|
||
|
||
void PIEvaluator::findUnknownVariables() {
|
||
PIString 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 PIEvaluator::isSign(const PIChar & ch) {
|
||
return ch == '+' || ch == '-' ||
|
||
ch == '*' || ch == '/' ||
|
||
ch == '%' || ch == '^' ||
|
||
ch == '=' || ch == ':' ||
|
||
ch == '>' || ch == '<' ||
|
||
ch == '}' || ch == '{' ||
|
||
ch == '&' || ch == '|';
|
||
}
|
||
|
||
|
||
void PIEvaluator::checkBrackets() {
|
||
PIString tmps = currentString;
|
||
PIChar 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 += PIString(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 PIEvaluator::fillElements() {
|
||
int fstart, flen, cnum = 0, cpart = 0, cfunc;
|
||
PIChar cc, nc, pc, fc = '!';
|
||
bool numFound = false;
|
||
PIString curfind, tmps = currentString;
|
||
elements.resize(tmps.length());
|
||
for (uint i = 0; i < elements.size(); i++) {
|
||
elements[i].type = PIEvaluatorTypes::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.find(curfind, fstart);
|
||
if (fstart < 0) break;
|
||
if (tmps[fstart + flen] != '(') {
|
||
currentString.insert(fstart + flen, "(");
|
||
return true;
|
||
}
|
||
for (int j = fstart; j < fstart + flen; j++) {
|
||
elements[j].set(PIEvaluatorTypes::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.find(curfind, fstart);
|
||
if (fstart < 0) break;
|
||
for (int j = fstart; j < fstart + flen; j++) {
|
||
elements[j].set(PIEvaluatorTypes::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(PIEvaluatorTypes::Variable("tmp" + PIString::fromNumber(cnum), curfind.toDouble()));
|
||
for (int j = i - curfind.length(); j < i; j++) {
|
||
elements[j].set(PIEvaluatorTypes::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(PIEvaluatorTypes::Variable("tmp" + PIString::fromNumber(cnum), curfind.toDouble()));
|
||
for (int j = tmps.length() - curfind.length(); j < tmps.length(); j++) {
|
||
elements[j].set(PIEvaluatorTypes::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(PIEvaluatorTypes::etOperator, -1);
|
||
continue;
|
||
}
|
||
if (cc == '-' || cc == '+') {
|
||
elements[i].set(PIEvaluatorTypes::etOperator, -1);
|
||
if (i < tmps.length() - 1) if (elements[i + 1].type == PIEvaluatorTypes::etVariable ||
|
||
elements[i + 1].type == PIEvaluatorTypes::etFunction) continue;
|
||
if ((pc == '(' || isSign(pc) || i == 0) && i < tmps.length() - 1) {
|
||
if (elements[i + 1].type != PIEvaluatorTypes::etOperator) {
|
||
cnum = elements[i + 1].num;
|
||
elements[i].set(PIEvaluatorTypes::etNumber, cnum);
|
||
tmps.replace(i, 1, fc);
|
||
///cout << "found sign " << cc << " :" << cnum - 1 << endl;
|
||
if (cc == '-' && currentVariables.size_s() >= cnum)
|
||
currentVariables[cnum - 1].value = -currentVariables[cnum - 1].value;
|
||
//i++;
|
||
continue;
|
||
}
|
||
}
|
||
}
|
||
if (isSign(cc)) {
|
||
elements[i].set(PIEvaluatorTypes::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 PIEvaluator::setSignes() {
|
||
int inserted = 0, ni, pi = 0, needInsert = 0;
|
||
PIChar fc, sc, pc;
|
||
PIString 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 == PIEvaluatorTypes::etOperator && elements[ni].type == PIEvaluatorTypes::etOperator) continue;
|
||
if (fc == ')' && (elements[ni].type == PIEvaluatorTypes::etNumber || elements[ni].type == PIEvaluatorTypes::etVariable || elements[ni].type == PIEvaluatorTypes::etFunction)) needInsert = 1;
|
||
if (sc == '(' && (elements[i].type == PIEvaluatorTypes::etNumber || elements[i].type == PIEvaluatorTypes::etVariable)) needInsert = 1;
|
||
if (elements[i].type == PIEvaluatorTypes::etNumber && elements[ni].type == PIEvaluatorTypes::etNumber && elements[i].num != elements[ni].num) needInsert = 1;
|
||
if (elements[i].type == PIEvaluatorTypes::etVariable && elements[ni].type == PIEvaluatorTypes::etVariable && elements[i].num != elements[ni].num) needInsert = 1;
|
||
if ((elements[i].type == PIEvaluatorTypes::etNumber && elements[ni].type == PIEvaluatorTypes::etVariable) || (elements[i].type == PIEvaluatorTypes::etVariable && elements[ni].type == PIEvaluatorTypes::etNumber)) needInsert = 1;
|
||
if ((elements[i].type == PIEvaluatorTypes::etNumber || elements[i].type == PIEvaluatorTypes::etVariable) && elements[ni].type == PIEvaluatorTypes::etFunction) needInsert = 1;
|
||
if (elements[i].type == PIEvaluatorTypes::etFunction && elements[ni].type == PIEvaluatorTypes::etFunction && elements[i].num != elements[ni].num) needInsert = 2;
|
||
if (elements[i].type == PIEvaluatorTypes::etFunction && elements[ni].type != PIEvaluatorTypes::etFunction && sc != '(') needInsert = 2;
|
||
if (elements[pi].type == PIEvaluatorTypes::etOperator && (elements[ni].type == PIEvaluatorTypes::etFunction || elements[ni].type == PIEvaluatorTypes::etVariable) && fc == '-') needInsert = 3;
|
||
switch (needInsert) {
|
||
case 1:
|
||
currentString.insert(ni + inserted, "*");
|
||
elements.insert(ni + inserted, PIEvaluatorTypes::Element(PIEvaluatorTypes::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, PIEvaluatorTypes::Element(PIEvaluatorTypes::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 PIEvaluator::convert() {
|
||
int j;
|
||
PIEvaluatorTypes::Element ce, pe;
|
||
for (int i = 0; i < currentString.length(); i++) {
|
||
pe = elements[i];
|
||
if (pe.type != PIEvaluatorTypes::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 != PIEvaluatorTypes::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 != PIEvaluatorTypes::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 PIString & PIEvaluator::preprocess(const PIString & string) {
|
||
static PIString ret;
|
||
int lind;
|
||
ret = prepare(string);
|
||
convert();
|
||
instructions.clear();
|
||
//qDebug() << preproc->currentString;
|
||
variables = currentVariables;
|
||
lind = parse(currentString);
|
||
if (instructions.size() == 0) {
|
||
variables.push_back(PIEvaluatorTypes::Variable());
|
||
instructions.push_back(PIEvaluatorTypes::Instruction(PIEvaluatorTypes::oNone, PIVector<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;
|
||
}
|
||
|
||
|
||
PIEvaluatorTypes::Operation PIEvaluator::operationInOrder(const int & index) {
|
||
switch (index) {
|
||
case 0: return PIEvaluatorTypes::oPower;
|
||
case 1: return PIEvaluatorTypes::oMultiply;
|
||
case 2: return PIEvaluatorTypes::oDivide;
|
||
case 3: return PIEvaluatorTypes::oResidue;
|
||
case 4: return PIEvaluatorTypes::oAdd;
|
||
case 5: return PIEvaluatorTypes::oSubtract;
|
||
case 6: return PIEvaluatorTypes::oEqual;
|
||
case 7: return PIEvaluatorTypes::oNotEqual;
|
||
case 8: return PIEvaluatorTypes::oGreaterEqual;
|
||
case 9: return PIEvaluatorTypes::oSmallerEqual;
|
||
case 10: return PIEvaluatorTypes::oGreater;
|
||
case 11: return PIEvaluatorTypes::oSmaller;
|
||
case 12: return PIEvaluatorTypes::oAnd;
|
||
case 13: return PIEvaluatorTypes::oOr;
|
||
default: return PIEvaluatorTypes::oNone;
|
||
}
|
||
}
|
||
|
||
|
||
int PIEvaluator::parse(const PIString & string, int offset) {
|
||
int slen = string.length(), facnt, farg, bcnt, k;
|
||
PIChar cc;
|
||
PIEvaluatorTypes::Element ce;
|
||
PIEvaluatorTypes::Function cfunc;
|
||
PIEvaluatorTypes::Operation coper;
|
||
PIString sbrackets, carg;
|
||
PIVector<int> args, atmp;
|
||
PIVector<PIEvaluatorTypes::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 PIEvaluatorTypes::etNumber:
|
||
args.push_back(ce.var_num);
|
||
continue;
|
||
case PIEvaluatorTypes::etVariable:
|
||
args.push_back(ce.var_num);
|
||
continue;
|
||
case PIEvaluatorTypes::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++) {
|
||
bcnt = 1;
|
||
carg = "";
|
||
k = i + 1;
|
||
//if (string.size_s() <= k || k < 0) return -666;
|
||
while (bcnt > 0) {
|
||
//if (k < facnt - 1) fcomma = string.indexOf(',', j);
|
||
cc = string[k];
|
||
switch (cc.toAscii()) {
|
||
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_s() > 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_s() > 0) if (atmp.back() < 0 && farg > 0) farg = atmp.back();
|
||
continue;
|
||
}
|
||
break;
|
||
}
|
||
carg += cc;
|
||
k++;
|
||
}
|
||
i = k - 1;
|
||
if (farg > 0) {
|
||
variables.push_back(PIEvaluatorTypes::Variable());
|
||
farg = -variables.size_s();
|
||
}
|
||
instructions.push_back(PIEvaluatorTypes::Instruction(PIEvaluatorTypes::oFunction, atmp, farg, ce.var_num));
|
||
args.push_back(farg);
|
||
//for (int i = 0; i < args.size_s(); i++) cout << preproc->currentVariables[-args[i]].value << endl;
|
||
//i = j + 1;
|
||
continue;
|
||
case PIEvaluatorTypes::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(PIEvaluatorTypes::oAdd); continue;}
|
||
if (cc == '-') {opers.push_back(PIEvaluatorTypes::oSubtract); continue;}
|
||
if (cc == '*') {opers.push_back(PIEvaluatorTypes::oMultiply); continue;}
|
||
if (cc == '/') {opers.push_back(PIEvaluatorTypes::oDivide); continue;}
|
||
if (cc == '%') {opers.push_back(PIEvaluatorTypes::oResidue); continue;}
|
||
if (cc == '^') {opers.push_back(PIEvaluatorTypes::oPower); continue;}
|
||
if (cc == '=') {opers.push_back(PIEvaluatorTypes::oEqual); continue;}
|
||
if (cc == ':') {opers.push_back(PIEvaluatorTypes::oNotEqual); continue;}
|
||
if (cc == '}') {opers.push_back(PIEvaluatorTypes::oGreaterEqual); continue;}
|
||
if (cc == '{') {opers.push_back(PIEvaluatorTypes::oSmallerEqual); continue;}
|
||
if (cc == '>') {opers.push_back(PIEvaluatorTypes::oGreater); continue;}
|
||
if (cc == '<') {opers.push_back(PIEvaluatorTypes::oSmaller); continue;}
|
||
if (cc == '&') {opers.push_back(PIEvaluatorTypes::oAnd); continue;}
|
||
if (cc == '|') {opers.push_back(PIEvaluatorTypes::oOr); continue;}
|
||
}
|
||
}
|
||
/*
|
||
cout << "stack: " << endl << "args: ";
|
||
for (int i = 0; i < args.size_s(); i++) cout << args[i] << ", ";
|
||
cout << endl << "opers: ";
|
||
for (int i = 0; i < opers.size_s(); i++) cout << opers[i] << ", ";
|
||
*/
|
||
if (opers.size_s() == 0) {
|
||
if (args.size_s() > 0) return args.back();
|
||
else return -666;
|
||
}
|
||
for (int i = 0; i < PIEvaluatorTypes::operationCount; i++) {
|
||
coper = operationInOrder(i);
|
||
for (int j = 0; j < opers.size_s(); j++) {
|
||
if (coper == PIEvaluatorTypes::oDivide || coper == PIEvaluatorTypes::oMultiply) {
|
||
if (opers[j] != PIEvaluatorTypes::oDivide && opers[j] != PIEvaluatorTypes::oMultiply) continue;
|
||
} else {
|
||
if (opers[j] != coper) continue;
|
||
}
|
||
atmp.clear();
|
||
if (j < args.size_s() && j >= 0) atmp.push_back(args[j]);
|
||
else atmp.push_back(-666);
|
||
if (j + 1 < args.size_s() && 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(PIEvaluatorTypes::Variable());
|
||
farg = -variables.size_s();
|
||
}
|
||
}
|
||
instructions.push_back(PIEvaluatorTypes::Instruction(opers[j], atmp, farg));
|
||
if (j >= 0 && j < args.size_s()) {
|
||
args.remove(j);
|
||
if (j < args.size_s()) args[j] = farg;
|
||
}
|
||
opers.remove(j);
|
||
j--;
|
||
}
|
||
}
|
||
return instructions.back().out;
|
||
///cout << endl;
|
||
}
|
||
|
||
|
||
bool PIEvaluator::check() {
|
||
PIEvaluatorTypes::Instruction ci;
|
||
bool error;
|
||
if (unknownVars.size_s() > 0) {
|
||
lastError = "Unknown variables: \"" + unknownVars.join("\", \"") + "\"";
|
||
return false;
|
||
}
|
||
for (int i = 0; i < instructions.size_s(); i++) {
|
||
error = false;
|
||
ci = instructions[i];
|
||
switch (ci.operation) {
|
||
case PIEvaluatorTypes::oNone: break;
|
||
case PIEvaluatorTypes::oFunction:
|
||
for (int j = 0; j < ci.operators.size_s(); j++) {
|
||
if (ci.operators[j] == -666) { //(ci.operators[j] < -variables.size_s() || ci.operators[j] >= kvars->size()) {
|
||
error = true;
|
||
break;
|
||
}
|
||
}
|
||
if (ci.operators.size_s() != 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_s() != 2 || error) {
|
||
lastError = "Invalid arguments count for operation \" " + operationChar(ci.operation) + " \"";
|
||
return false;
|
||
}
|
||
break;
|
||
}
|
||
if (ci.out < -variables.size_s()) {
|
||
lastError = "Invalid variable index \"" + PIString::fromNumber(ci.out) + "\"";
|
||
return false;
|
||
}
|
||
for (int j = 0; j < ci.operators.size_s(); j++) {
|
||
if (ci.operators[j] < -variables.size_s() || ci.operators[j] >= kvars->size_s()) {
|
||
lastError = "Invalid variable index \"" + PIString::fromNumber(ci.operators[j]) + "\"";
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
|
||
PIString PIEvaluator::inBrackets(const PIString & string) {
|
||
int slen = string.length(), bcnt = 0;
|
||
PIChar 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 PIString();
|
||
}
|
||
|
||
|
||
PIString PIEvaluator::operationChar(const PIEvaluatorTypes::Operation & operation) {
|
||
switch (operation) {
|
||
case PIEvaluatorTypes::oAdd: return "+";
|
||
case PIEvaluatorTypes::oSubtract: return "-";
|
||
case PIEvaluatorTypes::oMultiply: return "*";
|
||
case PIEvaluatorTypes::oDivide: return "/";
|
||
case PIEvaluatorTypes::oPower: return "^";
|
||
case PIEvaluatorTypes::oResidue: return "%";
|
||
case PIEvaluatorTypes::oEqual: return "=";
|
||
case PIEvaluatorTypes::oNotEqual: return ("≠");
|
||
case PIEvaluatorTypes::oGreaterEqual: return ("≥");
|
||
case PIEvaluatorTypes::oSmallerEqual: return ("≤");
|
||
case PIEvaluatorTypes::oGreater: return ">";
|
||
case PIEvaluatorTypes::oSmaller: return "<";
|
||
case PIEvaluatorTypes::oAnd: return ("⋀");
|
||
case PIEvaluatorTypes::oOr: return ("⋁");
|
||
default: return "???";
|
||
}
|
||
}
|
||
|
||
|
||
inline complexd PIEvaluator::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 PIEvaluator::execFunction(const PIEvaluatorTypes::Instruction & ci) {
|
||
PIEvaluatorTypes::Function cfunc = content.function(ci.function);
|
||
int oi = -ci.out - 1;
|
||
complexd tmp, stmp;
|
||
ldouble ldtmp;
|
||
//qDebug() << "function " << (int)cfunc.type;
|
||
switch (cfunc.type) {
|
||
case PIEvaluatorTypes::bfSin:
|
||
tmpvars[oi].value = sin(value(ci.operators[0]));
|
||
break;
|
||
case PIEvaluatorTypes::bfCos:
|
||
tmpvars[oi].value = cos(value(ci.operators[0]));
|
||
break;
|
||
case PIEvaluatorTypes::bfTg:
|
||
tmpvars[oi].value = tan(value(ci.operators[0]));
|
||
break;
|
||
case PIEvaluatorTypes::bfCtg:
|
||
tmp = tan(value(ci.operators[0]));
|
||
if (tmp == complexd_0) tmpvars[oi].value = 0.;
|
||
else tmpvars[oi].value = complexd_1 / tmp;
|
||
break;
|
||
case PIEvaluatorTypes::bfArcsin:
|
||
tmpvars[oi].value = asinc(value(ci.operators[0]));
|
||
break;
|
||
case PIEvaluatorTypes::bfArccos:
|
||
tmpvars[oi].value = acosc(value(ci.operators[0]));
|
||
break;
|
||
case PIEvaluatorTypes::bfArctg:
|
||
tmpvars[oi].value = atanc(value(ci.operators[0]));
|
||
break;
|
||
case PIEvaluatorTypes::bfArcctg:
|
||
tmp = atanc(value(ci.operators[0]));
|
||
if (tmp == complexd_0) tmpvars[oi].value = 0.;
|
||
else tmpvars[oi].value = complexd_1 / tmp;
|
||
break;
|
||
case PIEvaluatorTypes::bfSh:
|
||
tmpvars[oi].value = sinh(value(ci.operators[0]));
|
||
break;
|
||
case PIEvaluatorTypes::bfCh:
|
||
tmpvars[oi].value = cosh(value(ci.operators[0]));
|
||
break;
|
||
case PIEvaluatorTypes::bfTh:
|
||
tmpvars[oi].value = tanh(value(ci.operators[0]));
|
||
break;
|
||
case PIEvaluatorTypes::bfCth:
|
||
tmp = tanh(value(ci.operators[0]));
|
||
if (tmp == complexd_0) tmpvars[oi].value = 0.;
|
||
else tmpvars[oi].value = complexd_1 / tmp;
|
||
break;
|
||
case PIEvaluatorTypes::bfAbs:
|
||
tmpvars[oi].value = abs(value(ci.operators[0]));
|
||
break;
|
||
case PIEvaluatorTypes::bfSqrt:
|
||
tmpvars[oi].value = sqrt(value(ci.operators[0]));
|
||
break;
|
||
case PIEvaluatorTypes::bfSqr:
|
||
tmpvars[oi].value = value(ci.operators[0]) * value(ci.operators[0]);
|
||
break;
|
||
case PIEvaluatorTypes::bfExp:
|
||
tmpvars[oi].value = exp(value(ci.operators[0]));
|
||
break;
|
||
case PIEvaluatorTypes::bfPow:
|
||
tmpvars[oi].value = pow(value(ci.operators[0]), value(ci.operators[1]));
|
||
break;
|
||
case PIEvaluatorTypes::bfLn:
|
||
tmpvars[oi].value = log(value(ci.operators[0]));
|
||
break;
|
||
case PIEvaluatorTypes::bfLg:
|
||
tmpvars[oi].value = log10(value(ci.operators[0]));
|
||
break;
|
||
case PIEvaluatorTypes::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 PIEvaluatorTypes::bfRe:
|
||
tmpvars[oi].value = value(ci.operators[0]).real();
|
||
break;
|
||
case PIEvaluatorTypes::bfIm:
|
||
tmpvars[oi].value = value(ci.operators[0]).imag();
|
||
break;
|
||
case PIEvaluatorTypes::bfArg:
|
||
tmpvars[oi].value = arg(value(ci.operators[0]));
|
||
break;
|
||
case PIEvaluatorTypes::bfLen:
|
||
tmpvars[oi].value = abs(value(ci.operators[0]));
|
||
break;
|
||
case PIEvaluatorTypes::bfConj:
|
||
tmpvars[oi].value = conj(value(ci.operators[0]));
|
||
break;
|
||
case PIEvaluatorTypes::bfSign:
|
||
ldtmp = value(ci.operators[0]).real();
|
||
tmpvars[oi].value = ldtmp >= 0. ? complexd_1 : -complexd_1;
|
||
break;
|
||
case PIEvaluatorTypes::bfRad:
|
||
tmpvars[oi].value = value(ci.operators[0]) * complexd(deg2rad, 0.);
|
||
break;
|
||
case PIEvaluatorTypes::bfDeg:
|
||
tmpvars[oi].value = value(ci.operators[0]) * complexd(rad2deg, 0.);
|
||
break;
|
||
case PIEvaluatorTypes::bfRandom:
|
||
tmp = static_cast<ldouble>(rand()) / 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 PIEvaluator::execInstructions() {
|
||
PIEvaluatorTypes::Instruction ci;
|
||
int oi;
|
||
complexd tmp;
|
||
tmpvars = variables;
|
||
//cout << "var count " << tmpvars.size_s() << endl;
|
||
for (int i = 0; i < instructions.size_s(); 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 PIEvaluatorTypes::oAdd:
|
||
tmpvars[oi].value = value(ci.operators[0]) + value(ci.operators[1]);
|
||
break;
|
||
case PIEvaluatorTypes::oSubtract:
|
||
tmpvars[oi].value = value(ci.operators[0]) - value(ci.operators[1]);
|
||
break;
|
||
case PIEvaluatorTypes::oMultiply:
|
||
tmpvars[oi].value = value(ci.operators[0]) * value(ci.operators[1]);
|
||
break;
|
||
case PIEvaluatorTypes::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 PIEvaluatorTypes::oResidue:
|
||
tmpvars[oi].value = residue(value(ci.operators[0]), value(ci.operators[1]));
|
||
break;
|
||
case PIEvaluatorTypes::oPower:
|
||
tmpvars[oi].value = pow(value(ci.operators[0]), value(ci.operators[1]));
|
||
break;
|
||
case PIEvaluatorTypes::oEqual:
|
||
tmpvars[oi].value = value(ci.operators[0]) == value(ci.operators[1]);
|
||
break;
|
||
case PIEvaluatorTypes::oNotEqual:
|
||
tmpvars[oi].value = value(ci.operators[0]) != value(ci.operators[1]);
|
||
break;
|
||
case PIEvaluatorTypes::oGreaterEqual:
|
||
tmpvars[oi].value = value(ci.operators[0]).real() >= value(ci.operators[1]).real();
|
||
break;
|
||
case PIEvaluatorTypes::oSmallerEqual:
|
||
tmpvars[oi].value = value(ci.operators[0]).real() <= value(ci.operators[1]).real();
|
||
break;
|
||
case PIEvaluatorTypes::oGreater:
|
||
tmpvars[oi].value = value(ci.operators[0]).real() > value(ci.operators[1]).real();
|
||
break;
|
||
case PIEvaluatorTypes::oSmaller:
|
||
tmpvars[oi].value = value(ci.operators[0]).real() < value(ci.operators[1]).real();
|
||
break;
|
||
case PIEvaluatorTypes::oAnd:
|
||
tmpvars[oi].value = value(ci.operators[0]).real() > 0. && value(ci.operators[1]).real() > 0.;
|
||
break;
|
||
case PIEvaluatorTypes::oOr:
|
||
tmpvars[oi].value = value(ci.operators[0]).real() > 0. || value(ci.operators[1]).real() > 0.;
|
||
break;
|
||
case PIEvaluatorTypes::oFunction:
|
||
execFunction(ci);
|
||
break;
|
||
case PIEvaluatorTypes::oNone:
|
||
tmpvars[oi].value = value(ci.operators[0]);
|
||
break;
|
||
}
|
||
}
|
||
out = value(instructions.back().out);
|
||
return true;
|
||
}
|
||
|
||
|
||
bool PIEvaluator::check(const PIString & string) {
|
||
currentString = preprocess(string);
|
||
if (!check())
|
||
return false;
|
||
lastError = "Correct";
|
||
return true;
|
||
}
|
||
|
||
|
||
complexd PIEvaluator::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;
|
||
}
|