3 _____ __ _____________ _______ ______ ___________
4 / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \
5 | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/
6 |__|_| /____/| __(____ /__| /____ >\___ >__|
8 Copyright (C) 2004 - 2020 Ingo Berg
10 Redistribution and use in source and binary forms, with or without modification, are permitted
11 provided that the following conditions are met:
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.
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.
29 #include "muParserTest.h"
48 // Forward declarations
51 // Operator callback functions
52 static value_type Mega(value_type a_fVal) { return a_fVal * 1e6; }
53 static value_type Milli(value_type a_fVal) { return a_fVal / (value_type)1e3; }
54 static value_type Rnd(value_type v) { return v * std::rand() / (value_type)(RAND_MAX + 1.0); }
55 static value_type Not(value_type v) { return v == 0; }
56 static value_type Add(value_type v1, value_type v2) { return v1 + v2; }
57 static value_type Mul(value_type v1, value_type v2) { return v1 * v2; }
58 static value_type Arg2Of2(value_type /* v1 */, value_type v2) { return v2; }
59 static value_type Arg1Of2(value_type v1, value_type /* v2 */) { return v1; }
62 static value_type ThrowAnException(value_type)
64 throw std::runtime_error("This function does throw an exception.");
68 static value_type BulkFun1(int nBulkIdx, int nThreadIdx, value_type v1)
70 // Note: I'm just doing something with all three parameters to shut
71 // compiler warnings up!
72 return (value_type)nBulkIdx + nThreadIdx + v1;
76 static value_type Ping()
78 mu::console() << "ping\n";
83 static value_type StrFun0(const char_type* szMsg)
86 mu::console() << szMsg << std::endl;
92 static value_type StrFun2(const char_type* v1, value_type v2, value_type v3)
94 mu::console() << v1 << std::endl;
99 static value_type Debug(mu::value_type v1, mu::value_type v2)
101 ParserBase::EnableDebugDump(v1 != 0, v2 != 0);
102 mu::console() << _T("Bytecode dumping ") << ((v1 != 0) ? _T("active") : _T("inactive")) << _T("\n");
107 // Factory function for creating new parser variables
108 // This could as well be a function performing database queries.
109 static value_type* AddVariable(const char_type* a_szName, void* a_pUserData)
111 // I don't want dynamic allocation here, so i used this static buffer
112 // If you want dynamic allocation you must allocate all variables dynamically
113 // in order to delete them later on. Or you find other ways to keep track of
114 // variables that have been created implicitely.
115 static value_type afValBuf[100];
116 static int iVal = -1;
121 << _T("Generating new variable \"")
122 << a_szName << std::dec << _T("\" (slots left: ")
123 << 99 - iVal << _T(")")
124 << _T(" User data pointer is:")
125 << std::hex << a_pUserData << endl;
130 throw mu::ParserError(_T("Variable buffer overflow."));
132 return &afValBuf[iVal];
135 int IsBinValue(const char_type* a_szExpr, int* a_iPos, value_type* a_fVal)
137 if (a_szExpr[0] != 0 && a_szExpr[1] != 'b')
141 unsigned iBits = sizeof(iVal) * 8;
144 for (i = 0; (a_szExpr[i + 2] == '0' || a_szExpr[i + 2] == '1') && i < iBits; ++i)
145 iVal |= (int)(a_szExpr[i + 2] == '1') << ((iBits - 1) - i);
151 throw mu::Parser::exception_type(_T("Binary to integer conversion error (overflow)."));
153 *a_fVal = (unsigned)(iVal >> (iBits - i));
159 static int IsHexValue(const char_type* a_szExpr, int* a_iPos, value_type* a_fVal)
161 if (a_szExpr[1] == 0 || (a_szExpr[0] != '0' || a_szExpr[1] != 'x'))
166 // New code based on streams for UNICODE compliance:
167 stringstream_type::pos_type nPos(0);
168 stringstream_type ss(a_szExpr + 2);
169 ss >> std::hex >> iVal;
172 if (nPos == (stringstream_type::pos_type)0)
175 *a_iPos += (int)(2 + nPos);
176 *a_fVal = (value_type)iVal;
184 mu::console() << _T("\n");
185 mu::console() << _T(R"( _____ __ _____________ ________ _____ ____________ )") << _T("\n");
186 mu::console() << _T(R"( / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ )") << _T("\n");
187 mu::console() << _T(R"( | Y Y \ | / |_> > ___ \| | \/\___\\ ___/ | | \/ )") << _T("\n");
188 mu::console() << _T(R"( |__|_| /____/| __(____ /___| /___ >\___ >|__| )") << _T("\n");
189 mu::console() << _T(R"( \/ |__| \/ \/ \/ )") << _T("\n");
190 mu::console() << _T(" Version ") << Parser().GetVersion(pviFULL) << _T("\n");
191 mu::console() << _T(" (C) 2004 - 2020 Ingo Berg\n");
192 mu::console() << _T("\n");
193 mu::console() << _T("-----------------------------------------------------------\n");
195 #if defined(__clang__)
196 // Note: CLANG also identifies as GCC 4.2.1
197 mu::console() << _T(" Compiled with CLANG Version ") << __clang_major__ << _T(".") << __clang_minor__ << _T(".") << __clang_patchlevel__ << _T("\n");
198 #elif defined (__GNUC__)
199 mu::console() << _T(" Compiled with GCC Version ") << __GNUC__ << _T(".") << __GNUC_MINOR__ << _T(".") << __GNUC_PATCHLEVEL__ << _T("\n");
200 #elif defined(_MSC_VER)
201 mu::console() << _T(" Compiled with MSVC Version ") << _MSC_VER << _T("\n");
204 mu::console() << _T(" IEEE 754 (IEC 559) is ") << ((std::numeric_limits<double>::is_iec559) ? "Available" : " NOT AVAILABLE") << _T("\n");
205 mu::console() << _T(" ") << sizeof(void*) * 8 << _T("-bit build\n");
209 static value_type SelfTest()
211 mu::console() << _T("-----------------------------------------------------------\n");
212 mu::console() << _T("Running unit tests:\n\n");
214 // Skip the self test if the value type is set to an integer type.
215 if (mu::TypeInfo<mu::value_type>::IsInteger())
217 mu::console() << _T(" Test skipped: integer data type are not compatible with the unit test!\n\n");
221 mu::Test::ParserTester pt;
229 static value_type Help()
231 mu::console() << _T("-----------------------------------------------------------\n");
232 mu::console() << _T("Commands:\n\n");
233 mu::console() << _T(" list var - list parser variables\n");
234 mu::console() << _T(" list exprvar - list expression variables\n");
235 mu::console() << _T(" list const - list all numeric parser constants\n");
236 mu::console() << _T(" opt on - enable optimizer (default)\n");
237 mu::console() << _T(" opt off - disable optimizer\n");
238 mu::console() << _T(" locale de - switch to german locale\n");
239 mu::console() << _T(" locale en - switch to english locale\n");
240 mu::console() << _T(" locale reset - reset locale\n");
241 mu::console() << _T(" test bulk - test bulk mode\n");
242 mu::console() << _T(" quit - exits the parser\n");
243 mu::console() << _T("\nConstants:\n\n");
244 mu::console() << _T(" \"_e\" 2.718281828459045235360287\n");
245 mu::console() << _T(" \"_pi\" 3.141592653589793238462643\n");
246 mu::console() << _T("-----------------------------------------------------------\n");
251 static void ListVar(const mu::ParserBase& parser)
253 // Query the used variables (must be done after calc)
254 mu::varmap_type variables = parser.GetVar();
255 if (!variables.size())
258 cout << "\nParser variables:\n";
259 cout << "-----------------\n";
260 cout << "Number: " << (int)variables.size() << "\n";
261 varmap_type::const_iterator item = variables.begin();
262 for (; item != variables.end(); ++item)
263 mu::console() << _T("Name: ") << item->first << _T(" Address: [0x") << item->second << _T("]\n");
267 static void ListConst(const mu::ParserBase& parser)
269 mu::console() << _T("\nParser constants:\n");
270 mu::console() << _T("-----------------\n");
272 mu::valmap_type cmap = parser.GetConst();
275 mu::console() << _T("Expression does not contain constants\n");
279 valmap_type::const_iterator item = cmap.begin();
280 for (; item != cmap.end(); ++item)
281 mu::console() << _T(" ") << item->first << _T(" = ") << item->second << _T("\n");
286 static void ListExprVar(const mu::ParserBase& parser)
288 string_type sExpr = parser.GetExpr();
289 if (sExpr.length() == 0)
291 cout << _T("Expression string is empty\n");
295 // Query the used variables (must be done after calc)
296 mu::console() << _T("\nExpression variables:\n");
297 mu::console() << _T("---------------------\n");
298 mu::console() << _T("Expression: ") << parser.GetExpr() << _T("\n");
300 varmap_type variables = parser.GetUsedVar();
301 if (!variables.size())
303 mu::console() << _T("Expression does not contain variables\n");
307 mu::console() << _T("Number: ") << (int)variables.size() << _T("\n");
308 mu::varmap_type::const_iterator item = variables.begin();
309 for (; item != variables.end(); ++item)
310 mu::console() << _T("Name: ") << item->first << _T(" Address: [0x") << item->second << _T("]\n");
315 /** \brief Check for external keywords.
317 static int CheckKeywords(const mu::char_type* a_szLine, mu::Parser& a_Parser)
319 string_type sLine(a_szLine);
321 if (sLine == _T("quit"))
325 else if (sLine == _T("list var"))
330 else if (sLine == _T("opt on"))
332 a_Parser.EnableOptimizer(true);
333 mu::console() << _T("Optimizer enabled\n");
336 else if (sLine == _T("opt off"))
338 a_Parser.EnableOptimizer(false);
339 mu::console() << _T("Optimizer disabled\n");
342 else if (sLine == _T("list const"))
347 else if (sLine == _T("list exprvar"))
349 ListExprVar(a_Parser);
352 else if (sLine == _T("locale de"))
354 mu::console() << _T("Setting german locale: ArgSep=';' DecSep=',' ThousandsSep='.'\n");
355 a_Parser.SetArgSep(';');
356 a_Parser.SetDecSep(',');
357 a_Parser.SetThousandsSep('.');
360 else if (sLine == _T("locale en"))
362 mu::console() << _T("Setting english locale: ArgSep=',' DecSep='.' ThousandsSep=''\n");
363 a_Parser.SetArgSep(',');
364 a_Parser.SetDecSep('.');
365 a_Parser.SetThousandsSep();
368 else if (sLine == _T("locale reset"))
370 mu::console() << _T("Resetting locale\n");
371 a_Parser.ResetLocale();
374 else if (sLine == _T("test bulk"))
376 mu::console() << _T("Testing bulk mode\n");
380 else if (sLine == _T("dbg"))
382 std::string dbg = R"(6 - 6 ? 4 : "", ? 4 : "", ? 4 : ""), 1)";
383 a_Parser.SetExpr(dbg);
384 mu::console() << dbg;
387 double* v = a_Parser.Eval(stackSize);
388 mu::console() << *v << std::endl;
398 const int nBulkSize = 200;
399 value_type* x = new value_type[nBulkSize];
400 value_type* y = new value_type[nBulkSize];
401 value_type* result = new value_type[nBulkSize];
405 for (int i = 0; i < nBulkSize; ++i)
408 y[i] = (value_type)i / 10;
411 parser.DefineVar(_T("x"), x);
412 parser.DefineVar(_T("y"), y);
413 parser.DefineFun(_T("fun1"), BulkFun1);
414 parser.SetExpr(_T("fun1(0)+x+y"));
415 parser.Eval(result, nBulkSize);
417 for (int i = 0; i < nBulkSize; ++i)
419 mu::console() << _T("Eqn. ") << i << _T(": x=") << x[i] << _T("; y=") << y[i] << _T("; result=") << result[i] << _T("\n");
440 // Add some variables
441 value_type vVarVal[] = { 1, 2 }; // Values of the parser variables
442 parser.DefineVar(_T("a"), &vVarVal[0]); // Assign Variable names and bind them to the C++ variables
443 parser.DefineVar(_T("b"), &vVarVal[1]);
444 parser.DefineVar(_T("ft"), &vVarVal[1]);
445 parser.DefineStrConst(_T("sVar1"), _T("Sample string 1"));
446 parser.DefineStrConst(_T("sVar2"), _T("Sample string 2"));
447 parser.AddValIdent(IsHexValue);
448 parser.AddValIdent(IsBinValue);
450 // Add user defined unary operators
451 parser.DefinePostfixOprt(_T("M"), Mega);
452 parser.DefinePostfixOprt(_T("m"), Milli);
453 parser.DefineInfixOprt(_T("!"), Not);
454 parser.DefineFun(_T("strfun0"), StrFun0);
455 parser.DefineFun(_T("strfun2"), StrFun2);
456 parser.DefineFun(_T("ping"), Ping);
457 parser.DefineFun(_T("rnd"), Rnd); // Add an unoptimizeable function
458 parser.DefineFun(_T("throw"), ThrowAnException);
460 parser.DefineOprt(_T("add"), Add, 0);
461 parser.DefineOprt(_T("mul"), Mul, 1);
463 // These are service and debug functions
464 parser.DefineFun(_T("debug"), Debug);
465 parser.DefineFun(_T("selftest"), SelfTest);
466 parser.DefineFun(_T("help"), Help);
467 parser.DefineFun(_T("arg2of2"), Arg2Of2);
468 parser.DefineFun(_T("arg1of2"), Arg1Of2);
470 parser.DefinePostfixOprt(_T("{ft}"), Milli);
471 parser.DefinePostfixOprt(_T("ft"), Milli);
473 // Define the variable factory
474 parser.SetVarFactory(AddVariable, &parser);
481 std::getline(mu::console_in(), sLine);
483 switch (CheckKeywords(sLine.c_str(), parser))
493 parser.SetExpr(sLine);
494 mu::console() << std::setprecision(12);
496 // There are multiple ways to retrieve the result...
497 // 1.) If you know there is only a single return value or in case you only need the last
498 // result of an expression consisting of comma separated subexpressions you can
500 mu::console() << _T("ans=") << parser.Eval() << _T("\n");
502 // 2.) As an alternative you can also retrieve multiple return values using this API:
503 int nNum = parser.GetNumResults();
506 mu::console() << _T("Multiple return values detected! Complete list:\n");
508 // this is the hard way if you need to retrieve multiple subexpression
510 value_type* v = parser.Eval(nNum);
511 mu::console() << std::setprecision(12);
512 for (int i = 0; i < nNum; ++i)
514 mu::console() << v[i] << _T("\n");
518 catch (mu::Parser::exception_type& e)
520 mu::console() << _T("\nError:\n");
521 mu::console() << _T("------\n");
522 mu::console() << _T("Message: ") << e.GetMsg() << _T("\n");
523 mu::console() << _T("Expression: \"") << e.GetExpr() << _T("\"\n");
524 mu::console() << _T("Token: \"") << e.GetToken() << _T("\"\n");
525 mu::console() << _T("Position: ") << (int)e.GetPos() << _T("\n");
526 mu::console() << _T("Errc: ") << std::dec << e.GetCode() << _T("\n");
532 int main(int, char**)
538 mu::console() << _T("Enter an expression or a command:\n");
544 catch (Parser::exception_type& e)
546 // Only erros raised during the initialization will end up here
547 // formula related errors are treated in Calc()
548 console() << _T("Initialization error: ") << e.GetMsg() << endl;
549 console() << _T("aborting...") << endl;
551 console_in() >> sBuf;
553 catch (std::exception& /*exc*/)
555 // there is no unicode compliant way to query exc.what()
556 // i'll leave it for this example.
557 console() << _T("aborting...\n");