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