File indexing completed on 2024-05-12 03:47:44
0001 /* 0002 File : ExpressionParser.cpp 0003 Project : LabPlot 0004 Description : C++ wrapper for the bison generated parser. 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2014 Alexander Semke <alexander.semke@web.de> 0007 SPDX-FileCopyrightText: 2014-2022 Stefan Gerlach <stefan.gerlach@uni.kn> 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "backend/gsl/ExpressionParser.h" 0012 #include "backend/lib/macros.h" 0013 #include "backend/lib/trace.h" 0014 0015 #include <KLocalizedString> 0016 0017 #include <QRegularExpression> 0018 0019 #include <gsl/gsl_const_mksa.h> 0020 #include <gsl/gsl_const_num.h> 0021 #include <gsl/gsl_errno.h> 0022 #include <gsl/gsl_math.h> 0023 #include <gsl/gsl_version.h> 0024 0025 ExpressionParser* ExpressionParser::m_instance{nullptr}; 0026 0027 ExpressionParser::ExpressionParser() { 0028 init_table(); 0029 initFunctions(); 0030 initConstants(); 0031 } 0032 0033 // initialize function list (sync with functions.h and FunctionsWidget.cpp!) 0034 void ExpressionParser::initFunctions() { 0035 for (int i = 0; i < _number_functions; i++) { 0036 const auto& function = _functions[i]; 0037 m_functionsDescription << function.description(); 0038 m_functions << QLatin1String(function.name); 0039 m_functionsGroupIndex << function.group; 0040 } 0041 for (int i = 0; i < _number_specialfunctions; i++) { 0042 const auto& function = _special_functions[i]; 0043 m_functionsDescription << function.description(); 0044 m_functions << QLatin1String(function.name); 0045 m_functionsGroupIndex << function.group; 0046 } 0047 } 0048 0049 // TODO: decide whether we want to have i18n here in the backend part of the code 0050 void ExpressionParser::initConstants() { 0051 for (int i = 0; i < _number_constants; i++) { 0052 const auto& constant = _constants[i]; 0053 m_constantsDescription << constant.description(); 0054 m_constants << QLatin1String(constant.name); 0055 m_constantsValues << QString::number(constant.value, 'g', 15); 0056 m_constantsUnits << QLatin1String(constant.unit); 0057 m_constantsGroupIndex << constant.group; 0058 } 0059 } 0060 0061 /**********************************************************************************/ 0062 0063 ExpressionParser::~ExpressionParser() { 0064 delete_table(); 0065 } 0066 0067 ExpressionParser* ExpressionParser::getInstance() { 0068 if (!m_instance) 0069 m_instance = new ExpressionParser(); 0070 0071 return m_instance; 0072 } 0073 0074 const QStringList& ExpressionParser::functions() { 0075 return m_functions; 0076 } 0077 0078 const QStringList& ExpressionParser::functionsGroups() { 0079 return m_functionsGroups; 0080 } 0081 0082 const QStringList& ExpressionParser::functionsDescriptions() { 0083 return m_functionsDescription; 0084 } 0085 0086 const QVector<FunctionGroups>& ExpressionParser::functionsGroupIndices() { 0087 return m_functionsGroupIndex; 0088 } 0089 0090 /* another idea: 0091 * https://stackoverflow.com/questions/36797770/get-function-parameters-count 0092 * but this does not work since all function pointer have zero args in the struct 0093 */ 0094 int ExpressionParser::functionArgumentCount(const QString& functionName) { 0095 for (int i = 0; i < _number_functions; i++) { 0096 if (functionName == QLatin1String(_functions[i].name)) 0097 return _functions[i].argc; 0098 } 0099 for (int i = 0; i < _number_specialfunctions; i++) { 0100 if (functionName == QLatin1String(_special_functions[i].name)) 0101 return _special_functions[i].argc; 0102 } 0103 0104 // DEBUG(Q_FUNC_INFO << ", Found function " << STDSTRING(functionName) << " at index " << index); 0105 // DEBUG(Q_FUNC_INFO << ", function " << STDSTRING(functionName) << " has " << _functions[index].argc << " arguments"); 0106 return 0; 0107 } 0108 0109 QString ExpressionParser::parameters(const QString& functionName) { 0110 for (int i = 0; i < _number_functions; i++) { 0111 if (functionName == QLatin1String(_functions[i].name)) { 0112 int count = _functions[i].argc; 0113 const auto parameterFunction = _functions[i].parameterFunction; 0114 0115 if (parameterFunction == nullptr) 0116 return QStringLiteral(""); 0117 0118 if (count == 0) 0119 return QStringLiteral("()"); 0120 0121 QString parameter = QStringLiteral("("); 0122 for (int p = 0; p < count - 1; p++) 0123 parameter += parameterFunction(p) + QStringLiteral("; "); 0124 parameter += parameterFunction(count - 1); 0125 parameter += QStringLiteral(")"); 0126 return parameter; 0127 } 0128 // DEBUG(Q_FUNC_INFO << ", Found function " << STDSTRING(functionName) << " at index " << index); 0129 // DEBUG(Q_FUNC_INFO << ", function " << STDSTRING(functionName) << " has " << _functions[index].argc << " arguments"); 0130 } 0131 for (int i = 0; i < _number_specialfunctions; i++) { 0132 if (functionName == QLatin1String(_special_functions[i].name)) { 0133 int count = _special_functions[i].argc; 0134 const auto parameterFunction = _special_functions[i].parameterFunction; 0135 0136 if (parameterFunction == nullptr) 0137 return QStringLiteral(""); 0138 0139 if (count == 0) 0140 return QStringLiteral("()"); 0141 0142 QString parameter = QStringLiteral("("); 0143 for (int p = 0; p < count - 1; p++) 0144 parameter += parameterFunction(p) + QStringLiteral("; "); 0145 parameter += parameterFunction(count - 1); 0146 parameter += QStringLiteral(")"); 0147 return parameter; 0148 } 0149 // DEBUG(Q_FUNC_INFO << ", Found function " << STDSTRING(functionName) << " at index " << index); 0150 // DEBUG(Q_FUNC_INFO << ", function " << STDSTRING(functionName) << " has " << _functions[index].argc << " arguments"); 0151 } 0152 return QStringLiteral(""); 0153 } 0154 0155 QString ExpressionParser::functionArgumentString(const QString& functionName, const XYEquationCurve::EquationType type) { 0156 QString p = parameters(functionName); 0157 if (!p.isEmpty()) 0158 return p; 0159 0160 // Default parameters 0161 switch (functionArgumentCount(functionName)) { 0162 case 0: 0163 return QStringLiteral("()"); 0164 case 1: 0165 switch (type) { 0166 case XYEquationCurve::EquationType::Cartesian: 0167 return QStringLiteral("(x)"); 0168 case XYEquationCurve::EquationType::Polar: 0169 return QStringLiteral("(phi)"); 0170 case XYEquationCurve::EquationType::Parametric: 0171 return QStringLiteral("(t)"); 0172 case XYEquationCurve::EquationType::Implicit: 0173 case XYEquationCurve::EquationType::Neutral: 0174 return QStringLiteral("(x)"); 0175 } 0176 break; 0177 case 2: 0178 switch (type) { 0179 case XYEquationCurve::EquationType::Cartesian: 0180 return QStringLiteral("(x; y)"); 0181 case XYEquationCurve::EquationType::Polar: 0182 return QStringLiteral("(phi; theta)"); 0183 case XYEquationCurve::EquationType::Parametric: 0184 return QStringLiteral("(u; v)"); 0185 case XYEquationCurve::EquationType::Implicit: 0186 case XYEquationCurve::EquationType::Neutral: 0187 return QStringLiteral("(x; y)"); 0188 } 0189 break; 0190 case 3: 0191 switch (type) { 0192 case XYEquationCurve::EquationType::Cartesian: 0193 return QStringLiteral("(x; y; z)"); 0194 case XYEquationCurve::EquationType::Polar: 0195 return QStringLiteral("(alpha; beta; gamma)"); 0196 case XYEquationCurve::EquationType::Parametric: 0197 return QStringLiteral("(u; v; w)"); 0198 case XYEquationCurve::EquationType::Implicit: 0199 case XYEquationCurve::EquationType::Neutral: 0200 return QStringLiteral("(x; y; z)"); 0201 } 0202 break; 0203 case 4: 0204 switch (type) { 0205 case XYEquationCurve::EquationType::Cartesian: 0206 return QStringLiteral("(a; b; c; d)"); 0207 case XYEquationCurve::EquationType::Polar: 0208 return QStringLiteral("(alpha; beta; gamma; delta)"); 0209 case XYEquationCurve::EquationType::Parametric: 0210 return QStringLiteral("(a; b; c; d)"); 0211 case XYEquationCurve::EquationType::Implicit: 0212 case XYEquationCurve::EquationType::Neutral: 0213 return QStringLiteral("(a; b; c; d)"); 0214 } 0215 break; 0216 } 0217 0218 return QStringLiteral("(...)"); 0219 } 0220 0221 QString ExpressionParser::functionDescription(const QString& function) { 0222 for (int index = 0; index < _number_functions; index++) { 0223 if (function == QLatin1String(_functions[index].name)) 0224 return _functions[index].description(); 0225 } 0226 for (int index = 0; index < _number_specialfunctions; index++) { 0227 if (function == QLatin1String(_special_functions[index].name)) 0228 return _special_functions[index].description(); 0229 } 0230 return QStringLiteral(""); 0231 } 0232 QString ExpressionParser::constantDescription(const QString& constant) { 0233 for (int index = 0; index < _number_constants; index++) { 0234 if (constant == QLatin1String(_constants[index].name)) 0235 return QStringLiteral("%1 (%2 %3)").arg(_constants[index].description()).arg(_constants[index].value).arg(QLatin1String(_constants[index].unit)); 0236 } 0237 return QStringLiteral(""); 0238 } 0239 0240 const QStringList& ExpressionParser::constants() { 0241 return m_constants; 0242 } 0243 0244 const QStringList& ExpressionParser::constantsGroups() { 0245 return m_constantsGroups; 0246 } 0247 0248 const QStringList& ExpressionParser::constantsNames() { 0249 return m_constantsDescription; 0250 } 0251 0252 const QStringList& ExpressionParser::constantsValues() { 0253 return m_constantsValues; 0254 } 0255 0256 const QStringList& ExpressionParser::constantsUnits() { 0257 return m_constantsUnits; 0258 } 0259 0260 const QVector<ConstantGroups>& ExpressionParser::constantsGroupIndices() { 0261 return m_constantsGroupIndex; 0262 } 0263 0264 bool ExpressionParser::isValid(const QString& expr, const QStringList& vars) { 0265 QDEBUG(Q_FUNC_INFO << ", expr:" << expr << ", vars:" << vars); 0266 gsl_set_error_handler_off(); 0267 0268 Lock l(skipSpecialFunctionEvaluation); 0269 0270 for (const auto& var : vars) 0271 assign_symbol(qPrintable(var), 0); 0272 0273 // Row index 0274 assign_symbol("i", 0); 0275 0276 const auto numberLocale = QLocale(); 0277 DEBUG(Q_FUNC_INFO << ", number locale: " << STDSTRING(numberLocale.name())) 0278 parse(qPrintable(expr), qPrintable(numberLocale.name())); 0279 0280 // if parsing with number locale fails, try default locale 0281 if (parse_errors() > 0) { 0282 DEBUG(Q_FUNC_INFO << ", WARNING: failed parsing expr \"" << STDSTRING(expr) << "\" with locale " << numberLocale.name().toStdString() 0283 << ", errors = " << parse_errors()) 0284 parse(qPrintable(expr), "en_US"); 0285 if (parse_errors() > 0) 0286 DEBUG(Q_FUNC_INFO << ", ERROR: parsing FAILED, errors = " << parse_errors()) 0287 } 0288 0289 /* remove temporarily defined symbols */ 0290 for (const auto& var : vars) 0291 remove_symbol(qPrintable(var)); 0292 0293 return !(parse_errors() > 0); 0294 } 0295 0296 QStringList ExpressionParser::getParameter(const QString& expr, const QStringList& vars) { 0297 QDEBUG(Q_FUNC_INFO << ", variables:" << vars); 0298 QStringList parameters; 0299 0300 #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) 0301 QStringList strings = expr.split(QRegularExpression(QStringLiteral("\\W+")), Qt::SkipEmptyParts); 0302 #else 0303 QStringList strings = expr.split(QRegularExpression(QStringLiteral("\\W+")), QString::SkipEmptyParts); 0304 #endif 0305 QDEBUG(Q_FUNC_INFO << ", found strings:" << strings); 0306 // RE for any number 0307 const QRegularExpression re(QRegularExpression::anchoredPattern(QStringLiteral("[0-9]*"))); 0308 for (const QString& string : strings) { 0309 QDEBUG(string << ':' << constants().indexOf(string) << ' ' << functions().indexOf(string) << ' ' << vars.indexOf(string) << ' ' 0310 << re.match(string).hasMatch()); 0311 // check if token is not a known constant/function/variable or number 0312 if (constants().indexOf(string) == -1 && functions().indexOf(string) == -1 && vars.indexOf(string) == -1 && re.match(string).hasMatch() == false) 0313 parameters << string; 0314 } 0315 parameters.removeDuplicates(); 0316 QDEBUG(Q_FUNC_INFO << ", parameters found:" << parameters); 0317 0318 return parameters; 0319 } 0320 0321 /* 0322 * Evaluate cartesian expression returning true on success and false if parsing fails 0323 * using given range 0324 */ 0325 bool ExpressionParser::evaluateCartesian(const QString& expr, 0326 const Range<double> range, 0327 int count, 0328 QVector<double>* xVector, 0329 QVector<double>* yVector, 0330 const QStringList& paramNames, 0331 const QVector<double>& paramValues) { 0332 DEBUG(Q_FUNC_INFO << ", v0: range = " << range.toStdString()) 0333 const double step = range.stepSize(count); 0334 DEBUG(Q_FUNC_INFO << ", range = " << range.toStdString() << ", step = " << step) 0335 0336 for (int i = 0; i < paramNames.size(); ++i) 0337 assign_symbol(qPrintable(paramNames.at(i)), paramValues.at(i)); 0338 0339 const auto numberLocale = QLocale(); 0340 gsl_set_error_handler_off(); 0341 for (int i = 0; i < count; i++) { 0342 const double x{range.start() + step * i}; 0343 assign_symbol("x", x); 0344 0345 double y = parse(qPrintable(expr), qPrintable(numberLocale.name())); 0346 if (parse_errors() > 0) // try default locale if failing 0347 y = parse(qPrintable(expr), "en_US"); 0348 if (parse_errors() > 0) 0349 return false; 0350 0351 if (std::isnan(y)) 0352 WARN(Q_FUNC_INFO << ", WARNING: expression " << STDSTRING(expr) << " evaluated @ " << x << " is NAN") 0353 0354 (*xVector)[i] = x; 0355 (*yVector)[i] = y; 0356 } 0357 0358 return true; 0359 } 0360 /* 0361 * Evaluate cartesian expression returning true on success and false if parsing fails 0362 * min and max are localized strings which are parsed to support expressions like "pi + 1.5" 0363 */ 0364 bool ExpressionParser::evaluateCartesian(const QString& expr, 0365 const QString& min, 0366 const QString& max, 0367 int count, 0368 QVector<double>* xVector, 0369 QVector<double>* yVector, 0370 const QStringList& paramNames, 0371 const QVector<double>& paramValues) { 0372 DEBUG(Q_FUNC_INFO << ", v1: range = " << STDSTRING(min) << " .. " << STDSTRING(max)) 0373 0374 const Range<double> range{min, max}; 0375 return evaluateCartesian(expr, range, count, xVector, yVector, paramNames, paramValues); 0376 } 0377 0378 bool ExpressionParser::evaluateCartesian(const QString& expr, 0379 const QString& min, 0380 const QString& max, 0381 int count, 0382 QVector<double>* xVector, 0383 QVector<double>* yVector) { 0384 DEBUG(Q_FUNC_INFO << ", v2") 0385 gsl_set_error_handler_off(); 0386 0387 const Range<double> range{min, max}; 0388 const double step = range.stepSize(count); 0389 0390 const auto numberLocale = QLocale(); 0391 for (int i = 0; i < count; i++) { 0392 const double x{range.start() + step * i}; 0393 assign_symbol("x", x); 0394 0395 double y = parse(qPrintable(expr), qPrintable(numberLocale.name())); 0396 if (parse_errors() > 0) { // try default locale if failing 0397 y = parse(qPrintable(expr), "en_US"); 0398 // DEBUG(Q_FUNC_INFO << ", WARNING: PARSER failed, trying default locale: y = " << y) 0399 } 0400 if (parse_errors() > 0) 0401 return false; 0402 0403 if (std::isnan(y)) 0404 WARN(Q_FUNC_INFO << ", WARNING: expression " << STDSTRING(expr) << " evaluated @ " << x << " is NAN") 0405 0406 (*xVector)[i] = x; 0407 (*yVector)[i] = y; 0408 } 0409 0410 return true; 0411 } 0412 0413 bool ExpressionParser::evaluateCartesian(const QString& expr, QVector<double>* xVector, QVector<double>* yVector) { 0414 DEBUG(Q_FUNC_INFO << ", v3") 0415 gsl_set_error_handler_off(); 0416 0417 const auto numberLocale = QLocale(); 0418 for (int i = 0; i < xVector->count(); i++) { 0419 assign_symbol("x", xVector->at(i)); 0420 double y = parse(qPrintable(expr), qPrintable(numberLocale.name())); 0421 if (parse_errors() > 0) // try default locale if failing 0422 y = parse(qPrintable(expr), "en_US"); 0423 if (parse_errors() > 0) 0424 return false; 0425 0426 if (std::isnan(y)) 0427 WARN(Q_FUNC_INFO << ", WARNING: expression " << STDSTRING(expr) << " evaluated @ " << xVector->at(i) << " is NAN") 0428 0429 (*yVector)[i] = y; 0430 } 0431 0432 return true; 0433 } 0434 0435 bool ExpressionParser::evaluateCartesian(const QString& expr, 0436 const QVector<double>* xVector, 0437 QVector<double>* yVector, 0438 const QStringList& paramNames, 0439 const QVector<double>& paramValues) { 0440 DEBUG(Q_FUNC_INFO << ", v4") 0441 gsl_set_error_handler_off(); 0442 0443 for (int i = 0; i < paramNames.size(); ++i) 0444 assign_symbol(qPrintable(paramNames.at(i)), paramValues.at(i)); 0445 0446 const auto numberLocale = QLocale(); 0447 for (int i = 0; i < xVector->count(); i++) { 0448 assign_symbol("x", xVector->at(i)); 0449 0450 double y = parse(qPrintable(expr), qPrintable(numberLocale.name())); 0451 if (parse_errors() > 0) // try default locale if failing 0452 y = parse(qPrintable(expr), "en_US"); 0453 if (parse_errors() > 0) 0454 return false; 0455 0456 if (std::isnan(y)) 0457 WARN(Q_FUNC_INFO << ", WARNING: expression " << STDSTRING(expr) << " evaluated @ " << xVector->at(i) << " is NAN") 0458 0459 (*yVector)[i] = y; 0460 } 0461 0462 return true; 0463 } 0464 0465 struct PayloadExpressionParser : public Payload { 0466 PayloadExpressionParser() { 0467 } 0468 PayloadExpressionParser(const QStringList* vars, const QVector<QVector<double>*>* xVectors, bool constant = false) 0469 : Payload(constant) 0470 , vars(vars) 0471 , row(0) 0472 , xVectors(xVectors) { 0473 } 0474 const QStringList* vars; 0475 int row; 0476 const QVector<QVector<double>*>* xVectors; 0477 }; 0478 0479 double cell(double x, const char* variable, const std::weak_ptr<Payload> payload) { 0480 const auto p = std::dynamic_pointer_cast<PayloadExpressionParser>(payload.lock()); 0481 if (!p) { 0482 assert(p); // Debug build 0483 return NAN; 0484 } 0485 0486 const int index = (int)x - 1; 0487 for (int i = 0; i < p->vars->length(); i++) { 0488 if (p->vars->at(i).compare(QLatin1String(variable)) == 0) { 0489 if (index >= 0 && index < p->xVectors->at(i)->length()) 0490 return p->xVectors->at(i)->at(index); 0491 else 0492 break; 0493 } 0494 } 0495 0496 return NAN; 0497 } 0498 0499 double ma(const char* variable, const std::weak_ptr<Payload> payload) { 0500 const auto p = std::dynamic_pointer_cast<PayloadExpressionParser>(payload.lock()); 0501 if (!p) { 0502 assert(p); // Debug build 0503 return NAN; 0504 } 0505 return (cell(p->row, variable, payload) + cell(p->row + 1, variable, payload)) / 2.; 0506 } 0507 0508 double mr(const char* variable, const std::weak_ptr<Payload> payload) { 0509 const auto p = std::dynamic_pointer_cast<PayloadExpressionParser>(payload.lock()); 0510 if (!p) { 0511 assert(p); // Debug build 0512 return NAN; 0513 } 0514 return fabs(cell(p->row + 1, variable, payload) - cell(p->row + 1 - 1, variable, payload)); 0515 } 0516 0517 double smmin(double x, const char* variable, const std::weak_ptr<Payload> payload) { 0518 const auto p = std::dynamic_pointer_cast<PayloadExpressionParser>(payload.lock()); 0519 if (!p) { 0520 assert(p); // Debug build 0521 return NAN; 0522 } 0523 0524 for (int i = 0; i < p->vars->length(); i++) { 0525 if (p->vars->at(i).compare(QLatin1String(variable)) == 0) { 0526 const int N = x; 0527 DEBUG("N = " << N) 0528 if (N < 1) 0529 break; 0530 // calculate min of last n points 0531 double min = INFINITY; 0532 const int row = p->row; 0533 for (int index = std::max(0, row - N + 1); index <= row; index++) { 0534 const double v = p->xVectors->at(i)->at(index); 0535 if (v < min) 0536 min = v; 0537 } 0538 return min; 0539 } 0540 } 0541 return NAN; 0542 } 0543 0544 double smmax(double x, const char* variable, const std::weak_ptr<Payload> payload) { 0545 const auto p = std::dynamic_pointer_cast<PayloadExpressionParser>(payload.lock()); 0546 if (!p) { 0547 assert(p); // Debug build 0548 return NAN; 0549 } 0550 0551 for (int i = 0; i < p->vars->length(); i++) { 0552 if (p->vars->at(i).compare(QLatin1String(variable)) == 0) { 0553 const int N = x; 0554 DEBUG("N = " << N) 0555 if (N < 1) 0556 break; 0557 // calculate max of last n points 0558 double max = -INFINITY; 0559 const int row = p->row; 0560 for (int index = std::max(0, row - N + 1); index <= row; index++) { 0561 const double v = p->xVectors->at(i)->at(index); 0562 if (v > max) 0563 max = v; 0564 } 0565 return max; 0566 } 0567 } 0568 return NAN; 0569 } 0570 0571 double sma(double x, const char* variable, const std::weak_ptr<Payload> payload) { 0572 const auto p = std::dynamic_pointer_cast<PayloadExpressionParser>(payload.lock()); 0573 if (!p) { 0574 assert(p); // Debug build 0575 return NAN; 0576 } 0577 0578 for (int i = 0; i < p->vars->length(); i++) { 0579 if (p->vars->at(i).compare(QLatin1String(variable)) == 0) { 0580 const int N = x; 0581 DEBUG("N = " << N) 0582 if (N < 1) 0583 break; 0584 // calculate max of last n points 0585 double sum = 0.; 0586 const int row = p->row; 0587 for (int index = std::max(0, row - N + 1); index <= row; index++) 0588 sum += p->xVectors->at(i)->at(index); 0589 return sum / N; 0590 } 0591 } 0592 return NAN; 0593 } 0594 0595 double smr(double x, const char* variable, const std::weak_ptr<Payload> payload) { 0596 return smmax(x, variable, payload) - smmin(x, variable, payload); 0597 } 0598 0599 void ExpressionParser::setSpecialFunction1(const char* function_name, func_t1Payload funct, std::shared_ptr<Payload> payload) { 0600 set_specialfunction1(function_name, funct, payload); 0601 } 0602 0603 void ExpressionParser::setSpecialFunction2(const char* function_name, func_t2Payload funct, std::shared_ptr<Payload> payload) { 0604 set_specialfunction2(function_name, funct, payload); 0605 } 0606 0607 /*! 0608 evaluates multivariate function y=f(x_1, x_2, ...). 0609 Variable names (x_1, x_2, ...) are stored in \c vars. 0610 Data is stored in \c xVectors. 0611 */ 0612 bool ExpressionParser::evaluateCartesian(const QString& expr, const QStringList& vars, const QVector<QVector<double>*>& xVectors, QVector<double>* yVector) { 0613 #if PERFTRACE_EXPRESSION_PARSER 0614 PERFTRACE(QLatin1String(Q_FUNC_INFO)); 0615 #endif 0616 DEBUG(Q_FUNC_INFO << ", v5") 0617 Q_ASSERT(vars.size() == xVectors.size()); 0618 gsl_set_error_handler_off(); 0619 0620 // determine the minimal size of involved vectors 0621 int minSize{std::numeric_limits<int>::max()}; 0622 for (auto* xVector : xVectors) { 0623 if (xVector->size() < minSize) 0624 minSize = xVector->size(); 0625 } 0626 if (yVector->size() < minSize) 0627 minSize = yVector->size(); 0628 0629 // calculate values 0630 const auto numberLocale = QLocale(); 0631 DEBUG("Parsing with locale " << qPrintable(numberLocale.name())) 0632 0633 const auto payload = std::make_shared<PayloadExpressionParser>(&vars, &xVectors); 0634 const auto payloadConst = std::make_shared<PayloadExpressionParser>(&vars, &xVectors, true); 0635 0636 set_specialfunction2(specialfun_cell, cell, payloadConst); 0637 set_specialfunction1(specialfun_ma, ma, payload); 0638 set_specialfunction1(specialfun_mr, mr, payload); 0639 set_specialfunction2(specialfun_smmin, smmin, payload); 0640 set_specialfunction2(specialfun_smmax, smmax, payload); 0641 set_specialfunction2(specialfun_sma, sma, payload); 0642 set_specialfunction2(specialfun_smr, smr, payload); 0643 0644 bool constExpression = false; 0645 for (int i = 0; i < minSize || (constExpression && i < yVector->size()); i++) { 0646 QString tmpExpr = expr; 0647 0648 payload->row = i; // all special functions contain pointer to payload so they get this information 0649 assign_symbol("i", i + 1); 0650 0651 for (int n = 0; n < vars.size(); ++n) { 0652 if (!constExpression) 0653 assign_symbol(qPrintable(vars.at(n)), xVectors.at(n)->at(i)); 0654 } 0655 0656 double y = parse(qPrintable(tmpExpr), qPrintable(numberLocale.name())); 0657 if (parse_errors() > 0) { // try default locale if failing 0658 // DEBUG("Parsing with locale failed. Using en_US.") 0659 y = parse(qPrintable(tmpExpr), "en_US"); 0660 } 0661 0662 if (parse_errors() == 0) 0663 constExpression = variablesCounter() == 0; 0664 // continue with next value 0665 // if (parse_errors() > 0) 0666 // return false; 0667 0668 if (std::isnan(y)) 0669 WARN(Q_FUNC_INFO << ", WARNING: expression " << STDSTRING(tmpExpr) << " evaluated to NAN") 0670 0671 (*yVector)[i] = y; 0672 } 0673 0674 // if the y-vector is longer than the x-vector(s), set all exceeding elements to NaN 0675 if (!constExpression) { 0676 for (int i = minSize; i < yVector->size(); ++i) 0677 (*yVector)[i] = NAN; 0678 } 0679 0680 return true; 0681 } 0682 0683 bool ExpressionParser::evaluatePolar(const QString& expr, 0684 const QString& min, 0685 const QString& max, 0686 int count, 0687 QVector<double>* xVector, 0688 QVector<double>* yVector) { 0689 gsl_set_error_handler_off(); 0690 0691 const Range<double> range{min, max}; 0692 const double step = range.stepSize(count); 0693 0694 const auto numberLocale = QLocale(); 0695 for (int i = 0; i < count; i++) { 0696 const double phi = range.start() + step * i; 0697 assign_symbol("phi", phi); 0698 0699 double r = parse(qPrintable(expr), qPrintable(numberLocale.name())); 0700 if (parse_errors() > 0) // try default locale if failing 0701 r = parse(qPrintable(expr), "en_US"); 0702 if (parse_errors() > 0) 0703 return false; 0704 0705 if (std::isnan(r)) 0706 WARN(Q_FUNC_INFO << ", WARNING: expression " << STDSTRING(expr) << " evaluated @ " << phi << " is NAN") 0707 0708 (*xVector)[i] = r * cos(phi); 0709 (*yVector)[i] = r * sin(phi); 0710 } 0711 0712 return true; 0713 } 0714 0715 bool ExpressionParser::evaluateParametric(const QString& xexpr, 0716 const QString& yexpr, 0717 const QString& min, 0718 const QString& max, 0719 int count, 0720 QVector<double>* xVector, 0721 QVector<double>* yVector) { 0722 gsl_set_error_handler_off(); 0723 0724 const Range<double> range{min, max}; 0725 const double step = range.stepSize(count); 0726 0727 const auto numberLocale = QLocale(); 0728 for (int i = 0; i < count; i++) { 0729 assign_symbol("t", range.start() + step * i); 0730 0731 double x = parse(qPrintable(xexpr), qPrintable(numberLocale.name())); 0732 if (parse_errors() > 0) // try default locale if failing 0733 x = parse(qPrintable(xexpr), "en_US"); 0734 if (parse_errors() > 0) 0735 return false; 0736 0737 double y = parse(qPrintable(yexpr), qPrintable(numberLocale.name())); 0738 if (parse_errors() > 0) // try default locale if failing 0739 y = parse(qPrintable(yexpr), "en_US"); 0740 if (parse_errors() > 0) 0741 return false; 0742 0743 if (std::isnan(x)) 0744 WARN(Q_FUNC_INFO << ", WARNING: X expression " << STDSTRING(xexpr) << " evaluated @ " << range.start() + step * i << " is NAN") 0745 if (std::isnan(y)) 0746 WARN(Q_FUNC_INFO << ", WARNING: Y expression " << STDSTRING(yexpr) << " evaluated @ " << range.start() + step * i << " is NAN") 0747 0748 (*xVector)[i] = x; 0749 (*yVector)[i] = y; 0750 } 0751 0752 return true; 0753 } 0754 0755 QString ExpressionParser::errorMessage() const { 0756 return QLatin1String(lastErrorMessage()); 0757 }