1 /*
2     KmPlot - a math. function plotter for the KDE-Desktop
3 
4     SPDX-FileCopyrightText: 1998, 1999, 2000, 2002 Klaus-Dieter Möller <kd.moeller@t-online.de>
5     SPDX-FileCopyrightText: 2006 David Saxton <david@bluehaze.org>
6 
7     This file is part of the KDE Project.
8     KmPlot is part of the KDE-EDU Project.
9 
10     SPDX-License-Identifier: GPL-2.0-or-later
11 
12 */
13 
14 /** @file parser.h
15  * \brief Contains the parser core class Parser. */
16 
17 #ifndef parser_included
18 #define parser_included
19 
20 #include <QMap>
21 #include <QObject>
22 #include <QVector>
23 
24 #include "constants.h"
25 #include "function.h"
26 #include "vector.h"
27 
28 
29 // Various mathematical symbols
30 #define PiSymbol 				QChar(0x3c0)
31 #define InfinitySymbol			QChar(0x221e)
32 #define PmSymbol				QChar(0xb1)
33 #define AbsSymbol				QChar(0x2223)
34 #define SqrtSymbol				QChar(0x221a)
35 #define MinusSymbol				QChar(0x2212)
36 #define SubscriptZeroSymbol		QChar(0x2080)
37 #define GeSymbol				QChar(0x2265)
38 #define LeSymbol				QChar(0x2264)
39 
40 
41 class Parser;
42 
43 // Voreinstellungen bei Verwendung des Standardkonstruktors :
44 
45 #define	STACKSIZE	1000  	///< stack depth
46 
47 //@{
48 /** Token type. */
49 enum Token
50 {
51 	KONST,		//  0 - double value follows
52 	VAR,		//  1 - get a parameter (e.g. x or k)
53 	PUSH,		//  2 - push value to stack
54 	PLUS,		//  3 - add
55 	MINUS,		//  4 - subtract
56 	PM,			//  5 - plus-minus; add or subtract depending on the current signature
57 	MULT,		//  6 - multiply
58 	DIV,		//  7 - divide
59 	POW,		//  8 - exponentiate
60 	NEG,		//  9 - negate
61 	FKT_1,		// 10 - address to function with 1 argument follows
62 	FKT_N,		// 11 - address to functions with an indefinite number of arguments follows
63 	UFKT,		// 12 - address to user defined function follows
64 	SQRT,		// 13 - take square root
65 	FACT,		// 14 - take factorial
66 	GT,		// 15 - greater than
67 	GE,		// 16 - greater than or equal
68 	LT,		// 17 - less than
69 	LE,		// 18 - less than or equal
70 	ENDE,		// 19 - end of function
71 	ERROR		// 20 - error in function
72 };
73 
74 
75 const int legendreCount = 7; // number of legendre polynomials we allow for
76 const int ScalarCount = 40+legendreCount;	// number of mathematical scalar functions
77 const int VectorCount = 3; // number of vector functions
78 //@}
79 
80 //@{
81 /** Predefined mathematical function with one variable. */
82 double sign(double x);
83 double heaviside(double x);
84 double sqr(double x);
85 
86 double lsec(double x);
87 double lcosec(double x);
88 double lcot(double x);
89 double larcsec(double x);
90 double larccosec(double x);
91 double larccot(double x);
92 
93 double sech(double x);
94 double cosech(double x);
95 double coth(double x);
96 double arsech(double x);
97 double arcosech(double x);
98 double arcoth(double x);
99 
100 double lcos(double x);
101 double lsin(double x);
102 double ltan(double x);
103 
104 double larccos(double x);
105 double larcsin(double x);
106 double larctan(double x);
107 
108 double legendre0(double x);
109 double legendre1(double x);
110 double legendre2(double x);
111 double legendre3(double x);
112 double legendre4(double x);
113 double legendre5(double x);
114 double legendre6(double x);
115 
116 double factorial(double x);
117 double lerf(double x);
118 double lerfc(double x);
119 
120 /** Predefined mathematical functions with an indefinite number of variables. */
121 double min( const Vector & x );
122 double max( const Vector & x );
123 double mod( const Vector & x );
124 
125 
126 struct ScalarFunction
127 {
128 	QString name1;
129 	QString name2;
130 	double (*mfadr)(double);
131 };
132 
133 
134 struct VectorFunction
135 {
136 	QString name;
137 	double (*mfadr)(const Vector &);
138 };
139 
140 
141 /**
142  * Fixes user-entered expressions into a form that can be handled by the
143  * parser. Also keeps track of how the string was modified, so that if an error
144  * occurs, then the correct position can be reported to the user.
145  * \note The convention used here is that the first letter in a string
146  * is at position zero.
147  */
148 class ExpressionSanitizer
149 {
150 	public:
151 		explicit ExpressionSanitizer( Parser * parent );
152 
153 		/**
154 		 * Lots of changes to make it happy for the parser (e.g. adding extra
155 		 * *-characters, remove spaces, replace the locale .-character with '.',
156 		 * etc). This function will initialize m_evalMap.
157 		 * \param str The string to be fixed.
158 		 */
159 		void fixExpression( QString * str );
160 		/**
161 		 * \return the position in the input string (as given to fixExpression)
162 		 * that corresponds to the outputted string.
163 		 */
164 		int realPos( int evalPos );
165 
166 	protected:
167 		/**
168 		 * Maps the position of the string returned by fixExpression to that
169 		 * passed to it. This is so that if the parser comes across an error in the
170 		 * sanitized expression, this gives the corresponding position in the user
171 		 * string.
172 		 */
173 		QVector<int> m_map;
174 
175 		void remove( const QString & str );
176 		void remove( const QChar & str );
177 		void replace( QChar before, QChar after );
178 		void replace( QChar before, const QString & after );
179 		void replace( int pos, int len, const QString & after );
180 		void replace( const QString & before, const QString & after );
181 		void insert( int i, QChar ch );
182 		void append( QChar str );
183 		void stripWhiteSpace();
184 
185 		/**
186 		 * Prints the map and str to stdout; for debugging purposes.
187 		 */
188 		void displayMap();
189 
190 		QString * m_str;
191 
192 		QString m_decimalSymbol;
193 		Parser * m_parser;
194 };
195 
196 
197 /** @short Parser.
198  *
199  * Tokenizes a function equation to be evaluated.
200  */
201 class Parser : public QObject
202 {
203 	Q_OBJECT
204 	public:
205 
206 		enum Error
207 		{
208 			ParseSuccess,
209 			SyntaxError,
210 			MissingBracket,
211 			StackOverflow,
212 			FunctionNameReused , ///< function name already used
213 			RecursiveFunctionCall,
214 			EmptyFunction,
215 			NoSuchFunction,
216 			ZeroOrder, ///< zero-order differential
217 			TooManyPM, ///< too many plus-minus symbols
218 			InvalidPM, ///< Not allowed to have a plus-minus symbol, e.g. in a constant expression
219 			TooManyArguments, ///< Too many arguments in a function, e.g. "f(x,a,b,c)"
220 			IncorrectArgumentCount ///< wrong number of arguments being passed to a function
221 		};
222 
223 		~Parser();
224 
225 		/**
226 		 * \param includeAliases whether to return function aliases (e.g.
227 		 * arsinh for arcsinh).
228 		 * \return the list of predefined function names.
229 		 */
230 		QStringList predefinedFunctions( bool includeAliases ) const;
231 		/**
232 		 * \return the list of user defined function names.
233 		 */
234 		QStringList userFunctions() const;
235 		/**
236 		 * @return A string that is safe to use as a number in a string to be
237 		 * parsed. This is needed as e.g. "1.2e-3" is not allowed (e is a
238 		 * constant) - so cannot use the QString::number.
239 		 */
240 		static QString number( double value );
241 		/**
242 		 * Calls the array version of this function, after inserting the value
243 		 * of the equation's parameter into x.
244 		 */
245 		double fkt( Equation * it, double x );
246 		double fkt( uint id, int eq, double x );
247 		/**
248 		 * Returns the result of a calculation. \p x are parameters for the
249 		 * function (which are not necessarily all used).
250 		 */
251 		double fkt( Equation * it, const Vector & x );
252 		/**
253 		 * Evaluates the given expression.
254 		 * \param str the given expression.
255 		 * \param error if non-null, then will be set to the parser error (or
256 		 * ParserSuccess if no errors).
257 		 * \param errorPosition will be set to the position of the error (if
258 		 * there is one).
259 		 */
260 		double eval( const QString & str, Error * error = 0, int * errorPosition = 0 );
261 		/**
262 		 * Adds a user defined function with the given equation. The new
263 		 * function's ID-number is returned. \p force is used to force use of
264 		 * \p str1, \p str2, even if they cannot be parsed.
265 		 */
266 		int addFunction( const QString & str1, const QString & str2, Function::Type type, bool force = false );
267 		/**
268 		 * Removes the function with the given id.
269 		 */
270 		bool removeFunction( uint id );
271 		bool removeFunction( Function *item);
272 		/**
273 		 * Removes all functions.
274 		 */
275 		void removeAllFunctions();
276 		/**
277 		 * Returns the ID-number of the function "name". If the function
278 		 * couldn't be found, -1 is returned.
279 		 */
280 		int fnameToID(const QString &name);
281 		/**
282 		 * \return An error string appropriate for the given error.
283 		 */
284 		static QString errorString( Error error );
285 		/**
286 		 * Displays an error dialog appropriate to \p error.
287 		 */
288 		void displayErrorDialog( Error error );
289 		/**
290 		 * \return the number of radians per angle-unit that the user has
291 		 * selected (i.e. this will return 1.0 if the user has selected
292 		 * radians; and PI/180 if the user has selected degrees).
293 		 */
radiansPerAngleUnit()294 		static double radiansPerAngleUnit() { return m_radiansPerAngleUnit; }
295 
296 		enum AngleMode { Radians = 0, Degrees = 1 };
297 		/**
298 		 * Sets the angle mode (in which the calculations are performed).
299 		 */
300 		void setAngleMode( AngleMode mode );
301 		/**
302 		* Initializes the function for evaluation. Called after the functions
303 		* fstr is set.
304 		*/
305 		void initEquation( Equation * equation, Error * error = 0, int * errorPosition = 0 );
306 
307 		uint getNewId(); /// Returns the next ID-number
308 		uint countFunctions(); /// Returns how many functions there are
309 
310 		/// The constants used by the parser
constants()311 		Constants * constants() const { return m_constants; }
312 
313 		/// @return the function with the given id
314 		Function * functionWithID( int id ) const;
315 
316 		/// Points to the array of user defined functions, index by their IDs.
317 		QMap<int, Function *> m_ufkt;
318 
319         /// Reparses all functions, e.g. for when the value of a constant changes
320         void reparseAllFunctions();
321 
322 	signals:
323 		/// emitted when a function is deleted
324 		void functionRemoved( int id );
325 		/// emitted when a function is added
326 		void functionAdded( int id );
327 
328 	private:
329 		/** Mathematical function. */
330 		static ScalarFunction scalarFunctions[ScalarCount];
331 		static VectorFunction vectorFunctions[VectorCount];
332 
333 		void heir0();
334 		void heir1();
335 		void heir2();
336 		void heir3();
337 		void heir4();
338         void heir5();
339 		void primary();
340 		bool tryFunction();
341 		bool tryPredefinedFunction();
342 		bool tryUserFunction();
343 		bool tryVariable();
344 		bool tryConstant();
345 		bool tryNumber();
346 		void addToken( Token token );
347 		void addConstant(double);
348 		void adduint(uint);
349 		void addfptr(double(*)(double));
350 		void addfptr( double(*)(const Vector &), int argCount );
351 		/**
352 		 * \p id Id of the function
353 		 * \p eq_id Which equation of the function to use
354 		 * \p args The number of variables being passed to the function
355 		 */
356 		void addfptr( uint id, uint eq_id, uint args );
357 		/**
358 		 * Attempts to \p string to the current evaluation text. If the text at
359 		 * the current evaluation position is matched, then the evaluation
360 		 * position is incremented past the length of the string and true is
361 		 * returned. Else the evaluation position remains unchanged, and false
362 		 * is returned.
363 		 */
364 		bool match( const QString & string );
365 		/**
366 		 * Continues to read the expression inside a brackets of a vector
367 		 * function until get to the end of the argument list.
368 		 * \return the number of arguments
369 		 */
370 		int readFunctionArguments();
371 
372 		void growEqMem( int growth );
373 		QByteArray *mem; ///< Pointer to the array of tokens for the current equation being parsed
374 		char *mptr; ///< Pointer to the next position of insertion for the parsed equation data
375 		double * m_stack;
376 		double * stkptr;
377 		QString m_eval;
378 		int m_evalPos;
379 		int m_nextFunctionID;
380 		/// @return the m_eval starting at m_evalPos
381 		QString evalRemaining();
382 		QString m_evalRemaining;
383 		Equation * m_currentEquation; // Pointer to the current function
384 		Equation * m_ownEquation; ///< used for parsing constants, etc, and ensures that m_currentEquation is never null
385 		static double m_radiansPerAngleUnit;
386 		Constants * m_constants;
387 		ExpressionSanitizer m_sanitizer;
388 		int m_pmAt; ///< When parsing an expression, which plus-minus symbol at
389 		Error * m_error;
390 
391 	private:
392 		friend class XParser;
393 		friend class ExpressionSanitizer;
394 		Parser();
395 };
396 
397 #endif	// parser_included
398