1 //---------------------------------------------------------------------------
2 //
3 //                 __________
4 //    _____   __ __\______   \_____  _______  ______  ____ _______
5 //   /     \ |  |  \|     ___/\__  \ \_  __ \/  ___/_/ __ \\_  __ \
6 //  |  Y Y  \|  |  /|    |     / __ \_|  | \/\___ \ \  ___/ |  | \/
7 //  |__|_|  /|____/ |____|    (____  /|__|  /____  > \___  >|__|
8 //        \/                       \/            \/      \/
9 //  (C) 2015 Ingo Berg
10 //
11 //  example1.cpp - using the parser as a static library
12 //
13 //---------------------------------------------------------------------------
14 
15 #include "muParserTest.h"
16 
17 #if defined(_WIN32) && defined(_DEBUG)
18   #define _CRTDBG_MAP_ALLOC
19   #include <stdlib.h>
20   #include <crtdbg.h>
21   #define CREATE_LEAKAGE_REPORT
22 #endif
23 
24 #if defined( USINGDLL ) && defined( _WIN32 )
25 #error This sample can be used only with STATIC builds of muParser (on win32)
26 #endif
27 
28 /** \brief This macro will enable mathematical constants like M_PI. */
29 #define _USE_MATH_DEFINES
30 
31 #include <cstdlib>
32 #include <cstring>
33 #include <cmath>
34 #include <string>
35 #include <iostream>
36 #include <locale>
37 #include <limits>
38 #include <ios>
39 #include <iomanip>
40 #include <numeric>
41 
42 #include "muParser.h"
43 
44 using namespace std;
45 using namespace mu;
46 
47 
48 #if defined(CREATE_LEAKAGE_REPORT)
49 
50 // Dumping memory leaks in the destructor of the static guard
51 // guarantees i won't get false positives from the ParserErrorMsg
52 // class wich is a singleton with a static instance.
53 struct DumpLeaks
54 {
~DumpLeaksDumpLeaks55  ~DumpLeaks()
56   {
57     _CrtDumpMemoryLeaks();
58   }
59 } static LeakDumper;
60 
61 #endif
62 
63 // Forward declarations
64 void CalcBulk();
65 
66 // Operator callback functions
Mega(value_type a_fVal)67 value_type Mega(value_type a_fVal) { return a_fVal * 1e6; }
Milli(value_type a_fVal)68 value_type Milli(value_type a_fVal) { return a_fVal / (value_type)1e3; }
Rnd(value_type v)69 value_type Rnd(value_type v) { return v*std::rand()/(value_type)(RAND_MAX+1.0); }
Not(value_type v)70 value_type Not(value_type v) { return v==0; }
Add(value_type v1,value_type v2)71 value_type Add(value_type v1, value_type v2) { return v1+v2; }
Mul(value_type v1,value_type v2)72 value_type Mul(value_type v1, value_type v2) { return v1*v2; }
73 
74 //---------------------------------------------------------------------------
ThrowAnException(value_type)75 value_type ThrowAnException(value_type)
76 {
77   throw std::runtime_error("This function does throw an exception.");
78 }
79 
80 //---------------------------------------------------------------------------
BulkFun1(int nBulkIdx,int nThreadIdx,value_type v1)81 value_type BulkFun1(int nBulkIdx, int nThreadIdx, value_type v1)
82 {
83   // Note: I'm just doing something with all three parameters to shut
84   // compiler warnings up!
85   return nBulkIdx + nThreadIdx + v1;
86 }
87 
88 //---------------------------------------------------------------------------
Ping()89 value_type Ping()
90 {
91   mu::console() << "ping\n";
92   return 0;
93 }
94 
95 //---------------------------------------------------------------------------
StrFun0(const char_type * szMsg)96 value_type StrFun0(const char_type *szMsg)
97 {
98   if (szMsg)
99     mu::console() << szMsg << std::endl;
100 
101   return 999;
102 }
103 
104 //---------------------------------------------------------------------------
StrFun2(const char_type * v1,value_type v2,value_type v3)105 value_type StrFun2(const char_type *v1, value_type v2,value_type v3)
106 {
107   mu::console() << v1 << std::endl;
108   return v2+v3;
109 }
110 
111 //---------------------------------------------------------------------------
Debug(mu::value_type v1,mu::value_type v2)112 value_type Debug(mu::value_type v1, mu::value_type v2)
113 {
114   ParserBase::EnableDebugDump(v1!=0, v2!=0);
115   mu::console() << _T("Bytecode dumping ") << ((v1!=0) ? _T("active") : _T("inactive")) << _T("\n");
116   return 1;
117 }
118 
119 //---------------------------------------------------------------------------
120 // Factory function for creating new parser variables
121 // This could as well be a function performing database queries.
AddVariable(const char_type * a_szName,void * a_pUserData)122 value_type* AddVariable(const char_type *a_szName, void *a_pUserData)
123 {
124   // I don't want dynamic allocation here, so i used this static buffer
125   // If you want dynamic allocation you must allocate all variables dynamically
126   // in order to delete them later on. Or you find other ways to keep track of
127   // variables that have been created implicitely.
128   static value_type afValBuf[100];
129   static int iVal = -1;
130 
131   ++iVal;
132 
133   mu::console() << _T("Generating new variable \"")
134                 << a_szName << std::dec << _T("\" (slots left: ")
135                 << 99-iVal << _T(")")
136                 << _T(" User data pointer is:")
137                 << std::hex << a_pUserData <<endl;
138   afValBuf[iVal] = 0;
139 
140   if (iVal>=99)
141     throw mu::ParserError( _T("Variable buffer overflow.") );
142   else
143     return &afValBuf[iVal];
144 }
145 
IsHexValue(const char_type * a_szExpr,int * a_iPos,value_type * a_fVal)146 int IsHexValue(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal)
147 {
148   if (a_szExpr[1]==0 || (a_szExpr[0]!='0' || a_szExpr[1]!='x') )
149     return 0;
150 
151   unsigned iVal(0);
152 
153   // New code based on streams for UNICODE compliance:
154   stringstream_type::pos_type nPos(0);
155   stringstream_type ss(a_szExpr + 2);
156   ss >> std::hex >> iVal;
157   nPos = ss.tellg();
158 
159   if (nPos==(stringstream_type::pos_type)0)
160     return 1;
161 
162   *a_iPos += (int)(2 + nPos);
163   *a_fVal = (value_type)iVal;
164 
165   return 1;
166 }
167 
168 //---------------------------------------------------------------------------
Splash()169 void Splash()
170 {
171   mu::console() << _T("                 __________                                       \n");
172   mu::console() << _T("    _____   __ __\\______   \\_____  _______  ______  ____ _______\n");
173   mu::console() << _T("   /     \\ |  |  \\|     ___/\\__  \\ \\_  __ \\/  ___/_/ __ \\\\_  __ \\ \n");
174   mu::console() << _T("  |  Y Y  \\|  |  /|    |     / __ \\_|  | \\/\\___ \\ \\  ___/ |  | \\/ \n");
175   mu::console() << _T("  |__|_|  /|____/ |____|    (____  /|__|  /____  > \\___  >|__|    \n");
176   mu::console() << _T("        \\/                       \\/            \\/      \\/         \n");
177   mu::console() << _T("  Version ") << Parser().GetVersion(pviFULL) << _T("\n");
178   mu::console() << _T("  (C) 2015 Ingo Berg\n");
179 }
180 
181 //---------------------------------------------------------------------------
SelfTest()182 value_type SelfTest()
183 {
184   mu::console() << _T( "-----------------------------------------------------------\n");
185   mu::console() << _T( "Running test suite:\n\n");
186 
187   // Skip the self test if the value type is set to an integer type.
188   if (mu::TypeInfo<mu::value_type>::IsInteger())
189   {
190     mu::console() << _T( "  Test skipped: integer data type are not compatible with the unit test!\n\n");
191   }
192   else
193   {
194     mu::Test::ParserTester pt;
195     pt.Run();
196   }
197 
198   return 0;
199 }
200 
201 //---------------------------------------------------------------------------
Help()202 value_type Help()
203 {
204   mu::console() << _T( "-----------------------------------------------------------\n");
205   mu::console() << _T( "Commands:\n\n");
206   mu::console() << _T( "  list var     - list parser variables\n");
207   mu::console() << _T( "  list exprvar - list expression variables\n");
208   mu::console() << _T( "  list const   - list all numeric parser constants\n");
209   mu::console() << _T( "  opt on       - enable optimizer (default)\n");
210   mu::console() << _T( "  opt off      - disable optimizer\n");
211   mu::console() << _T( "  locale de    - switch to german locale\n");
212   mu::console() << _T( "  locale en    - switch to english locale\n");
213   mu::console() << _T( "  locale reset - reset locale\n");
214   mu::console() << _T( "  test bulk    - test bulk mode\n");
215   mu::console() << _T( "  quit         - exits the parser\n");
216   mu::console() << _T( "\nConstants:\n\n");
217   mu::console() << _T( "  \"_e\"   2.718281828459045235360287\n");
218   mu::console() << _T( "  \"_pi\"  3.141592653589793238462643\n");
219   mu::console() << _T( "-----------------------------------------------------------\n");
220   return 0;
221 }
222 
223 //---------------------------------------------------------------------------
224 /*
225 void CheckLocale()
226 {
227   // Local names:
228   // "C" - the classic C locale
229   // "de_DE" - not for Windows?
230   // "en_US" - not for Windows?
231   // "German_germany" - For MSVC8
232   try
233   {
234     std::locale loc("German_germany");
235     console() << _T("Locale settings:\n");
236     console() << _T("  Decimal point:  '") << std::use_facet<numpunct<char_type> >(loc).decimal_point() << _T("'\n");
237     console() << _T("  Thousands sep:  '") << std::use_facet<numpunct<char_type> >(loc).thousands_sep() << _T("'\n");
238     console() << _T("  Grouping:       '") << std::use_facet<numpunct<char_type> >(loc).grouping()  << _T("'\n");
239     console() << _T("  True is named:  '") << std::use_facet<numpunct<char_type> >(loc).truename()  << _T("'\n");
240     console() << _T("  False is named: '") << std::use_facet<numpunct<char_type> >(loc).falsename() << _T("'\n");
241     console() << _T("-----------------------------------------------------------\n");
242   }
243   catch(...)
244   {
245     console() << _T("Locale settings:\n");
246     console() << _T("  invalid locale name\n");
247     console() << _T("-----------------------------------------------------------\n");
248   }
249 }
250 
251 //---------------------------------------------------------------------------
252 void CheckDiff()
253 {
254   mu::Parser  parser;
255   value_type x = 1,
256              v1,
257              v2,
258              v3,
259              eps(pow(std::numeric_limits<value_type>::epsilon(), 0.2));
260   parser.DefineVar(_T("x"), &x);
261   parser.SetExpr(_T("_e^-x*sin(x)"));
262 
263   v1 = parser.Diff(&x, 1),
264   v2 = parser.Diff(&x, 1, eps);
265   v3 = cos((value_type)1.0)/exp((value_type)1) - sin((value_type)1.0)/exp((value_type)1); //-0.110793765307;
266   mu::console() << parser.GetExpr() << _T("\n");
267   mu::console() << _T("v1 = ") << v1 << _T("; v1-v3 = ") << v1-v3 << _T("\n");
268   mu::console() << _T("v2 = ") << v2 << _T("; v2-v3 = ") << v2-v3 << _T("\n");
269 }
270 */
271 
272 //---------------------------------------------------------------------------
ListVar(const mu::ParserBase & parser)273 void ListVar(const mu::ParserBase &parser)
274 {
275   // Query the used variables (must be done after calc)
276   mu::varmap_type variables = parser.GetVar();
277   if (!variables.size())
278     return;
279 
280   cout << "\nParser variables:\n";
281   cout <<   "-----------------\n";
282   cout << "Number: " << (int)variables.size() << "\n";
283   varmap_type::const_iterator item = variables.begin();
284   for (; item!=variables.end(); ++item)
285     mu::console() << _T("Name: ") << item->first << _T("   Address: [0x") << item->second << _T("]\n");
286 }
287 
288 //---------------------------------------------------------------------------
ListConst(const mu::ParserBase & parser)289 void ListConst(const mu::ParserBase &parser)
290 {
291   mu::console() << _T("\nParser constants:\n");
292   mu::console() << _T("-----------------\n");
293 
294   mu::valmap_type cmap = parser.GetConst();
295   if (!cmap.size())
296   {
297     mu::console() << _T("Expression does not contain constants\n");
298   }
299   else
300   {
301     valmap_type::const_iterator item = cmap.begin();
302     for (; item!=cmap.end(); ++item)
303       mu::console() << _T("  ") << item->first << _T(" =  ") << item->second << _T("\n");
304   }
305 }
306 
307 //---------------------------------------------------------------------------
ListExprVar(const mu::ParserBase & parser)308 void ListExprVar(const mu::ParserBase &parser)
309 {
310   string_type sExpr = parser.GetExpr();
311   if (sExpr.length()==0)
312   {
313     cout << _T("Expression string is empty\n");
314     return;
315   }
316 
317   // Query the used variables (must be done after calc)
318   mu::console() << _T("\nExpression variables:\n");
319   mu::console() <<   _T("---------------------\n");
320   mu::console() << _T("Expression: ") << parser.GetExpr() << _T("\n");
321 
322   varmap_type variables = parser.GetUsedVar();
323   if (!variables.size())
324   {
325     mu::console() << _T("Expression does not contain variables\n");
326   }
327   else
328   {
329     mu::console() << _T("Number: ") << (int)variables.size() << _T("\n");
330     mu::varmap_type::const_iterator item = variables.begin();
331     for (; item!=variables.end(); ++item)
332       mu::console() << _T("Name: ") << item->first << _T("   Address: [0x") << item->second << _T("]\n");
333   }
334 }
335 
336 //---------------------------------------------------------------------------
337 /** \brief Check for external keywords.
338 */
CheckKeywords(const mu::char_type * a_szLine,mu::Parser & a_Parser)339 int CheckKeywords(const mu::char_type *a_szLine, mu::Parser &a_Parser)
340 {
341   string_type sLine(a_szLine);
342 
343   if ( sLine == _T("quit") )
344   {
345     return -1;
346   }
347   else if ( sLine == _T("list var") )
348   {
349     ListVar(a_Parser);
350     return 1;
351   }
352   else if ( sLine == _T("opt on") )
353   {
354     a_Parser.EnableOptimizer(true);
355     mu::console() << _T("Optimizer enabled\n");
356     return 1;
357   }
358   else if ( sLine == _T("opt off") )
359   {
360     a_Parser.EnableOptimizer(false);
361     mu::console() << _T("Optimizer disabled\n");
362     return 1;
363   }
364   else if ( sLine == _T("list const") )
365   {
366     ListConst(a_Parser);
367     return 1;
368   }
369   else if ( sLine == _T("list exprvar") )
370   {
371     ListExprVar(a_Parser);
372     return 1;
373   }
374   else if ( sLine == _T("locale de") )
375   {
376     mu::console() << _T("Setting german locale: ArgSep=';' DecSep=',' ThousandsSep='.'\n");
377     a_Parser.SetArgSep(';');
378     a_Parser.SetDecSep(',');
379     a_Parser.SetThousandsSep('.');
380     return 1;
381   }
382   else if ( sLine == _T("locale en") )
383   {
384     mu::console() << _T("Setting english locale: ArgSep=',' DecSep='.' ThousandsSep=''\n");
385     a_Parser.SetArgSep(',');
386     a_Parser.SetDecSep('.');
387     a_Parser.SetThousandsSep();
388     return 1;
389   }
390   else if ( sLine == _T("locale reset") )
391   {
392     mu::console() << _T("Resetting locale\n");
393     a_Parser.ResetLocale();
394     return 1;
395   }
396   else if ( sLine == _T("test bulk") )
397   {
398     mu::console() << _T("Testing bulk mode\n");
399     CalcBulk();
400     return 1;
401   }
402 
403   return 0;
404 }
405 
406 //---------------------------------------------------------------------------
CalcBulk()407 void CalcBulk()
408 {
409   const int nBulkSize = 200;
410   value_type *x = new value_type[nBulkSize];
411   value_type *y = new value_type[nBulkSize];
412   value_type *result = new value_type[nBulkSize];
413 
414   try
415   {
416     for (int i=0; i<nBulkSize; ++i)
417     {
418       x[i] = i;
419       y[i] = (value_type)i/10;
420     }
421     mu::Parser  parser;
422     parser.DefineVar(_T("x"), x);
423     parser.DefineVar(_T("y"), y);
424     parser.DefineFun(_T("fun1"), BulkFun1);
425     parser.SetExpr(_T("fun1(0)+x+y"));
426     parser.Eval(result, nBulkSize);
427 
428     for (int i=0; i<nBulkSize; ++i)
429     {
430       mu::console() << _T("Eqn. ") << i << _T(": x=") << x[i] << _T("; y=") << y[i] << _T("; result=") << result[i] << _T("\n");
431     }
432   }
433   catch(...)
434   {
435     delete [] x;
436     delete [] y;
437     delete [] result;
438     throw;
439   }
440 
441   delete [] x;
442   delete [] y;
443   delete [] result;
444 }
445 
446 //---------------------------------------------------------------------------
Calc()447 void Calc()
448 {
449   mu::Parser  parser;
450 
451   // Change locale settings if necessary
452   // function argument separator:   sum(2;3;4) vs. sum(2,3,4)
453   // decimal separator:             3,14       vs. 3.14
454   // thousands separator:           1000000    vs 1.000.000
455 //#define USE_GERMAN_LOCALE
456 #ifdef  USE_GERMAN_LOCALE
457   parser.SetArgSep(';');
458   parser.SetDecSep(',');
459   parser.SetThousandsSep('.');
460 #else
461   // this is the default, so i it's commented:
462   //parser.SetArgSep(',');
463   //parser.SetDecSep('.');
464   //parser.SetThousandsSep('');
465 #endif
466 
467   // Add some variables
468   value_type  vVarVal[] = { 1, 2 }; // Values of the parser variables
469   parser.DefineVar(_T("a"), &vVarVal[0]);  // Assign Variable names and bind them to the C++ variables
470   parser.DefineVar(_T("b"), &vVarVal[1]);
471   parser.DefineVar(_T("ft"), &vVarVal[1]);
472   parser.DefineStrConst(_T("sVar1"), _T("Sample string 1") );
473   parser.DefineStrConst(_T("sVar2"), _T("Sample string 2") );
474   parser.AddValIdent(IsHexValue);
475 
476   // Add user defined unary operators
477   parser.DefinePostfixOprt(_T("M"), Mega);
478   parser.DefinePostfixOprt(_T("m"), Milli);
479   parser.DefineInfixOprt(_T("!"), Not);
480   parser.DefineFun(_T("strfun0"), StrFun0);
481   parser.DefineFun(_T("strfun2"), StrFun2);
482   parser.DefineFun(_T("ping"), Ping);
483   parser.DefineFun(_T("rnd"), Rnd);     // Add an unoptimizeable function
484   parser.DefineFun(_T("throw"), ThrowAnException);
485 
486 
487   parser.DefineOprt(_T("add"), Add, 0);
488   parser.DefineOprt(_T("mul"), Mul, 1);
489 
490   // These are service and debug functions
491   parser.DefineFun(_T("debug"), Debug);
492   parser.DefineFun(_T("selftest"), SelfTest);
493   parser.DefineFun(_T("help"), Help);
494 
495   parser.DefinePostfixOprt(_T("{ft}"), Milli);
496   parser.DefinePostfixOprt(_T("ft"), Milli);
497 #ifdef _DEBUG
498 //  parser.EnableDebugDump(1, 0);
499 #endif
500 
501   // Define the variable factory
502   parser.SetVarFactory(AddVariable, &parser);
503 
504   for(;;)
505   {
506     try
507     {
508       string_type sLine;
509       std::getline(mu::console_in(), sLine);
510 
511       switch (CheckKeywords(sLine.c_str(), parser))
512       {
513       case  0: break;
514       case  1: continue;
515       case -1: return;
516       }
517 
518       if (!sLine.length())
519         continue;
520 
521       parser.SetExpr(sLine);
522       mu::console() << std::setprecision(12);
523 
524       // There are multiple ways to retrieve the result...
525       // 1.) If you know there is only a single return value or in case you only need the last
526       //     result of an expression consisting of comma separated subexpressions you can
527       //     simply use:
528       mu::console() << _T("ans=") << parser.Eval() << _T("\n");
529 
530       // 2.) As an alternative you can also retrieve multiple return values using this API:
531       int nNum = parser.GetNumResults();
532       if (nNum>1)
533       {
534         mu::console() << _T("Multiple return values detected! Complete list:\n");
535 
536         // this is the hard way if you need to retrieve multiple subexpression
537         // results
538         value_type *v = parser.Eval(nNum);
539         mu::console() << std::setprecision(12);
540         for (int i=0; i<nNum; ++i)
541         {
542           mu::console() << v[i] << _T("\n");
543         }
544       }
545     }
546     catch(mu::Parser::exception_type &e)
547     {
548       mu::console() << _T("\nError:\n");
549       mu::console() << _T("------\n");
550       mu::console() << _T("Message:     ")   << e.GetMsg()   << _T("\n");
551       mu::console() << _T("Expression:  \"") << e.GetExpr()  << _T("\"\n");
552       mu::console() << _T("Token:       \"") << e.GetToken()    << _T("\"\n");
553       mu::console() << _T("Position:    ")   << (int)e.GetPos() << _T("\n");
554       mu::console() << _T("Errc:        ")   << std::dec << e.GetCode() << _T("\n");
555     }
556   } // while running
557 }
558 
559 //---------------------------------------------------------------------------
main(int,char **)560 int main(int, char**)
561 {
562   Splash();
563   SelfTest();
564   Help();
565 
566 //  CheckLocale();
567 //  CheckDiff();
568 
569   mu::console() << _T("Enter an expression or a command:\n");
570 
571   try
572   {
573     Calc();
574   }
575   catch(Parser::exception_type &e)
576   {
577     // Only erros raised during the initialization will end up here
578     // formula related errors are treated in Calc()
579     console() << _T("Initialization error:  ") << e.GetMsg() << endl;
580     console() << _T("aborting...") << endl;
581     string_type sBuf;
582     console_in() >> sBuf;
583   }
584   catch(std::exception & /*exc*/)
585   {
586     // there is no unicode compliant way to query exc.what()
587     // so i'll leave it for this example.
588     console() << _T("aborting...\n");
589   }
590 
591   return 0;
592 }
593