NumeRe v1.1.4
NumeRe: Framework für Numerische Rechnungen
muParserTest.cpp
Go to the documentation of this file.
1/*
2 __________
3 _____ __ __\______ \_____ _______ ______ ____ _______
4 / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
5 | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
6 |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
7 \/ \/ \/ \/
8 Copyright (C) 2012 Ingo Berg
9
10 Permission is hereby granted, free of charge, to any person obtaining a copy of this
11 software and associated documentation files (the "Software"), to deal in the Software
12 without restriction, including without limitation the rights to use, copy, modify,
13 merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to the following conditions:
15
16 The above copyright notice and this permission notice shall be included in all copies or
17 substantial portions of the Software.
18
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
20 NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24*/
25
26#include "muParserTest.h"
27
28#include <cstdio>
29#include <cmath>
30#include <iostream>
31#include <limits>
32
33#define PARSER_CONST_PI 3.141592653589793238462643
34#define PARSER_CONST_E 2.718281828459045235360287
35
36using namespace std;
37
42namespace mu
43{
44 namespace Test
45 {
47
48 //---------------------------------------------------------------------------------------------
50 :m_vTestFun()
51 {
64
66 }
67
68 //---------------------------------------------------------------------------------------------
69 int ParserTester::IsHexVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal)
70 {
71 if (a_szExpr[1]==0 || (a_szExpr[0]!='0' || a_szExpr[1]!='x') )
72 return 0;
73
74 unsigned iVal(0);
75
76 // New code based on streams for UNICODE compliance:
77 stringstream_type::pos_type nPos(0);
78 stringstream_type ss(a_szExpr + 2);
79 ss >> std::hex >> iVal;
80 nPos = ss.tellg();
81
82 if (nPos==(stringstream_type::pos_type)0)
83 return 1;
84
85 *a_iPos += (int)(2 + nPos);
86 *a_fVal = (value_type)iVal;
87 return 1;
88 }
89
90 //---------------------------------------------------------------------------------------------
92 {
93 int iStat = 0;
94 cerr << "\r \r";
95 mu::console() << _nrT(" -> Teste Parserfunktionsfaehigkeit ... ");
96
97 // Test RemoveVar
98 value_type afVal[3] = {1,2,3};
99 Parser p;
100
101 try
102 {
103 p.DefineVar( _nrT("a"), &afVal[0]);
104 p.DefineVar( _nrT("b"), &afVal[1]);
105 p.DefineVar( _nrT("c"), &afVal[2]);
106 p.SetExpr( string("a+b+c") );
107 p.Eval();
108 }
109 catch(...)
110 {
111 iStat += 1; // this is not supposed to happen
112 }
113
114 try
115 {
116 p.RemoveVar( _nrT("c") );
117 p.Eval();
118 iStat += 1; // not supposed to reach this, nonexisting variable "c" deleted...
119 }
120 catch(...)
121 {
122 // failure is expected...
123 }
124
125 if (iStat==0)
126 mu::console() << _nrT("Abgeschlossen.");
127 else
128 mu::console() << _nrT("\n -> Funktionsfaehigkeit fehlgeschlagen mit ") << iStat << _nrT(" Fehlern.") << endl;
129
130 return iStat;
131 }
132
133 //---------------------------------------------------------------------------------------------
135 {
136 int iStat = 0;
137 cerr << "\r \r";
138 mu::console() << _nrT(" -> Teste Zeichenkettenargumente ... ");
139
140 iStat += EqnTest(_nrT("valueof(\"\")"), 123, true); // empty string arguments caused a crash
141 iStat += EqnTest(_nrT("valueof(\"aaa\")+valueof(\"bbb\") "), 246, true);
142 iStat += EqnTest(_nrT("2*(valueof(\"aaa\")-23)+valueof(\"bbb\")"), 323, true);
143 // use in expressions with variables
144 iStat += EqnTest(_nrT("a*(atof(\"10\")-b)"), 8, true);
145 iStat += EqnTest(_nrT("a-(atof(\"10\")*b)"), -19, true);
146 // string + numeric arguments
147 iStat += EqnTest(_nrT("strfun1(\"100\")"), 100, true);
148 iStat += EqnTest(_nrT("strfun2(\"100\",1)"), 101, true);
149 iStat += EqnTest(_nrT("strfun3(\"99\",1,2)"), 102, true);
150
151 if (iStat==0)
152 mu::console() << _nrT("Abgeschlossen.");
153 else
154 mu::console() << _nrT("\n -> Zeichenkettenargumente fehlgeschlagen mit ") << iStat << _nrT(" Fehlern.") << endl;
155
156 return iStat;
157 }
158
159 //---------------------------------------------------------------------------------------------
161 {
162 int iStat = 0;
163 cerr << "\r \r";
164 mu::console() << _nrT(" -> Teste binaere Operatoren ... ");
165
166 // built in operators
167 // xor operator
168 //iStat += EqnTest(_nrT("1 xor 2"), 3, true);
169 //iStat += EqnTest(_nrT("a xor b"), 3, true); // with a=1 and b=2
170 //iStat += EqnTest(_nrT("1 xor 2 xor 3"), 0, true);
171 //iStat += EqnTest(_nrT("a xor b xor 3"), 0, true); // with a=1 and b=2
172 //iStat += EqnTest(_nrT("a xor b xor c"), 0, true); // with a=1 and b=2
173 //iStat += EqnTest(_nrT("(1 xor 2) xor 3"), 0, true);
174 //iStat += EqnTest(_nrT("(a xor b) xor c"), 0, true); // with a=1 and b=2
175 //iStat += EqnTest(_nrT("(a) xor (b) xor c"), 0, true); // with a=1 and b=2
176 //iStat += EqnTest(_nrT("1 or 2"), 3, true);
177 //iStat += EqnTest(_nrT("a or b"), 3, true); // with a=1 and b=2
178 iStat += EqnTest(_nrT("a++b"), 3, true);
179 iStat += EqnTest(_nrT("a ++ b"), 3, true);
180 iStat += EqnTest(_nrT("1++2"), 3, true);
181 iStat += EqnTest(_nrT("1 ++ 2"), 3, true);
182 iStat += EqnTest(_nrT("a add b"), 3, true);
183 iStat += EqnTest(_nrT("1 add 2"), 3, true);
184 iStat += EqnTest(_nrT("a<b"), 1, true);
185 iStat += EqnTest(_nrT("b>a"), 1, true);
186 iStat += EqnTest(_nrT("a>a"), 0, true);
187 iStat += EqnTest(_nrT("a<a"), 0, true);
188 iStat += EqnTest(_nrT("a>a"), 0, true);
189 iStat += EqnTest(_nrT("a<=a"), 1, true);
190 iStat += EqnTest(_nrT("a<=b"), 1, true);
191 iStat += EqnTest(_nrT("b<=a"), 0, true);
192 iStat += EqnTest(_nrT("a>=a"), 1, true);
193 iStat += EqnTest(_nrT("b>=a"), 1, true);
194 iStat += EqnTest(_nrT("a>=b"), 0, true);
195
196 // Test logical operators, expecially if user defined "&" and the internal "&&" collide
197 iStat += EqnTest(_nrT("1 && 1"), 1, true);
198 iStat += EqnTest(_nrT("1 && 0"), 0, true);
199 iStat += EqnTest(_nrT("(a<b) && (b>a)"), 1, true);
200 iStat += EqnTest(_nrT("(a<b) && (a>b)"), 0, true);
201 //iStat += EqnTest(_nrT("12 and 255"), 12, true);
202 //iStat += EqnTest(_nrT("12 and 0"), 0, true);
203 iStat += EqnTest(_nrT("12 & 255"), 12, true);
204 iStat += EqnTest(_nrT("12 & 0"), 0, true);
205 iStat += EqnTest(_nrT("12&255"), 12, true);
206 iStat += EqnTest(_nrT("12&0"), 0, true);
207
208
209 // Assignement operator
210 iStat += EqnTest(_nrT("a = b"), 2, true);
211 iStat += EqnTest(_nrT("a = sin(b)"), 0.909297, true);
212 iStat += EqnTest(_nrT("a = 1+sin(b)"), 1.909297, true);
213 iStat += EqnTest(_nrT("(a=b)*2"), 4, true);
214 iStat += EqnTest(_nrT("2*(a=b)"), 4, true);
215 iStat += EqnTest(_nrT("2*(a=b+1)"), 6, true);
216 iStat += EqnTest(_nrT("(a=b+1)*2"), 6, true);
217 iStat += EqnTest(_nrT("2^2^3"), 256, true);
218 iStat += EqnTest(_nrT("1/2/3"), 1.0/6.0, true);
219
220 // reference: http://www.wolframalpha.com/input/?i=3%2B4*2%2F%281-5%29^2^3
221 iStat += EqnTest(_nrT("3+4*2/(1-5)^2^3"), 3.0001220703125, true);
222 // Test user defined binary operators
223 iStat += EqnTestInt(_nrT("1 | 2"), 3, true);
224 iStat += EqnTestInt(_nrT("1 || 2"), 1, true);
225 iStat += EqnTestInt(_nrT("123 & 456"), 72, true);
226 iStat += EqnTestInt(_nrT("(123 & 456) % 10"), 2, true);
227 iStat += EqnTestInt(_nrT("1 && 0"), 0, true);
228 iStat += EqnTestInt(_nrT("123 && 456"), 1, true);
229 iStat += EqnTestInt(_nrT("1 << 3"), 8, true);
230 iStat += EqnTestInt(_nrT("8 >> 3"), 1, true);
231 iStat += EqnTestInt(_nrT("9 / 4"), 2, true);
232 iStat += EqnTestInt(_nrT("9 % 4"), 1, true);
233 iStat += EqnTestInt(_nrT("if(5%2,1,0)"), 1, true);
234 iStat += EqnTestInt(_nrT("if(4%2,1,0)"), 0, true);
235 iStat += EqnTestInt(_nrT("-10+1"), -9, true);
236 iStat += EqnTestInt(_nrT("1+2*3"), 7, true);
237 iStat += EqnTestInt(_nrT("const1 != const2"), 1, true);
238 iStat += EqnTestInt(_nrT("const1 != const2"), 0, false);
239 iStat += EqnTestInt(_nrT("const1 == const2"), 0, true);
240 iStat += EqnTestInt(_nrT("const1 == 1"), 1, true);
241 iStat += EqnTestInt(_nrT("10*(const1 == 1)"), 10, true);
242 iStat += EqnTestInt(_nrT("2*(const1 | const2)"), 6, true);
243 iStat += EqnTestInt(_nrT("2*(const1 | const2)"), 7, false);
244 iStat += EqnTestInt(_nrT("const1 < const2"), 1, true);
245 iStat += EqnTestInt(_nrT("const2 > const1"), 1, true);
246 iStat += EqnTestInt(_nrT("const1 <= 1"), 1, true);
247 iStat += EqnTestInt(_nrT("const2 >= 2"), 1, true);
248 iStat += EqnTestInt(_nrT("2*(const1 + const2)"), 6, true);
249 iStat += EqnTestInt(_nrT("2*(const1 - const2)"), -2, true);
250 iStat += EqnTestInt(_nrT("a != b"), 1, true);
251 iStat += EqnTestInt(_nrT("a != b"), 0, false);
252 iStat += EqnTestInt(_nrT("a == b"), 0, true);
253 iStat += EqnTestInt(_nrT("a == 1"), 1, true);
254 iStat += EqnTestInt(_nrT("10*(a == 1)"), 10, true);
255 iStat += EqnTestInt(_nrT("2*(a | b)"), 6, true);
256 iStat += EqnTestInt(_nrT("2*(a | b)"), 7, false);
257 iStat += EqnTestInt(_nrT("a < b"), 1, true);
258 iStat += EqnTestInt(_nrT("b > a"), 1, true);
259 iStat += EqnTestInt(_nrT("a <= 1"), 1, true);
260 iStat += EqnTestInt(_nrT("b >= 2"), 1, true);
261 iStat += EqnTestInt(_nrT("2*(a + b)"), 6, true);
262 iStat += EqnTestInt(_nrT("2*(a - b)"), -2, true);
263 iStat += EqnTestInt(_nrT("a + (a << b)"), 5, true);
264 iStat += EqnTestInt(_nrT("-2^2"), -4, true);
265 iStat += EqnTestInt(_nrT("3--a"), 4, true);
266 iStat += EqnTestInt(_nrT("3+-3^2"), -6, true);
267 // Test reading of hex values:
268 iStat += EqnTestInt(_nrT("0xff"), 255, true);
269 iStat += EqnTestInt(_nrT("10+0xff"), 265, true);
270 iStat += EqnTestInt(_nrT("0xff+10"), 265, true);
271 iStat += EqnTestInt(_nrT("10*0xff"), 2550, true);
272 iStat += EqnTestInt(_nrT("0xff*10"), 2550, true);
273 iStat += EqnTestInt(_nrT("10+0xff+1"), 266, true);
274 iStat += EqnTestInt(_nrT("1+0xff+10"), 266, true);
275// incorrect: '^' is yor here, not power
276// iStat += EqnTestInt("-(1+2)^2", -9, true);
277// iStat += EqnTestInt("-1^3", -1, true);
278
279 // Test precedence
280 // a=1, b=2, c=3
281 iStat += EqnTestInt(_nrT("a + b * c"), 7, true);
282 iStat += EqnTestInt(_nrT("a * b + c"), 5, true);
283 iStat += EqnTestInt(_nrT("a<b && b>10"), 0, true);
284 iStat += EqnTestInt(_nrT("a<b && b<10"), 1, true);
285
286 iStat += EqnTestInt(_nrT("a + b << c"), 17, true);
287 iStat += EqnTestInt(_nrT("a << b + c"), 7, true);
288 iStat += EqnTestInt(_nrT("c * b < a"), 0, true);
289 iStat += EqnTestInt(_nrT("c * b == 6 * a"), 1, true);
290 iStat += EqnTestInt(_nrT("2^2^3"), 256, true);
291
292 if (iStat==0)
293 mu::console() << _nrT("Abgeschlossen.");
294 else
295 mu::console() << _nrT("\n -> Binaere Operatoren fehlgeschlagen mit ") << iStat << _nrT(" Fehlern.") << endl;
296
297 return iStat;
298 }
299
300 //---------------------------------------------------------------------------------------------
303 {
304 int iStat= 0,
305 iErr = 0;
306
307 cerr << "\r \r";
308 mu::console() << " -> Teste Namensbeschraenkungen ... ";
309
310 Parser p;
311
312 #define PARSER_THROWCHECK(DOMAIN, FAIL, EXPR, ARG) \
313 iErr = 0; \
314 ParserTester::c_iCount++; \
315 try \
316 { \
317 p.Define##DOMAIN(EXPR, ARG); \
318 } \
319 catch(Parser::exception_type&) \
320 { \
321 iErr = (FAIL==false) ? 0 : 1; \
322 } \
323 iStat += iErr;
324
325 // constant names
326 PARSER_THROWCHECK(Const, false, _nrT("0a"), 1)
327 PARSER_THROWCHECK(Const, false, _nrT("9a"), 1)
328 PARSER_THROWCHECK(Const, false, _nrT("+a"), 1)
329 PARSER_THROWCHECK(Const, false, _nrT("-a"), 1)
330 PARSER_THROWCHECK(Const, false, _nrT("a-"), 1)
331 PARSER_THROWCHECK(Const, false, _nrT("a*"), 1)
332 PARSER_THROWCHECK(Const, false, _nrT("a?"), 1)
333 PARSER_THROWCHECK(Const, true, _nrT("a"), 1)
334 PARSER_THROWCHECK(Const, true, _nrT("a_min"), 1)
335 PARSER_THROWCHECK(Const, true, _nrT("a_min0"), 1)
336 PARSER_THROWCHECK(Const, true, _nrT("a_min9"), 1)
337 // variable names
338 value_type a;
339 p.ClearConst();
340 PARSER_THROWCHECK(Var, false, _nrT("123abc"), &a)
341 PARSER_THROWCHECK(Var, false, _nrT("9a"), &a)
342 PARSER_THROWCHECK(Var, false, _nrT("0a"), &a)
343 PARSER_THROWCHECK(Var, false, _nrT("+a"), &a)
344 PARSER_THROWCHECK(Var, false, _nrT("-a"), &a)
345 PARSER_THROWCHECK(Var, false, _nrT("?a"), &a)
346 PARSER_THROWCHECK(Var, false, _nrT("!a"), &a)
347 PARSER_THROWCHECK(Var, false, _nrT("a+"), &a)
348 PARSER_THROWCHECK(Var, false, _nrT("a-"), &a)
349 PARSER_THROWCHECK(Var, false, _nrT("a*"), &a)
350 PARSER_THROWCHECK(Var, false, _nrT("a?"), &a)
351 PARSER_THROWCHECK(Var, true, _nrT("a"), &a)
352 PARSER_THROWCHECK(Var, true, _nrT("a_min"), &a)
353 PARSER_THROWCHECK(Var, true, _nrT("a_min0"), &a)
354 PARSER_THROWCHECK(Var, true, _nrT("a_min9"), &a)
355 PARSER_THROWCHECK(Var, false, _nrT("a_min9"), 0)
356 // Postfix operators
357 // fail
358 PARSER_THROWCHECK(PostfixOprt, false, _nrT("(k"), f1of1)
359 PARSER_THROWCHECK(PostfixOprt, false, _nrT("9+"), f1of1)
360 PARSER_THROWCHECK(PostfixOprt, false, _nrT("+"), 0)
361 // pass
362 PARSER_THROWCHECK(PostfixOprt, true, _nrT("-a"), f1of1)
363 PARSER_THROWCHECK(PostfixOprt, true, _nrT("?a"), f1of1)
364 PARSER_THROWCHECK(PostfixOprt, true, _nrT("_"), f1of1)
365 PARSER_THROWCHECK(PostfixOprt, true, _nrT("#"), f1of1)
366 PARSER_THROWCHECK(PostfixOprt, true, _nrT("&&"), f1of1)
367 PARSER_THROWCHECK(PostfixOprt, true, _nrT("||"), f1of1)
368 PARSER_THROWCHECK(PostfixOprt, true, _nrT("&"), f1of1)
369 PARSER_THROWCHECK(PostfixOprt, true, _nrT("|"), f1of1)
370 PARSER_THROWCHECK(PostfixOprt, true, _nrT("++"), f1of1)
371 PARSER_THROWCHECK(PostfixOprt, true, _nrT("--"), f1of1)
372 PARSER_THROWCHECK(PostfixOprt, true, _nrT("?>"), f1of1)
373 PARSER_THROWCHECK(PostfixOprt, true, _nrT("?<"), f1of1)
374 PARSER_THROWCHECK(PostfixOprt, true, _nrT("**"), f1of1)
375 PARSER_THROWCHECK(PostfixOprt, true, _nrT("xor"), f1of1)
376 PARSER_THROWCHECK(PostfixOprt, true, _nrT("and"), f1of1)
377 PARSER_THROWCHECK(PostfixOprt, true, _nrT("or"), f1of1)
378 PARSER_THROWCHECK(PostfixOprt, true, _nrT("not"), f1of1)
379 PARSER_THROWCHECK(PostfixOprt, true, _nrT("!"), f1of1)
380 // Binary operator
381 // The following must fail with builtin operators activated
382 // p.EnableBuiltInOp(true); -> this is the default
384 PARSER_THROWCHECK(Oprt, false, _nrT("+"), f1of2)
385 PARSER_THROWCHECK(Oprt, false, _nrT("-"), f1of2)
386 PARSER_THROWCHECK(Oprt, false, _nrT("*"), f1of2)
387 PARSER_THROWCHECK(Oprt, false, _nrT("/"), f1of2)
388 PARSER_THROWCHECK(Oprt, false, _nrT("^"), f1of2)
389 PARSER_THROWCHECK(Oprt, false, _nrT("&&"), f1of2)
390 PARSER_THROWCHECK(Oprt, false, _nrT("||"), f1of2)
391 // without activated built in operators it should work
392 p.EnableBuiltInOprt(false);
393 PARSER_THROWCHECK(Oprt, true, _nrT("+"), f1of2)
394 PARSER_THROWCHECK(Oprt, true, _nrT("-"), f1of2)
395 PARSER_THROWCHECK(Oprt, true, _nrT("*"), f1of2)
396 PARSER_THROWCHECK(Oprt, true, _nrT("/"), f1of2)
397 PARSER_THROWCHECK(Oprt, true, _nrT("^"), f1of2)
398 PARSER_THROWCHECK(Oprt, true, _nrT("&&"), f1of2)
399 PARSER_THROWCHECK(Oprt, true, _nrT("||"), f1of2)
400 #undef PARSER_THROWCHECK
401
402 if (iStat==0)
403 mu::console() << _nrT("Abgeschlossen.");
404 else
405 mu::console() << _nrT("\n -> Namensbeschraenkung fehlgeschlagen mit ") << iStat << _nrT(" Fehlern.") << endl;
406
407 return iStat;
408 }
409
410 //---------------------------------------------------------------------------
412 {
413 int iStat = 0;
414 cerr << "\r \r";
415 mu::console() << _nrT(" -> Teste Syntaxerkennung ... ");
416
417 iStat += ThrowTest(_nrT("1,"), ecUNEXPECTED_EOF); // incomplete hex definition
418 iStat += ThrowTest(_nrT("a,"), ecUNEXPECTED_EOF); // incomplete hex definition
419 iStat += ThrowTest(_nrT("sin(8),"), ecUNEXPECTED_EOF); // incomplete hex definition
420 iStat += ThrowTest(_nrT("(sin(8)),"), ecUNEXPECTED_EOF); // incomplete hex definition
421 iStat += ThrowTest(_nrT("a m,"), ecUNEXPECTED_EOF); // incomplete hex definition
422
423
424 iStat += EqnTest(_nrT("(1+ 2*a)"), 3, true); // Spaces within formula
425 iStat += EqnTest(_nrT("sqrt((4))"), 2, true); // Multiple brackets
426 iStat += EqnTest(_nrT("sqrt((2)+2)"), 2, true);// Multiple brackets
427 iStat += EqnTest(_nrT("sqrt(2+(2))"), 2, true);// Multiple brackets
428 iStat += EqnTest(_nrT("sqrt(a+(3))"), 2, true);// Multiple brackets
429 iStat += EqnTest(_nrT("sqrt((3)+a)"), 2, true);// Multiple brackets
430 iStat += EqnTest(_nrT("order(1,2)"), 1, true); // May not cause name collision with operator "or"
431 iStat += EqnTest(_nrT("(2+"), 0, false); // missing closing bracket
432 iStat += EqnTest(_nrT("2++4"), 0, false); // unexpected operator
433 iStat += EqnTest(_nrT("2+-4"), 0, false); // unexpected operator
434 iStat += EqnTest(_nrT("(2+)"), 0, false); // unexpected closing bracket
435 iStat += EqnTest(_nrT("--2"), 0, false); // double sign
436 iStat += EqnTest(_nrT("ksdfj"), 0, false); // unknown token
437 iStat += EqnTest(_nrT("()"), 0, false); // empty bracket without a function
438 iStat += EqnTest(_nrT("5+()"), 0, false); // empty bracket without a function
439 iStat += EqnTest(_nrT("sin(cos)"), 0, false); // unexpected function
440 iStat += EqnTest(_nrT("5t6"), 0, false); // unknown token
441 iStat += EqnTest(_nrT("5 t 6"), 0, false); // unknown token
442 iStat += EqnTest(_nrT("8*"), 0, false); // unexpected end of formula
443 iStat += EqnTest(_nrT(",3"), 0, false); // unexpected comma
444 iStat += EqnTest(_nrT("3,5"), 0, false); // unexpected comma
445 iStat += EqnTest(_nrT("sin(8,8)"), 0, false); // too many function args
446 iStat += EqnTest(_nrT("(7,8)"), 0, false); // too many function args
447 iStat += EqnTest(_nrT("sin)"), 0, false); // unexpected closing bracket
448 iStat += EqnTest(_nrT("a)"), 0, false); // unexpected closing bracket
449 iStat += EqnTest(_nrT("pi)"), 0, false); // unexpected closing bracket
450 iStat += EqnTest(_nrT("sin(())"), 0, false); // unexpected closing bracket
451 iStat += EqnTest(_nrT("sin()"), 0, false); // unexpected closing bracket
452
453
454 if (iStat==0)
455 mu::console() << _nrT("Abgeschlossen.");
456 else
457 mu::console() << _nrT("\n -> Syntaxerkennung fehlgeschlagen mit ") << iStat << _nrT(" Fehlern.") << endl;
458
459 return iStat;
460 }
461
462 //---------------------------------------------------------------------------
464 {
465 int iStat = 0;
466 cerr << "\r \r";
467 mu::console() << _nrT(" -> Teste Variablen-/Konstantenerkennung ... ");
468
469 // Test if the result changes when a variable changes
470 iStat += EqnTestWithVarChange( _nrT("a"), 1, 1, 2, 2 );
471 iStat += EqnTestWithVarChange( _nrT("2*a"), 2, 4, 3, 6 );
472
473 // distinguish constants with same basename
474 iStat += EqnTest( _nrT("const"), 1, true);
475 iStat += EqnTest( _nrT("const1"), 2, true);
476 iStat += EqnTest( _nrT("const2"), 3, true);
477 iStat += EqnTest( _nrT("2*const"), 2, true);
478 iStat += EqnTest( _nrT("2*const1"), 4, true);
479 iStat += EqnTest( _nrT("2*const2"), 6, true);
480 iStat += EqnTest( _nrT("2*const+1"), 3, true);
481 iStat += EqnTest( _nrT("2*const1+1"), 5, true);
482 iStat += EqnTest( _nrT("2*const2+1"), 7, true);
483 iStat += EqnTest( _nrT("const"), 0, false);
484 iStat += EqnTest( _nrT("const1"), 0, false);
485 iStat += EqnTest( _nrT("const2"), 0, false);
486
487 // distinguish variables with same basename
488 iStat += EqnTest( _nrT("a"), 1, true);
489 iStat += EqnTest( _nrT("aa"), 2, true);
490 iStat += EqnTest( _nrT("2*a"), 2, true);
491 iStat += EqnTest( _nrT("2*aa"), 4, true);
492 iStat += EqnTest( _nrT("2*a-1"), 1, true);
493 iStat += EqnTest( _nrT("2*aa-1"), 3, true);
494
495 // custom value recognition
496 iStat += EqnTest( _nrT("0xff"), 255, true);
497 iStat += EqnTest( _nrT("0x97 + 0xff"), 406, true);
498
499 // Finally test querying of used variables
500 try
501 {
502 int idx;
503 mu::Parser p;
504 mu::value_type vVarVal[] = { 1, 2, 3, 4, 5};
505 p.DefineVar( _nrT("a"), &vVarVal[0]);
506 p.DefineVar( _nrT("b"), &vVarVal[1]);
507 p.DefineVar( _nrT("c"), &vVarVal[2]);
508 p.DefineVar( _nrT("d"), &vVarVal[3]);
509 p.DefineVar( _nrT("e"), &vVarVal[4]);
510
511 // Test lookup of defined variables
512 // 4 used variables
513 p.SetExpr( _nrT("a+b+c+d") );
514 mu::varmap_type UsedVar = p.GetUsedVar();
515 int iCount = (int)UsedVar.size();
516 if (iCount!=4)
517 throw false;
518
519 // the next check will fail if the parser
520 // erroneousely creates new variables internally
521 if (p.GetVar().size()!=5)
522 throw false;
523
524 mu::varmap_type::const_iterator item = UsedVar.begin();
525 for (idx=0; item!=UsedVar.end(); ++item)
526 {
527 if (&vVarVal[idx++]!=item->second)
528 throw false;
529 }
530
531 // Test lookup of undefined variables
532 p.SetExpr( _nrT("undef1+undef2+undef3") );
533 UsedVar = p.GetUsedVar();
534 iCount = (int)UsedVar.size();
535 if (iCount!=3)
536 throw false;
537
538 // the next check will fail if the parser
539 // erroneousely creates new variables internally
540 if (p.GetVar().size()!=5)
541 throw false;
542
543 for (item = UsedVar.begin(); item!=UsedVar.end(); ++item)
544 {
545 if (item->second!=0)
546 throw false; // all pointers to undefined variables must be null
547 }
548
549 // 1 used variables
550 p.SetExpr( _nrT("a+b") );
551 UsedVar = p.GetUsedVar();
552 iCount = (int)UsedVar.size();
553 if (iCount!=2) throw false;
554 item = UsedVar.begin();
555 for (idx=0; item!=UsedVar.end(); ++item)
556 if (&vVarVal[idx++]!=item->second) throw false;
557
558 }
559 catch(...)
560 {
561 iStat += 1;
562 }
563
564 if (iStat==0)
565 mu::console() << _nrT("Abgeschlossen.");
566 else
567 mu::console() << _nrT("\n -> Variablen-/Konstantenerkennung fehlgeschlagen mit ") << iStat << _nrT(" Fehlern.") << endl;
568
569 return iStat;
570 }
571
572 //---------------------------------------------------------------------------
574 {
575 int iStat = 0;
576 cerr << "\r \r";
577 mu::console() << _nrT(" -> Teste Mehrfachargumentausdruecke ... ");
578
579 // Compound expressions
580 iStat += EqnTest( _nrT("1,2,3"), 3, true);
581 iStat += EqnTest( _nrT("a,b,c"), 3, true);
582 iStat += EqnTest( _nrT("a=10,b=20,c=a*b"), 200, true);
583 iStat += EqnTest( _nrT("1,\n2,\n3"), 3, true);
584 iStat += EqnTest( _nrT("a,\nb,\nc"), 3, true);
585 iStat += EqnTest( _nrT("a=10,\nb=20,\nc=a*b"), 200, true);
586 iStat += EqnTest( _nrT("1,\r\n2,\r\n3"), 3, true);
587 iStat += EqnTest( _nrT("a,\r\nb,\r\nc"), 3, true);
588 iStat += EqnTest( _nrT("a=10,\r\nb=20,\r\nc=a*b"), 200, true);
589
590 // picking the right argument
591 iStat += EqnTest( _nrT("f1of1(1)"), 1, true);
592 iStat += EqnTest( _nrT("f1of2(1, 2)"), 1, true);
593 iStat += EqnTest( _nrT("f2of2(1, 2)"), 2, true);
594 iStat += EqnTest( _nrT("f1of3(1, 2, 3)"), 1, true);
595 iStat += EqnTest( _nrT("f2of3(1, 2, 3)"), 2, true);
596 iStat += EqnTest( _nrT("f3of3(1, 2, 3)"), 3, true);
597 iStat += EqnTest( _nrT("f1of4(1, 2, 3, 4)"), 1, true);
598 iStat += EqnTest( _nrT("f2of4(1, 2, 3, 4)"), 2, true);
599 iStat += EqnTest( _nrT("f3of4(1, 2, 3, 4)"), 3, true);
600 iStat += EqnTest( _nrT("f4of4(1, 2, 3, 4)"), 4, true);
601 iStat += EqnTest( _nrT("f1of5(1, 2, 3, 4, 5)"), 1, true);
602 iStat += EqnTest( _nrT("f2of5(1, 2, 3, 4, 5)"), 2, true);
603 iStat += EqnTest( _nrT("f3of5(1, 2, 3, 4, 5)"), 3, true);
604 iStat += EqnTest( _nrT("f4of5(1, 2, 3, 4, 5)"), 4, true);
605 iStat += EqnTest( _nrT("f5of5(1, 2, 3, 4, 5)"), 5, true);
606
607 // Too few arguments / Too many arguments
608 iStat += EqnTest( _nrT("1+ping()"), 11, true);
609 iStat += EqnTest( _nrT("ping()+1"), 11, true);
610 iStat += EqnTest( _nrT("2*ping()"), 20, true);
611 iStat += EqnTest( _nrT("ping()*2"), 20, true);
612 iStat += EqnTest( _nrT("ping(1,2)"), 0, false);
613 iStat += EqnTest( _nrT("1+ping(1,2)"), 0, false);
614 iStat += EqnTest( _nrT("f1of1(1,2)"), 0, false);
615 iStat += EqnTest( _nrT("f1of1()"), 0, false);
616 iStat += EqnTest( _nrT("f1of2(1, 2, 3)"), 0, false);
617 iStat += EqnTest( _nrT("f1of2(1)"), 0, false);
618 iStat += EqnTest( _nrT("f1of3(1, 2, 3, 4)"), 0, false);
619 iStat += EqnTest( _nrT("f1of3(1)"), 0, false);
620 iStat += EqnTest( _nrT("f1of4(1, 2, 3, 4, 5)"), 0, false);
621 iStat += EqnTest( _nrT("f1of4(1)"), 0, false);
622 iStat += EqnTest( _nrT("(1,2,3)"), 0, false);
623 iStat += EqnTest( _nrT("1,2,3"), 0, false);
624 iStat += EqnTest( _nrT("(1*a,2,3)"), 0, false);
625 iStat += EqnTest( _nrT("1,2*a,3"), 0, false);
626
627 // correct calculation of arguments
628 iStat += EqnTest( _nrT("min(a, 1)"), 1, true);
629 iStat += EqnTest( _nrT("min(3*2, 1)"), 1, true);
630 iStat += EqnTest( _nrT("min(3*2, 1)"), 6, false);
631 iStat += EqnTest( _nrT("firstArg(2,3,4)"), 2, true);
632 iStat += EqnTest( _nrT("lastArg(2,3,4)"), 4, true);
633 iStat += EqnTest( _nrT("min(3*a+1, 1)"), 1, true);
634 iStat += EqnTest( _nrT("max(3*a+1, 1)"), 4, true);
635 iStat += EqnTest( _nrT("max(3*a+1, 1)*2"), 8, true);
636 iStat += EqnTest( _nrT("2*max(3*a+1, 1)+2"), 10, true);
637
638 // functions with Variable argument count
639 iStat += EqnTest( _nrT("sum(a)"), 1, true);
640 iStat += EqnTest( _nrT("sum(1,2,3)"), 6, true);
641 iStat += EqnTest( _nrT("sum(a,b,c)"), 6, true);
642 iStat += EqnTest( _nrT("sum(1,-max(1,2),3)*2"), 4, true);
643 iStat += EqnTest( _nrT("2*sum(1,2,3)"), 12, true);
644 iStat += EqnTest( _nrT("2*sum(1,2,3)+2"), 14, true);
645 iStat += EqnTest( _nrT("2*sum(-1,2,3)+2"), 10, true);
646 iStat += EqnTest( _nrT("2*sum(-1,2,-(-a))+2"), 6, true);
647 iStat += EqnTest( _nrT("2*sum(-1,10,-a)+2"), 18, true);
648 iStat += EqnTest( _nrT("2*sum(1,2,3)*2"), 24, true);
649 iStat += EqnTest( _nrT("sum(1,-max(1,2),3)*2"), 4, true);
650 iStat += EqnTest( _nrT("sum(1*3, 4, a+2)"), 10, true);
651 iStat += EqnTest( _nrT("sum(1*3, 2*sum(1,2,2), a+2)"), 16, true);
652 iStat += EqnTest( _nrT("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);
653
654 // some failures
655 iStat += EqnTest( _nrT("sum()"), 0, false);
656 iStat += EqnTest( _nrT("sum(,)"), 0, false);
657 iStat += EqnTest( _nrT("sum(1,2,)"), 0, false);
658 iStat += EqnTest( _nrT("sum(,1,2)"), 0, false);
659
660 if (iStat==0)
661 mu::console() << _nrT("Abgeschlossen.");
662 else
663 mu::console() << _nrT("\n -> Mehrfachausdruecke fehlgeschlagen mit ") << iStat << _nrT(" Fehlern.") << endl;
664
665 return iStat;
666 }
667
668
669 //---------------------------------------------------------------------------
671 {
672 int iStat(0);
673 cerr << "\r \r";
674 mu::console() << " -> Teste Infix Operatoren ... ";
675
676 iStat += EqnTest( _nrT("-1"), -1, true);
677 iStat += EqnTest( _nrT("-(-1)"), 1, true);
678 iStat += EqnTest( _nrT("-(-1)*2"), 2, true);
679 iStat += EqnTest( _nrT("-(-2)*sqrt(4)"), 4, true);
680 iStat += EqnTest( _nrT("-_pi"), -PARSER_CONST_PI, true);
681 iStat += EqnTest( _nrT("-a"), -1, true);
682 iStat += EqnTest( _nrT("-(a)"), -1, true);
683 iStat += EqnTest( _nrT("-(-a)"), 1, true);
684 iStat += EqnTest( _nrT("-(-a)*2"), 2, true);
685 iStat += EqnTest( _nrT("-(8)"), -8, true);
686 iStat += EqnTest( _nrT("-8"), -8, true);
687 iStat += EqnTest( _nrT("-(2+1)"), -3, true);
688 iStat += EqnTest( _nrT("-(f1of1(1+2*3)+1*2)"), -9, true);
689 iStat += EqnTest( _nrT("-(-f1of1(1+2*3)+1*2)"), 5, true);
690 iStat += EqnTest( _nrT("-sin(8)"), -0.989358, true);
691 iStat += EqnTest( _nrT("3-(-a)"), 4, true);
692 iStat += EqnTest( _nrT("3--a"), 4, true);
693 iStat += EqnTest( _nrT("-1*3"), -3, true);
694
695 // Postfix / infix priorities
696 iStat += EqnTest( _nrT("~2#"), 8, true);
697 iStat += EqnTest( _nrT("~f1of1(2)#"), 8, true);
698 iStat += EqnTest( _nrT("~(b)#"), 8, true);
699 iStat += EqnTest( _nrT("(~b)#"), 12, true);
700 iStat += EqnTest( _nrT("~(2#)"), 8, true);
701 iStat += EqnTest( _nrT("~(f1of1(2)#)"), 8, true);
702 //
703 iStat += EqnTest( _nrT("-2^2"),-4, true);
704 iStat += EqnTest( _nrT("-(a+b)^2"),-9, true);
705 iStat += EqnTest( _nrT("(-3)^2"),9, true);
706 iStat += EqnTest( _nrT("-(-2^2)"),4, true);
707 iStat += EqnTest( _nrT("3+-3^2"),-6, true);
708 // The following assumes use of sqr as postfix operator ("§") together
709 // with a sign operator of low priority:
710 iStat += EqnTest( _nrT("-2'"), -4, true);
711 iStat += EqnTest( _nrT("-(1+1)'"),-4, true);
712 iStat += EqnTest( _nrT("2+-(1+1)'"),-2, true);
713 iStat += EqnTest( _nrT("2+-2'"), -2, true);
714 // This is the classic behaviour of the infix sign operator (here: "$") which is
715 // now deprecated:
716 iStat += EqnTest( _nrT("$2^2"),4, true);
717 iStat += EqnTest( _nrT("$(a+b)^2"),9, true);
718 iStat += EqnTest( _nrT("($3)^2"),9, true);
719 iStat += EqnTest( _nrT("$($2^2)"),-4, true);
720 iStat += EqnTest( _nrT("3+$3^2"),12, true);
721
722 // infix operators sharing the first few characters
723 iStat += EqnTest( _nrT("~ 123"), 123+2, true);
724 iStat += EqnTest( _nrT("~~ 123"), 123+2, true);
725
726 if (iStat==0)
727 mu::console() << _nrT("Abgeschlossen.");
728 else
729 mu::console() << _nrT("\n -> Infix-Operatoren fehlgeschlagen mit ") << iStat << _nrT(" Fehlern.") << endl;
730
731 return iStat;
732 }
733
734
735 //---------------------------------------------------------------------------
737 {
738 int iStat = 0;
739 cerr << "\r \r";
740 mu::console() << _nrT(" -> Teste Postfix Operatoren ... ");
741
742 // application
743 iStat += EqnTest( _nrT("3m+5"), 5.003, true);
744 iStat += EqnTest( _nrT("1000m"), 1, true);
745 iStat += EqnTest( _nrT("1000 m"), 1, true);
746 iStat += EqnTest( _nrT("(a)m"), 1e-3, true);
747 iStat += EqnTest( _nrT("a m"), 1e-3, true);
748 //iStat += EqnTest( _nrT("a m"), 1e-3, true);
749 iStat += EqnTest( _nrT("-(a)m"), -1e-3, true);
750 iStat += EqnTest( _nrT("-2m"), -2e-3, true);
751 iStat += EqnTest( _nrT("-2 m"), -2e-3, true);
752 iStat += EqnTest( _nrT("f1of1(1000)m"), 1, true);
753 iStat += EqnTest( _nrT("-f1of1(1000)m"), -1, true);
754 iStat += EqnTest( _nrT("-f1of1(-1000)m"), 1, true);
755 iStat += EqnTest( _nrT("f4of4(0,0,0,1000)m"), 1, true);
756 iStat += EqnTest( _nrT("2+(a*1000)m"), 3, true);
757
758 // can postfix operators "m" und "meg" be told apart properly?
759 iStat += EqnTest( _nrT("2*3000meg+2"), 2*3e9+2, true);
760
761 // some incorrect results
762 iStat += EqnTest( _nrT("1000m"), 0.1, false);
763 iStat += EqnTest( _nrT("(a)m"), 2, false);
764 // failure due to syntax checking
765 iStat += ThrowTest(_nrT("0x"), ecUNASSIGNABLE_TOKEN); // incomplete hex definition
766 iStat += ThrowTest(_nrT("3+"), ecUNEXPECTED_EOF);
767 iStat += ThrowTest( _nrT("4 + m"), ecUNASSIGNABLE_TOKEN);
768 iStat += ThrowTest( _nrT("m4"), ecUNASSIGNABLE_TOKEN);
769 iStat += ThrowTest( _nrT("sin(m)"), ecUNASSIGNABLE_TOKEN);
770 iStat += ThrowTest( _nrT("m m"), ecUNASSIGNABLE_TOKEN);
771 iStat += ThrowTest( _nrT("m(8)"), ecUNASSIGNABLE_TOKEN);
772 iStat += ThrowTest( _nrT("4,m"), ecUNASSIGNABLE_TOKEN);
773 iStat += ThrowTest( _nrT("-m"), ecUNASSIGNABLE_TOKEN);
774 iStat += ThrowTest( _nrT("2(-m)"), ecUNEXPECTED_PARENS);
775 iStat += ThrowTest( _nrT("2(m)"), ecUNEXPECTED_PARENS);
776
777 iStat += ThrowTest( _nrT("multi*1.0"), ecUNASSIGNABLE_TOKEN);
778
779 if (iStat==0)
780 mu::console() << _nrT("Abgeschlossen.");
781 else
782 mu::console() << _nrT("\n -> Postfix-Operatoren fehlgeschlagen mit ") << iStat << _nrT(" Fehlern.") << endl;
783
784 return iStat;
785 }
786
787 //---------------------------------------------------------------------------
789 {
790 int iStat = 0;
791 cerr << "\r \r";
792 mu::console() << _nrT(" -> Teste Beispielausdruecke ... ");
793
794 value_type b = 2;
795
796 // Optimization
797 iStat += EqnTest( _nrT("2*b*5"), 20, true);
798 iStat += EqnTest( _nrT("2*b*5 + 4*b"), 28, true);
799 iStat += EqnTest( _nrT("2*a/3"), 2.0/3.0, true);
800
801 // Addition auf cmVARMUL
802 iStat += EqnTest( _nrT("3+b"), b+3, true);
803 iStat += EqnTest( _nrT("b+3"), b+3, true);
804 iStat += EqnTest( _nrT("b*3+2"), b*3+2, true);
805 iStat += EqnTest( _nrT("3*b+2"), b*3+2, true);
806 iStat += EqnTest( _nrT("2+b*3"), b*3+2, true);
807 iStat += EqnTest( _nrT("2+3*b"), b*3+2, true);
808 iStat += EqnTest( _nrT("b+3*b"), b+3*b, true);
809 iStat += EqnTest( _nrT("3*b+b"), b+3*b, true);
810
811 iStat += EqnTest( _nrT("2+b*3+b"), 2+b*3+b, true);
812 iStat += EqnTest( _nrT("b+2+b*3"), b+2+b*3, true);
813
814 iStat += EqnTest( _nrT("(2*b+1)*4"), (2*b+1)*4, true);
815 iStat += EqnTest( _nrT("4*(2*b+1)"), (2*b+1)*4, true);
816
817 // operator precedencs
818 iStat += EqnTest( _nrT("1+2-3*4/5^6"), 2.99923, true);
819 iStat += EqnTest( _nrT("1^2/3*4-5+6"), 2.33333333, true);
820 iStat += EqnTest( _nrT("1+2*3"), 7, true);
821 iStat += EqnTest( _nrT("1+2*3"), 7, true);
822 iStat += EqnTest( _nrT("(1+2)*3"), 9, true);
823 iStat += EqnTest( _nrT("(1+2)*(-3)"), -9, true);
824 iStat += EqnTest( _nrT("2/4"), 0.5, true);
825
826 iStat += EqnTest( _nrT("exp(ln(7))"), 7, true);
827 iStat += EqnTest( _nrT("e^ln(7)"), 7, true);
828 iStat += EqnTest( _nrT("e^(ln(7))"), 7, true);
829 iStat += EqnTest( _nrT("(e^(ln(7)))"), 7, true);
830 iStat += EqnTest( _nrT("1-(e^(ln(7)))"), -6, true);
831 iStat += EqnTest( _nrT("2*(e^(ln(7)))"), 14, true);
832 iStat += EqnTest( _nrT("10^log(5)"), 5, true);
833 iStat += EqnTest( _nrT("10^log10(5)"), 5, true);
834 iStat += EqnTest( _nrT("2^log2(4)"), 4, true);
835 iStat += EqnTest( _nrT("-(sin(0)+1)"), -1, true);
836 iStat += EqnTest( _nrT("-(2^1.1)"), -2.14354692, true);
837
838 iStat += EqnTest( _nrT("(cos(2.41)/b)"), -0.372056, true);
839 iStat += EqnTest( _nrT("(1*(2*(3*(4*(5*(6*(a+b)))))))"), 2160, true);
840 iStat += EqnTest( _nrT("(1*(2*(3*(4*(5*(6*(7*(a+b))))))))"), 15120, true);
841 iStat += EqnTest( _nrT("(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);
842
843 // long formula (Reference: Matlab)
844 iStat += EqnTest(
845 _nrT("(((-9))-e/(((((((pi-(((-7)+(-3)/4/e))))/(((-5))-2)-((pi+(-0))*(sqrt((e+e))*(-8))*(((-pi)+(-pi)-(-9)*(6*5))")
846 _nrT("/(-e)-e))/2)/((((sqrt(2/(-e)+6)-(4-2))+((5/(-2))/(1*(-pi)+3))/8)*pi*((pi/((-2)/(-6)*1*(-1))*(-6)+(-e)))))/")
847 _nrT("((e+(-2)+(-e)*((((-3)*9+(-e)))+(-9)))))))-((((e-7+(((5/pi-(3/1+pi)))))/e)/(-5))/(sqrt((((((1+(-7))))+((((-")
848 _nrT("e)*(-e)))-8))*(-5)/((-e)))*(-6)-((((((-2)-(-9)-(-e)-1)/3))))/(sqrt((8+(e-((-6))+(9*(-9))))*(((3+2-8))*(7+6")
849 _nrT("+(-5))+((0/(-e)*(-pi))+7)))+(((((-e)/e/e)+((-6)*5)*e+(3+(-5)/pi))))+pi))/sqrt((((9))+((((pi))-8+2))+pi))/e")
850 _nrT("*4)*((-5)/(((-pi))*(sqrt(e)))))-(((((((-e)*(e)-pi))/4+(pi)*(-9)))))))+(-pi)"), -12.23016549, true);
851
852 // long formula (Reference: Matlab)
853 iStat += EqnTest(
854 _nrT("(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")
855 _nrT(")+a)))*2.77)"), -2.16995656, true);
856
857 // long formula (Reference: Matlab)
858 iStat += EqnTest( _nrT("1+2-3*4/5^6*(2*(1-5+(3*7^9)*(4+6*7-3)))+12"), -7995810.09926, true);
859
860 if (iStat==0)
861 mu::console() << _nrT("Abgeschlossen.");
862 else
863 mu::console() << _nrT("\n Beispielausdruecke fehlgeschlagen mit ") << iStat << _nrT(" Fehlern.") << endl;
864
865 return iStat;
866 }
867
868
869
870 //---------------------------------------------------------------------------
872 {
873 int iStat = 0;
874 cerr << "\r \r";
875 mu::console() << _nrT(" -> Teste Wenn-Dann-Sonst Operator ... ");
876
877 // Test error detection
878 iStat += ThrowTest(_nrT(":3"), ecUNEXPECTED_CONDITIONAL);
879 iStat += ThrowTest(_nrT("? 1 : 2"), ecUNEXPECTED_CONDITIONAL);
880 iStat += ThrowTest(_nrT("(a<b) ? (b<c) ? 1 : 2"), ecMISSING_ELSE_CLAUSE);
881 iStat += ThrowTest(_nrT("(a<b) ? 1"), ecMISSING_ELSE_CLAUSE);
882 iStat += ThrowTest(_nrT("(a<b) ? a"), ecMISSING_ELSE_CLAUSE);
883 iStat += ThrowTest(_nrT("(a<b) ? a+b"), ecMISSING_ELSE_CLAUSE);
884 iStat += ThrowTest(_nrT("a : b"), ecMISPLACED_COLON);
885 iStat += ThrowTest(_nrT("1 : 2"), ecMISPLACED_COLON);
886 iStat += ThrowTest(_nrT("(1) ? 1 : 2 : 3"), ecMISPLACED_COLON);
887 iStat += ThrowTest(_nrT("(true) ? 1 : 2 : 3"), ecUNASSIGNABLE_TOKEN);
888
889 iStat += EqnTest(_nrT("1 ? 128 : 255"), 128, true);
890 iStat += EqnTest(_nrT("1<2 ? 128 : 255"), 128, true);
891 iStat += EqnTest(_nrT("a<b ? 128 : 255"), 128, true);
892 iStat += EqnTest(_nrT("(a<b) ? 128 : 255"), 128, true);
893 iStat += EqnTest(_nrT("(1) ? 10 : 11"), 10, true);
894 iStat += EqnTest(_nrT("(0) ? 10 : 11"), 11, true);
895 iStat += EqnTest(_nrT("(1) ? a+b : c+d"), 3, true);
896 iStat += EqnTest(_nrT("(0) ? a+b : c+d"), 1, true);
897 iStat += EqnTest(_nrT("(1) ? 0 : 1"), 0, true);
898 iStat += EqnTest(_nrT("(0) ? 0 : 1"), 1, true);
899 iStat += EqnTest(_nrT("(a<b) ? 10 : 11"), 10, true);
900 iStat += EqnTest(_nrT("(a>b) ? 10 : 11"), 11, true);
901 iStat += EqnTest(_nrT("(a<b) ? c : d"), 3, true);
902 iStat += EqnTest(_nrT("(a>b) ? c : d"), -2, true);
903
904 iStat += EqnTest(_nrT("(a>b) ? 1 : 0"), 0, true);
905 iStat += EqnTest(_nrT("((a>b) ? 1 : 0) ? 1 : 2"), 2, true);
906 iStat += EqnTest(_nrT("((a>b) ? 1 : 0) ? 1 : sum((a>b) ? 1 : 2)"), 2, true);
907 iStat += EqnTest(_nrT("((a>b) ? 0 : 1) ? 1 : sum((a>b) ? 1 : 2)"), 1, true);
908
909 iStat += EqnTest(_nrT("sum((a>b) ? 1 : 2)"), 2, true);
910 iStat += EqnTest(_nrT("sum((1) ? 1 : 2)"), 1, true);
911 iStat += EqnTest(_nrT("sum((a>b) ? 1 : 2, 100)"), 102, true);
912 iStat += EqnTest(_nrT("sum((1) ? 1 : 2, 100)"), 101, true);
913 iStat += EqnTest(_nrT("sum(3, (a>b) ? 3 : 10)"), 13, true);
914 iStat += EqnTest(_nrT("sum(3, (a<b) ? 3 : 10)"), 6, true);
915 iStat += EqnTest(_nrT("10*sum(3, (a>b) ? 3 : 10)"), 130, true);
916 iStat += EqnTest(_nrT("10*sum(3, (a<b) ? 3 : 10)"), 60, true);
917 iStat += EqnTest(_nrT("sum(3, (a>b) ? 3 : 10)*10"), 130, true);
918 iStat += EqnTest(_nrT("sum(3, (a<b) ? 3 : 10)*10"), 60, true);
919 iStat += EqnTest(_nrT("(a<b) ? sum(3, (a<b) ? 3 : 10)*10 : 99"), 60, true);
920 iStat += EqnTest(_nrT("(a>b) ? sum(3, (a<b) ? 3 : 10)*10 : 99"), 99, true);
921 iStat += EqnTest(_nrT("(a<b) ? sum(3, (a<b) ? 3 : 10,10,20)*10 : 99"), 360, true);
922 iStat += EqnTest(_nrT("(a>b) ? sum(3, (a<b) ? 3 : 10,10,20)*10 : 99"), 99, true);
923 iStat += EqnTest(_nrT("(a>b) ? sum(3, (a<b) ? 3 : 10,10,20)*10 : sum(3, (a<b) ? 3 : 10)*10"), 60, true);
924
925 // todo: auch für muParserX hinzufügen!
926 iStat += EqnTest(_nrT("(a<b)&&(a<b) ? 128 : 255"), 128, true);
927 iStat += EqnTest(_nrT("(a>b)&&(a<b) ? 128 : 255"), 255, true);
928 iStat += EqnTest(_nrT("(1<2)&&(1<2) ? 128 : 255"), 128, true);
929 iStat += EqnTest(_nrT("(1>2)&&(1<2) ? 128 : 255"), 255, true);
930 iStat += EqnTest(_nrT("((1<2)&&(1<2)) ? 128 : 255"), 128, true);
931 iStat += EqnTest(_nrT("((1>2)&&(1<2)) ? 128 : 255"), 255, true);
932 iStat += EqnTest(_nrT("((a<b)&&(a<b)) ? 128 : 255"), 128, true);
933 iStat += EqnTest(_nrT("((a>b)&&(a<b)) ? 128 : 255"), 255, true);
934
935 iStat += EqnTest(_nrT("1>0 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 64"), 255, true);
936 iStat += EqnTest(_nrT("1>0 ? 1>2 ? 128 : 255 :(1>0 ? 32 : 64)"), 255, true);
937 iStat += EqnTest(_nrT("1>0 ? 1>0 ? 128 : 255 : 1>2 ? 32 : 64"), 128, true);
938 iStat += EqnTest(_nrT("1>0 ? 1>0 ? 128 : 255 :(1>2 ? 32 : 64)"), 128, true);
939 iStat += EqnTest(_nrT("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 64"), 32, true);
940 iStat += EqnTest(_nrT("1>2 ? 1>0 ? 128 : 255 : 1>2 ? 32 : 64"), 64, true);
941 iStat += EqnTest(_nrT("1>0 ? 50 : 1>0 ? 128 : 255"), 50, true);
942 iStat += EqnTest(_nrT("1>0 ? 50 : (1>0 ? 128 : 255)"), 50, true);
943 iStat += EqnTest(_nrT("1>0 ? 1>0 ? 128 : 255 : 50"), 128, true);
944 iStat += EqnTest(_nrT("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 1>2 ? 64 : 16"), 32, true);
945 iStat += EqnTest(_nrT("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 :(1>2 ? 64 : 16)"), 32, true);
946 iStat += EqnTest(_nrT("1>0 ? 1>2 ? 128 : 255 : 1>0 ? 32 :1>2 ? 64 : 16"), 255, true);
947 iStat += EqnTest(_nrT("1>0 ? 1>2 ? 128 : 255 : (1>0 ? 32 :1>2 ? 64 : 16)"), 255, true);
948 iStat += EqnTest(_nrT("1 ? 0 ? 128 : 255 : 1 ? 32 : 64"), 255, true);
949
950 // assignment operators
951 iStat += EqnTest(_nrT("a= 0 ? 128 : 255, a"), 255, true);
952 iStat += EqnTest(_nrT("a=((a>b)&&(a<b)) ? 128 : 255, a"), 255, true);
953 iStat += EqnTest(_nrT("c=(a<b)&&(a<b) ? 128 : 255, c"), 128, true);
954 iStat += EqnTest(_nrT("0 ? a=a+1 : 666, a"), 1, true);
955 iStat += EqnTest(_nrT("1?a=10:a=20, a"), 10, true);
956 iStat += EqnTest(_nrT("0?a=10:a=20, a"), 20, true);
957 iStat += EqnTest(_nrT("0?a=sum(3,4):10, a"), 1, true); // a should not change its value due to lazy calculation
958
959 iStat += EqnTest(_nrT("a=1?b=1?3:4:5, a"), 3, true);
960 iStat += EqnTest(_nrT("a=1?b=1?3:4:5, b"), 3, true);
961 iStat += EqnTest(_nrT("a=0?b=1?3:4:5, a"), 5, true);
962 iStat += EqnTest(_nrT("a=0?b=1?3:4:5, b"), 2, true);
963
964 iStat += EqnTest(_nrT("a=1?5:b=1?3:4, a"), 5, true);
965 iStat += EqnTest(_nrT("a=1?5:b=1?3:4, b"), 2, true);
966 iStat += EqnTest(_nrT("a=0?5:b=1?3:4, a"), 3, true);
967 iStat += EqnTest(_nrT("a=0?5:b=1?3:4, b"), 3, true);
968
969 if (iStat==0)
970 mu::console() << _nrT("Abgeschlossen.");
971 else
972 mu::console() << _nrT("\n -> Wenn-Dann-Sonst fehlgeschlagen mit ") << iStat << _nrT(" Fehlern.") << endl;
973
974 return iStat;
975 }
976
977 //---------------------------------------------------------------------------
979 {
980 int iStat = 0;
981 cerr << "\r \r";
982 mu::console() << _nrT(" -> Teste Fehlercodes ... ");
983
984 iStat += ThrowTest(_nrT("3+"), ecUNEXPECTED_EOF);
985 iStat += ThrowTest(_nrT("3+)"), ecUNEXPECTED_PARENS);
986 iStat += ThrowTest(_nrT("()"), ecUNEXPECTED_PARENS);
987 iStat += ThrowTest(_nrT("3+()"), ecUNEXPECTED_PARENS);
988 iStat += ThrowTest(_nrT("sin(3,4)"), ecTOO_MANY_PARAMS);
989 iStat += ThrowTest(_nrT("sin()"), ecTOO_FEW_PARAMS);
990 iStat += ThrowTest(_nrT("(1+2"), ecMISSING_PARENS);
991 iStat += ThrowTest(_nrT("sin(3)3"), ecUNEXPECTED_VAL);
992 iStat += ThrowTest(_nrT("sin(3)xyz"), ecUNASSIGNABLE_TOKEN);
993 iStat += ThrowTest(_nrT("sin(3)cos(3)"), ecUNEXPECTED_FUN);
994 iStat += ThrowTest(_nrT("a+b+c=10"), ecUNEXPECTED_OPERATOR);
995 iStat += ThrowTest(_nrT("a=b=3"), ecUNEXPECTED_OPERATOR);
996
997 // functions without parameter
998 iStat += ThrowTest( _nrT("3+ping(2)"), ecTOO_MANY_PARAMS);
999 iStat += ThrowTest( _nrT("3+ping(a+2)"), ecTOO_MANY_PARAMS);
1000 iStat += ThrowTest( _nrT("3+ping(sin(a)+2)"), ecTOO_MANY_PARAMS);
1001 iStat += ThrowTest( _nrT("3+ping(1+sin(a))"), ecTOO_MANY_PARAMS);
1002
1003 // String function related
1004 iStat += ThrowTest( _nrT("valueof(\"xxx\")"), 999, false);
1005 iStat += ThrowTest( _nrT("valueof()"), ecUNEXPECTED_PARENS);
1006 iStat += ThrowTest( _nrT("1+valueof(\"abc\""), ecMISSING_PARENS);
1007 iStat += ThrowTest( _nrT("valueof(\"abc\""), ecMISSING_PARENS);
1008 iStat += ThrowTest( _nrT("valueof(\"abc"), ecUNTERMINATED_STRING);
1009 iStat += ThrowTest( _nrT("valueof(\"abc\",3)"), ecTOO_MANY_PARAMS);
1010 iStat += ThrowTest( _nrT("valueof(3)"), ecSTRING_EXPECTED);
1011 iStat += ThrowTest( _nrT("sin(\"abc\")"), ecVAL_EXPECTED);
1012 iStat += ThrowTest( _nrT("valueof(\"\\\"abc\\\"\")"), 999, false);
1013 iStat += ThrowTest( _nrT("\"hello world\""), ecSTR_RESULT);
1014 iStat += ThrowTest( _nrT("(\"hello world\")"), ecSTR_RESULT);
1015 iStat += ThrowTest( _nrT("\"abcd\"+100"), ecOPRT_TYPE_CONFLICT);
1016 iStat += ThrowTest( _nrT("\"a\"+\"b\""), ecOPRT_TYPE_CONFLICT);
1017 iStat += ThrowTest( _nrT("strfun1(\"100\",3)"), ecTOO_MANY_PARAMS);
1018 iStat += ThrowTest( _nrT("strfun2(\"100\",3,5)"), ecTOO_MANY_PARAMS);
1019 iStat += ThrowTest( _nrT("strfun3(\"100\",3,5,6)"), ecTOO_MANY_PARAMS);
1020 iStat += ThrowTest( _nrT("strfun2(\"100\")"), ecTOO_FEW_PARAMS);
1021 iStat += ThrowTest( _nrT("strfun3(\"100\",6)"), ecTOO_FEW_PARAMS);
1022 iStat += ThrowTest( _nrT("strfun2(1,1)"), ecSTRING_EXPECTED);
1023 iStat += ThrowTest( _nrT("strfun2(a,1)"), ecSTRING_EXPECTED);
1024 iStat += ThrowTest( _nrT("strfun2(1,1,1)"), ecTOO_MANY_PARAMS);
1025 iStat += ThrowTest( _nrT("strfun2(a,1,1)"), ecTOO_MANY_PARAMS);
1026 iStat += ThrowTest( _nrT("strfun3(1,2,3)"), ecSTRING_EXPECTED);
1027 iStat += ThrowTest( _nrT("strfun3(1, \"100\",3)"), ecSTRING_EXPECTED);
1028 iStat += ThrowTest( _nrT("strfun3(\"1\", \"100\",3)"), ecVAL_EXPECTED);
1029 iStat += ThrowTest( _nrT("strfun3(\"1\", 3, \"100\")"), ecVAL_EXPECTED);
1030 iStat += ThrowTest( _nrT("strfun3(\"1\", \"100\", \"100\", \"100\")"), ecTOO_MANY_PARAMS);
1031
1032 // assignement operator
1033 iStat += ThrowTest( _nrT("3=4"), ecUNEXPECTED_OPERATOR);
1034 iStat += ThrowTest( _nrT("sin(8)=4"), ecUNEXPECTED_OPERATOR);
1035 iStat += ThrowTest( _nrT("\"test\"=a"), ecUNEXPECTED_OPERATOR);
1036
1037 // <ibg 20090529>
1038 // this is now legal, for reference see:
1039 // https://sourceforge.net/forum/message.php?msg_id=7411373
1040 // iStat += ThrowTest( _nrT("sin=9"), ecUNEXPECTED_OPERATOR);
1041 // </ibg>
1042
1043 iStat += ThrowTest( _nrT("(8)=5"), ecUNEXPECTED_OPERATOR);
1044 iStat += ThrowTest( _nrT("(a)=5"), ecUNEXPECTED_OPERATOR);
1045 iStat += ThrowTest( _nrT("a=\"tttt\""), ecOPRT_TYPE_CONFLICT);
1046
1047 if (iStat==0)
1048 mu::console() << _nrT("Abgeschlossen.");
1049 else
1050 mu::console() << _nrT("\n -> Fehlercodes fehlgeschlagen mit ") << iStat << _nrT(" Fehlern.") << endl;
1051
1052 return iStat;
1053 }
1054
1055
1056 //---------------------------------------------------------------------------
1057 void ParserTester::AddTest(testfun_type a_pFun)
1058 {
1059 m_vTestFun.push_back(a_pFun);
1060 }
1061
1062 //---------------------------------------------------------------------------
1064 {
1065 int iStat = 0;
1066 try
1067 {
1068 for (int i=0; i<(int)m_vTestFun.size(); ++i)
1069 iStat += (this->*m_vTestFun[i])();
1070 }
1071 catch(Parser::exception_type &e)
1072 {
1073 mu::console() << "\n" << e.GetMsg() << endl;
1074 mu::console() << e.GetToken() << endl;
1075 Abort();
1076 }
1077 catch(std::exception &e)
1078 {
1079 mu::console() << e.what() << endl;
1080 Abort();
1081 }
1082 catch(...)
1083 {
1084 mu::console() << "Internal error";
1085 Abort();
1086 }
1087
1088 if (iStat==0)
1089 {
1090 cerr << "\r \r";
1091 mu::console() << " -> Erfolgreich abgeschlossen (" << ParserTester::c_iCount << " Ausdruecke)";
1092 }
1093 else
1094 {
1095 mu::console() << " -> FEHLSCHLAG: " << iStat
1096 << " Fehler (" << ParserTester::c_iCount
1097 << " Ausdruecke)" << endl;
1098 }
1100 }
1101
1102
1103 //---------------------------------------------------------------------------
1104 int ParserTester::ThrowTest(const string_type &a_str, int a_iErrc, bool a_bFail)
1105 {
1107
1108 try
1109 {
1110 value_type fVal[] = {1,1,1};
1111 Parser p;
1112
1113 p.DefineVar( _nrT("a"), &fVal[0]);
1114 p.DefineVar( _nrT("b"), &fVal[1]);
1115 p.DefineVar( _nrT("c"), &fVal[2]);
1116 //p.DefinePostfixOprt( _nrT("{m}"), Milli);
1117 p.DefinePostfixOprt( _nrT("m"), Milli);
1118 p.DefineFun( _nrT("ping"), Ping);
1119 p.DefineFun( _nrT("valueof"), ValueOf);
1120 p.DefineFun( _nrT("strfun1"), StrFun1);
1121 p.DefineFun( _nrT("strfun2"), StrFun2);
1122 p.DefineFun( _nrT("strfun3"), StrFun3);
1123 p.SetExpr(a_str);
1124 p.Eval();
1125 }
1126 catch(ParserError &e)
1127 {
1128 // output the formula in case of an failed test
1129 if (a_bFail==false || (a_bFail==true && a_iErrc!=e.GetCode()) )
1130 {
1131 mu::console() << _nrT("\n ")
1132 << _nrT("Expression: ") << a_str
1133 << _nrT(" Code:") << e.GetCode() << _nrT("(") << e.GetMsg() << _nrT(")")
1134 << _nrT(" Expected:") << a_iErrc;
1135 }
1136
1137 return (a_iErrc==e.GetCode()) ? 0 : 1;
1138 }
1139
1140 // if a_bFail==false no exception is expected
1141 bool bRet((a_bFail==false) ? 0 : 1);
1142 if (bRet==1)
1143 {
1144 mu::console() << _nrT("\n ")
1145 << _nrT("Expression: ") << a_str
1146 << _nrT(" did evaluate; Expected error:") << a_iErrc;
1147 }
1148
1149 return bRet;
1150 }
1151
1152 //---------------------------------------------------------------------------
1158 double a_fVar1,
1159 double a_fRes1,
1160 double a_fVar2,
1161 double a_fRes2)
1162 {
1164 value_type fVal[2] = {-999, -999 }; // should be equalinitially
1165
1166 try
1167 {
1168 Parser p;
1169
1170 // variable
1171 value_type var = 0;
1172 p.DefineVar( _nrT("a"), &var);
1173 p.SetExpr(a_str);
1174
1175 var = a_fVar1;
1176 fVal[0] = p.Eval();
1177
1178 var = a_fVar2;
1179 fVal[1] = p.Eval();
1180
1181 if ( fabs(a_fRes1-fVal[0]) > 0.0000000001)
1182 throw std::runtime_error("incorrect result (first pass)");
1183
1184 if ( fabs(a_fRes2-fVal[1]) > 0.0000000001)
1185 throw std::runtime_error("incorrect result (second pass)");
1186 }
1187 catch(Parser::exception_type &e)
1188 {
1189 mu::console() << _nrT("\n fail: ") << a_str.c_str() << _nrT(" (") << e.GetMsg() << _nrT(")");
1190 return 1;
1191 }
1192 catch(std::exception &e)
1193 {
1194 mu::console() << _nrT("\n fail: ") << a_str.c_str() << _nrT(" (") << e.what() << _nrT(")");
1195 return 1; // always return a failure since this exception is not expected
1196 }
1197 catch(...)
1198 {
1199 mu::console() << _nrT("\n fail: ") << a_str.c_str() << _nrT(" (unexpected exception)");
1200 return 1; // exceptions other than ParserException are not allowed
1201 }
1202
1203 return 0;
1204 }
1205
1206 //---------------------------------------------------------------------------
1211 int ParserTester::EqnTest(const string_type &a_str, double a_fRes, bool a_fPass)
1212 {
1214 int iRet(0);
1215 value_type fVal[5] = {-999, -998, -997, -996, -995}; // initially should be different
1216
1217 try
1218 {
1219 std::unique_ptr<Parser> p1;
1220 Parser p2, p3; // three parser objects
1221 // they will be used for testing copy and assihnment operators
1222 // p1 is a pointer since i'm going to delete it in order to test if
1223 // parsers after copy construction still refer to members of it.
1224 // !! If this is the case this function will crash !!
1225 //cerr << 0 << endl;
1226 p1.reset(new mu::Parser());
1227 //cerr << 1 << endl;
1228 // Add constants
1230 p1->DefineConst( _nrT("e"), (value_type)PARSER_CONST_E);
1231 p1->DefineConst( _nrT("const"), 1);
1232 p1->DefineConst( _nrT("const1"), 2);
1233 p1->DefineConst( _nrT("const2"), 3);
1234 // variables
1235 value_type vVarVal[] = { 1, 2, 3, -2};
1236 p1->DefineVar( _nrT("a"), &vVarVal[0]);
1237 p1->DefineVar( _nrT("aa"), &vVarVal[1]);
1238 p1->DefineVar( _nrT("b"), &vVarVal[1]);
1239 p1->DefineVar( _nrT("c"), &vVarVal[2]);
1240 p1->DefineVar( _nrT("d"), &vVarVal[3]);
1241
1242 // custom value ident functions
1243 p1->AddValIdent(&ParserTester::IsHexVal);
1244 //cerr << 2 << endl;
1245 // functions
1246 p1->DefineFun( _nrT("ping"), Ping);
1247 p1->DefineFun( _nrT("f1of1"), f1of1); // one parameter
1248 p1->DefineFun( _nrT("f1of2"), f1of2); // two parameter
1249 p1->DefineFun( _nrT("f2of2"), f2of2);
1250 p1->DefineFun( _nrT("f1of3"), f1of3); // three parameter
1251 p1->DefineFun( _nrT("f2of3"), f2of3);
1252 p1->DefineFun( _nrT("f3of3"), f3of3);
1253 p1->DefineFun( _nrT("f1of4"), f1of4); // four parameter
1254 p1->DefineFun( _nrT("f2of4"), f2of4);
1255 p1->DefineFun( _nrT("f3of4"), f3of4);
1256 p1->DefineFun( _nrT("f4of4"), f4of4);
1257 p1->DefineFun( _nrT("f1of5"), f1of5); // five parameter
1258 p1->DefineFun( _nrT("f2of5"), f2of5);
1259 p1->DefineFun( _nrT("f3of5"), f3of5);
1260 p1->DefineFun( _nrT("f4of5"), f4of5);
1261 p1->DefineFun( _nrT("f5of5"), f5of5);
1262
1263 // binary operators
1264 p1->DefineOprt( _nrT("add"), add, 0);
1265 p1->DefineOprt( _nrT("++"), add, 0);
1266 p1->DefineOprt( _nrT("&"), land, prLAND);
1267
1268 // sample functions
1269 p1->DefineFun( _nrT("min"), Min);
1270 p1->DefineFun( _nrT("max"), Max);
1271 p1->DefineFun( _nrT("sum"), Sum);
1272 p1->DefineFun( _nrT("valueof"), ValueOf);
1273 p1->DefineFun( _nrT("atof"), StrToFloat);
1274 p1->DefineFun( _nrT("strfun1"), StrFun1);
1275 p1->DefineFun( _nrT("strfun2"), StrFun2);
1276 p1->DefineFun( _nrT("strfun3"), StrFun3);
1277 p1->DefineFun( _nrT("lastArg"), LastArg);
1278 p1->DefineFun( _nrT("firstArg"), FirstArg);
1279 p1->DefineFun( _nrT("order"), FirstArg);
1280 //cerr << 3 << endl;
1281 // infix / postfix operator
1282 // Note: Identifiers used here do not have any meaning
1283 // they are mere placeholders to test certain features.
1284 p1->DefineInfixOprt( _nrT("$"), sign, prPOW+1); // sign with high priority
1285 p1->DefineInfixOprt( _nrT("~"), plus2); // high priority
1286 p1->DefineInfixOprt( _nrT("~~"), plus2);
1287 //p1->DefinePostfixOprt( _nrT("{m}"), Milli);
1288 //p1->DefinePostfixOprt( _nrT("{M}"), Mega);
1289 p1->DefinePostfixOprt( _nrT("m"), Milli);
1290 p1->DefinePostfixOprt( _nrT("meg"), Mega);
1291 p1->DefinePostfixOprt( _nrT("#"), times3);
1292 p1->DefinePostfixOprt( _nrT("'"), sqr);
1293 //cerr << 4 << endl;
1294 p1->SetExpr(a_str);
1295 // Test bytecode integrity
1296 // String parsing and bytecode parsing must yield the same result
1297 fVal[0] = p1->Eval(); // result from stringparsing
1298 fVal[1] = p1->Eval(); // result from bytecode
1299 if (fVal[0]!=fVal[1])
1300 throw Parser::exception_type( _nrT("Bytecode / string parsing mismatch.") );
1301
1302 //std::cerr << 1 << endl;
1303 // Test copy and assignement operators
1304 try
1305 {
1306 // Test copy constructor
1307 std::vector<mu::Parser> vParser;
1308 vParser.push_back(*(p1.get()));
1309 mu::Parser p2 = vParser[0]; // take parser from vector
1310
1311 // destroy the originals from p2
1312 vParser.clear(); // delete the vector
1313 p1.reset(0);
1314
1315 fVal[2] = p2.Eval();
1316
1317 // Test assignement operator
1318 // additionally disable Optimizer this time
1319 mu::Parser p3;
1320 p3 = p2;
1321 p3.EnableOptimizer(false);
1322 fVal[3] = p3.Eval();
1323
1324 // Test Eval function for multiple return values
1325 // use p2 since it has the optimizer enabled!
1326 int nNum;
1327 value_type *v = p2.Eval(nNum);
1328 fVal[4] = v[nNum-1];
1329 //std::cerr << 2 << endl;
1330 }
1331 catch(std::exception &e)
1332 {
1333 mu::console() << _nrT("\n ") << e.what() << _nrT("\n");
1334 }
1335
1336 // limited floating point accuracy requires the following test
1337 bool bCloseEnough(true);
1338 for (unsigned i=0; i<sizeof(fVal)/sizeof(value_type); ++i)
1339 {
1340 bCloseEnough &= (fabs(a_fRes-fVal[i]) <= fabs(fVal[i]*0.00001));
1341
1342 // The tests equations never result in infinity, if they do thats a bug.
1343 // reference:
1344 // http://sourceforge.net/projects/muparser/forums/forum/462843/topic/5037825
1345 if (numeric_limits<value_type>::has_infinity)
1346 bCloseEnough &= (fabs(fVal[i]) != numeric_limits<value_type>::infinity());
1347 }
1348 //std::cerr << 3 << endl;
1349 iRet = ((bCloseEnough && a_fPass) || (!bCloseEnough && !a_fPass)) ? 0 : 1;
1350
1351
1352 if (iRet==1)
1353 {
1354 mu::console() << _nrT("\n fail: ") << a_str.c_str()
1355 << _nrT(" (incorrect result; expected: ") << a_fRes
1356 << _nrT(" ;calculated: ") << fVal[0] << _nrT(",")
1357 << fVal[1] << _nrT(",")
1358 << fVal[2] << _nrT(",")
1359 << fVal[3] << _nrT(",")
1360 << fVal[4] << _nrT(").");
1361 }
1362 }
1363 catch(Parser::exception_type &e)
1364 {
1365 if (a_fPass)
1366 {
1367 if (fVal[0]!=fVal[2] && fVal[0]!=-999 && fVal[1]!=-998)
1368 mu::console() << _nrT("\n fail: ") << a_str.c_str() << _nrT(" (copy construction)");
1369 else
1370 mu::console() << _nrT("\n fail: ") << a_str.c_str() << _nrT(" (") << e.GetMsg() << _nrT(")");
1371 return 1;
1372 }
1373 }
1374 catch(std::exception &e)
1375 {
1376 mu::console() << _nrT("\n fail: ") << a_str.c_str() << _nrT(" (") << e.what() << _nrT(")");
1377 return 1; // always return a failure since this exception is not expected
1378 }
1379 catch(...)
1380 {
1381 mu::console() << _nrT("\n fail: ") << a_str.c_str() << _nrT(" (unexpected exception)");
1382 return 1; // exceptions other than ParserException are not allowed
1383 }
1384
1385 return iRet;
1386 }
1387
1388 //---------------------------------------------------------------------------
1389 int ParserTester::EqnTestInt(const string_type &a_str, double a_fRes, bool a_fPass)
1390 {
1392
1393 value_type vVarVal[] = {1, 2, 3}; // variable values
1394 value_type fVal[2] = {-99, -999}; // results: initially should be different
1395 int iRet(0);
1396
1397 try
1398 {
1399 ParserInt p;
1400 p.DefineConst( _nrT("const1"), 1);
1401 p.DefineConst( _nrT("const2"), 2);
1402 p.DefineVar( _nrT("a"), &vVarVal[0]);
1403 p.DefineVar( _nrT("b"), &vVarVal[1]);
1404 p.DefineVar( _nrT("c"), &vVarVal[2]);
1405
1406 p.SetExpr(a_str);
1407 fVal[0] = p.Eval(); // result from stringparsing
1408 fVal[1] = p.Eval(); // result from bytecode
1409
1410 if (fVal[0]!=fVal[1])
1411 throw Parser::exception_type( _nrT("Bytecode corrupt.") );
1412
1413 iRet = ( (a_fRes==fVal[0] && a_fPass) ||
1414 (a_fRes!=fVal[0] && !a_fPass) ) ? 0 : 1;
1415 if (iRet==1)
1416 {
1417 mu::console() << _nrT("\n fail: ") << a_str.c_str()
1418 << _nrT(" (incorrect result; expected: ") << a_fRes
1419 << _nrT(" ;calculated: ") << fVal[0]<< _nrT(").");
1420 }
1421 }
1422 catch(Parser::exception_type &e)
1423 {
1424 if (a_fPass)
1425 {
1426 mu::console() << _nrT("\n fail: ") << e.GetExpr() << _nrT(" : ") << e.GetMsg();
1427 iRet = 1;
1428 }
1429 }
1430 catch(...)
1431 {
1432 mu::console() << _nrT("\n fail: ") << a_str.c_str() << _nrT(" (unexpected exception)");
1433 iRet = 1; // exceptions other than ParserException are not allowed
1434 }
1435
1436 return iRet;
1437 }
1438
1439 //---------------------------------------------------------------------------
1442 {
1443 mu::console() << _nrT("Test failed (internal error in test class)") << endl;
1444 while (!getchar());
1445 exit(-1);
1446 }
1447 } // namespace test
1448} // namespace mu
void SetExpr(StringView a_sExpr)
Set the expression. Triggers first time calculation thus the creation of the bytecode and scanning of...
value_type Eval()
Single-value wrapper around the vectorized overload of this member function.
const varmap_type & GetVar() const
Return a map containing the used variables only.
void EnableOptimizer(bool a_bIsOn=true)
Enable or disable the formula optimization feature.
const varmap_type & GetUsedVar()
Return a map containing the used variables only.
void DefineVar(const string_type &a_sName, value_type *a_fVar)
Add a user defined variable.
void DefineConst(const string_type &a_sName, value_type a_fVal)
Add a user defined constant.
void RemoveVar(const string_type &a_strVarName)
Remove a variable from internal storage.
void DefinePostfixOprt(const string_type &a_strFun, fun_type1 a_pOprt, bool optimizeAway=true)
Add a user defined operator.
ParserError exception_type
Type of the error class.
Definition: muParserBase.h:96
void ClearPostfixOprt()
Clear all user defined postfix operators.
void ClearConst()
Clear all user defined constants.
void DefineFun(const string_type &a_strName, T a_pFun, bool optimizeAway=true)
Define a parser function without arguments.
Definition: muParserBase.h:156
void EnableBuiltInOprt(bool a_bIsOn=true)
Enable or disable the built in binary operators.
Error class of the parser.
EErrorCodes GetCode() const
Return the error code.
const string_type & GetMsg() const
Returns the message string for this error.
const string_type & GetExpr() const
gets the expression related tp this error.
const string_type & GetToken() const
Return string related with this token (if available).
Mathematical expressions parser.
Definition: muParser.h:51
Mathematical expressions parser.
Definition: muParserInt.h:47
static value_type f2of4(value_type, value_type v, value_type, value_type)
Definition: muParserTest.h:65
static value_type ValueOf(const char_type *)
Definition: muParserTest.h:127
static value_type Sum(const value_type *a_afArg, int a_iArgc)
Definition: muParserTest.h:102
static value_type f2of3(value_type, value_type v, value_type)
Definition: muParserTest.h:61
static value_type StrFun3(const char_type *v1, value_type v2, value_type v3)
Definition: muParserTest.h:146
std::vector< testfun_type > m_vTestFun
Definition: muParserTest.h:190
static value_type Mega(value_type a_fVal)
Definition: muParserTest.h:161
void Abort() const
Internal error in test class Test is going to be aborted.
static value_type Min(value_type a_fVal1, value_type a_fVal2)
Definition: muParserTest.h:75
int ThrowTest(const string_type &a_str, int a_iErrc, bool a_bFail=true)
int EqnTestInt(const string_type &a_str, double a_fRes, bool a_fPass)
static value_type add(value_type v1, value_type v2)
Definition: muParserTest.h:82
static value_type f4of5(value_type, value_type, value_type, value_type v, value_type)
Definition: muParserTest.h:72
static value_type f3of3(value_type, value_type, value_type v)
Definition: muParserTest.h:62
static value_type FirstArg(const value_type *a_afArg, int a_iArgc)
Definition: muParserTest.h:86
static value_type plus2(value_type v1)
Definition: muParserTest.h:78
static value_type land(value_type v1, value_type v2)
Definition: muParserTest.h:83
static value_type times3(value_type v1)
Definition: muParserTest.h:79
static value_type LastArg(const value_type *a_afArg, int a_iArgc)
Definition: muParserTest.h:94
static value_type Ping()
Definition: muParserTest.h:122
static value_type f2of2(value_type, value_type v)
Definition: muParserTest.h:58
static value_type f4of4(value_type, value_type, value_type, value_type v)
Definition: muParserTest.h:67
static value_type Milli(value_type a_fVal)
Definition: muParserTest.h:163
static value_type f1of4(value_type v, value_type, value_type, value_type)
Definition: muParserTest.h:64
static value_type Max(value_type a_fVal1, value_type a_fVal2)
Definition: muParserTest.h:76
static value_type sign(value_type v)
Definition: muParserTest.h:81
void AddTest(testfun_type a_pFun)
int EqnTest(const string_type &a_str, double a_fRes, bool a_fPass)
Evaluate a tet expression.
static value_type f3of4(value_type, value_type, value_type v, value_type)
Definition: muParserTest.h:66
static value_type f2of5(value_type, value_type v, value_type, value_type, value_type)
Definition: muParserTest.h:70
int EqnTestWithVarChange(const string_type &a_str, double a_fRes1, double a_fVar1, double a_fRes2, double a_fVar2)
Evaluate a tet expression.
static value_type StrFun1(const char_type *v1)
Definition: muParserTest.h:132
int TestNames()
Check muParser name restriction enforcement.
static value_type f1of3(value_type v, value_type, value_type)
Definition: muParserTest.h:60
static value_type f1of1(value_type v)
Definition: muParserTest.h:55
static value_type f3of5(value_type, value_type, value_type v, value_type, value_type)
Definition: muParserTest.h:71
static value_type StrToFloat(const char_type *a_szMsg)
Definition: muParserTest.h:153
static value_type f5of5(value_type, value_type, value_type, value_type, value_type v)
Definition: muParserTest.h:73
static value_type f1of2(value_type v, value_type)
Definition: muParserTest.h:57
static value_type sqr(value_type v1)
Definition: muParserTest.h:80
static value_type f1of5(value_type v, value_type, value_type, value_type, value_type)
Definition: muParserTest.h:69
static value_type StrFun2(const char_type *v1, value_type v2)
Definition: muParserTest.h:139
static int IsHexVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal)
#define _nrT(x)
Activate this option in order to compile with OpenMP support.
Definition: muParserDef.h:62
#define PARSER_CONST_E
#define PARSER_CONST_PI
#define PARSER_THROWCHECK(DOMAIN, FAIL, EXPR, ARG)
This file contains the parser test class.
Namespace for mathematical applications.
Definition: muParser.cpp:53
MUP_BASETYPE value_type
The numeric datatype used by the parser.
Definition: muParserDef.h:251
string_type::value_type char_type
The character type used by the parser.
Definition: muParserDef.h:263
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:268
std::map< string_type, value_type * > varmap_type
Type used for storing variables.
Definition: muParserDef.h:273
std::ostream & console()
Encapsulate cout.
Definition: muParserDef.h:131
@ ecMISPLACED_COLON
Definition: muParserError.h:91
@ ecUNASSIGNABLE_TOKEN
Token cant be identified.
Definition: muParserError.h:53
@ ecMISSING_PARENS
Missing parens. (Example: "3*sin(3")
Definition: muParserError.h:63
@ ecUNEXPECTED_EOF
Unexpected end of formula. (Example: "2+sin(")
Definition: muParserError.h:54
@ ecSTRING_EXPECTED
A string function has been called with a different type of argument.
Definition: muParserError.h:61
@ ecTOO_MANY_PARAMS
Too many function parameters.
Definition: muParserError.h:66
@ ecVAL_EXPECTED
A numerical function has been called with a non value type of argument.
Definition: muParserError.h:62
@ ecUNEXPECTED_FUN
Unexpected function found. (Example: "sin(8)cos(9)")
Definition: muParserError.h:64
@ ecSTR_RESULT
result is a string
Definition: muParserError.h:69
@ ecUNEXPECTED_OPERATOR
Unexpected binary operator found.
Definition: muParserError.h:52
@ ecOPRT_TYPE_CONFLICT
binary operators may only be applied to value items of the same type
Definition: muParserError.h:68
@ ecUNEXPECTED_PARENS
Unexpected Parenthesis, opening or closing.
Definition: muParserError.h:59
@ ecMISSING_ELSE_CLAUSE
Definition: muParserError.h:90
@ ecUNTERMINATED_STRING
unterminated string constant. (Example: "3*valueof("hello)")
Definition: muParserError.h:65
@ ecUNEXPECTED_CONDITIONAL
Definition: muParserError.h:89
@ ecTOO_FEW_PARAMS
Too few function parameters. (Example: "ite(1<2,2)")
Definition: muParserError.h:67
@ ecUNEXPECTED_VAL
An unexpected value token has been found.
Definition: muParserError.h:57
std::string string_type
The stringtype used by the parser.
Definition: muParserDef.h:257
@ prPOW
power operator priority (highest)
Definition: muParserDef.h:237
@ prLAND
Definition: muParserDef.h:232