muParser API -  1.35
muParserTest.cpp
Go to the documentation of this file.
1 /*
2 
3  _____ __ _____________ _______ ______ ___________
4  / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \
5  | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/
6  |__|_| /____/| __(____ /__| /____ >\___ >__|
7  \/ |__| \/ \/ \/
8  Copyright (C) 2022 Ingo Berg
9 
10  Redistribution and use in source and binary forms, with or without modification, are permitted
11  provided that the following conditions are met:
12 
13  * Redistributions of source code must retain the above copyright notice, this list of
14  conditions and the following disclaimer.
15  * Redistributions in binary form must reproduce the above copyright notice, this list of
16  conditions and the following disclaimer in the documentation and/or other materials provided
17  with the distribution.
18 
19  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
20  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 #include "muParserTest.h"
30 
31 #include <cstdio>
32 #include <cmath>
33 #include <iostream>
34 #include <limits>
35 
36 using namespace std;
37 
38 /** \file
39  \brief This file contains the implementation of parser test cases.
40 */
41 
42 namespace mu
43 {
44  namespace Test
45  {
46  int ParserTester::c_iCount = 0;
47 
48  //---------------------------------------------------------------------------------------------
49  ParserTester::ParserTester()
50  :m_vTestFun()
51  {
52  AddTest(&ParserTester::TestNames);
53  AddTest(&ParserTester::TestSyntax);
54  AddTest(&ParserTester::TestPostFix);
55  AddTest(&ParserTester::TestInfixOprt);
56  AddTest(&ParserTester::TestVarConst);
57  AddTest(&ParserTester::TestMultiArg);
58  AddTest(&ParserTester::TestExpression);
59  AddTest(&ParserTester::TestIfThenElse);
60  AddTest(&ParserTester::TestInterface);
61  AddTest(&ParserTester::TestBinOprt);
62  AddTest(&ParserTester::TestException);
63  AddTest(&ParserTester::TestStrArg);
64  AddTest(&ParserTester::TestBulkMode);
65  AddTest(&ParserTester::TestOptimizer);
66 
67  ParserTester::c_iCount = 0;
68  }
69 
70  //---------------------------------------------------------------------------------------------
71  int ParserTester::IsHexVal(const char_type* a_szExpr, int* a_iPos, value_type* a_fVal)
72  {
73  if (a_szExpr[1] == 0 || (a_szExpr[0] != '0' || a_szExpr[1] != 'x'))
74  return 0;
75 
76  unsigned iVal(0);
77 
78  // New code based on streams for UNICODE compliance:
79  stringstream_type::pos_type nPos(0);
80  stringstream_type ss(a_szExpr + 2);
81  ss >> std::hex >> iVal;
82  nPos = ss.tellg();
83 
84  if (nPos == (stringstream_type::pos_type)0)
85  return 1;
86 
87  *a_iPos += (int)(2 + nPos);
88  *a_fVal = (value_type)iVal;
89  return 1;
90  }
91 
92  //---------------------------------------------------------------------------------------------
93  int ParserTester::TestInterface()
94  {
95  int iStat = 0;
96  mu::console() << _T("testing member functions...");
97 
98  // Test RemoveVar
99  value_type afVal[3] = { 1,2,3 };
100  Parser p;
101 
102  try
103  {
104  p.DefineVar(_T("a"), &afVal[0]);
105  p.DefineVar(_T("b"), &afVal[1]);
106  p.DefineVar(_T("c"), &afVal[2]);
107  p.SetExpr(_T("a+b+c"));
108  p.Eval();
109  }
110  catch (...)
111  {
112  iStat += 1; // this is not supposed to happen
113  }
114 
115  try
116  {
117  p.RemoveVar(_T("c"));
118  p.Eval();
119  iStat += 1; // not supposed to reach this, nonexisting variable "c" deleted...
120  }
121  catch (...)
122  {
123  // failure is expected...
124  }
125 
126  if (iStat == 0)
127  mu::console() << _T("passed") << endl;
128  else
129  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
130 
131  return iStat;
132  }
133 
134  //---------------------------------------------------------------------------------------------
135  int ParserTester::TestOptimizer()
136  {
137  int iStat = 0;
138  mu::console() << _T("testing optimizer...");
139 
140  // Test RemoveVar
141  Parser p;
142  try
143  {
144  // test for #93 (https://github.com/beltoforion/muparser/issues/93)
145  // expected bytecode is:
146  // VAL, FUN
147  {
148  p.DefineFun(_T("unoptimizable"), f1of1, false);
149  p.SetExpr(_T("unoptimizable(1)"));
150  p.Eval();
151 
152  auto& bc = p.GetByteCode();
153  const SToken* tok = bc.GetBase();
154  if (bc.GetSize() != 2 && tok[1].Cmd != cmFUNC)
155  {
156  mu::console() << _T("#93 an unoptimizable expression was optimized!") << endl;
157  iStat += 1;
158  }
159  }
160 
161  {
162  p.ClearFun();
163  p.DefineFun(_T("unoptimizable"), f1of1, true);
164  p.SetExpr(_T("unoptimizable(1)"));
165  p.Eval();
166 
167  auto& bc = p.GetByteCode();
168  const SToken* tok = bc.GetBase();
169  if (bc.GetSize() != 1 && tok[0].Cmd != cmVAL)
170  {
171  mu::console() << _T("#93 optimizer error") << endl;
172  iStat += 1;
173  }
174  }
175  }
176  catch (...)
177  {
178  iStat += 1; // this is not supposed to happen
179  }
180 
181  if (iStat == 0)
182  mu::console() << _T("passed") << endl;
183  else
184  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
185 
186  return iStat;
187  }
188 
189  //---------------------------------------------------------------------------------------------
190  int ParserTester::TestStrArg()
191  {
192  int iStat = 0;
193  mu::console() << _T("testing string arguments...");
194 
195  // from oss-fuzz: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=23410
196  iStat += ThrowTest(_T(R"(6 - 6 ? 4 : "", ? 4 : "", ? 4 : "")"), ecUNEXPECTED_STR, true);
197  // variations:
198  iStat += ThrowTest(_T(R"(avg(0?4:(""),1))"), ecUNEXPECTED_STR);
199  iStat += ThrowTest(_T(R"(1 ? 4 : "")"), ecUNEXPECTED_STR);
200  iStat += ThrowTest(_T(R"(1 ? "" : 4)"), ecUNEXPECTED_STR);
201  iStat += ThrowTest(_T(R"(1 ? "" : "")"), ecUNEXPECTED_STR);
202  iStat += ThrowTest(_T(R"(0 ? 4 : "")"), ecUNEXPECTED_STR);
203  iStat += ThrowTest(_T(R"(0 ? 4 : (""))"), ecUNEXPECTED_STR);
204  iStat += ThrowTest(_T(R"(1 ? 4 : "")"), ecUNEXPECTED_STR);
205 
206  // from oss-fuzz: https://oss-fuzz.com/testcase-detail/5106868061208576
207  iStat += ThrowTest(_T(R"("","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",8)"), ecSTR_RESULT);
208 
209  // derived from oss-fuzz: https://oss-fuzz.com/testcase-detail/5758791700971520
210  iStat += ThrowTest(_T("(\"\"), 7"), ecSTR_RESULT);
211  iStat += ThrowTest(_T("((\"\")), 7"), ecSTR_RESULT);
212  //iStat += ThrowTest(_T("(\"\"),(\" \"), 7, (3)"), ecSTR_RESULT);
213  //iStat += ThrowTest(_T("(\"\"),(\"\"), 7, (3)"), ecSTR_RESULT);
214  //iStat += ThrowTest(_T("(\"\"),(\"\"), (3)"), ecSTR_RESULT);
215  //iStat += ThrowTest(_T("(\"\"),(\"\"), 7"), ecSTR_RESULT);
216 
217 
218  // variations:
219  iStat += ThrowTest(_T(R"("","",9)"), ecSTR_RESULT);
220 
221  iStat += EqnTest(_T("valueof(\"\")"), 123, true); // empty string arguments caused a crash
222  iStat += EqnTest(_T("valueof(\"aaa\")+valueof(\"bbb\") "), 246, true);
223  iStat += EqnTest(_T("2*(valueof(\"aaa\")-23)+valueof(\"bbb\")"), 323, true);
224 
225  // use in expressions with variables
226  iStat += EqnTest(_T("a*(atof(\"10\")-b)"), 8, true);
227  iStat += EqnTest(_T("a-(atof(\"10\")*b)"), -19, true);
228 
229  // string + numeric arguments
230  iStat += EqnTest(_T("strfun1(\"100\")"), 100, true);
231  iStat += EqnTest(_T("strfun2(\"100\",1)"), 101, true);
232  iStat += EqnTest(_T("strfun3(\"99\",1,2)"), 102, true);
233  iStat += EqnTest(_T("strfun4(\"99\",1,2,3)"), 105, true);
234  iStat += EqnTest(_T("strfun5(\"99\",1,2,3,4)"), 109, true);
235  iStat += EqnTest(_T("strfun6(\"99\",1,2,3,4,5)"), 114, true);
236 
237  // string constants
238  iStat += EqnTest(_T("atof(str1)+atof(str2)"), 3.33, true);
239 
240  // user data
241  iStat += EqnTest(_T("strfunud3_10(\"99\",1,2)"), 112, true);
242 
243  if (iStat == 0)
244  mu::console() << _T("passed") << endl;
245  else
246  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
247 
248  return iStat;
249  }
250 
251  //---------------------------------------------------------------------------------------------
252  int ParserTester::TestBulkMode()
253  {
254  int iStat = 0;
255  mu::console() << _T("testing bulkmode...");
256 
257 #define EQN_TEST_BULK(EXPR, R1, R2, R3, R4, PASS) \
258  { \
259  double res[] = { R1, R2, R3, R4 }; \
260  iStat += EqnTestBulk(_T(EXPR), res, (PASS)); \
261  }
262 
263  // Bulk Variables for the test:
264  // a: 1,2,3,4
265  // b: 2,2,2,2
266  // c: 3,3,3,3
267  // d: 5,4,3,2
268  EQN_TEST_BULK("a", 1, 1, 1, 1, false)
269  EQN_TEST_BULK("a", 1, 2, 3, 4, true)
270  EQN_TEST_BULK("b=a", 1, 2, 3, 4, true)
271  EQN_TEST_BULK("b=a, b*10", 10, 20, 30, 40, true)
272  EQN_TEST_BULK("b=a, b*10, a", 1, 2, 3, 4, true)
273  EQN_TEST_BULK("a+b", 3, 4, 5, 6, true)
274  EQN_TEST_BULK("c*(a+b)", 9, 12, 15, 18, true)
275 #undef EQN_TEST_BULK
276 
277  if (iStat == 0)
278  mu::console() << _T("passed") << endl;
279  else
280  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
281 
282  return iStat;
283  }
284 
285  //---------------------------------------------------------------------------------------------
286  int ParserTester::TestBinOprt()
287  {
288  int iStat = 0;
289  mu::console() << _T("testing binary operators...");
290 
291  // built in operators
292  // xor operator
293 
294  iStat += EqnTest(_T("a++b"), 3, true);
295  iStat += EqnTest(_T("a ++ b"), 3, true);
296  iStat += EqnTest(_T("1++2"), 3, true);
297  iStat += EqnTest(_T("1 ++ 2"), 3, true);
298  iStat += EqnTest(_T("a add b"), 3, true);
299  iStat += EqnTest(_T("1 add 2"), 3, true);
300  iStat += EqnTest(_T("a<b"), 1, true);
301  iStat += EqnTest(_T("b>a"), 1, true);
302  iStat += EqnTest(_T("a>a"), 0, true);
303  iStat += EqnTest(_T("a<a"), 0, true);
304  iStat += EqnTest(_T("a>a"), 0, true);
305  iStat += EqnTest(_T("a<=a"), 1, true);
306  iStat += EqnTest(_T("a<=b"), 1, true);
307  iStat += EqnTest(_T("b<=a"), 0, true);
308  iStat += EqnTest(_T("a>=a"), 1, true);
309  iStat += EqnTest(_T("b>=a"), 1, true);
310  iStat += EqnTest(_T("a>=b"), 0, true);
311 
312  // Test logical operators, especially if user defined "&" and the internal "&&" collide
313  iStat += EqnTest(_T("1 && 1"), 1, true);
314  iStat += EqnTest(_T("1 && 0"), 0, true);
315  iStat += EqnTest(_T("(a<b) && (b>a)"), 1, true);
316  iStat += EqnTest(_T("(a<b) && (a>b)"), 0, true);
317  //iStat += EqnTest(_T("12 and 255"), 12, true);
318  //iStat += EqnTest(_T("12 and 0"), 0, true);
319  iStat += EqnTest(_T("12 & 255"), 12, true);
320  iStat += EqnTest(_T("12 & 0"), 0, true);
321  iStat += EqnTest(_T("12&255"), 12, true);
322  iStat += EqnTest(_T("12&0"), 0, true);
323 
324  // Assignment operator
325  iStat += EqnTest(_T("a = b"), 2, true);
326  iStat += EqnTest(_T("a = sin(b)"), 0.909297, true);
327  iStat += EqnTest(_T("a = 1+sin(b)"), 1.909297, true);
328  iStat += EqnTest(_T("(a=b)*2"), 4, true);
329  iStat += EqnTest(_T("2*(a=b)"), 4, true);
330  iStat += EqnTest(_T("2*(a=b+1)"), 6, true);
331  iStat += EqnTest(_T("(a=b+1)*2"), 6, true);
332  iStat += EqnTest(_T("a=c, a*10"), 30, true);
333 
334  iStat += EqnTest(_T("2^2^3"), 256, true);
335  iStat += EqnTest(_T("1/2/3"), 1.0 / 6.0, true);
336 
337  // reference: http://www.wolframalpha.com/input/?i=3%2B4*2%2F%281-5%29^2^3
338  iStat += EqnTest(_T("3+4*2/(1-5)^2^3"), 3.0001220703125, true);
339 
340  // Test user defined binary operators
341  iStat += EqnTestInt(_T("1 | 2"), 3, true);
342  iStat += EqnTestInt(_T("1 || 2"), 1, true);
343  iStat += EqnTestInt(_T("123 & 456"), 72, true);
344  iStat += EqnTestInt(_T("(123 & 456) % 10"), 2, true);
345  iStat += EqnTestInt(_T("1 && 0"), 0, true);
346  iStat += EqnTestInt(_T("123 && 456"), 1, true);
347  iStat += EqnTestInt(_T("1 << 3"), 8, true);
348  iStat += EqnTestInt(_T("8 >> 3"), 1, true);
349  iStat += EqnTestInt(_T("9 / 4"), 2, true);
350  iStat += EqnTestInt(_T("9 % 4"), 1, true);
351  iStat += EqnTestInt(_T("if(5%2,1,0)"), 1, true);
352  iStat += EqnTestInt(_T("if(4%2,1,0)"), 0, true);
353  iStat += EqnTestInt(_T("-10+1"), -9, true);
354  iStat += EqnTestInt(_T("1+2*3"), 7, true);
355  iStat += EqnTestInt(_T("const1 != const2"), 1, true);
356  iStat += EqnTestInt(_T("const1 != const2"), 0, false);
357  iStat += EqnTestInt(_T("const1 == const2"), 0, true);
358  iStat += EqnTestInt(_T("const1 == 1"), 1, true);
359  iStat += EqnTestInt(_T("10*(const1 == 1)"), 10, true);
360  iStat += EqnTestInt(_T("2*(const1 | const2)"), 6, true);
361  iStat += EqnTestInt(_T("2*(const1 | const2)"), 7, false);
362  iStat += EqnTestInt(_T("const1 < const2"), 1, true);
363  iStat += EqnTestInt(_T("const2 > const1"), 1, true);
364  iStat += EqnTestInt(_T("const1 <= 1"), 1, true);
365  iStat += EqnTestInt(_T("const2 >= 2"), 1, true);
366  iStat += EqnTestInt(_T("2*(const1 + const2)"), 6, true);
367  iStat += EqnTestInt(_T("2*(const1 - const2)"), -2, true);
368  iStat += EqnTestInt(_T("a != b"), 1, true);
369  iStat += EqnTestInt(_T("a != b"), 0, false);
370  iStat += EqnTestInt(_T("a == b"), 0, true);
371  iStat += EqnTestInt(_T("a == 1"), 1, true);
372  iStat += EqnTestInt(_T("10*(a == 1)"), 10, true);
373  iStat += EqnTestInt(_T("2*(a | b)"), 6, true);
374  iStat += EqnTestInt(_T("2*(a | b)"), 7, false);
375  iStat += EqnTestInt(_T("a < b"), 1, true);
376  iStat += EqnTestInt(_T("b > a"), 1, true);
377  iStat += EqnTestInt(_T("a <= 1"), 1, true);
378  iStat += EqnTestInt(_T("b >= 2"), 1, true);
379  iStat += EqnTestInt(_T("2*(a + b)"), 6, true);
380  iStat += EqnTestInt(_T("2*(a - b)"), -2, true);
381  iStat += EqnTestInt(_T("a + (a << b)"), 5, true);
382  iStat += EqnTestInt(_T("-2^2"), -4, true);
383  iStat += EqnTestInt(_T("3--a"), 4, true);
384  iStat += EqnTestInt(_T("3+-3^2"), -6, true);
385 
386  // Test reading of hex values:
387  iStat += EqnTestInt(_T("0xff"), 255, true);
388  iStat += EqnTestInt(_T("10+0xff"), 265, true);
389  iStat += EqnTestInt(_T("0xff+10"), 265, true);
390  iStat += EqnTestInt(_T("10*0xff"), 2550, true);
391  iStat += EqnTestInt(_T("0xff*10"), 2550, true);
392  iStat += EqnTestInt(_T("10+0xff+1"), 266, true);
393  iStat += EqnTestInt(_T("1+0xff+10"), 266, true);
394 
395  // incorrect: '^' is yor here, not power
396  // iStat += EqnTestInt("-(1+2)^2", -9, true);
397  // iStat += EqnTestInt("-1^3", -1, true);
398 
399  // Test precedence
400  // a=1, b=2, c=3
401  iStat += EqnTestInt(_T("a + b * c"), 7, true);
402  iStat += EqnTestInt(_T("a * b + c"), 5, true);
403  iStat += EqnTestInt(_T("a<b && b>10"), 0, true);
404  iStat += EqnTestInt(_T("a<b && b<10"), 1, true);
405 
406  iStat += EqnTestInt(_T("a + b << c"), 17, true);
407  iStat += EqnTestInt(_T("a << b + c"), 7, true);
408  iStat += EqnTestInt(_T("c * b < a"), 0, true);
409  iStat += EqnTestInt(_T("c * b == 6 * a"), 1, true);
410  iStat += EqnTestInt(_T("2^2^3"), 256, true);
411 
412 
413  if (iStat == 0)
414  mu::console() << _T("passed") << endl;
415  else
416  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
417 
418  return iStat;
419  }
420 
421  //---------------------------------------------------------------------------------------------
422  /** \brief Check muParser name restriction enforcement. */
423  int ParserTester::TestNames()
424  {
425  int iStat = 0,
426  iErr = 0;
427 
428  mu::console() << "testing name restriction enforcement...";
429 
430  Parser p;
431 
432 #define PARSER_THROWCHECK(DOMAIN, FAIL, EXPR, ARG) \
433  iErr = 0; \
434  ParserTester::c_iCount++; \
435  try \
436  { \
437  p.Define##DOMAIN(EXPR, ARG); \
438  iErr = (FAIL) ? 0 : 1; \
439  } \
440  catch(...) \
441  { \
442  iErr = (!FAIL) ? 0 : 1; \
443  } \
444  iStat += iErr;
445 
446  // constant names
447  PARSER_THROWCHECK(Const, false, _T("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), 1)
448  PARSER_THROWCHECK(Const, false, _T("0a"), 1)
449  PARSER_THROWCHECK(Const, false, _T("9a"), 1)
450  PARSER_THROWCHECK(Const, false, _T("+a"), 1)
451  PARSER_THROWCHECK(Const, false, _T("-a"), 1)
452  PARSER_THROWCHECK(Const, false, _T("a-"), 1)
453  PARSER_THROWCHECK(Const, false, _T("a*"), 1)
454  PARSER_THROWCHECK(Const, false, _T("a?"), 1)
455  PARSER_THROWCHECK(Const, true, _T("a"), 1)
456  PARSER_THROWCHECK(Const, true, _T("a_min"), 1)
457  PARSER_THROWCHECK(Const, true, _T("a_min0"), 1)
458  PARSER_THROWCHECK(Const, true, _T("a_min9"), 1)
459 
460  // variable names
461  value_type a;
462  p.ClearConst();
463  PARSER_THROWCHECK(Var, false, _T("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), &a);
464  PARSER_THROWCHECK(Var, false, _T("123abc"), &a)
465  PARSER_THROWCHECK(Var, false, _T("9a"), &a)
466  PARSER_THROWCHECK(Var, false, _T("0a"), &a)
467  PARSER_THROWCHECK(Var, false, _T("+a"), &a)
468  PARSER_THROWCHECK(Var, false, _T("-a"), &a)
469  PARSER_THROWCHECK(Var, false, _T("?a"), &a)
470  PARSER_THROWCHECK(Var, false, _T("!a"), &a)
471  PARSER_THROWCHECK(Var, false, _T("a+"), &a)
472  PARSER_THROWCHECK(Var, false, _T("a-"), &a)
473  PARSER_THROWCHECK(Var, false, _T("a*"), &a)
474  PARSER_THROWCHECK(Var, false, _T("a?"), &a)
475  PARSER_THROWCHECK(Var, true, _T("a"), &a)
476  PARSER_THROWCHECK(Var, true, _T("a_min"), &a)
477  PARSER_THROWCHECK(Var, true, _T("a_min0"), &a)
478  PARSER_THROWCHECK(Var, true, _T("a_min9"), &a)
479  PARSER_THROWCHECK(Var, false, _T("a_min9"), 0)
480 
481  // Postfix operators
482  // fail
483  PARSER_THROWCHECK(PostfixOprt, false, _T("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), f1of1);
484  PARSER_THROWCHECK(PostfixOprt, false, _T("(k"), f1of1)
485  PARSER_THROWCHECK(PostfixOprt, false, _T("9+"), f1of1)
486  PARSER_THROWCHECK(PostfixOprt, false, _T("+"), 0)
487  // pass
488  PARSER_THROWCHECK(PostfixOprt, true, _T("-a"), f1of1)
489  PARSER_THROWCHECK(PostfixOprt, true, _T("?a"), f1of1)
490  PARSER_THROWCHECK(PostfixOprt, true, _T("_"), f1of1)
491  PARSER_THROWCHECK(PostfixOprt, true, _T("#"), f1of1)
492  PARSER_THROWCHECK(PostfixOprt, true, _T("&&"), f1of1)
493  PARSER_THROWCHECK(PostfixOprt, true, _T("||"), f1of1)
494  PARSER_THROWCHECK(PostfixOprt, true, _T("&"), f1of1)
495  PARSER_THROWCHECK(PostfixOprt, true, _T("|"), f1of1)
496  PARSER_THROWCHECK(PostfixOprt, true, _T("++"), f1of1)
497  PARSER_THROWCHECK(PostfixOprt, true, _T("--"), f1of1)
498  PARSER_THROWCHECK(PostfixOprt, true, _T("?>"), f1of1)
499  PARSER_THROWCHECK(PostfixOprt, true, _T("?<"), f1of1)
500  PARSER_THROWCHECK(PostfixOprt, true, _T("**"), f1of1)
501  PARSER_THROWCHECK(PostfixOprt, true, _T("xor"), f1of1)
502  PARSER_THROWCHECK(PostfixOprt, true, _T("and"), f1of1)
503  PARSER_THROWCHECK(PostfixOprt, true, _T("or"), f1of1)
504  PARSER_THROWCHECK(PostfixOprt, true, _T("not"), f1of1)
505  PARSER_THROWCHECK(PostfixOprt, true, _T("!"), f1of1)
506 
507  // Binary operator
508  // The following must fail with builtin operators activated
509  // p.EnableBuiltInOp(true); -> this is the default
510  p.ClearPostfixOprt();
511  PARSER_THROWCHECK(Oprt, false, _T("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), f1of2);
512  PARSER_THROWCHECK(Oprt, false, _T("+"), f1of2)
513  PARSER_THROWCHECK(Oprt, false, _T("-"), f1of2)
514  PARSER_THROWCHECK(Oprt, false, _T("*"), f1of2)
515  PARSER_THROWCHECK(Oprt, false, _T("/"), f1of2)
516  PARSER_THROWCHECK(Oprt, false, _T("^"), f1of2)
517  PARSER_THROWCHECK(Oprt, false, _T("&&"), f1of2)
518  PARSER_THROWCHECK(Oprt, false, _T("||"), f1of2)
519 
520  // without activated built in operators it should work
521  p.EnableBuiltInOprt(false);
522  PARSER_THROWCHECK(Oprt, true, _T("+"), f1of2)
523  PARSER_THROWCHECK(Oprt, true, _T("-"), f1of2)
524  PARSER_THROWCHECK(Oprt, true, _T("*"), f1of2)
525  PARSER_THROWCHECK(Oprt, true, _T("/"), f1of2)
526  PARSER_THROWCHECK(Oprt, true, _T("^"), f1of2)
527  PARSER_THROWCHECK(Oprt, true, _T("&&"), f1of2)
528  PARSER_THROWCHECK(Oprt, true, _T("||"), f1of2)
529 #undef PARSER_THROWCHECK
530 
531  if (iStat == 0)
532  mu::console() << _T("passed") << endl;
533  else
534  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
535 
536  return iStat;
537  }
538 
539  //---------------------------------------------------------------------------
540  int ParserTester::TestSyntax()
541  {
542  int iStat = 0;
543  mu::console() << _T("testing syntax engine...");
544 
545  iStat += ThrowTest(_T("1,"), ecUNEXPECTED_EOF); // incomplete hex definition
546  iStat += ThrowTest(_T("a,"), ecUNEXPECTED_EOF); // incomplete hex definition
547  iStat += ThrowTest(_T("sin(8),"), ecUNEXPECTED_EOF); // incomplete hex definition
548  iStat += ThrowTest(_T("(sin(8)),"), ecUNEXPECTED_EOF); // incomplete hex definition
549  iStat += ThrowTest(_T("a{m},"), ecUNEXPECTED_EOF); // incomplete hex definition
550 
551  iStat += EqnTest(_T("(1+ 2*a)"), 3, true); // Spaces within formula
552  iStat += EqnTest(_T("sqrt((4))"), 2, true); // Multiple brackets
553  iStat += EqnTest(_T("sqrt((2)+2)"), 2, true);// Multiple brackets
554  iStat += EqnTest(_T("sqrt(2+(2))"), 2, true);// Multiple brackets
555  iStat += EqnTest(_T("sqrt(a+(3))"), 2, true);// Multiple brackets
556  iStat += EqnTest(_T("sqrt((3)+a)"), 2, true);// Multiple brackets
557  iStat += EqnTest(_T("order(1,2)"), 1, true); // May not cause name collision with operator "or"
558  iStat += EqnTest(_T("(2+"), 0, false); // missing closing bracket
559  iStat += EqnTest(_T("2++4"), 0, false); // unexpected operator
560  iStat += EqnTest(_T("2+-4"), 0, false); // unexpected operator
561  iStat += EqnTest(_T("(2+)"), 0, false); // unexpected closing bracket
562  iStat += EqnTest(_T("--2"), 0, false); // double sign
563  iStat += EqnTest(_T("ksdfj"), 0, false); // unknown token
564  iStat += EqnTest(_T("()"), 0, false); // empty bracket without a function
565  iStat += EqnTest(_T("5+()"), 0, false); // empty bracket without a function
566  iStat += EqnTest(_T("sin(cos)"), 0, false); // unexpected function
567  iStat += EqnTest(_T("5t6"), 0, false); // unknown token
568  iStat += EqnTest(_T("5 t 6"), 0, false); // unknown token
569  iStat += EqnTest(_T("8*"), 0, false); // unexpected end of formula
570  iStat += EqnTest(_T(",3"), 0, false); // unexpected comma
571  iStat += EqnTest(_T("3,5"), 0, false); // unexpected comma
572  iStat += EqnTest(_T("sin(8,8)"), 0, false); // too many function args
573  iStat += EqnTest(_T("(7,8)"), 0, false); // too many function args
574  iStat += EqnTest(_T("sin)"), 0, false); // unexpected closing bracket
575  iStat += EqnTest(_T("a)"), 0, false); // unexpected closing bracket
576  iStat += EqnTest(_T("pi)"), 0, false); // unexpected closing bracket
577  iStat += EqnTest(_T("sin(())"), 0, false); // unexpected closing bracket
578  iStat += EqnTest(_T("sin()"), 0, false); // unexpected closing bracket
579 
580  if (iStat == 0)
581  mu::console() << _T("passed") << endl;
582  else
583  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
584 
585  return iStat;
586  }
587 
588  //---------------------------------------------------------------------------
589  int ParserTester::TestVarConst()
590  {
591  int iStat = 0;
592  mu::console() << _T("testing variable/constant detection...");
593 
594  // Test if the result changes when a variable changes
595  iStat += EqnTestWithVarChange(_T("a"), 1, 1, 2, 2);
596  iStat += EqnTestWithVarChange(_T("2*a"), 2, 4, 3, 6);
597 
598  // distinguish constants with same basename
599  iStat += EqnTest(_T("const"), 1, true);
600  iStat += EqnTest(_T("const1"), 2, true);
601  iStat += EqnTest(_T("const2"), 3, true);
602  iStat += EqnTest(_T("2*const"), 2, true);
603  iStat += EqnTest(_T("2*const1"), 4, true);
604  iStat += EqnTest(_T("2*const2"), 6, true);
605  iStat += EqnTest(_T("2*const+1"), 3, true);
606  iStat += EqnTest(_T("2*const1+1"), 5, true);
607  iStat += EqnTest(_T("2*const2+1"), 7, true);
608  iStat += EqnTest(_T("const"), 0, false);
609  iStat += EqnTest(_T("const1"), 0, false);
610  iStat += EqnTest(_T("const2"), 0, false);
611 
612  // distinguish variables with same basename
613  iStat += EqnTest(_T("a"), 1, true);
614  iStat += EqnTest(_T("aa"), 2, true);
615  iStat += EqnTest(_T("2*a"), 2, true);
616  iStat += EqnTest(_T("2*aa"), 4, true);
617  iStat += EqnTest(_T("2*a-1"), 1, true);
618  iStat += EqnTest(_T("2*aa-1"), 3, true);
619 
620  // custom value recognition
621  iStat += EqnTest(_T("0xff"), 255, true);
622  iStat += EqnTest(_T("0x97 + 0xff"), 406, true);
623 
624  // Finally test querying of used variables
625  try
626  {
627  int idx;
628  mu::Parser p;
629  mu::value_type vVarVal[] = { 1, 2, 3, 4, 5 };
630  p.DefineVar(_T("a"), &vVarVal[0]);
631  p.DefineVar(_T("b"), &vVarVal[1]);
632  p.DefineVar(_T("c"), &vVarVal[2]);
633  p.DefineVar(_T("d"), &vVarVal[3]);
634  p.DefineVar(_T("e"), &vVarVal[4]);
635 
636  // Test lookup of defined variables
637  // 4 used variables
638  p.SetExpr(_T("a+b+c+d"));
639  mu::varmap_type UsedVar = p.GetUsedVar();
640  int iCount = (int)UsedVar.size();
641  if (iCount != 4)
642  throw false;
643 
644  // the next check will fail if the parser
645  // erroneously creates new variables internally
646  if (p.GetVar().size() != 5)
647  throw false;
648 
649  mu::varmap_type::const_iterator item = UsedVar.begin();
650  for (idx = 0; item != UsedVar.end(); ++item)
651  {
652  if (&vVarVal[idx++] != item->second)
653  throw false;
654  }
655 
656  // Test lookup of undefined variables
657  p.SetExpr(_T("undef1+undef2+undef3"));
658  UsedVar = p.GetUsedVar();
659  iCount = (int)UsedVar.size();
660  if (iCount != 3)
661  throw false;
662 
663  // the next check will fail if the parser
664  // erroneously creates new variables internally
665  if (p.GetVar().size() != 5)
666  throw false;
667 
668  for (item = UsedVar.begin(); item != UsedVar.end(); ++item)
669  {
670  if (item->second != 0)
671  throw false; // all pointers to undefined variables must be null
672  }
673 
674  // 1 used variables
675  p.SetExpr(_T("a+b"));
676  UsedVar = p.GetUsedVar();
677  iCount = (int)UsedVar.size();
678  if (iCount != 2) throw false;
679  item = UsedVar.begin();
680  for (idx = 0; item != UsedVar.end(); ++item)
681  if (&vVarVal[idx++] != item->second) throw false;
682 
683  }
684  catch (...)
685  {
686  iStat += 1;
687  }
688 
689  if (iStat == 0)
690  mu::console() << _T("passed") << endl;
691  else
692  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
693 
694  return iStat;
695  }
696 
697  //---------------------------------------------------------------------------
698  int ParserTester::TestMultiArg()
699  {
700  int iStat = 0;
701  mu::console() << _T("testing multiarg functions...");
702 
703  // from oss-fzz.com: UNKNOWN READ; https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=23330#c1
704  iStat += ThrowTest(_T("6, +, +, +, +, +, +, +, +, +, +, +, +, +, +, 1, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +"), ecUNEXPECTED_ARG_SEP, true);
705 
706  // misplaced string argument
707  iStat += ThrowTest(_T(R"(sin(0?4:("")))"), ecUNEXPECTED_STR);
708  iStat += ThrowTest(_T(R"(avg(0?4:(""),1))"), ecUNEXPECTED_STR);
709 
710  // Compound expressions
711  iStat += EqnTest(_T("1,2,3"), 3, true);
712  iStat += EqnTest(_T("a,b,c"), 3, true);
713  iStat += EqnTest(_T("a=10,b=20,c=a*b"), 200, true);
714  iStat += EqnTest(_T("1,\n2,\n3"), 3, true);
715  iStat += EqnTest(_T("a,\nb,\nc"), 3, true);
716  iStat += EqnTest(_T("a=10,\nb=20,\nc=a*b"), 200, true);
717  iStat += EqnTest(_T("1,\r\n2,\r\n3"), 3, true);
718  iStat += EqnTest(_T("a,\r\nb,\r\nc"), 3, true);
719  iStat += EqnTest(_T("a=10,\r\nb=20,\r\nc=a*b"), 200, true);
720 
721  // picking the right argument
722  iStat += EqnTest(_T("f1of1(1)"), 1, true);
723  iStat += EqnTest(_T("f1of2(1, 2)"), 1, true);
724  iStat += EqnTest(_T("f2of2(1, 2)"), 2, true);
725  iStat += EqnTest(_T("f1of3(1, 2, 3)"), 1, true);
726  iStat += EqnTest(_T("f2of3(1, 2, 3)"), 2, true);
727  iStat += EqnTest(_T("f3of3(1, 2, 3)"), 3, true);
728  iStat += EqnTest(_T("f1of4(1, 2, 3, 4)"), 1, true);
729  iStat += EqnTest(_T("f2of4(1, 2, 3, 4)"), 2, true);
730  iStat += EqnTest(_T("f3of4(1, 2, 3, 4)"), 3, true);
731  iStat += EqnTest(_T("f4of4(1, 2, 3, 4)"), 4, true);
732  iStat += EqnTest(_T("f1of5(1, 2, 3, 4, 5)"), 1, true);
733  iStat += EqnTest(_T("f2of5(1, 2, 3, 4, 5)"), 2, true);
734  iStat += EqnTest(_T("f3of5(1, 2, 3, 4, 5)"), 3, true);
735  iStat += EqnTest(_T("f4of5(1, 2, 3, 4, 5)"), 4, true);
736  iStat += EqnTest(_T("f5of5(1, 2, 3, 4, 5)"), 5, true);
737  // Too few arguments / Too many arguments
738  iStat += EqnTest(_T("1+ping()"), 11, true);
739  iStat += EqnTest(_T("ping()+1"), 11, true);
740  iStat += EqnTest(_T("2*ping()"), 20, true);
741  iStat += EqnTest(_T("ping()*2"), 20, true);
742  iStat += EqnTest(_T("ping(1,2)"), 0, false);
743  iStat += EqnTest(_T("1+ping(1,2)"), 0, false);
744  iStat += EqnTest(_T("f1of1(1,2)"), 0, false);
745  iStat += EqnTest(_T("f1of1()"), 0, false);
746  iStat += EqnTest(_T("f1of2(1, 2, 3)"), 0, false);
747  iStat += EqnTest(_T("f1of2(1)"), 0, false);
748  iStat += EqnTest(_T("f1of3(1, 2, 3, 4)"), 0, false);
749  iStat += EqnTest(_T("f1of3(1)"), 0, false);
750  iStat += EqnTest(_T("f1of4(1, 2, 3, 4, 5)"), 0, false);
751  iStat += EqnTest(_T("f1of4(1)"), 0, false);
752  iStat += EqnTest(_T("(1,2,3)"), 0, false);
753  iStat += EqnTest(_T("1,2,3"), 0, false);
754  iStat += EqnTest(_T("(1*a,2,3)"), 0, false);
755  iStat += EqnTest(_T("1,2*a,3"), 0, false);
756 
757  // correct calculation of arguments
758  iStat += EqnTest(_T("min(a, 1)"), 1, true);
759  iStat += EqnTest(_T("min(3*2, 1)"), 1, true);
760  iStat += EqnTest(_T("min(3*2, 1)"), 6, false);
761  iStat += EqnTest(_T("firstArg(2,3,4)"), 2, true);
762  iStat += EqnTest(_T("lastArg(2,3,4)"), 4, true);
763  iStat += EqnTest(_T("min(3*a+1, 1)"), 1, true);
764  iStat += EqnTest(_T("max(3*a+1, 1)"), 4, true);
765  iStat += EqnTest(_T("max(3*a+1, 1)*2"), 8, true);
766  iStat += EqnTest(_T("2*max(3*a+1, 1)+2"), 10, true);
767 
768  // functions with Variable argument count
769  iStat += EqnTest(_T("sum(a)"), 1, true);
770  iStat += EqnTest(_T("sum(1,2,3)"), 6, true);
771  iStat += EqnTest(_T("sum(a,b,c)"), 6, true);
772  iStat += EqnTest(_T("sum(1,-max(1,2),3)*2"), 4, true);
773  iStat += EqnTest(_T("2*sum(1,2,3)"), 12, true);
774  iStat += EqnTest(_T("2*sum(1,2,3)+2"), 14, true);
775  iStat += EqnTest(_T("2*sum(-1,2,3)+2"), 10, true);
776  iStat += EqnTest(_T("2*sum(-1,2,-(-a))+2"), 6, true);
777  iStat += EqnTest(_T("2*sum(-1,10,-a)+2"), 18, true);
778  iStat += EqnTest(_T("2*sum(1,2,3)*2"), 24, true);
779  iStat += EqnTest(_T("sum(1,-max(1,2),3)*2"), 4, true);
780  iStat += EqnTest(_T("sum(1*3, 4, a+2)"), 10, true);
781  iStat += EqnTest(_T("sum(1*3, 2*sum(1,2,2), a+2)"), 16, true);
782  iStat += EqnTest(_T("sum(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2)"), 24, true);
783 
784  // some failures
785  iStat += EqnTest(_T("sum()"), 0, false);
786  iStat += EqnTest(_T("sum(,)"), 0, false);
787  iStat += EqnTest(_T("sum(1,2,)"), 0, false);
788  iStat += EqnTest(_T("sum(,1,2)"), 0, false);
789 
790  // user data
791  iStat += EqnTest(_T("funud0_8()"), 8, true);
792  iStat += EqnTest(_T("funud1_16(10)"), 26, true);
793  iStat += EqnTest(_T("funud2_24(10, 100)"), 134, true);
794  iStat += EqnTest(_T("funud10_32(1,2,3,4,5,6,7,8,9,10)"), 87, true);
795  iStat += EqnTest(_T("funud0_9()"), 9, true);
796  iStat += EqnTest(_T("funud1_17(10)"), 27, true);
797  iStat += EqnTest(_T("funud2_25(10, 100)"), 135, true);
798  iStat += EqnTest(_T("funud10_33(1,2,3,4,5,6,7,8,9,10)"), 88, true);
799  iStat += EqnTest(_T("sumud_100(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2)"), 124, true);
800  iStat += EqnTest(_T("sumud_100()"), 0, false);
801 
802  if (iStat == 0)
803  mu::console() << _T("passed") << endl;
804  else
805  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
806 
807  return iStat;
808  }
809 
810 
811  //---------------------------------------------------------------------------
812  int ParserTester::TestInfixOprt()
813  {
814  int iStat(0);
815  mu::console() << "testing infix operators...";
816 
817  iStat += EqnTest(_T("+1"), +1, true);
818  iStat += EqnTest(_T("-(+1)"), -1, true);
819  iStat += EqnTest(_T("-(+1)*2"), -2, true);
820  iStat += EqnTest(_T("-(+2)*sqrt(4)"), -4, true);
821  iStat += EqnTest(_T("3-+a"), 2, true);
822  iStat += EqnTest(_T("+1*3"), 3, true);
823 
824  iStat += EqnTest(_T("-1"), -1, true);
825  iStat += EqnTest(_T("-(-1)"), 1, true);
826  iStat += EqnTest(_T("-(-1)*2"), 2, true);
827  iStat += EqnTest(_T("-(-2)*sqrt(4)"), 4, true);
828  iStat += EqnTest(_T("-_pi"), -MathImpl<double>::CONST_PI, true);
829  iStat += EqnTest(_T("-a"), -1, true);
830  iStat += EqnTest(_T("-(a)"), -1, true);
831  iStat += EqnTest(_T("-(-a)"), 1, true);
832  iStat += EqnTest(_T("-(-a)*2"), 2, true);
833  iStat += EqnTest(_T("-(8)"), -8, true);
834  iStat += EqnTest(_T("-8"), -8, true);
835  iStat += EqnTest(_T("-(2+1)"), -3, true);
836  iStat += EqnTest(_T("-(f1of1(1+2*3)+1*2)"), -9, true);
837  iStat += EqnTest(_T("-(-f1of1(1+2*3)+1*2)"), 5, true);
838  iStat += EqnTest(_T("-sin(8)"), -0.989358, true);
839  iStat += EqnTest(_T("3-(-a)"), 4, true);
840  iStat += EqnTest(_T("3--a"), 4, true);
841  iStat += EqnTest(_T("-1*3"), -3, true);
842 
843  // Postfix / infix priorities
844  iStat += EqnTest(_T("~2#"), 8, true);
845  iStat += EqnTest(_T("~f1of1(2)#"), 8, true);
846  iStat += EqnTest(_T("~(b)#"), 8, true);
847  iStat += EqnTest(_T("(~b)#"), 12, true);
848  iStat += EqnTest(_T("~(2#)"), 8, true);
849  iStat += EqnTest(_T("~(f1of1(2)#)"), 8, true);
850  //
851  iStat += EqnTest(_T("-2^2"), -4, true);
852  iStat += EqnTest(_T("-(a+b)^2"), -9, true);
853  iStat += EqnTest(_T("(-3)^2"), 9, true);
854  iStat += EqnTest(_T("-(-2^2)"), 4, true);
855  iStat += EqnTest(_T("3+-3^2"), -6, true);
856  // The following assumes use of sqr as postfix operator together
857  // with a sign operator of low priority:
858  iStat += EqnTest(_T("-2'"), -4, true);
859  iStat += EqnTest(_T("-(1+1)'"), -4, true);
860  iStat += EqnTest(_T("2+-(1+1)'"), -2, true);
861  iStat += EqnTest(_T("2+-2'"), -2, true);
862  // This is the classic behaviour of the infix sign operator (here: "$") which is
863  // now deprecated:
864  iStat += EqnTest(_T("$2^2"), 4, true);
865  iStat += EqnTest(_T("$(a+b)^2"), 9, true);
866  iStat += EqnTest(_T("($3)^2"), 9, true);
867  iStat += EqnTest(_T("$($2^2)"), -4, true);
868  iStat += EqnTest(_T("3+$3^2"), 12, true);
869 
870  // infix operators sharing the first few characters
871  iStat += EqnTest(_T("~ 123"), (value_type)123.0 + 2, true);
872  iStat += EqnTest(_T("~~ 123"), (value_type)123.0 + 2, true);
873 
874  if (iStat == 0)
875  mu::console() << _T("passed") << endl;
876  else
877  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
878 
879  return iStat;
880  }
881 
882 
883  //---------------------------------------------------------------------------
884  int ParserTester::TestPostFix()
885  {
886  int iStat = 0;
887  mu::console() << _T("testing postfix operators...");
888 
889  // application
890  iStat += EqnTest(_T("3{m}+5"), 5.003, true);
891  iStat += EqnTest(_T("1000{m}"), 1, true);
892  iStat += EqnTest(_T("1000 {m}"), 1, true);
893  iStat += EqnTest(_T("(a){m}"), 1e-3, true);
894  iStat += EqnTest(_T("a{m}"), 1e-3, true);
895  iStat += EqnTest(_T("a {m}"), 1e-3, true);
896  iStat += EqnTest(_T("-(a){m}"), -1e-3, true);
897  iStat += EqnTest(_T("-2{m}"), -2e-3, true);
898  iStat += EqnTest(_T("-2 {m}"), -2e-3, true);
899  iStat += EqnTest(_T("f1of1(1000){m}"), 1, true);
900  iStat += EqnTest(_T("-f1of1(1000){m}"), -1, true);
901  iStat += EqnTest(_T("-f1of1(-1000){m}"), 1, true);
902  iStat += EqnTest(_T("f4of4(0,0,0,1000){m}"), 1, true);
903  iStat += EqnTest(_T("2+(a*1000){m}"), 3, true);
904 
905  // can postfix operators "m" und "meg" be told apart properly?
906  iStat += EqnTest(_T("2*3000meg+2"), 2 * 3e9 + 2, true);
907 
908  // some incorrect results
909  iStat += EqnTest(_T("1000{m}"), 0.1, false);
910  iStat += EqnTest(_T("(a){m}"), 2, false);
911  // failure due to syntax checking
912  iStat += ThrowTest(_T("0x"), ecUNASSIGNABLE_TOKEN); // incomplete hex definition
913  iStat += ThrowTest(_T("3+"), ecUNEXPECTED_EOF);
914  iStat += ThrowTest(_T("4 + {m}"), ecUNASSIGNABLE_TOKEN);
915  iStat += ThrowTest(_T("{m}4"), ecUNASSIGNABLE_TOKEN);
916  iStat += ThrowTest(_T("sin({m})"), ecUNASSIGNABLE_TOKEN);
917  iStat += ThrowTest(_T("{m} {m}"), ecUNASSIGNABLE_TOKEN);
918  iStat += ThrowTest(_T("{m}(8)"), ecUNASSIGNABLE_TOKEN);
919  iStat += ThrowTest(_T("4,{m}"), ecUNASSIGNABLE_TOKEN);
920  iStat += ThrowTest(_T("-{m}"), ecUNASSIGNABLE_TOKEN);
921  iStat += ThrowTest(_T("2(-{m})"), ecUNEXPECTED_PARENS);
922  iStat += ThrowTest(_T("2({m})"), ecUNEXPECTED_PARENS);
923 
924  iStat += ThrowTest(_T("multi*1.0"), ecUNASSIGNABLE_TOKEN);
925 
926  if (iStat == 0)
927  mu::console() << _T("passed") << endl;
928  else
929  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
930 
931  return iStat;
932  }
933 
934  //---------------------------------------------------------------------------
935  int ParserTester::TestExpression()
936  {
937  int iStat = 0;
938  mu::console() << _T("testing expression samples...");
939 
940  value_type b = 2;
941 
942  iStat += EqnTest(_T("f0()"), 42, true);
943  iStat += EqnTest(_T("b^2"), 4, true);
944  iStat += EqnTest(_T("b^1"), 2, true);
945  iStat += EqnTest(_T("b^0"), 1, true);
946  iStat += EqnTest(_T("b^-1"), 0.5, true);
947 
948  // Optimization
949  iStat += EqnTest(_T("2*b*5"), 20, true);
950  iStat += EqnTest(_T("2*b*5 + 4*b"), 28, true);
951  iStat += EqnTest(_T("2*a/3"), 2.0 / 3.0, true);
952 
953  // Addition auf cmVARMUL
954  iStat += EqnTest(_T("3+b"), b + 3, true);
955  iStat += EqnTest(_T("b+3"), b + 3, true);
956  iStat += EqnTest(_T("b*3+2"), b * 3 + 2, true);
957  iStat += EqnTest(_T("3*b+2"), b * 3 + 2, true);
958  iStat += EqnTest(_T("2+b*3"), b * 3 + 2, true);
959  iStat += EqnTest(_T("2+3*b"), b * 3 + 2, true);
960  iStat += EqnTest(_T("b+3*b"), b + 3 * b, true);
961  iStat += EqnTest(_T("3*b+b"), b + 3 * b, true);
962 
963  iStat += EqnTest(_T("2+b*3+b"), 2 + b * 3 + b, true);
964  iStat += EqnTest(_T("b+2+b*3"), b + 2 + b * 3, true);
965 
966  iStat += EqnTest(_T("(2*b+1)*4"), (2 * b + 1) * 4, true);
967  iStat += EqnTest(_T("4*(2*b+1)"), (2 * b + 1) * 4, true);
968 
969  // operator precedences
970  iStat += EqnTest(_T("1+2-3*4/5^6"), 2.99923, true);
971  iStat += EqnTest(_T("1^2/3*4-5+6"), 2.33333333, true);
972  iStat += EqnTest(_T("1+2*3"), 7, true);
973  iStat += EqnTest(_T("1+2*3"), 7, true);
974  iStat += EqnTest(_T("(1+2)*3"), 9, true);
975  iStat += EqnTest(_T("(1+2)*(-3)"), -9, true);
976  iStat += EqnTest(_T("2/4"), 0.5, true);
977 
978  iStat += EqnTest(_T("exp(ln(7))"), 7, true);
979  iStat += EqnTest(_T("e^ln(7)"), 7, true);
980  iStat += EqnTest(_T("e^(ln(7))"), 7, true);
981  iStat += EqnTest(_T("(e^(ln(7)))"), 7, true);
982  iStat += EqnTest(_T("1-(e^(ln(7)))"), -6, true);
983  iStat += EqnTest(_T("2*(e^(ln(7)))"), 14, true);
984  iStat += EqnTest(_T("10^log(5)"), pow(10.0, log(5.0)), true);
985  iStat += EqnTest(_T("10^log10(5)"), 5, true);
986  iStat += EqnTest(_T("2^log2(4)"), 4, true);
987  iStat += EqnTest(_T("-(sin(0)+1)"), -1, true);
988  iStat += EqnTest(_T("-(2^1.1)"), -2.14354692, true);
989 
990  iStat += EqnTest(_T("(cos(2.41)/b)"), -0.372056, true);
991  iStat += EqnTest(_T("(1*(2*(3*(4*(5*(6*(a+b)))))))"), 2160, true);
992  iStat += EqnTest(_T("(1*(2*(3*(4*(5*(6*(7*(a+b))))))))"), 15120, true);
993  iStat += EqnTest(_T("(a/((((b+(((e*(((((pi*((((3.45*((pi+a)+pi))+b)+b)*a))+0.68)+e)+a)/a))+a)+b))+b)*a)-pi))"), 0.00377999, true);
994 
995  // long formula (Reference: Matlab)
996  iStat += EqnTest(
997  _T("(((-9))-e/(((((((pi-(((-7)+(-3)/4/e))))/(((-5))-2)-((pi+(-0))*(sqrt((e+e))*(-8))*(((-pi)+(-pi)-(-9)*(6*5))")
998  _T("/(-e)-e))/2)/((((sqrt(2/(-e)+6)-(4-2))+((5/(-2))/(1*(-pi)+3))/8)*pi*((pi/((-2)/(-6)*1*(-1))*(-6)+(-e)))))/")
999  _T("((e+(-2)+(-e)*((((-3)*9+(-e)))+(-9)))))))-((((e-7+(((5/pi-(3/1+pi)))))/e)/(-5))/(sqrt((((((1+(-7))))+((((-")
1000  _T("e)*(-e)))-8))*(-5)/((-e)))*(-6)-((((((-2)-(-9)-(-e)-1)/3))))/(sqrt((8+(e-((-6))+(9*(-9))))*(((3+2-8))*(7+6")
1001  _T("+(-5))+((0/(-e)*(-pi))+7)))+(((((-e)/e/e)+((-6)*5)*e+(3+(-5)/pi))))+pi))/sqrt((((9))+((((pi))-8+2))+pi))/e")
1002  _T("*4)*((-5)/(((-pi))*(sqrt(e)))))-(((((((-e)*(e)-pi))/4+(pi)*(-9)))))))+(-pi)"), -12.23016549, true);
1003 
1004  // long formula (Reference: Matlab)
1005  iStat += EqnTest(
1006  _T("(atan(sin((((((((((((((((pi/cos((a/((((0.53-b)-pi)*e)/b))))+2.51)+a)-0.54)/0.98)+b)*b)+e)/a)+b)+a)+b)+pi)/e")
1007  _T(")+a)))*2.77)"), -2.16995656, true);
1008 
1009  // long formula (Reference: Matlab)
1010  iStat += EqnTest(_T("1+2-3*4/5^6*(2*(1-5+(3*7^9)*(4+6*7-3)))+12"), -7995810.09926, true);
1011 
1012  if (iStat == 0)
1013  mu::console() << _T("passed") << endl;
1014  else
1015  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
1016 
1017  return iStat;
1018  }
1019 
1020 
1021 
1022  //---------------------------------------------------------------------------
1023  int ParserTester::TestIfThenElse()
1024  {
1025  int iStat = 0;
1026  mu::console() << _T("testing if-then-else operator...");
1027 
1028  // from oss-fuzz.com: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=24167
1029  iStat += ThrowTest(_T(R"(0^3^avg(0>3?4:(""),0^3?4:("")))"), ecUNEXPECTED_STR);
1030  // derivatives
1031  iStat += ThrowTest(_T(R"(avg(0?(""):4,1))"), ecUNEXPECTED_STR);
1032  iStat += ThrowTest(_T(R"(avg(0>3?4:(""),0^3?4:("")))"), ecUNEXPECTED_STR);
1033 
1034  iStat += ThrowTest(_T(R"(0?4:(""))"), ecUNEXPECTED_STR);
1035  iStat += ThrowTest(_T(R"((0)?4:(""))"), ecUNEXPECTED_STR);
1036  iStat += ThrowTest(_T(R"((0>3)?4:(""))"), ecUNEXPECTED_STR);
1037  iStat += ThrowTest(_T(R"(0>3?4:(""))"), ecUNEXPECTED_STR);
1038 
1039  // from oss-fuzz.com: https://oss-fuzz.com/testcase-detail/4777121158529024
1040  iStat += ThrowTest(_T("3!=min(0?2>2,2>5,1:6)"), ecUNEXPECTED_ARG_SEP);
1041 
1042  // Test error detection
1043  iStat += ThrowTest(_T(":3"), ecUNEXPECTED_CONDITIONAL);
1044  iStat += ThrowTest(_T("? 1 : 2"), ecUNEXPECTED_CONDITIONAL);
1045  iStat += ThrowTest(_T("(a<b) ? (b<c) ? 1 : 2"), ecMISSING_ELSE_CLAUSE);
1046  iStat += ThrowTest(_T("(a<b) ? 1"), ecMISSING_ELSE_CLAUSE);
1047  iStat += ThrowTest(_T("(a<b) ? a"), ecMISSING_ELSE_CLAUSE);
1048  iStat += ThrowTest(_T("(a<b) ? a+b"), ecMISSING_ELSE_CLAUSE);
1049  iStat += ThrowTest(_T("a : b"), ecMISPLACED_COLON);
1050  iStat += ThrowTest(_T("1 : 2"), ecMISPLACED_COLON);
1051  iStat += ThrowTest(_T("(1) ? 1 : 2 : 3"), ecMISPLACED_COLON);
1052  iStat += ThrowTest(_T("(true) ? 1 : 2 : 3"), ecUNASSIGNABLE_TOKEN);
1053 
1054  // from oss-fzz.com: UNKNOWN READ; https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=22922#c1
1055  iStat += ThrowTest(_T("1?2:0?(7:1)"), ecMISPLACED_COLON);
1056 
1057  // from oss-fuzz.com: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=22938
1058  iStat += ThrowTest(_T("sum(0?1,0,0:3)"), ecUNEXPECTED_ARG_SEP);
1059  iStat += ThrowTest(_T("sum(0?(1,0,0):3)"), ecUNEXPECTED_ARG);
1060  iStat += ThrowTest(_T("sum(2>3?2,4,2:4)"), ecUNEXPECTED_ARG_SEP);
1061  iStat += ThrowTest(_T("sum(2>3?2,4,sin(2):4)"), ecUNEXPECTED_ARG_SEP);
1062  iStat += ThrowTest(_T("sum(2>3?sin(2),4,2:4)"), ecUNEXPECTED_ARG_SEP);
1063  iStat += ThrowTest(_T("sum(2>3?sin(a),4,2:4)"), ecUNEXPECTED_ARG_SEP);
1064  iStat += ThrowTest(_T("sum(2>3?sin(2),4,2:4)"), ecUNEXPECTED_ARG_SEP);
1065 
1066  iStat += EqnTest(_T("1 ? 128 : 255"), 128, true);
1067  iStat += EqnTest(_T("1<2 ? 128 : 255"), 128, true);
1068  iStat += EqnTest(_T("a<b ? 128 : 255"), 128, true);
1069  iStat += EqnTest(_T("(a<b) ? 128 : 255"), 128, true);
1070  iStat += EqnTest(_T("(1) ? 10 : 11"), 10, true);
1071  iStat += EqnTest(_T("(0) ? 10 : 11"), 11, true);
1072  iStat += EqnTest(_T("(1) ? a+b : c+d"), 3, true);
1073  iStat += EqnTest(_T("(0) ? a+b : c+d"), 1, true);
1074  iStat += EqnTest(_T("(1) ? 0 : 1"), 0, true);
1075  iStat += EqnTest(_T("(0) ? 0 : 1"), 1, true);
1076  iStat += EqnTest(_T("(a<b) ? 10 : 11"), 10, true);
1077  iStat += EqnTest(_T("(a>b) ? 10 : 11"), 11, true);
1078  iStat += EqnTest(_T("(a<b) ? c : d"), 3, true);
1079  iStat += EqnTest(_T("(a>b) ? c : d"), -2, true);
1080 
1081  iStat += EqnTest(_T("(a>b) ? 1 : 0"), 0, true);
1082  iStat += EqnTest(_T("((a>b) ? 1 : 0) ? 1 : 2"), 2, true);
1083  iStat += EqnTest(_T("((a>b) ? 1 : 0) ? 1 : sum((a>b) ? 1 : 2)"), 2, true);
1084  iStat += EqnTest(_T("((a>b) ? 0 : 1) ? 1 : sum((a>b) ? 1 : 2)"), 1, true);
1085 
1086  iStat += EqnTest(_T("sum((a>b) ? 1 : 2)"), 2, true);
1087  iStat += EqnTest(_T("sum((1) ? 1 : 2)"), 1, true);
1088  iStat += EqnTest(_T("sum((a>b) ? 1 : 2, 100)"), 102, true);
1089  iStat += EqnTest(_T("sum((1) ? 1 : 2, 100)"), 101, true);
1090  iStat += EqnTest(_T("sum(3, (a>b) ? 3 : 10)"), 13, true);
1091  iStat += EqnTest(_T("sum(3, (a<b) ? 3 : 10)"), 6, true);
1092  iStat += EqnTest(_T("10*sum(3, (a>b) ? 3 : 10)"), 130, true);
1093  iStat += EqnTest(_T("10*sum(3, (a<b) ? 3 : 10)"), 60, true);
1094  iStat += EqnTest(_T("sum(3, (a>b) ? 3 : 10)*10"), 130, true);
1095  iStat += EqnTest(_T("sum(3, (a<b) ? 3 : 10)*10"), 60, true);
1096  iStat += EqnTest(_T("(a<b) ? sum(3, (a<b) ? 3 : 10)*10 : 99"), 60, true);
1097  iStat += EqnTest(_T("(a>b) ? sum(3, (a<b) ? 3 : 10)*10 : 99"), 99, true);
1098  iStat += EqnTest(_T("(a<b) ? sum(3, (a<b) ? 3 : 10,10,20)*10 : 99"), 360, true);
1099  iStat += EqnTest(_T("(a>b) ? sum(3, (a<b) ? 3 : 10,10,20)*10 : 99"), 99, true);
1100  iStat += EqnTest(_T("(a>b) ? sum(3, (a<b) ? 3 : 10,10,20)*10 : sum(3, (a<b) ? 3 : 10)*10"), 60, true);
1101 
1102  // todo: also add for muParserX!
1103  iStat += EqnTest(_T("(a<b)&&(a<b) ? 128 : 255"), 128, true);
1104  iStat += EqnTest(_T("(a>b)&&(a<b) ? 128 : 255"), 255, true);
1105  iStat += EqnTest(_T("(1<2)&&(1<2) ? 128 : 255"), 128, true);
1106  iStat += EqnTest(_T("(1>2)&&(1<2) ? 128 : 255"), 255, true);
1107  iStat += EqnTest(_T("((1<2)&&(1<2)) ? 128 : 255"), 128, true);
1108  iStat += EqnTest(_T("((1>2)&&(1<2)) ? 128 : 255"), 255, true);
1109  iStat += EqnTest(_T("((a<b)&&(a<b)) ? 128 : 255"), 128, true);
1110  iStat += EqnTest(_T("((a>b)&&(a<b)) ? 128 : 255"), 255, true);
1111 
1112  iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 64"), 255, true);
1113  iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 :(1>0 ? 32 : 64)"), 255, true);
1114  iStat += EqnTest(_T("1>0 ? 1>0 ? 128 : 255 : 1>2 ? 32 : 64"), 128, true);
1115  iStat += EqnTest(_T("1>0 ? 1>0 ? 128 : 255 :(1>2 ? 32 : 64)"), 128, true);
1116  iStat += EqnTest(_T("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 64"), 32, true);
1117  iStat += EqnTest(_T("1>2 ? 1>0 ? 128 : 255 : 1>2 ? 32 : 64"), 64, true);
1118  iStat += EqnTest(_T("1>0 ? 50 : 1>0 ? 128 : 255"), 50, true);
1119  iStat += EqnTest(_T("1>0 ? 50 : (1>0 ? 128 : 255)"), 50, true);
1120  iStat += EqnTest(_T("1>0 ? 1>0 ? 128 : 255 : 50"), 128, true);
1121  iStat += EqnTest(_T("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 1>2 ? 64 : 16"), 32, true);
1122  iStat += EqnTest(_T("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 :(1>2 ? 64 : 16)"), 32, true);
1123  iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 : 1>0 ? 32 :1>2 ? 64 : 16"), 255, true);
1124  iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 : (1>0 ? 32 :1>2 ? 64 : 16)"), 255, true);
1125  iStat += EqnTest(_T("1 ? 0 ? 128 : 255 : 1 ? 32 : 64"), 255, true);
1126 
1127  // assignment operators
1128  iStat += EqnTest(_T("a= 0 ? 128 : 255, a"), 255, true);
1129  iStat += EqnTest(_T("a=((a>b)&&(a<b)) ? 128 : 255, a"), 255, true);
1130  iStat += EqnTest(_T("c=(a<b)&&(a<b) ? 128 : 255, c"), 128, true);
1131  iStat += EqnTest(_T("0 ? a=a+1 : 666, a"), 1, true);
1132  iStat += EqnTest(_T("1?a=10:a=20, a"), 10, true);
1133  iStat += EqnTest(_T("0?a=10:a=20, a"), 20, true);
1134  iStat += EqnTest(_T("0?a=sum(3,4):10, a"), 1, true); // a should not change its value due to lazy calculation
1135 
1136  iStat += EqnTest(_T("a=1?b=1?3:4:5, a"), 3, true);
1137  iStat += EqnTest(_T("a=1?b=1?3:4:5, b"), 3, true);
1138  iStat += EqnTest(_T("a=0?b=1?3:4:5, a"), 5, true);
1139  iStat += EqnTest(_T("a=0?b=1?3:4:5, b"), 2, true);
1140 
1141  iStat += EqnTest(_T("a=1?5:b=1?3:4, a"), 5, true);
1142  iStat += EqnTest(_T("a=1?5:b=1?3:4, b"), 2, true);
1143  iStat += EqnTest(_T("a=0?5:b=1?3:4, a"), 3, true);
1144  iStat += EqnTest(_T("a=0?5:b=1?3:4, b"), 3, true);
1145 
1146  if (iStat == 0)
1147  mu::console() << _T("passed") << endl;
1148  else
1149  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
1150 
1151  return iStat;
1152  }
1153 
1154  //---------------------------------------------------------------------------
1155  int ParserTester::TestException()
1156  {
1157  int iStat = 0;
1158  mu::console() << _T("testing error codes...");
1159 
1160  iStat += ThrowTest(_T("3+"), ecUNEXPECTED_EOF);
1161  iStat += ThrowTest(_T("3+)"), ecUNEXPECTED_PARENS);
1162  iStat += ThrowTest(_T("()"), ecUNEXPECTED_PARENS);
1163  iStat += ThrowTest(_T("3+()"), ecUNEXPECTED_PARENS);
1164  iStat += ThrowTest(_T("sin(3,4)"), ecTOO_MANY_PARAMS);
1165  iStat += ThrowTest(_T("sin()"), ecTOO_FEW_PARAMS);
1166  iStat += ThrowTest(_T("(1+2"), ecMISSING_PARENS);
1167  iStat += ThrowTest(_T("sin(3)3"), ecUNEXPECTED_VAL);
1168  iStat += ThrowTest(_T("sin(3)xyz"), ecUNASSIGNABLE_TOKEN);
1169  iStat += ThrowTest(_T("sin(3)cos(3)"), ecUNEXPECTED_FUN);
1170  iStat += ThrowTest(_T("a+b+c=10"), ecUNEXPECTED_OPERATOR);
1171  iStat += ThrowTest(_T("a=b=3"), ecUNEXPECTED_OPERATOR);
1172 
1173  // functions without parameter
1174  iStat += ThrowTest(_T("3+ping(2)"), ecTOO_MANY_PARAMS);
1175  iStat += ThrowTest(_T("3+ping(a+2)"), ecTOO_MANY_PARAMS);
1176  iStat += ThrowTest(_T("3+ping(sin(a)+2)"), ecTOO_MANY_PARAMS);
1177  iStat += ThrowTest(_T("3+ping(1+sin(a))"), ecTOO_MANY_PARAMS);
1178 
1179  // String function related
1180  iStat += ThrowTest(_T("valueof(\"xxx\")"), 999, false);
1181  iStat += ThrowTest(_T("valueof()"), ecUNEXPECTED_PARENS);
1182  iStat += ThrowTest(_T("1+valueof(\"abc\""), ecMISSING_PARENS);
1183  iStat += ThrowTest(_T("valueof(\"abc\""), ecMISSING_PARENS);
1184  iStat += ThrowTest(_T("valueof(\"abc"), ecUNTERMINATED_STRING);
1185  iStat += ThrowTest(_T("valueof(\"abc\",3)"), ecTOO_MANY_PARAMS);
1186  iStat += ThrowTest(_T("valueof(3)"), ecSTRING_EXPECTED);
1187  iStat += ThrowTest(_T("sin(\"abc\")"), ecVAL_EXPECTED);
1188  iStat += ThrowTest(_T("valueof(\"\\\"abc\\\"\")"), 999, false);
1189  iStat += ThrowTest(_T("\"hello world\""), ecSTR_RESULT);
1190  iStat += ThrowTest(_T("(\"hello world\")"), ecSTR_RESULT);
1191  iStat += ThrowTest(_T("\"abcd\"+100"), ecSTR_RESULT);
1192  iStat += ThrowTest(_T("\"a\"+\"b\""), ecSTR_RESULT);
1193  iStat += ThrowTest(_T("strfun1(\"100\",3)"), ecTOO_MANY_PARAMS);
1194  iStat += ThrowTest(_T("strfun2(\"100\",3,5)"), ecTOO_MANY_PARAMS);
1195  iStat += ThrowTest(_T("strfun3(\"100\",3,5,6)"), ecTOO_MANY_PARAMS);
1196  iStat += ThrowTest(_T("strfun2(\"100\")"), ecTOO_FEW_PARAMS);
1197  iStat += ThrowTest(_T("strfun3(\"100\",6)"), ecTOO_FEW_PARAMS);
1198  iStat += ThrowTest(_T("strfun2(1,1)"), ecSTRING_EXPECTED);
1199  iStat += ThrowTest(_T("strfun2(a,1)"), ecSTRING_EXPECTED);
1200  iStat += ThrowTest(_T("strfun2(1,1,1)"), ecTOO_MANY_PARAMS);
1201  iStat += ThrowTest(_T("strfun2(a,1,1)"), ecTOO_MANY_PARAMS);
1202  iStat += ThrowTest(_T("strfun3(1,2,3)"), ecSTRING_EXPECTED);
1203  iStat += ThrowTest(_T("strfun3(1, \"100\",3)"), ecSTRING_EXPECTED);
1204  iStat += ThrowTest(_T("strfun3(\"1\", \"100\",3)"), ecVAL_EXPECTED);
1205  iStat += ThrowTest(_T("strfun3(\"1\", 3, \"100\")"), ecVAL_EXPECTED);
1206  iStat += ThrowTest(_T("strfun3(\"1\", \"100\", \"100\", \"100\")"), ecTOO_MANY_PARAMS);
1207 
1208  // assignment operator
1209  iStat += ThrowTest(_T("3=4"), ecUNEXPECTED_OPERATOR);
1210  iStat += ThrowTest(_T("sin(8)=4"), ecUNEXPECTED_OPERATOR);
1211  iStat += ThrowTest(_T("\"test\"=a"), ecSTR_RESULT);
1212 
1213  // <ibg 20090529>
1214  // this is now legal, for reference see:
1215  // https://sourceforge.net/forum/message.php?msg_id=7411373
1216  // iStat += ThrowTest( _T("sin=9"), ecUNEXPECTED_OPERATOR);
1217  // </ibg>
1218 
1219  iStat += ThrowTest(_T("(8)=5"), ecUNEXPECTED_OPERATOR);
1220  iStat += ThrowTest(_T("(a)=5"), ecUNEXPECTED_OPERATOR);
1221  iStat += ThrowTest(_T("a=\"tttt\""), ecOPRT_TYPE_CONFLICT);
1222 
1223  if (iStat == 0)
1224  mu::console() << _T("passed") << endl;
1225  else
1226  mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
1227 
1228  return iStat;
1229  }
1230 
1231 
1232  //---------------------------------------------------------------------------
1233  void ParserTester::AddTest(testfun_type a_pFun)
1234  {
1235  m_vTestFun.push_back(a_pFun);
1236  }
1237 
1238  //---------------------------------------------------------------------------
1239  int ParserTester::Run()
1240  {
1241  int iStat = 0;
1242  try
1243  {
1244  for (int i = 0; i < (int)m_vTestFun.size(); ++i)
1245  iStat += (this->*m_vTestFun[i])();
1246  }
1247  catch (Parser::exception_type& e)
1248  {
1249  mu::console() << "\n" << e.GetMsg() << endl;
1250  mu::console() << e.GetToken() << endl;
1251  Abort();
1252  }
1253  catch (std::exception& e)
1254  {
1255  mu::console() << e.what() << endl;
1256  Abort();
1257  }
1258  catch (...)
1259  {
1260  mu::console() << "Internal error";
1261  Abort();
1262  }
1263 
1264  if (iStat == 0)
1265  {
1266  mu::console() << "Test passed (" << ParserTester::c_iCount << " expressions)" << endl;
1267  }
1268  else
1269  {
1270  mu::console() << "Test failed with " << iStat
1271  << " errors (" << ParserTester::c_iCount
1272  << " expressions)" << endl;
1273  }
1274  ParserTester::c_iCount = 0;
1275  return iStat;
1276  }
1277 
1278 
1279  //---------------------------------------------------------------------------
1280  int ParserTester::ThrowTest(const string_type& a_str, int a_iErrc, bool a_expectedToFail)
1281  {
1282  ParserTester::c_iCount++;
1283 
1284  try
1285  {
1286  value_type fVal[] = { 1,1,1 };
1287  Parser p;
1288 
1289  p.DefineVar(_T("a"), &fVal[0]);
1290  p.DefineVar(_T("b"), &fVal[1]);
1291  p.DefineVar(_T("c"), &fVal[2]);
1292  p.DefinePostfixOprt(_T("{m}"), Milli);
1293  p.DefinePostfixOprt(_T("m"), Milli);
1294  p.DefineFun(_T("ping"), Ping);
1295  p.DefineFun(_T("valueof"), ValueOf);
1296  p.DefineFun(_T("strfun1"), StrFun1);
1297  p.DefineFun(_T("strfun2"), StrFun2);
1298  p.DefineFun(_T("strfun3"), StrFun3);
1299  p.DefineFun(_T("strfun4"), StrFun4);
1300  p.DefineFun(_T("strfun5"), StrFun5);
1301  p.DefineFun(_T("strfun6"), StrFun6);
1302  p.SetExpr(a_str);
1303  // p.EnableDebugDump(1, 0);
1304  p.Eval();
1305  }
1306  catch (ParserError& e)
1307  {
1308  // output the formula in case of an failed test
1309  if (a_expectedToFail == false || (a_expectedToFail == true && a_iErrc != e.GetCode()))
1310  {
1311  mu::console() << _T("\n ")
1312  << _T("Expression: ") << a_str
1313  << _T(" Code:") << e.GetCode() << _T("(") << e.GetMsg() << _T(")")
1314  << _T(" Expected:") << a_iErrc;
1315  }
1316 
1317  return (a_iErrc == e.GetCode()) ? 0 : 1;
1318  }
1319 
1320  // if a_expectedToFail == false no exception is expected
1321  bool bRet((a_expectedToFail == false) ? 0 : 1);
1322  if (bRet == 1)
1323  {
1324  mu::console() << _T("\n ")
1325  << _T("Expression: ") << a_str
1326  << _T(" did evaluate; Expected error:") << a_iErrc;
1327  }
1328 
1329  return bRet;
1330  }
1331 
1332  //---------------------------------------------------------------------------
1333  /** \brief Evaluate a tet expression.
1334 
1335  \return 1 in case of a failure, 0 otherwise.
1336  */
1337  int ParserTester::EqnTestWithVarChange(const string_type& a_str,
1338  double a_fVar1,
1339  double a_fRes1,
1340  double a_fVar2,
1341  double a_fRes2)
1342  {
1343  ParserTester::c_iCount++;
1344 
1345  try
1346  {
1347  value_type fVal[2] = { -999, -999 }; // should be equal
1348 
1349  Parser p;
1350  value_type var = 0;
1351 
1352  // variable
1353  p.DefineVar(_T("a"), &var);
1354  p.SetExpr(a_str);
1355 
1356  var = a_fVar1;
1357  fVal[0] = p.Eval();
1358 
1359  var = a_fVar2;
1360  fVal[1] = p.Eval();
1361 
1362  if (fabs(a_fRes1 - fVal[0]) > 0.0000000001)
1363  throw std::runtime_error("incorrect result (first pass)");
1364 
1365  if (fabs(a_fRes2 - fVal[1]) > 0.0000000001)
1366  throw std::runtime_error("incorrect result (second pass)");
1367  }
1368  catch (Parser::exception_type& e)
1369  {
1370  mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.GetMsg() << _T(")");
1371  return 1;
1372  }
1373  catch (std::exception& e)
1374  {
1375  mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.what() << _T(")");
1376  return 1; // always return a failure since this exception is not expected
1377  }
1378  catch (...)
1379  {
1380  mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)");
1381  return 1; // exceptions other than ParserException are not allowed
1382  }
1383 
1384  return 0;
1385  }
1386 
1387  //---------------------------------------------------------------------------
1388  /** \brief Evaluate a tet expression.
1389 
1390  \return 1 in case of a failure, 0 otherwise.
1391  */
1392  int ParserTester::EqnTest(const string_type& a_str, double a_fRes, bool a_fPass)
1393  {
1394  ParserTester::c_iCount++;
1395  int iRet(0);
1396  value_type fVal[6] = { -999, -998, -997, -996, -995, -994 }; // initially should be different
1397 
1398  try
1399  {
1400  std::unique_ptr<Parser> p1;
1401  Parser p2, p3; // three parser objects
1402  // they will be used for testing copy and assignment operators
1403  // p1 is a pointer since i'm going to delete it in order to test if
1404  // parsers after copy construction still refer to members of it.
1405  // !! If this is the case this function will crash !!
1406 
1407  p1.reset(new mu::Parser());
1408  // Add constants
1409  p1->DefineConst(_T("pi"), MathImpl<value_type>::CONST_PI);
1410  p1->DefineConst(_T("e"), MathImpl<value_type>::CONST_E);
1411  p1->DefineConst(_T("const"), 1);
1412  p1->DefineConst(_T("const1"), 2);
1413  p1->DefineConst(_T("const2"), 3);
1414  // string constants
1415  p1->DefineStrConst(_T("str1"), _T("1.11"));
1416  p1->DefineStrConst(_T("str2"), _T("2.22"));
1417  // variables
1418  value_type vVarVal[] = { 1, 2, 3, -2 };
1419  p1->DefineVar(_T("a"), &vVarVal[0]);
1420  p1->DefineVar(_T("aa"), &vVarVal[1]);
1421  p1->DefineVar(_T("b"), &vVarVal[1]);
1422  p1->DefineVar(_T("c"), &vVarVal[2]);
1423  p1->DefineVar(_T("d"), &vVarVal[3]);
1424 
1425  // custom value ident functions
1426  p1->AddValIdent(&ParserTester::IsHexVal);
1427 
1428  // functions
1429  p1->DefineFun(_T("ping"), Ping);
1430  p1->DefineFun(_T("f0"), f0); // no parameter
1431  p1->DefineFun(_T("f1of1"), f1of1); // one parameter
1432  p1->DefineFun(_T("f1of2"), f1of2); // two parameter
1433  p1->DefineFun(_T("f2of2"), f2of2);
1434  p1->DefineFun(_T("f1of3"), f1of3); // three parameter
1435  p1->DefineFun(_T("f2of3"), f2of3);
1436  p1->DefineFun(_T("f3of3"), f3of3);
1437  p1->DefineFun(_T("f1of4"), f1of4); // four parameter
1438  p1->DefineFun(_T("f2of4"), f2of4);
1439  p1->DefineFun(_T("f3of4"), f3of4);
1440  p1->DefineFun(_T("f4of4"), f4of4);
1441  p1->DefineFun(_T("f1of5"), f1of5); // five parameter
1442  p1->DefineFun(_T("f2of5"), f2of5);
1443  p1->DefineFun(_T("f3of5"), f3of5);
1444  p1->DefineFun(_T("f4of5"), f4of5);
1445  p1->DefineFun(_T("f5of5"), f5of5);
1446 
1447  // binary operators
1448  p1->DefineOprt(_T("add"), add, 0);
1449  p1->DefineOprt(_T("++"), add, 0);
1450  p1->DefineOprt(_T("&"), land, prLAND);
1451 
1452  // sample functions
1453  p1->DefineFun(_T("min"), Min);
1454  p1->DefineFun(_T("max"), Max);
1455  p1->DefineFun(_T("sum"), Sum);
1456  p1->DefineFun(_T("valueof"), ValueOf);
1457  p1->DefineFun(_T("atof"), StrToFloat);
1458  p1->DefineFun(_T("strfun1"), StrFun1);
1459  p1->DefineFun(_T("strfun2"), StrFun2);
1460  p1->DefineFun(_T("strfun3"), StrFun3);
1461  p1->DefineFun(_T("strfun4"), StrFun4);
1462  p1->DefineFun(_T("strfun5"), StrFun5);
1463  p1->DefineFun(_T("strfun6"), StrFun6);
1464  p1->DefineFun(_T("lastArg"), LastArg);
1465  p1->DefineFun(_T("firstArg"), FirstArg);
1466  p1->DefineFun(_T("order"), FirstArg);
1467 
1468  // functions with user data
1469  p1->DefineFunUserData(_T("funud0_8"), FunUd0, reinterpret_cast<void*>(8));
1470  p1->DefineFunUserData(_T("funud1_16"), FunUd1, reinterpret_cast<void*>(16));
1471  p1->DefineFunUserData(_T("funud2_24"), FunUd2, reinterpret_cast<void*>(24));
1472  p1->DefineFunUserData(_T("funud10_32"), FunUd10, reinterpret_cast<void*>(32));
1473  p1->DefineFunUserData(_T("funud0_9"), FunUd0, reinterpret_cast<void*>(9));
1474  p1->DefineFunUserData(_T("funud1_17"), FunUd1, reinterpret_cast<void*>(17));
1475  p1->DefineFunUserData(_T("funud2_25"), FunUd2, reinterpret_cast<void*>(25));
1476  p1->DefineFunUserData(_T("funud10_33"), FunUd10, reinterpret_cast<void*>(33));
1477  p1->DefineFunUserData(_T("strfunud3_10"), StrFunUd3, reinterpret_cast<void*>(10));
1478  p1->DefineFunUserData(_T("sumud_100"), SumUd, reinterpret_cast<void*>(100));
1479 
1480  // infix / postfix operator
1481  // Note: Identifiers used here do not have any meaning
1482  // they are mere placeholders to test certain features.
1483  p1->DefineInfixOprt(_T("$"), sign, prPOW + 1); // sign with high priority
1484  p1->DefineInfixOprt(_T("~"), plus2); // high priority
1485  p1->DefineInfixOprt(_T("~~"), plus2);
1486  p1->DefinePostfixOprt(_T("{m}"), Milli);
1487  p1->DefinePostfixOprt(_T("{M}"), Mega);
1488  p1->DefinePostfixOprt(_T("m"), Milli);
1489  p1->DefinePostfixOprt(_T("meg"), Mega);
1490  p1->DefinePostfixOprt(_T("#"), times3);
1491  p1->DefinePostfixOprt(_T("'"), sqr);
1492  p1->SetExpr(a_str);
1493 
1494  // Test bytecode integrity
1495  // String parsing and bytecode parsing must yield the same result
1496  fVal[0] = p1->Eval(); // result from stringparsing
1497  fVal[1] = p1->Eval(); // result from bytecode
1498  if (fVal[0] != fVal[1])
1499  throw Parser::exception_type(_T("Bytecode / string parsing mismatch."));
1500 
1501  // Test copy and assignment operators
1502  try
1503  {
1504  // Test copy constructor
1505  std::vector<mu::Parser> vParser;
1506  vParser.push_back(*(p1.get()));
1507  mu::Parser p4 = vParser[0]; // take parser from vector
1508 
1509  // destroy the originals from p2
1510  vParser.clear(); // delete the vector
1511  p1.reset(nullptr);
1512 
1513  fVal[2] = p4.Eval();
1514 
1515  // Test assignment operator
1516  // additionally disable Optimizer this time
1517  mu::Parser p5;
1518  p5 = p4;
1519  p5.EnableOptimizer(false);
1520  fVal[3] = p5.Eval();
1521 
1522  // Test Eval function for multiple return values
1523  // use p2 since it has the optimizer enabled!
1524  int nNum;
1525  p4.SetExpr(a_str); // reset bytecode to trigger #94 (https://github.com/beltoforion/muparser/issues/94)
1526  value_type* v = p4.Eval(nNum);
1527  fVal[4] = v[nNum - 1];
1528 
1529  v = p4.Eval(nNum);
1530  fVal[5] = v[nNum - 1];
1531 
1532  }
1533  catch (std::exception& e)
1534  {
1535  mu::console() << _T("\n ") << e.what() << _T("\n");
1536  }
1537 
1538  // limited floating point accuracy requires the following test
1539  bool bCloseEnough(true);
1540  for (unsigned i = 0; i < sizeof(fVal) / sizeof(value_type); ++i)
1541  {
1542  bCloseEnough &= (fabs(a_fRes - fVal[i]) <= fabs(fVal[i] * 0.00001));
1543 
1544  // The tests equations never result in infinity, if they do thats a bug.
1545  // reference:
1546  // http://sourceforge.net/projects/muparser/forums/forum/462843/topic/5037825
1547 #ifdef _MSC_VER
1548 #pragma warning(push)
1549 #pragma warning(disable:4127)
1550 #endif
1551  if (std::numeric_limits<value_type>::has_infinity)
1552 #ifdef _MSC_VER
1553 #pragma warning(pop)
1554 #endif
1555  {
1556  bCloseEnough &= (fabs(fVal[i]) != numeric_limits<value_type>::infinity());
1557  }
1558  }
1559 
1560  iRet = ((bCloseEnough && a_fPass) || (!bCloseEnough && !a_fPass)) ? 0 : 1;
1561 
1562 
1563  if (iRet == 1)
1564  {
1565  mu::console() << _T("\n fail: ") << a_str.c_str()
1566  << _T(" (incorrect result; expected: ") << a_fRes
1567  << _T(" ;calculated: ") << fVal[0] << _T(",")
1568  << fVal[1] << _T(",")
1569  << fVal[2] << _T(",")
1570  << fVal[3] << _T(",")
1571  << fVal[4] << _T(",")
1572  << fVal[5] << _T(").");
1573  }
1574  }
1575  catch (Parser::exception_type& e)
1576  {
1577  if (a_fPass)
1578  {
1579  if (fVal[0] != fVal[2] && fVal[0] != -999 && fVal[1] != -998)
1580  mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (copy construction)");
1581  else
1582  mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.GetMsg() << _T(")");
1583  return 1;
1584  }
1585  }
1586  catch (std::exception& e)
1587  {
1588  mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.what() << _T(")");
1589  return 1; // always return a failure since this exception is not expected
1590  }
1591  catch (...)
1592  {
1593  mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)");
1594  return 1; // exceptions other than ParserException are not allowed
1595  }
1596 
1597  return iRet;
1598  }
1599 
1600  //---------------------------------------------------------------------------
1601  int ParserTester::EqnTestInt(const string_type& a_str, double a_fRes, bool a_fPass)
1602  {
1603  ParserTester::c_iCount++;
1604 
1605  value_type vVarVal[] = { 1, 2, 3 }; // variable values
1606  int iRet(0);
1607 
1608  try
1609  {
1610  value_type fVal[2] = { -99, -999 }; // results: initially should be different
1611  ParserInt p;
1612  p.DefineConst(_T("const1"), 1);
1613  p.DefineConst(_T("const2"), 2);
1614  p.DefineVar(_T("a"), &vVarVal[0]);
1615  p.DefineVar(_T("b"), &vVarVal[1]);
1616  p.DefineVar(_T("c"), &vVarVal[2]);
1617 
1618  p.SetExpr(a_str);
1619  fVal[0] = p.Eval(); // result from stringparsing
1620  fVal[1] = p.Eval(); // result from bytecode
1621 
1622  if (fVal[0] != fVal[1])
1623  throw Parser::exception_type(_T("Bytecode corrupt."));
1624 
1625  iRet = ((a_fRes == fVal[0] && a_fPass) ||
1626  (a_fRes != fVal[0] && !a_fPass)) ? 0 : 1;
1627  if (iRet == 1)
1628  {
1629  mu::console() << _T("\n fail: ") << a_str.c_str()
1630  << _T(" (incorrect result; expected: ") << a_fRes
1631  << _T(" ;calculated: ") << fVal[0] << _T(").");
1632  }
1633  }
1634  catch (Parser::exception_type& e)
1635  {
1636  if (a_fPass)
1637  {
1638  mu::console() << _T("\n fail: ") << e.GetExpr() << _T(" : ") << e.GetMsg();
1639  iRet = 1;
1640  }
1641  }
1642  catch (...)
1643  {
1644  mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)");
1645  iRet = 1; // exceptions other than ParserException are not allowed
1646  }
1647 
1648  return iRet;
1649  }
1650 
1651  //---------------------------------------------------------------------------
1652  /** \brief Test an expression in Bulk Mode. */
1653  int ParserTester::EqnTestBulk(const string_type& a_str, double a_fRes[4], bool a_fPass)
1654  {
1655  ParserTester::c_iCount++;
1656 
1657  // Define Bulk Variables
1658  int nBulkSize = 4;
1659  value_type vVariableA[] = { 1, 2, 3, 4 }; // variable values
1660  value_type vVariableB[] = { 2, 2, 2, 2 }; // variable values
1661  value_type vVariableC[] = { 3, 3, 3, 3 }; // variable values
1662  value_type vResults[] = { 0, 0, 0, 0 }; // variable values
1663  int iRet(0);
1664 
1665  try
1666  {
1667  Parser p;
1668  p.DefineConst(_T("const1"), 1);
1669  p.DefineConst(_T("const2"), 2);
1670  p.DefineVar(_T("a"), vVariableA);
1671  p.DefineVar(_T("b"), vVariableB);
1672  p.DefineVar(_T("c"), vVariableC);
1673 
1674  p.SetExpr(a_str);
1675  p.Eval(vResults, nBulkSize);
1676 
1677  bool bCloseEnough(true);
1678  for (int i = 0; i < nBulkSize; ++i)
1679  {
1680  bCloseEnough &= (fabs(a_fRes[i] - vResults[i]) <= fabs(a_fRes[i] * 0.00001));
1681  }
1682 
1683  iRet = ((bCloseEnough && a_fPass) || (!bCloseEnough && !a_fPass)) ? 0 : 1;
1684  if (iRet == 1)
1685  {
1686  mu::console() << _T("\n fail: ") << a_str.c_str()
1687  << _T(" (incorrect result; expected: {") << a_fRes[0] << _T(",") << a_fRes[1] << _T(",") << a_fRes[2] << _T(",") << a_fRes[3] << _T("}")
1688  << _T(" ;calculated: ") << vResults[0] << _T(",") << vResults[1] << _T(",") << vResults[2] << _T(",") << vResults[3] << _T("}");
1689  }
1690  }
1691  catch (Parser::exception_type& e)
1692  {
1693  if (a_fPass)
1694  {
1695  mu::console() << _T("\n fail: ") << e.GetExpr() << _T(" : ") << e.GetMsg();
1696  iRet = 1;
1697  }
1698  }
1699  catch (...)
1700  {
1701  mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)");
1702  iRet = 1; // exceptions other than ParserException are not allowed
1703  }
1704 
1705  return iRet;
1706  }
1707 
1708  //---------------------------------------------------------------------------
1709  /** \brief Internal error in test class Test is going to be aborted. */
1710  void ParserTester::Abort() const
1711  {
1712  mu::console() << _T("Test failed (internal error in test class)") << endl;
1713  while (!getchar());
1714  exit(-1);
1715  }
1716  } // namespace test
1717 } // namespace mu
void DefinePostfixOprt(const string_type &a_strFun, fun_type1 a_pOprt, bool a_bAllowOpt=true)
Add a user defined operator.
#define _T(x)
Activate this option in order to compile with OpenMP support.
Definition: muParserDef.h:69
const string_type & GetExpr() const
gets the expression related tp this error.
binary operators may only be applied to value items of the same type
Definition: muParserDef.h:245
An unexpected comma has been found. (Example: "1,23")
Definition: muParserDef.h:232
void DefineVar(const string_type &a_sName, value_type *a_fVar)
Add a user defined variable.
std::ostream & console()
Encapsulate cout.
Definition: muParserDef.h:115
Token can't be identified.
Definition: muParserDef.h:230
result is a string
Definition: muParserDef.h:246
An unexpected argument has been found.
Definition: muParserDef.h:233
std::map< string_type, value_type * > varmap_type
Type used for storing variables.
Definition: muParserDef.h:314
unterminated string constant. (Example: "3*valueof("hello)")
Definition: muParserDef.h:242
void ClearConst()
Clear all user defined constants.
STL namespace.
Unexpected function found. (Example: "sin(8)cos(9)")
Definition: muParserDef.h:241
power operator priority (highest)
Definition: muParserDef.h:217
value_type Eval() const
Calculate the result.
std::basic_stringstream< char_type, std::char_traits< char_type >, std::allocator< char_type > > stringstream_type
Typedef for easily using stringstream that respect the parser stringtype.
Definition: muParserDef.h:309
void EnableOptimizer(bool a_bIsOn=true)
Enable or disable the formula optimization feature.
Code for a generic function item.
Definition: muParserDef.h:170
An unexpected value token has been found.
Definition: muParserDef.h:234
void ClearPostfixOprt()
Clear all user defined postfix operators.
void DefineFun(const string_type &a_strName, T a_pFun, bool a_bAllowOpt=true)
Define a parser function without arguments.
Definition: muParserBase.h:139
Error class of the parser.
Definition: muParserError.h:74
const varmap_type & GetVar() const
Return a map containing the used variables only.
MUP_BASETYPE value_type
The numeric datatype used by the parser.
Definition: muParserDef.h:294
void SetExpr(const string_type &a_sExpr)
Set the formula.
Mathematical expressions parser.
Definition: muParserInt.h:49
Too many function parameters.
Definition: muParserDef.h:243
A numerical function has been called with a non value type of argument.
Definition: muParserDef.h:239
A template class for providing wrappers for essential math functions.
Namespace for mathematical applications.
Definition: muParser.cpp:46
Unexpected end of formula. (Example: "2+sin(")
Definition: muParserDef.h:231
Too few function parameters. (Example: "ite(1<2,2)")
Definition: muParserDef.h:244
A string function has been called with a different type of argument.
Definition: muParserDef.h:238
value item
Definition: muParserDef.h:161
EErrorCodes GetCode() const
Return the error code.
void RemoveVar(const string_type &a_strVarName)
Remove a variable from internal storage.
string_type::value_type char_type
The character type used by the parser.
Definition: muParserDef.h:306
Mathematical expressions parser.
Definition: muParser.h:50
void DefineConst(const string_type &a_sName, value_type a_fVal)
Add a user defined constant.
void EnableBuiltInOprt(bool a_bIsOn=true)
Enable or disable the built in binary operators.
This file contains the parser test class.
Unexpected binary operator found.
Definition: muParserDef.h:229
MUP_STRING_TYPE string_type
The stringtype used by the parser.
Definition: muParserDef.h:300
void ClearFun()
Clear all functions.
Unexpected Parenthesis, opening or closing.
Definition: muParserDef.h:236
const string_type & GetToken() const
Return string related with this token (if available).
Missing parens. (Example: "3*sin(3")
Definition: muParserDef.h:240
const string_type & GetMsg() const
Returns the message string for this error.
A string has been found at an inapropriate position.
Definition: muParserDef.h:237
const ParserByteCode & GetByteCode() const
Returns the bytecode of the current expression.
const varmap_type & GetUsedVar() const
Return a map containing the used variables only.