File indexing completed on 2024-04-21 03:42:10

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 /** @file parser.h
0015  * \brief Contains the parser core class Parser. */
0016 
0017 #ifndef parser_included
0018 #define parser_included
0019 
0020 #include <QMap>
0021 #include <QObject>
0022 #include <QVector>
0023 
0024 #include "constants.h"
0025 #include "function.h"
0026 #include "vector.h"
0027 
0028 // Various mathematical symbols
0029 #define PiSymbol QChar(0x3c0)
0030 #define InfinitySymbol QChar(0x221e)
0031 #define PmSymbol QChar(0xb1)
0032 #define AbsSymbol QChar(0x2223)
0033 #define SqrtSymbol QChar(0x221a)
0034 #define MinusSymbol QChar(0x2212)
0035 #define SubscriptZeroSymbol QChar(0x2080)
0036 #define GeSymbol QChar(0x2265)
0037 #define LeSymbol QChar(0x2264)
0038 
0039 class Parser;
0040 
0041 // Voreinstellungen bei Verwendung des Standardkonstruktors :
0042 
0043 #define STACKSIZE 1000 ///< stack depth
0044 
0045 //@{
0046 /** Token type. */
0047 enum Token {
0048     KONST, //  0 - double value follows
0049     VAR, //  1 - get a parameter (e.g. x or k)
0050     PUSH, //  2 - push value to stack
0051     PLUS, //  3 - add
0052     MINUS, //  4 - subtract
0053     PM, //  5 - plus-minus; add or subtract depending on the current signature
0054     MULT, //  6 - multiply
0055     DIV, //  7 - divide
0056     POW, //  8 - exponentiate
0057     NEG, //  9 - negate
0058     FKT_1, // 10 - address to function with 1 argument follows
0059     FKT_N, // 11 - address to functions with an indefinite number of arguments follows
0060     UFKT, // 12 - address to user defined function follows
0061     SQRT, // 13 - take square root
0062     FACT, // 14 - take factorial
0063     GT, // 15 - greater than
0064     GE, // 16 - greater than or equal
0065     LT, // 17 - less than
0066     LE, // 18 - less than or equal
0067     ENDE, // 19 - end of function
0068     ERROR // 20 - error in function
0069 };
0070 
0071 const int legendreCount = 7; // number of legendre polynomials we allow for
0072 const int ScalarCount = 40 + legendreCount; // number of mathematical scalar functions
0073 const int VectorCount = 3; // number of vector functions
0074 //@}
0075 
0076 //@{
0077 /** Predefined mathematical function with one variable. */
0078 double sign(double x);
0079 double heaviside(double x);
0080 double sqr(double x);
0081 
0082 double lsec(double x);
0083 double lcosec(double x);
0084 double lcot(double x);
0085 double larcsec(double x);
0086 double larccosec(double x);
0087 double larccot(double x);
0088 
0089 double sech(double x);
0090 double cosech(double x);
0091 double coth(double x);
0092 double arsech(double x);
0093 double arcosech(double x);
0094 double arcoth(double x);
0095 
0096 double lcos(double x);
0097 double lsin(double x);
0098 double ltan(double x);
0099 
0100 double larccos(double x);
0101 double larcsin(double x);
0102 double larctan(double x);
0103 
0104 double legendre0(double x);
0105 double legendre1(double x);
0106 double legendre2(double x);
0107 double legendre3(double x);
0108 double legendre4(double x);
0109 double legendre5(double x);
0110 double legendre6(double x);
0111 
0112 double factorial(double x);
0113 double lerf(double x);
0114 double lerfc(double x);
0115 
0116 /** Predefined mathematical functions with an indefinite number of variables. */
0117 double min(const Vector &x);
0118 double max(const Vector &x);
0119 double mod(const Vector &x);
0120 
0121 struct ScalarFunction {
0122     QString name1;
0123     QString name2;
0124     double (*mfadr)(double);
0125 };
0126 
0127 struct VectorFunction {
0128     QString name;
0129     double (*mfadr)(const Vector &);
0130 };
0131 
0132 /**
0133  * Fixes user-entered expressions into a form that can be handled by the
0134  * parser. Also keeps track of how the string was modified, so that if an error
0135  * occurs, then the correct position can be reported to the user.
0136  * \note The convention used here is that the first letter in a string
0137  * is at position zero.
0138  */
0139 class ExpressionSanitizer
0140 {
0141 public:
0142     explicit ExpressionSanitizer(Parser *parent);
0143 
0144     /**
0145      * Lots of changes to make it happy for the parser (e.g. adding extra
0146      * *-characters, remove spaces, replace the locale .-character with '.',
0147      * etc). This function will initialize m_evalMap.
0148      * \param str The string to be fixed.
0149      */
0150     void fixExpression(QString *str);
0151     /**
0152      * \return the position in the input string (as given to fixExpression)
0153      * that corresponds to the outputted string.
0154      */
0155     int realPos(int evalPos);
0156 
0157 protected:
0158     /**
0159      * Maps the position of the string returned by fixExpression to that
0160      * passed to it. This is so that if the parser comes across an error in the
0161      * sanitized expression, this gives the corresponding position in the user
0162      * string.
0163      */
0164     QVector<int> m_map;
0165 
0166     void remove(const QString &str);
0167     void remove(const QChar &str);
0168     void replace(QChar before, QChar after);
0169     void replace(QChar before, const QString &after);
0170     void replace(int pos, int len, const QString &after);
0171     void replace(const QString &before, const QString &after);
0172     void insert(int i, QChar ch);
0173     void append(QChar str);
0174     void stripWhiteSpace();
0175 
0176     /**
0177      * Prints the map and str to stdout; for debugging purposes.
0178      */
0179     void displayMap();
0180 
0181     QString *m_str;
0182 
0183     QString m_decimalSymbol;
0184     Parser *m_parser;
0185 };
0186 
0187 /** @short Parser.
0188  *
0189  * Tokenizes a function equation to be evaluated.
0190  */
0191 class Parser : public QObject
0192 {
0193     Q_OBJECT
0194 public:
0195     enum Error {
0196         ParseSuccess,
0197         SyntaxError,
0198         MissingBracket,
0199         StackOverflow,
0200         FunctionNameReused, ///< function name already used
0201         RecursiveFunctionCall,
0202         EmptyFunction,
0203         NoSuchFunction,
0204         ZeroOrder, ///< zero-order differential
0205         TooManyPM, ///< too many plus-minus symbols
0206         InvalidPM, ///< Not allowed to have a plus-minus symbol, e.g. in a constant expression
0207         TooManyArguments, ///< Too many arguments in a function, e.g. "f(x,a,b,c)"
0208         IncorrectArgumentCount ///< wrong number of arguments being passed to a function
0209     };
0210 
0211     ~Parser();
0212 
0213     /**
0214      * \param includeAliases whether to return function aliases (e.g.
0215      * arsinh for arcsinh).
0216      * \return the list of predefined function names.
0217      */
0218     QStringList predefinedFunctions(bool includeAliases) const;
0219     /**
0220      * \return the list of user defined function names.
0221      */
0222     QStringList userFunctions() const;
0223     /**
0224      * @return A string that is safe to use as a number in a string to be
0225      * parsed. This is needed as e.g. "1.2e-3" is not allowed (e is a
0226      * constant) - so cannot use the QString::number.
0227      */
0228     static QString number(double value);
0229     /**
0230      * Calls the array version of this function, after inserting the value
0231      * of the equation's parameter into x.
0232      */
0233     double fkt(Equation *it, double x);
0234     double fkt(uint id, int eq, double x);
0235     /**
0236      * Returns the result of a calculation. \p x are parameters for the
0237      * function (which are not necessarily all used).
0238      */
0239     double fkt(Equation *it, const Vector &x);
0240     /**
0241      * Evaluates the given expression.
0242      * \param str the given expression.
0243      * \param error if non-null, then will be set to the parser error (or
0244      * ParserSuccess if no errors).
0245      * \param errorPosition will be set to the position of the error (if
0246      * there is one).
0247      */
0248     double eval(const QString &str, Error *error = nullptr, int *errorPosition = nullptr);
0249     /**
0250      * Adds a user defined function with the given equation. The new
0251      * function's ID-number is returned. \p force is used to force use of
0252      * \p str1, \p str2, even if they cannot be parsed.
0253      */
0254     int addFunction(const QString &str1, const QString &str2, Function::Type type, bool force = false);
0255     /**
0256      * Removes the function with the given id.
0257      */
0258     bool removeFunction(uint id);
0259     bool removeFunction(Function *item);
0260     /**
0261      * Removes all functions.
0262      */
0263     void removeAllFunctions();
0264     /**
0265      * Returns the ID-number of the function "name". If the function
0266      * couldn't be found, -1 is returned.
0267      */
0268     int fnameToID(const QString &name);
0269     /**
0270      * \return An error string appropriate for the given error.
0271      */
0272     static QString errorString(Error error);
0273     /**
0274      * Displays an error dialog appropriate to \p error.
0275      */
0276     void displayErrorDialog(Error error);
0277     /**
0278      * \return the number of radians per angle-unit that the user has
0279      * selected (i.e. this will return 1.0 if the user has selected
0280      * radians; and PI/180 if the user has selected degrees).
0281      */
0282     static double radiansPerAngleUnit()
0283     {
0284         return m_radiansPerAngleUnit;
0285     }
0286 
0287     enum AngleMode { Radians = 0, Degrees = 1 };
0288     /**
0289      * Sets the angle mode (in which the calculations are performed).
0290      */
0291     void setAngleMode(AngleMode mode);
0292     /**
0293      * Initializes the function for evaluation. Called after the functions
0294      * fstr is set.
0295      */
0296     void initEquation(Equation *equation, Error *error = nullptr, int *errorPosition = nullptr);
0297 
0298     uint getNewId(); /// Returns the next ID-number
0299     uint countFunctions(); /// Returns how many functions there are
0300 
0301     /// The constants used by the parser
0302     Constants *constants() const
0303     {
0304         return m_constants;
0305     }
0306 
0307     /// @return the function with the given id
0308     Function *functionWithID(int id) const;
0309 
0310     /// Points to the array of user defined functions, index by their IDs.
0311     QMap<int, Function *> m_ufkt;
0312 
0313     /// Reparses all functions, e.g. for when the value of a constant changes
0314     void reparseAllFunctions();
0315 
0316 signals:
0317     /// emitted when a function is deleted
0318     void functionRemoved(int id);
0319     /// emitted when a function is added
0320     void functionAdded(int id);
0321 
0322 private:
0323     /** Mathematical function. */
0324     static ScalarFunction scalarFunctions[ScalarCount];
0325     static VectorFunction vectorFunctions[VectorCount];
0326 
0327     void heir0();
0328     void heir1();
0329     void heir2();
0330     void heir3();
0331     void heir4();
0332     void heir5();
0333     void primary();
0334     bool tryFunction();
0335     bool tryPredefinedFunction();
0336     bool tryUserFunction();
0337     bool tryVariable();
0338     bool tryConstant();
0339     bool tryNumber();
0340     void addToken(Token token);
0341     void addConstant(double);
0342     void adduint(uint);
0343     void addfptr(double (*)(double));
0344     void addfptr(double (*)(const Vector &), int argCount);
0345     /**
0346      * \p id Id of the function
0347      * \p eq_id Which equation of the function to use
0348      * \p args The number of variables being passed to the function
0349      */
0350     void addfptr(uint id, uint eq_id, uint args);
0351     /**
0352      * Attempts to \p string to the current evaluation text. If the text at
0353      * the current evaluation position is matched, then the evaluation
0354      * position is incremented past the length of the string and true is
0355      * returned. Else the evaluation position remains unchanged, and false
0356      * is returned.
0357      */
0358     bool match(const QString &string);
0359     /**
0360      * Continues to read the expression inside a brackets of a vector
0361      * function until get to the end of the argument list.
0362      * \return the number of arguments
0363      */
0364     int readFunctionArguments();
0365 
0366     void growEqMem(int growth);
0367     QByteArray *mem; ///< Pointer to the array of tokens for the current equation being parsed
0368     char *mptr; ///< Pointer to the next position of insertion for the parsed equation data
0369     double *m_stack;
0370     double *stkptr;
0371     QString m_eval;
0372     int m_evalPos;
0373     int m_nextFunctionID;
0374     /// @return the m_eval starting at m_evalPos
0375     QString evalRemaining();
0376     QString m_evalRemaining;
0377     Equation *m_currentEquation; // Pointer to the current function
0378     Equation *m_ownEquation; ///< used for parsing constants, etc, and ensures that m_currentEquation is never null
0379     static double m_radiansPerAngleUnit;
0380     Constants *m_constants;
0381     ExpressionSanitizer m_sanitizer;
0382     int m_pmAt; ///< When parsing an expression, which plus-minus symbol at
0383     Error *m_error;
0384 
0385 private:
0386     friend class XParser;
0387     friend class ExpressionSanitizer;
0388     Parser();
0389 };
0390 
0391 #endif // parser_included