File indexing completed on 2024-04-14 03:40:48

0001 /*
0002     KmPlot - a math. function plotter for the KDE-Desktop
0003 
0004     SPDX-FileCopyrightText: 1998, 1999, 2000, 2002 Klaus-Dieter Möller <kd.moeller@t-online.de>
0005     SPDX-FileCopyrightText: 2006 David Saxton <david@bluehaze.org>
0006 
0007     This file is part of the KDE Project.
0008     KmPlot is part of the KDE-EDU Project.
0009 
0010     SPDX-License-Identifier: GPL-2.0-or-later
0011 
0012 */
0013 
0014 // local includes
0015 #include "parser.h"
0016 #include "parseradaptor.h"
0017 #include "settings.h"
0018 #include "xparser.h"
0019 
0020 // KDE includes
0021 #include <KConfig>
0022 #include <KLocalizedString>
0023 #include <KMessageBox>
0024 
0025 #include <QDebug>
0026 #include <QList>
0027 
0028 // standard c(++) includes
0029 #include <assert.h>
0030 #include <cmath>
0031 #include <limits>
0032 #include <locale.h>
0033 #include <math.h>
0034 #include <stdio.h>
0035 #include <stdlib.h>
0036 
0037 double Parser::m_radiansPerAngleUnit = 0;
0038 
0039 /**
0040  * List of predefined functions.
0041  * \note Some function names include other function names (e.g. "sinh" has the
0042  * string "sin" in it). The Parser will stop once it has found a matching
0043  * function name, so such functions must be in order of longest first.
0044  */
0045 ScalarFunction Parser::scalarFunctions[ScalarCount] = {
0046     // Hyperbolic trig
0047     {"sinh", QString(), sinh}, // Sinus hyperbolicus
0048     {"cosh", QString(), cosh}, // Cosinus hyperbolicus
0049     {"tanh", QString(), tanh}, // Tangens hyperbolicus
0050     {"arcsinh", "arsinh", asinh}, // Area-sinus hyperbolicus = inverse of sinh
0051     {"arccosh", "arcosh", acosh}, // Area-cosinus hyperbolicus = inverse of cosh
0052     {"arctanh", "artanh", atanh}, // Area-tangens hyperbolicus = inverse of tanh
0053 
0054     // Reciprocal-hyperbolic
0055     {"cosech", QString(), cosech}, // Co-Secans hyperbolicus
0056     {"sech", QString(), sech}, // Secans hyperbolicus
0057     {"coth", QString(), coth}, // Co-Tangens hyperbolicus
0058     {"arccosech", "arcosech", arcosech}, // Area-co-secans hyperbolicus = inverse of cosech
0059     {"arcsech", "arsech", arsech}, // Area-secans hyperbolicus = inverse of sech
0060     {"arccoth", "arcoth", arcoth}, // Area-co-tangens hyperbolicus = inverse of coth
0061 
0062     // Reciprocal-trig
0063     {"cosec", QString(), lcosec}, // Co-Secans = 1/sin
0064     {"sec", QString(), lsec}, // Secans = 1/cos
0065     {"cot", QString(), lcot}, // Co-Tangens = 1/tan
0066     {"arccosec", "arcosech", larccosec}, // Arcus co-secans = inverse of cosec
0067     {"arcsec", "arsec", larcsec}, // Arcus secans = inverse of sec
0068     {"arccot", "arcot", larccot}, // Arcus co-tangens = inverse of cotan
0069 
0070     // Trigonometric functions
0071     {"sin", QString(), lsin}, // Sinus
0072     {"cos", QString(), lcos}, // Cosinus
0073     {"tan", QString(), ltan}, // Tangens
0074     {"arcsin", QString(), larcsin}, // Arcus sinus = inverse of sin
0075     {"arccos", QString(), larccos}, // Arcus cosinus = inverse of cos
0076     {"arctan", QString(), larctan}, // Arcus tangens = inverse of tan
0077 
0078     // Other
0079     {"sqrt", QString(), sqrt}, // Square root
0080     {"sqr", QString(), sqr}, // Square
0081     {"sign", QString(), sign}, // Signum
0082     {"H", QString(), heaviside}, // Heaviside step function
0083     {"log", QString(), log10}, // Logarithm base 10
0084     {"ln", QString(), log}, // Logarithm base e
0085     {"exp", QString(), exp}, // Exponential function base e
0086     {"abs", QString(), fabs}, // Absolute value
0087     {"floor", QString(), floor}, // round down to nearest integer
0088     {"ceil", QString(), ceil}, // round up to nearest integer
0089     {"round", QString(), round}, // round to nearest integer
0090     {"gamma", QString(), tgamma}, // gamma function
0091     {"lgamma", QString(), lgamma}, // log-gamma function
0092     {"factorial", QString(), factorial}, // factorial
0093     {"erfc", QString(), lerfc}, // error function
0094     {"erf", QString(), lerf}, // complementary error function
0095 
0096     // legendre
0097     {"P_0", QString(), legendre0}, // lengedre polynomial (n=0)
0098     {"P_1", QString(), legendre1}, // lengedre polynomial (n=1)
0099     {"P_2", QString(), legendre2}, // lengedre polynomial (n=2)
0100     {"P_3", QString(), legendre3}, // lengedre polynomial (n=3)
0101     {"P_4", QString(), legendre4}, // lengedre polynomial (n=4)
0102     {"P_5", QString(), legendre5}, // lengedre polynomial (n=5)
0103     {"P_6", QString(), legendre6}, // lengedre polynomial (n=6)
0104 };
0105 
0106 VectorFunction Parser::vectorFunctions[VectorCount] = {
0107     {"min", min}, // minimum of a set of reals
0108     {"max", max}, // maximum of a set of reals
0109     {"mod", mod}, // l2 modulus of a set of reals
0110 };
0111 
0112 /**
0113  * Order by longest string first, useful in parsing since we want to at each point
0114  * match the longest string first, so e.g. "sinh(x)" shouldn't be read as "sin(h) * x"
0115  */
0116 class LengthOrderedString : public QString
0117 {
0118 public:
0119     LengthOrderedString()
0120     {
0121     }
0122     LengthOrderedString(const QString &s)
0123         : QString(s)
0124     {
0125     }
0126 
0127     bool operator<(const LengthOrderedString &other) const
0128     {
0129         return (length() > other.length()) || ((length() == other.length()) && (static_cast<const QString &>(*this) < static_cast<const QString &>(other)));
0130     }
0131 };
0132 
0133 // BEGIN class Parser
0134 Parser::Parser()
0135     : m_sanitizer(this)
0136 {
0137     m_evalPos = 0;
0138     m_nextFunctionID = 0;
0139     m_stack = new double[STACKSIZE];
0140     stkptr = m_stack;
0141     m_constants = new Constants;
0142 
0143     m_error = nullptr;
0144     m_ownEquation = nullptr;
0145     m_currentEquation = nullptr;
0146 }
0147 
0148 Parser::~Parser()
0149 {
0150     for (Function *function : qAsConst(m_ufkt))
0151         delete function;
0152     delete m_ownEquation;
0153     delete m_constants;
0154     delete[] m_stack;
0155 }
0156 
0157 QStringList Parser::predefinedFunctions(bool includeAliases) const
0158 {
0159     QStringList names;
0160 
0161     for (int func = 0; func < ScalarCount; ++func) {
0162         names << scalarFunctions[func].name1;
0163         if (includeAliases && !scalarFunctions[func].name2.isEmpty())
0164             names << scalarFunctions[func].name2;
0165     }
0166 
0167     for (int func = 0; func < VectorCount; ++func)
0168         names << vectorFunctions[func].name;
0169 
0170     return names;
0171 }
0172 
0173 QStringList Parser::userFunctions() const
0174 {
0175     QStringList names;
0176 
0177     for (Function *f : qAsConst(m_ufkt)) {
0178         for (Equation *eq : qAsConst(f->eq)) {
0179             if (!eq->name().isEmpty())
0180                 names << eq->name();
0181         }
0182     }
0183 
0184     names.sort();
0185     return names;
0186 }
0187 
0188 void Parser::reparseAllFunctions()
0189 {
0190     for (Function *f : m_ufkt) {
0191         for (Equation *eq : f->eq)
0192             initEquation(eq);
0193     }
0194 }
0195 
0196 void Parser::setAngleMode(AngleMode mode)
0197 {
0198     switch (mode) {
0199     case Radians:
0200         m_radiansPerAngleUnit = 1.0;
0201         break;
0202 
0203     case Degrees:
0204         m_radiansPerAngleUnit = M_PI / 180;
0205         break;
0206     }
0207 }
0208 
0209 uint Parser::getNewId()
0210 {
0211     uint i = m_nextFunctionID;
0212     while (1) {
0213         if (!m_ufkt.contains(i)) {
0214             m_nextFunctionID = i + 1;
0215             return i;
0216         }
0217         ++i;
0218     }
0219 }
0220 
0221 double Parser::eval(const QString &str, Error *error, int *errorPosition)
0222 {
0223     Error t1;
0224     if (!error)
0225         error = &t1;
0226     int t2;
0227     if (!errorPosition)
0228         errorPosition = &t2;
0229 
0230     if (!m_ownEquation)
0231         m_ownEquation = new Equation(Equation::Constant, nullptr);
0232 
0233     QString fName = XParser::self()->findFunctionName(QStringLiteral("f"), -1);
0234 
0235     QString eq = QStringLiteral("%1=%2").arg(fName).arg(str);
0236     if (!m_ownEquation->setFstr(eq, (int *)error, errorPosition)) {
0237         if (errorPosition)
0238             *errorPosition -= fName.length() + 1;
0239         return 0;
0240     }
0241 
0242     return fkt(m_ownEquation, Vector());
0243 }
0244 
0245 double Parser::fkt(uint id, int eq, double x)
0246 {
0247     if (!m_ufkt.contains(id) || m_ufkt[id]->eq.size() <= eq) {
0248         *m_error = NoSuchFunction;
0249         return 0;
0250     }
0251 
0252     return fkt(m_ufkt[id]->eq[eq], x);
0253 }
0254 
0255 double Parser::fkt(Equation *eq, double x)
0256 {
0257     Function *function = eq->parent();
0258     Q_ASSERT_X(function->type() != Function::Differential, "Parser::fkt", "Do not use this function directly! Instead, call XParser::differential");
0259 
0260     switch (function->type()) {
0261     case Function::Cartesian:
0262     case Function::Parametric:
0263     case Function::Polar: {
0264         Vector var(2);
0265         var[0] = x;
0266         var[1] = function->k;
0267 
0268         return fkt(eq, var);
0269     }
0270 
0271     case Function::Implicit: {
0272         Vector var(3);
0273 
0274         // Can only calculate when one of x, y is fixed
0275         assert(function->m_implicitMode != Function::UnfixedXY);
0276 
0277         if (function->m_implicitMode == Function::FixedX) {
0278             var[0] = function->x;
0279             var[1] = x;
0280         } else {
0281             // fixed y
0282             var[0] = x;
0283             var[1] = function->y;
0284         }
0285         var[2] = function->k;
0286 
0287         return fkt(eq, var);
0288     }
0289 
0290     case Function::Differential:
0291         return 0;
0292     }
0293 
0294     qWarning() << "Unknown function type!\n";
0295     return 0;
0296 }
0297 
0298 double Parser::fkt(Equation *eq, const Vector &x)
0299 {
0300     if (eq->mem.isEmpty())
0301         return 0;
0302 
0303     // Consistency check: Make sure that we leave the stkptr at the same place
0304     // that we started it
0305     double *stkInitial = stkptr;
0306 
0307     double *pDouble;
0308     double (**pScalarFunction)(double);
0309     double (**pVectorFunction)(const Vector &);
0310     uint *pUint;
0311     eq->mptr = eq->mem.data();
0312 
0313     // Start with zero in our stackpointer
0314     //
0315     *stkptr = 0;
0316 
0317     while (1) {
0318         //      qDebug() << "*eq->mptr: "<<int(*eq->mptr);
0319 
0320         switch (*eq->mptr++) {
0321         case KONST: {
0322             pDouble = (double *)eq->mptr;
0323             *stkptr = *pDouble++;
0324             eq->mptr = (char *)pDouble;
0325             break;
0326         }
0327 
0328         case VAR: {
0329             pUint = (uint *)eq->mptr;
0330             uint var = *pUint++;
0331             if (int(var) >= x.size()) {
0332                 // Assume variable has value zero
0333                 *stkptr = 0;
0334             } else
0335                 *stkptr = x[var];
0336             eq->mptr = (char *)pUint;
0337             break;
0338         }
0339 
0340         case PUSH: {
0341             ++stkptr;
0342             break;
0343         }
0344 
0345         case PLUS: {
0346             stkptr[-1] += *stkptr;
0347             --stkptr;
0348             break;
0349         }
0350 
0351         case MINUS: {
0352             stkptr[-1] -= *stkptr;
0353             --stkptr;
0354             break;
0355         }
0356 
0357         case GT: {
0358             stkptr[-1] = (*(stkptr - 1) > *stkptr) ? 1 : 0;
0359             stkptr--;
0360             break;
0361         }
0362 
0363         case GE: {
0364             stkptr[-1] = (*(stkptr - 1) >= *stkptr) ? 1 : 0;
0365             stkptr--;
0366             break;
0367         }
0368 
0369         case LT: {
0370             stkptr[-1] = (*(stkptr - 1) < *stkptr) ? 1 : 0;
0371             stkptr--;
0372             break;
0373         }
0374 
0375         case LE: {
0376             stkptr[-1] = (*(stkptr - 1) <= *stkptr) ? 1 : 0;
0377             stkptr--;
0378             break;
0379         }
0380 
0381         case PM: {
0382             pUint = (uint *)eq->mptr;
0383             uint whichPM = *pUint++;
0384             eq->mptr = (char *)pUint;
0385 
0386             assert(int(whichPM) < eq->pmSignature().size());
0387             bool plus = eq->pmSignature()[whichPM];
0388 
0389             if (plus)
0390                 stkptr[-1] += *stkptr;
0391             else
0392                 stkptr[-1] -= *stkptr;
0393 
0394             --stkptr;
0395             break;
0396         }
0397 
0398         case MULT: {
0399             stkptr[-1] *= *stkptr;
0400             --stkptr;
0401             break;
0402         }
0403 
0404         case DIV: {
0405             if (*stkptr == 0.)
0406                 *(--stkptr) = HUGE_VAL;
0407             else {
0408                 stkptr[-1] /= *stkptr;
0409                 --stkptr;
0410             }
0411             break;
0412         }
0413 
0414         case POW: {
0415             stkptr[-1] = pow(*(stkptr - 1), *stkptr);
0416             --stkptr;
0417             break;
0418         }
0419 
0420         case NEG: {
0421             *stkptr = -*stkptr;
0422             break;
0423         }
0424 
0425         case SQRT: {
0426             *stkptr = sqrt(*stkptr);
0427             break;
0428         }
0429 
0430         case FACT: {
0431             *stkptr = factorial(*stkptr);
0432             break;
0433         }
0434 
0435         case FKT_1: {
0436             pScalarFunction = (double (**)(double))eq->mptr;
0437             *stkptr = (*pScalarFunction++)(*stkptr);
0438             eq->mptr = (char *)pScalarFunction;
0439             break;
0440         }
0441 
0442         case FKT_N: {
0443             pUint = (uint *)eq->mptr;
0444             int numArgs = *pUint++;
0445 
0446             eq->mptr = (char *)pUint;
0447 
0448             pVectorFunction = (double (**)(const Vector &))eq->mptr;
0449 
0450             Vector args(numArgs);
0451             for (int i = 0; i < int(numArgs); ++i)
0452                 args[i] = *(stkptr - numArgs + 1 + i);
0453 
0454             if (numArgs > 0)
0455                 stkptr += 1 - numArgs;
0456             *stkptr = (*pVectorFunction++)(args);
0457 
0458             eq->mptr = (char *)pVectorFunction;
0459             break;
0460         }
0461 
0462         case UFKT: {
0463             pUint = (uint *)eq->mptr;
0464             uint id = *pUint++;
0465             uint id_eq = *pUint++;
0466 
0467             // The number of arguments being passed to the function
0468             int numArgs = *pUint++;
0469 
0470             Vector args(numArgs);
0471             for (int i = 0; i < numArgs; ++i)
0472                 args[i] = *(stkptr - numArgs + 1 + i);
0473 
0474             if (m_ufkt.contains(id)) {
0475                 if (numArgs > 0)
0476                     stkptr += 1 - numArgs;
0477                 *stkptr = fkt(m_ufkt[id]->eq[id_eq], args);
0478             }
0479 
0480             eq->mptr = (char *)pUint;
0481             break;
0482         }
0483 
0484         case ENDE: {
0485             // If the stack isn't where we started at, then we've gone
0486             // up / down the wrong number of places - definitely a bug (and
0487             // will lead to crashes over time as memory rapidly runs out).
0488             assert(stkptr == stkInitial);
0489             return *stkptr;
0490         }
0491         case ERROR: {
0492             // something went wrong due to a incorrect formular or
0493             // missing const.
0494             qDebug() << "Error in equation " << eq->fstr();
0495             // Adjust stack again. Stack is wrong, only if we have a PUSH token
0496             // just before the ERROR token, afaik.
0497             while (stkptr != stkInitial) {
0498                 stkptr--;
0499             }
0500             return *stkptr;
0501         }
0502         }
0503     }
0504 }
0505 
0506 int Parser::addFunction(const QString &str1, const QString &str2, Function::Type type, bool force)
0507 {
0508     QString str[2] = {str1, str2};
0509 
0510     Function *temp = new Function(type);
0511     temp->setId(getNewId());
0512 
0513     for (int i = 0; i < 2; ++i) {
0514         if (str[i].isEmpty() || temp->eq.size() <= i)
0515             continue;
0516 
0517         int error;
0518         if (!temp->eq[i]->setFstr(str[i], &error, nullptr, force) && !force) {
0519             qDebug() << "could not set fstr to \"" << str[i] << "\"!  error:" << errorString(Error(error)) << "\n";
0520             delete temp;
0521             return -1;
0522         }
0523 
0524         bool duplicate = (fnameToID(temp->eq[i]->name()) != -1);
0525         if (temp->eq[i]->looksLikeFunction() && duplicate && !force) {
0526             qDebug() << "function name reused.\n";
0527             *m_error = FunctionNameReused;
0528             delete temp;
0529             return -1;
0530         }
0531     }
0532 
0533     m_ufkt[temp->id()] = temp;
0534 
0535     temp->plotAppearance(Function::Derivative0).color = XParser::self()->defaultColor(temp->id());
0536     temp->plotAppearance(Function::Derivative1).color = QColor::fromRgb(QRandomGenerator::global()->generate());
0537     temp->plotAppearance(Function::Derivative2).color = QColor::fromRgb(QRandomGenerator::global()->generate());
0538     temp->plotAppearance(Function::Integral).color = QColor::fromRgb(QRandomGenerator::global()->generate());
0539 
0540     emit functionAdded(temp->id());
0541     return temp->id(); // return the unique ID-number for the function
0542 }
0543 
0544 void Parser::initEquation(Equation *eq, Error *error, int *errorPosition)
0545 {
0546     Error t1;
0547     if (!error)
0548         error = &t1;
0549     int t2;
0550     if (!errorPosition)
0551         errorPosition = &t2;
0552 
0553     if (eq->parent())
0554         eq->parent()->clearFunctionDependencies();
0555 
0556     m_error = error;
0557 
0558     *m_error = ParseSuccess;
0559     *errorPosition = -1;
0560 
0561     m_currentEquation = eq;
0562     mem = &eq->mem;
0563     mptr = mem->data();
0564     m_pmAt = 0;
0565 
0566     m_eval = eq->fstr();
0567     m_sanitizer.fixExpression(&m_eval);
0568     m_evalRemaining = m_eval;
0569     m_evalPos = m_eval.indexOf('=') + 1;
0570     heir0();
0571 
0572     if (!evalRemaining().isEmpty() && *m_error == ParseSuccess)
0573         *m_error = SyntaxError;
0574 
0575     if (*m_error != ParseSuccess) {
0576         *errorPosition = m_sanitizer.realPos(m_evalPos);
0577         qDebug() << "add an error token for " << eq->fstr();
0578         // add an error token and let the user decide
0579         addToken(ERROR);
0580     }
0581     addToken(ENDE);
0582 }
0583 
0584 bool Parser::removeFunction(Function *item)
0585 {
0586     // Build up a list of functions that need to be removed is this function is removed
0587     QList<Function *> toRemove;
0588     QStringList otherRemoveNames;
0589     QList<Function *> newFunctions; // Added since the last iteration
0590 
0591     toRemove << item;
0592     newFunctions << item;
0593 
0594     while (!newFunctions.isEmpty()) {
0595         const QList<Function *> currentFunctions = newFunctions;
0596         newFunctions.clear();
0597 
0598         for (Function *f : currentFunctions) {
0599             for (Function *other : qAsConst(m_ufkt)) {
0600                 if ((other == f) || toRemove.contains(other))
0601                     continue;
0602 
0603                 if (other->dependsOn(f)) {
0604                     toRemove << other;
0605                     otherRemoveNames << other->name();
0606                     newFunctions << other;
0607                 }
0608             }
0609         }
0610     }
0611 
0612     if (toRemove.size() > 1) {
0613         KGuiItem buttonContinue = KStandardGuiItem::cont();
0614         buttonContinue.setText(i18n("Remove all"));
0615 
0616         int answer =
0617             KMessageBox::warningContinueCancel(nullptr,
0618                                                i18n("The function %1 is depended upon by the following functions: %2. These must be removed in addition.",
0619                                                     item->name(),
0620                                                     otherRemoveNames.join(", ")),
0621                                                QString(),
0622                                                buttonContinue);
0623 
0624         if (answer == KMessageBox::Cancel)
0625             return false;
0626     }
0627 
0628     for (Function *f : qAsConst(toRemove)) {
0629         uint id = f->id();
0630         m_ufkt.remove(id);
0631         delete f;
0632         emit functionRemoved(id);
0633     }
0634 
0635     return true;
0636 }
0637 
0638 bool Parser::removeFunction(uint id)
0639 {
0640     return m_ufkt.contains(id) && removeFunction(m_ufkt[id]);
0641 }
0642 
0643 void Parser::removeAllFunctions()
0644 {
0645     while (!m_ufkt.isEmpty()) {
0646         Function *f = *m_ufkt.begin();
0647         int id = f->id();
0648         m_ufkt.remove(id);
0649         delete f;
0650         emit functionRemoved(id);
0651     }
0652 }
0653 
0654 uint Parser::countFunctions()
0655 {
0656     return m_ufkt.count();
0657 }
0658 
0659 void Parser::heir0()
0660 {
0661     heir1();
0662 
0663     if (*m_error != ParseSuccess)
0664         return;
0665 
0666     while (1) {
0667         if (m_eval.length() <= m_evalPos)
0668             return;
0669 
0670         QChar c = m_eval[m_evalPos];
0671 
0672         switch (c.unicode()) {
0673         default:
0674             return;
0675 
0676         case '<':
0677         case '>':
0678         case 0x2264: // less than or equal
0679         case 0x2265: // greater than or equal
0680             ++m_evalPos;
0681             addToken(PUSH);
0682             heir1();
0683             if (*m_error != ParseSuccess)
0684                 return;
0685         }
0686         switch (c.unicode()) {
0687         case '<':
0688             addToken(LT);
0689             break;
0690 
0691         case '>':
0692             addToken(GT);
0693             break;
0694 
0695         case 0x2264: // less than or equal
0696             addToken(LE);
0697             break;
0698 
0699         case 0x2265: // greater than or equal
0700             addToken(GE);
0701             break;
0702         }
0703     }
0704 }
0705 
0706 void Parser::heir1()
0707 {
0708     heir2();
0709 
0710     if (*m_error != ParseSuccess)
0711         return;
0712 
0713     while (1) {
0714         if (m_eval.length() <= m_evalPos)
0715             return;
0716 
0717         QChar c = m_eval[m_evalPos];
0718 
0719         switch (c.unicode()) {
0720         default:
0721             return;
0722 
0723         case 0xb1:
0724             if (m_pmAt >= MAX_PM) {
0725                 *m_error = TooManyPM;
0726                 return;
0727             }
0728             if (m_currentEquation == m_ownEquation) {
0729                 *m_error = InvalidPM;
0730                 return;
0731             }
0732             // no break
0733             Q_FALLTHROUGH();
0734         case '+':
0735         case '-':
0736             ++m_evalPos;
0737             addToken(PUSH);
0738             heir2();
0739             if (*m_error != ParseSuccess)
0740                 return;
0741         }
0742         switch (c.unicode()) {
0743         case '+':
0744             addToken(PLUS);
0745             break;
0746 
0747         case '-':
0748             addToken(MINUS);
0749             break;
0750 
0751         case 0xb1:
0752             addToken(PM);
0753             adduint(m_pmAt++);
0754             break;
0755         }
0756     }
0757 }
0758 
0759 void Parser::heir2()
0760 {
0761     if (match(SqrtSymbol)) // square root symbol
0762     {
0763         heir2();
0764         if (*m_error != ParseSuccess)
0765             return;
0766         addToken(SQRT);
0767     } else
0768         heir3();
0769 }
0770 
0771 void Parser::heir3()
0772 {
0773     QChar c;
0774     heir4();
0775     if (*m_error != ParseSuccess)
0776         return;
0777     while (1) {
0778         if (m_eval.length() <= m_evalPos)
0779             return;
0780 
0781         c = m_eval[m_evalPos];
0782         switch (c.unicode()) {
0783         default:
0784             return;
0785         case '*':
0786         case '/':
0787             ++m_evalPos;
0788             addToken(PUSH);
0789             heir4();
0790             if (*m_error != ParseSuccess)
0791                 return;
0792         }
0793         switch (c.unicode()) {
0794         case '*':
0795             addToken(MULT);
0796             break;
0797         case '/':
0798             addToken(DIV);
0799             break;
0800         }
0801     }
0802 }
0803 
0804 void Parser::heir4()
0805 {
0806     if (match(QStringLiteral("-"))) {
0807         heir4();
0808         if (*m_error != ParseSuccess)
0809             return;
0810         addToken(NEG);
0811     } else if (match(QStringLiteral("+"))) {
0812         heir4();
0813     } else {
0814         heir5();
0815     }
0816 }
0817 
0818 void Parser::heir5()
0819 {
0820     primary();
0821     if (*m_error != ParseSuccess)
0822         return;
0823 
0824     while (true) {
0825         if (match(QStringLiteral("^"))) {
0826             addToken(PUSH);
0827             heir4();
0828             if (*m_error != ParseSuccess)
0829                 return;
0830             addToken(POW);
0831         } else if (match(QStringLiteral("!")))
0832             addToken(FACT);
0833         else
0834             return;
0835     }
0836 }
0837 
0838 void Parser::primary()
0839 {
0840     // Notes:
0841     // - tryUserFunction has to go after tryVariable since differential
0842     //   equations treat the function name as a variable
0843     // - tryConstant has to go before tryUserFunction. This solves a problem,
0844     //   when a function and a constant share the same name
0845 
0846     tryFunction() || tryPredefinedFunction() || tryVariable() || tryConstant() || tryUserFunction() || tryNumber();
0847 }
0848 
0849 bool Parser::tryFunction()
0850 {
0851     if (!match(QStringLiteral("(")) && !match(QStringLiteral(",")))
0852         return false;
0853 
0854     heir0();
0855     if (!match(QStringLiteral(")")) && !match(QStringLiteral(",")))
0856         *m_error = MissingBracket;
0857     return true;
0858 }
0859 
0860 bool Parser::tryPredefinedFunction()
0861 {
0862     for (int i = 0; i < ScalarCount; ++i) {
0863         if (match(scalarFunctions[i].name1) || match(scalarFunctions[i].name2)) {
0864             primary();
0865             addToken(FKT_1);
0866             addfptr(scalarFunctions[i].mfadr);
0867             return true;
0868         }
0869     }
0870     for (int i = 0; i < VectorCount; ++i) {
0871         if (match(vectorFunctions[i].name)) {
0872             int argCount = readFunctionArguments();
0873 
0874             addToken(FKT_N);
0875             addfptr(vectorFunctions[i].mfadr, argCount);
0876             return true;
0877         }
0878     }
0879 
0880     return false;
0881 }
0882 
0883 bool Parser::tryVariable()
0884 {
0885     const QStringList variables = m_currentEquation->variables();
0886 
0887     // Sort the parameters by size, so that when identifying parameters, want to
0888     // match e.g. "ab" before "a"
0889     typedef QMultiMap<int, QString> ISMap;
0890     ISMap sorted;
0891     for (const QString &var : variables)
0892         sorted.insert(-var.length(), var);
0893 
0894     for (const QString &var : qAsConst(sorted)) {
0895         if (match(var)) {
0896             addToken(VAR);
0897             adduint(variables.indexOf(var));
0898             return true;
0899         }
0900     }
0901 
0902     return false;
0903 }
0904 
0905 bool Parser::tryUserFunction()
0906 {
0907     for (Function *it : qAsConst(m_ufkt)) {
0908         for (int i = 0; i < it->eq.size(); ++i) {
0909             if (!match(it->eq[i]->name()))
0910                 continue;
0911 
0912             if (it->eq[i] == m_currentEquation || (m_currentEquation && it->dependsOn(m_currentEquation->parent()))) {
0913                 *m_error = RecursiveFunctionCall;
0914                 return true;
0915             }
0916 
0917             int argCount = readFunctionArguments();
0918             if (argCount != it->eq[i]->variables().size()) {
0919                 *m_error = IncorrectArgumentCount;
0920                 return true;
0921             }
0922 
0923             addToken(UFKT);
0924             addfptr(it->id(), i, argCount);
0925             if (m_currentEquation->parent())
0926                 m_currentEquation->parent()->addFunctionDependency(it);
0927 
0928             return true;
0929         }
0930     }
0931 
0932     return false;
0933 }
0934 
0935 bool Parser::tryConstant()
0936 {
0937 #define CHECK_CONSTANT(a, b)                                                                                                                                   \
0938     if (match(a)) {                                                                                                                                            \
0939         addConstant(b);                                                                                                                                        \
0940         return true;                                                                                                                                           \
0941     }
0942 
0943     ConstantList constants = m_constants->list(Constant::All);
0944 
0945     QMap<LengthOrderedString, Constant> orderedConstants;
0946     for (ConstantList::iterator i = constants.begin(); i != constants.end(); ++i)
0947         orderedConstants[i.key()] = i.value();
0948 
0949     for (QMap<LengthOrderedString, Constant>::iterator i = orderedConstants.begin(); i != orderedConstants.end(); ++i)
0950         CHECK_CONSTANT(i.key(), i.value().value.value());
0951 
0952     // Or a predefined constant?
0953     CHECK_CONSTANT("pi", M_PI);
0954     CHECK_CONSTANT(PiSymbol, M_PI);
0955     CHECK_CONSTANT("e", M_E);
0956     CHECK_CONSTANT(InfinitySymbol, std::numeric_limits<double>::infinity());
0957 
0958     return false;
0959 }
0960 
0961 bool Parser::tryNumber()
0962 {
0963     QByteArray remaining = evalRemaining().toLatin1();
0964     char *lptr = remaining.data();
0965     char *p = nullptr;
0966     // we converted all to "C" format in fixExpression
0967     char *oldLocale = setlocale(LC_NUMERIC, "C");
0968     double const w = strtod(lptr, &p);
0969     setlocale(LC_NUMERIC, oldLocale);
0970     if (lptr != p) {
0971         m_evalPos += p - lptr;
0972         addConstant(w);
0973         return true;
0974     }
0975 
0976     return false;
0977 }
0978 
0979 int Parser::readFunctionArguments()
0980 {
0981     if (!evalRemaining().startsWith('('))
0982         return 0;
0983 
0984     int argCount = 0;
0985     bool argLeft = true;
0986     do {
0987         argCount++;
0988         primary();
0989 
0990         argLeft = m_eval.at(m_evalPos - 1) == ',';
0991         if (argLeft) {
0992             addToken(PUSH);
0993             m_evalPos--;
0994         }
0995     } while (*m_error == ParseSuccess && argLeft && !evalRemaining().isEmpty());
0996 
0997     return argCount;
0998 }
0999 
1000 void Parser::growEqMem(int growth)
1001 {
1002     int pos = mptr - mem->data();
1003     mem->resize(mem->size() + growth);
1004     mptr = mem->data() + pos;
1005 }
1006 
1007 void Parser::addToken(Token token)
1008 {
1009     growEqMem(sizeof(Token));
1010     *mptr++ = token;
1011 }
1012 
1013 void Parser::addConstant(double x)
1014 {
1015     addToken(KONST);
1016 
1017     growEqMem(sizeof(double));
1018     double *pd = (double *)mptr;
1019 
1020     *pd++ = x;
1021     mptr = (char *)pd;
1022 }
1023 
1024 void Parser::adduint(uint x)
1025 {
1026     growEqMem(sizeof(uint));
1027     uint *p = (uint *)mptr;
1028     *p++ = x;
1029     mptr = (char *)p;
1030 }
1031 
1032 void Parser::addfptr(double (*fadr)(double))
1033 {
1034     typedef double (**sfPtr)(double);
1035 
1036     growEqMem(sizeof(sfPtr));
1037     //  double (**pf)(double)=(double(**)(double))mptr;
1038 
1039     sfPtr pf = (sfPtr)mptr;
1040     *pf++ = fadr;
1041     mptr = (char *)pf;
1042 }
1043 
1044 void Parser::addfptr(double (*fadr)(const Vector &), int argCount)
1045 {
1046     typedef double (**vfPtr)(const Vector &);
1047 
1048     growEqMem(sizeof(uint));
1049     uint *p = (uint *)mptr;
1050     *p++ = argCount;
1051     mptr = (char *)p;
1052 
1053     growEqMem(sizeof(vfPtr));
1054     vfPtr pf = (vfPtr)mptr;
1055     *pf++ = fadr;
1056     mptr = (char *)pf;
1057 }
1058 
1059 void Parser::addfptr(uint id, uint eq_id, uint args)
1060 {
1061     growEqMem(3 * sizeof(uint));
1062 
1063     uint *p = (uint *)mptr;
1064     *p++ = id;
1065     *p++ = eq_id;
1066     *p++ = args;
1067     mptr = (char *)p;
1068 }
1069 
1070 int Parser::fnameToID(const QString &name)
1071 {
1072     for (Function *it : qAsConst(m_ufkt)) {
1073         for (Equation *eq : qAsConst(it->eq)) {
1074             if (eq->looksLikeFunction() && (name == eq->name()))
1075                 return it->id();
1076         }
1077     }
1078     return -1; // Name not found
1079 }
1080 
1081 // static
1082 QString Parser::errorString(Error error)
1083 {
1084     switch (error) {
1085     case ParseSuccess:
1086         return QString();
1087 
1088     case SyntaxError:
1089         return i18n("Syntax error");
1090 
1091     case MissingBracket:
1092         return i18n("Missing parenthesis");
1093 
1094     case StackOverflow:
1095         return i18n("Stack overflow");
1096 
1097     case FunctionNameReused:
1098         return i18n("Name of function is not free");
1099 
1100     case RecursiveFunctionCall:
1101         return i18n("recursive function not allowed");
1102 
1103     case EmptyFunction:
1104         return i18n("Empty function");
1105 
1106     case NoSuchFunction:
1107         return i18n("Function could not be found");
1108 
1109     case ZeroOrder:
1110         return i18n("The differential equation must be at least first-order");
1111 
1112     case TooManyPM:
1113         return i18n("Too many plus-minus symbols");
1114 
1115     case InvalidPM:
1116         return i18n("Invalid plus-minus symbol (expression must be constant)");
1117 
1118     case TooManyArguments:
1119         return i18n("The function has too many arguments");
1120 
1121     case IncorrectArgumentCount:
1122         return i18n("The function does not have the correct number of arguments");
1123     }
1124 
1125     return QString();
1126 }
1127 
1128 void Parser::displayErrorDialog(Error error)
1129 {
1130     QString message(errorString(error));
1131     if (!message.isEmpty())
1132         KMessageBox::error(nullptr, message, QStringLiteral("KmPlot"));
1133 }
1134 
1135 QString Parser::evalRemaining()
1136 {
1137     /// note changing this code may need to change code in match() as well; similar
1138     int newLength = qMax(0, m_eval.length() - m_evalPos);
1139     if (newLength != m_evalRemaining.length())
1140         m_evalRemaining = m_eval.right(newLength);
1141     return m_evalRemaining;
1142 }
1143 
1144 bool Parser::match(const QString &lit)
1145 {
1146     if (lit.isEmpty())
1147         return false;
1148 
1149     /// note changing this code may need to change code in evalRemaining() as well; similar
1150     // Do we need to update m_evalRemaining ?
1151     int newLength = qMax(0, m_eval.length() - m_evalPos);
1152     if (newLength != m_evalRemaining.length())
1153         evalRemaining();
1154 
1155     if (!m_evalRemaining.startsWith(lit))
1156         return false;
1157 
1158     m_evalPos += lit.length();
1159     return true;
1160 }
1161 
1162 Function *Parser::functionWithID(int id) const
1163 {
1164     return m_ufkt.contains(id) ? m_ufkt[id] : nullptr;
1165 }
1166 
1167 // static
1168 QString Parser::number(double value)
1169 {
1170     QString str = QString::number(value, 'g', 16);
1171     str.replace('e', QLatin1String("*10^"));
1172     return str;
1173 }
1174 // END class Parser
1175 
1176 // BEGIN predefined mathematical functions
1177 double sqr(double x)
1178 {
1179     return x * x;
1180 }
1181 double lsec(double x)
1182 {
1183     return (1 / cos(x * Parser::radiansPerAngleUnit()));
1184 }
1185 double lcosec(double x)
1186 {
1187     return (1 / sin(x * Parser::radiansPerAngleUnit()));
1188 }
1189 double lcot(double x)
1190 {
1191     return (1 / tan(x * Parser::radiansPerAngleUnit()));
1192 }
1193 double larcsec(double x)
1194 {
1195     return acos(1 / x) / Parser::radiansPerAngleUnit();
1196 }
1197 double larccosec(double x)
1198 {
1199     return asin(1 / x) / Parser::radiansPerAngleUnit();
1200 }
1201 double larccot(double x)
1202 {
1203     return (M_PI / 2 - atan(x)) / Parser::radiansPerAngleUnit();
1204 }
1205 double sech(double x)
1206 {
1207     return (1 / cosh(x));
1208 }
1209 double cosech(double x)
1210 {
1211     return (1 / sinh(x));
1212 }
1213 double coth(double x)
1214 {
1215     return (1 / tanh(x));
1216 }
1217 double arsech(double x)
1218 {
1219     return acosh(1 / x);
1220 }
1221 double arcosech(double x)
1222 {
1223     return asinh(1 / x);
1224 }
1225 double arcoth(double x)
1226 {
1227     return atanh(1 / x);
1228 }
1229 double lcos(double x)
1230 {
1231     return cos(x * Parser::radiansPerAngleUnit());
1232 }
1233 double lsin(double x)
1234 {
1235     return sin(x * Parser::radiansPerAngleUnit());
1236 }
1237 double ltan(double x)
1238 {
1239     return tan(x * Parser::radiansPerAngleUnit());
1240 }
1241 double larccos(double x)
1242 {
1243     return acos(x) / Parser::radiansPerAngleUnit();
1244 }
1245 double larcsin(double x)
1246 {
1247     return asin(x) / Parser::radiansPerAngleUnit();
1248 }
1249 double larctan(double x)
1250 {
1251     return atan(x) / Parser::radiansPerAngleUnit();
1252 }
1253 double factorial(double x)
1254 {
1255     return tgamma(x + 1);
1256 }
1257 double legendre0(double)
1258 {
1259     return 1.0;
1260 }
1261 double legendre1(double x)
1262 {
1263     return x;
1264 }
1265 double legendre2(double x)
1266 {
1267     return (3 * x * x - 1) / 2;
1268 }
1269 double legendre3(double x)
1270 {
1271     return (5 * x * x * x - 3 * x) / 2;
1272 }
1273 double legendre4(double x)
1274 {
1275     return (35 * x * x * x * x - 30 * x * x + 3) / 8;
1276 }
1277 double legendre5(double x)
1278 {
1279     return (63 * x * x * x * x * x - 70 * x * x * x + 15 * x) / 8;
1280 }
1281 double legendre6(double x)
1282 {
1283     return (231 * x * x * x * x * x * x - 315 * x * x * x * x + 105 * x * x - 5) / 16;
1284 }
1285 
1286 double sign(double x)
1287 {
1288     if (x < 0.)
1289         return -1.;
1290     else if (x > 0.)
1291         return 1.;
1292     return 0.;
1293 }
1294 
1295 double heaviside(double x)
1296 {
1297     if (x < 0.0)
1298         return 0.0;
1299     else if (x > 0.0)
1300         return 1.0;
1301     else
1302         return 0.5;
1303 }
1304 
1305 double min(const Vector &args)
1306 {
1307     double best = HUGE_VAL;
1308     for (int i = 0; i < args.size(); ++i) {
1309         if (args[i] < best)
1310             best = args[i];
1311     }
1312 
1313     return best;
1314 }
1315 
1316 double max(const Vector &args)
1317 {
1318     double best = -HUGE_VAL;
1319     for (int i = 0; i < args.size(); ++i) {
1320         if (args[i] > best)
1321             best = args[i];
1322     }
1323 
1324     return best;
1325 }
1326 
1327 double mod(const Vector &args)
1328 {
1329     double squared = 0;
1330     for (int i = 0; i < args.size(); ++i)
1331         squared += args[i] * args[i];
1332 
1333     return std::sqrt(squared);
1334 }
1335 
1336 double lerf(double x)
1337 {
1338     return erf(x);
1339 }
1340 
1341 double lerfc(double x)
1342 {
1343     return erfc(x);
1344 }
1345 
1346 // END predefined mathematical functions
1347 
1348 // BEGIN class ExpressionSanitizer
1349 enum StringType { ConstantString, NumberString, UnknownLetter, FunctionString, Other };
1350 
1351 ExpressionSanitizer::ExpressionSanitizer(Parser *parser)
1352     : m_parser(parser)
1353 {
1354     m_str = nullptr;
1355     m_decimalSymbol = QLocale().decimalPoint();
1356 }
1357 
1358 void ExpressionSanitizer::fixExpression(QString *str)
1359 {
1360     m_str = str;
1361 
1362     m_map.resize(m_str->length());
1363     for (int i = 0; i < m_str->length(); ++i)
1364         m_map[i] = i;
1365 
1366     // greater-equal, less-equal with proper symbols
1367     // note that this must go before the next code for implicit equations, since
1368     // it removes the spurious equals signs
1369     replace(QStringLiteral(">="), GeSymbol);
1370     replace(QStringLiteral("<="), LeSymbol);
1371 
1372     // hack for implicit functions: change e.g. "y = x + 2" to "y - (x+2)" so
1373     // that they can be evaluated via equality with zero.
1374     if (str->count('=') > 1) {
1375         int equalsPos = str->lastIndexOf('=');
1376         replace(equalsPos, 1, QStringLiteral("-("));
1377         append(')');
1378     }
1379 
1380     stripWhiteSpace();
1381 
1382     // make sure all minus-like signs (including the actual unicode minus sign)
1383     // are represented by a dash (unicode 0x002d)
1384     QChar dashes[6] = {QChar(0x2012), QChar(0x2013), QChar(0x2014), QChar(0x2015), QChar(0x2053), QChar(0x2212)};
1385     for (unsigned i = 0; i < 6; ++i)
1386         replace(dashes[i], '-');
1387 
1388     // replace the proper unicode divide sign by the forward-slash
1389     replace(QChar(0xf7), '/');
1390     replace(QChar(0x2215), '/');
1391 
1392     // replace the unicode middle-dot for multiplication by the star symbol
1393     replace(QChar(0xd7), '*');
1394     replace(QChar(0x2219), '*');
1395 
1396     // minus-plus symbol to plus-minus symbol
1397     replace(QChar(0x2213), PmSymbol);
1398 
1399     // various power symbols
1400     replace(QChar(0x00B2), QStringLiteral("^2"));
1401     replace(QChar(0x00B3), QStringLiteral("^3"));
1402     replace(QChar(0x2070), QStringLiteral("^0"));
1403     replace(QChar(0x2074), QStringLiteral("^4"));
1404     replace(QChar(0x2075), QStringLiteral("^5"));
1405     replace(QChar(0x2076), QStringLiteral("^6"));
1406     replace(QChar(0x2077), QStringLiteral("^7"));
1407     replace(QChar(0x2078), QStringLiteral("^8"));
1408     replace(QChar(0x2079), QStringLiteral("^9"));
1409 
1410     // fractions
1411     replace(QChar(0x00BC), QStringLiteral("(1/4)"));
1412     replace(QChar(0x00BD), QStringLiteral("(1/2)"));
1413     replace(QChar(0x00BE), QStringLiteral("(3/4)"));
1414     replace(QChar(0x2153), QStringLiteral("(1/3)"));
1415     replace(QChar(0x2154), QStringLiteral("(2/3)"));
1416     replace(QChar(0x2155), QStringLiteral("(1/5)"));
1417     replace(QChar(0x2156), QStringLiteral("(2/5)"));
1418     replace(QChar(0x2157), QStringLiteral("(3/5)"));
1419     replace(QChar(0x2158), QStringLiteral("(4/5)"));
1420     replace(QChar(0x2159), QStringLiteral("(1/6)"));
1421     replace(QChar(0x215a), QStringLiteral("(5/6)"));
1422     replace(QChar(0x215b), QStringLiteral("(1/8)"));
1423     replace(QChar(0x215c), QStringLiteral("(3/8)"));
1424     replace(QChar(0x215d), QStringLiteral("(5/8)"));
1425     replace(QChar(0x215e), QStringLiteral("(7/8)"));
1426 
1427     // BEGIN replace e.g. |x+2| with abs(x+2)
1428     str->replace(AbsSymbol, '|');
1429 
1430     int maxDepth = str->count('(');
1431     QVector<bool> absAt(maxDepth + 1);
1432     for (int i = 0; i < maxDepth + 1; ++i)
1433         absAt[i] = false;
1434 
1435     int depth = 0;
1436 
1437     for (int i = 0; i < str->length(); ++i) {
1438         if (str->at(i) == '|') {
1439             if (absAt[depth]) {
1440                 // Closing it
1441                 replace(i, 1, QStringLiteral(")"));
1442                 absAt[depth] = false;
1443             } else {
1444                 // Opening it
1445                 replace(i, 1, QStringLiteral("abs("));
1446                 i += 3;
1447                 absAt[depth] = true;
1448             }
1449         } else if (str->at(i) == '(')
1450             depth++;
1451         else if (str->at(i) == ')') {
1452             depth--;
1453             if (depth < 0)
1454                 depth = 0;
1455         }
1456     }
1457     // END replace e.g. |x+2| with abs(x+2)
1458 
1459     if (m_decimalSymbol == QLatin1String(","))
1460         str->replace(QRegularExpression(QStringLiteral("(\\d),(\\d)")),
1461                      "\\1.\\2"); // if we use comma as a decimal separator it is reasonable to separate numbers in function arguments by comma with space
1462     else
1463         str->replace(m_decimalSymbol, QLatin1String(".")); // replace the locale decimal symbol with a '.' otherwise
1464 
1465     // BEGIN build up strings
1466     QMap<LengthOrderedString, StringType> strings;
1467 
1468     const QStringList predefinedFunctions = XParser::self()->predefinedFunctions(true);
1469     for (const QString &f : predefinedFunctions)
1470         strings[f] = FunctionString;
1471 
1472     for (Function *it : qAsConst(m_parser->m_ufkt)) {
1473         for (Equation *eq : qAsConst(it->eq))
1474             strings[eq->name()] = FunctionString;
1475     }
1476 
1477     const QStringList constantNames = m_parser->constants()->names();
1478     for (const QString &name : constantNames)
1479         strings[name] = ConstantString;
1480     strings[QStringLiteral("pi")] = ConstantString;
1481     // END build up strings
1482 
1483     strings.remove(QString());
1484 
1485     StringType prevType = Other;
1486 
1487     for (int i = 1; i < str->length();) {
1488         int incLength = 1;
1489         StringType currentType = Other;
1490         QChar ch = str->at(i);
1491 
1492         QString remaining = str->right(str->length() - i);
1493 
1494         QMap<LengthOrderedString, StringType>::const_iterator end = strings.constEnd();
1495         for (QMap<LengthOrderedString, StringType>::const_iterator it = strings.constBegin(); it != end; ++it) {
1496             if (!remaining.startsWith(it.key()))
1497                 continue;
1498 
1499             currentType = it.value();
1500             incLength = it.key().length();
1501             break;
1502         }
1503 
1504         if (currentType == Other) {
1505             if (ch.isNumber() || (ch == '.'))
1506                 currentType = NumberString;
1507         }
1508 
1509         if (currentType == Other) {
1510             if (ch.isLetter())
1511                 currentType = UnknownLetter; // probably a variable
1512         }
1513 
1514         if (((currentType == FunctionString) || (ch == '(') || (currentType == UnknownLetter) || (currentType == ConstantString))
1515             && ((prevType == NumberString) || (prevType == ConstantString) || (prevType == UnknownLetter) || (str->at(i - 1) == ')'))) {
1516             insert(i, '*');
1517             incLength++;
1518         }
1519 
1520         prevType = currentType;
1521         i += incLength;
1522     }
1523 }
1524 
1525 void ExpressionSanitizer::stripWhiteSpace()
1526 {
1527     int i = 0;
1528 
1529     while (i < m_str->length()) {
1530         if (m_str->at(i).isSpace()) {
1531             m_str->remove(i, 1);
1532             m_map.remove(i, 1);
1533         } else
1534             i++;
1535     }
1536 }
1537 
1538 void ExpressionSanitizer::remove(const QString &str)
1539 {
1540     int at = 0;
1541 
1542     do {
1543         at = m_str->indexOf(str, at);
1544         if (at != -1) {
1545             m_map.remove(at, str.length());
1546             m_str->remove(at, str.length());
1547         }
1548     } while (at != -1);
1549 }
1550 
1551 void ExpressionSanitizer::remove(const QChar &str)
1552 {
1553     remove(QString(str));
1554 }
1555 
1556 void ExpressionSanitizer::replace(QChar before, QChar after)
1557 {
1558     m_str->replace(before, after);
1559 }
1560 
1561 void ExpressionSanitizer::replace(QChar before, const QString &after)
1562 {
1563     if (after.isEmpty()) {
1564         remove(before);
1565         return;
1566     }
1567 
1568     int at = 0;
1569 
1570     do {
1571         at = m_str->indexOf(before, at);
1572         if (at != -1) {
1573             int to = m_map[at];
1574             for (int i = at + 1; i < at + after.length(); ++i)
1575                 m_map.insert(i, to);
1576 
1577             m_str->replace(at, 1, after);
1578             at += after.length() - 1;
1579         }
1580     } while (at != -1);
1581 }
1582 
1583 void ExpressionSanitizer::replace(int pos, int len, const QString &after)
1584 {
1585     int before = m_map[pos];
1586     m_map.remove(pos, len);
1587     m_map.insert(pos, after.length(), before);
1588     m_str->replace(pos, len, after);
1589 }
1590 
1591 void ExpressionSanitizer::replace(const QString &before, const QString &after)
1592 {
1593     int index;
1594     while ((index = m_str->indexOf(before)) > -1)
1595         replace(index, before.length(), after);
1596 }
1597 
1598 void ExpressionSanitizer::insert(int i, QChar ch)
1599 {
1600     m_map.insert(i, m_map[i]);
1601     m_str->insert(i, ch);
1602 }
1603 
1604 void ExpressionSanitizer::append(QChar str)
1605 {
1606     m_map.insert(m_map.size(), m_map[m_map.size() - 1]);
1607     m_str->append(str);
1608 }
1609 
1610 int ExpressionSanitizer::realPos(int evalPos)
1611 {
1612     if (m_map.isEmpty() || (evalPos < 0))
1613         return -1;
1614 
1615     if (evalPos >= m_map.size()) {
1616         //      qWarning() << "evalPos="<<evalPos<<" is out of range.\n";
1617         //      return m_map[ m_map.size() - 1 ];
1618         return -1;
1619     }
1620 
1621     return m_map[evalPos];
1622 }
1623 
1624 void ExpressionSanitizer::displayMap()
1625 {
1626     QString out('\n');
1627 
1628     for (int i = 0; i < m_map.size(); ++i)
1629         out += QStringLiteral("%1").arg(m_map[i], 3);
1630     out += '\n';
1631 
1632     for (int i = 0; i < m_str->length(); ++i)
1633         out += "  " + (*m_str)[i];
1634     out += '\n';
1635 
1636     qDebug() << out;
1637 }
1638 // END class ExpressionSanitizer
1639 
1640 #include "moc_parser.cpp"