Files
pip/pievaluator.cpp
2011-07-29 08:17:24 +04:00

1034 lines
32 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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;
}