Build internal muparser more simply
[alexxy/gromacs.git] / src / external / muparser / samples / example1 / example1.cpp
1 /*
2
3          _____  __ _____________ _______  ______ ___________
4         /     \|  |  \____ \__  \\_  __ \/  ___// __ \_  __ \
5    |  Y Y  \  |  /  |_> > __ \|  | \/\___ \\  ___/|  | \/
6    |__|_|  /____/|   __(____  /__|  /____  >\___  >__|
7                  \/      |__|       \/           \/     \/
8    Copyright (C) 2004 - 2020 Ingo Berg
9
10         Redistribution and use in source and binary forms, with or without modification, are permitted
11         provided that the following conditions are met:
12
13           * Redistributions of source code must retain the above copyright notice, this list of
14                 conditions and the following disclaimer.
15           * Redistributions in binary form must reproduce the above copyright notice, this list of
16                 conditions and the following disclaimer in the documentation and/or other materials provided
17                 with the distribution.
18
19         THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
20         IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21         FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22         CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23         DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24         DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25         IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26         OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "muParserTest.h"
30
31 #include <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 // Forward declarations
49 void CalcBulk();
50
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; }
60
61
62 static value_type ThrowAnException(value_type)
63 {
64         throw std::runtime_error("This function does throw an exception.");
65 }
66
67
68 static value_type BulkFun1(int nBulkIdx, int nThreadIdx, value_type v1)
69 {
70         // Note: I'm just doing something with all three parameters to shut 
71         // compiler warnings up!
72         return (value_type)nBulkIdx + nThreadIdx + v1;
73 }
74
75
76 static value_type Ping()
77 {
78         mu::console() << "ping\n";
79         return 0;
80 }
81
82
83 static value_type StrFun0(const char_type* szMsg)
84 {
85         if (szMsg)
86                 mu::console() << szMsg << std::endl;
87
88         return 999;
89 }
90
91
92 static value_type StrFun2(const char_type* v1, value_type v2, value_type v3)
93 {
94         mu::console() << v1 << std::endl;
95         return v2 + v3;
96 }
97
98
99 static value_type Debug(mu::value_type v1, mu::value_type v2)
100 {
101         ParserBase::EnableDebugDump(v1 != 0, v2 != 0);
102         mu::console() << _T("Bytecode dumping ") << ((v1 != 0) ? _T("active") : _T("inactive")) << _T("\n");
103         return 1;
104 }
105
106
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)
110 {
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;
117
118         ++iVal;
119
120         mu::console()
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;
126
127         afValBuf[iVal] = 0;
128
129         if (iVal >= 99)
130                 throw mu::ParserError(_T("Variable buffer overflow."));
131         else
132                 return &afValBuf[iVal];
133 }
134
135 int IsBinValue(const char_type* a_szExpr, int* a_iPos, value_type* a_fVal)
136 {
137         if (a_szExpr[0] != 0 && a_szExpr[1] != 'b')
138                 return 0;
139
140         unsigned iVal = 0;
141         unsigned iBits = sizeof(iVal) * 8;
142         unsigned i = 0;
143
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);
146
147         if (i == 0)
148                 return 0;
149
150         if (i == iBits)
151                 throw mu::Parser::exception_type(_T("Binary to integer conversion error (overflow)."));
152
153         *a_fVal = (unsigned)(iVal >> (iBits - i));
154         *a_iPos += i + 2;
155
156         return 1;
157 }
158
159 static int IsHexValue(const char_type* a_szExpr, int* a_iPos, value_type* a_fVal)
160 {
161         if (a_szExpr[1] == 0 || (a_szExpr[0] != '0' || a_szExpr[1] != 'x'))
162                 return 0;
163
164         unsigned iVal(0);
165
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;
170         nPos = ss.tellg();
171
172         if (nPos == (stringstream_type::pos_type)0)
173                 return 1;
174
175         *a_iPos += (int)(2 + nPos);
176         *a_fVal = (value_type)iVal;
177
178         return 1;
179 }
180
181
182 static void Splash()
183 {
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");
194
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");
202 #endif
203
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");
206 }
207
208
209 static value_type SelfTest()
210 {
211         mu::console() << _T("-----------------------------------------------------------\n");
212         mu::console() << _T("Running unit tests:\n\n");
213
214         // Skip the self test if the value type is set to an integer type.
215         if (mu::TypeInfo<mu::value_type>::IsInteger())
216         {
217                 mu::console() << _T("  Test skipped: integer data type are not compatible with the unit test!\n\n");
218         }
219         else
220         {
221                 mu::Test::ParserTester pt;
222                 pt.Run();
223         }
224
225         return 0;
226 }
227
228
229 static value_type Help()
230 {
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");
247         return 0;
248 }
249
250
251 static void ListVar(const mu::ParserBase& parser)
252 {
253         // Query the used variables (must be done after calc)
254         mu::varmap_type variables = parser.GetVar();
255         if (!variables.size())
256                 return;
257
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");
264 }
265
266
267 static void ListConst(const mu::ParserBase& parser)
268 {
269         mu::console() << _T("\nParser constants:\n");
270         mu::console() << _T("-----------------\n");
271
272         mu::valmap_type cmap = parser.GetConst();
273         if (!cmap.size())
274         {
275                 mu::console() << _T("Expression does not contain constants\n");
276         }
277         else
278         {
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");
282         }
283 }
284
285
286 static void ListExprVar(const mu::ParserBase& parser)
287 {
288         string_type sExpr = parser.GetExpr();
289         if (sExpr.length() == 0)
290         {
291                 cout << _T("Expression string is empty\n");
292                 return;
293         }
294
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");
299
300         varmap_type variables = parser.GetUsedVar();
301         if (!variables.size())
302         {
303                 mu::console() << _T("Expression does not contain variables\n");
304         }
305         else
306         {
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");
311         }
312 }
313
314
315 /** \brief Check for external keywords.
316 */
317 static int CheckKeywords(const mu::char_type* a_szLine, mu::Parser& a_Parser)
318 {
319         string_type sLine(a_szLine);
320
321         if (sLine == _T("quit"))
322         {
323                 return -1;
324         }
325         else if (sLine == _T("list var"))
326         {
327                 ListVar(a_Parser);
328                 return 1;
329         }
330         else if (sLine == _T("opt on"))
331         {
332                 a_Parser.EnableOptimizer(true);
333                 mu::console() << _T("Optimizer enabled\n");
334                 return 1;
335         }
336         else if (sLine == _T("opt off"))
337         {
338                 a_Parser.EnableOptimizer(false);
339                 mu::console() << _T("Optimizer disabled\n");
340                 return 1;
341         }
342         else if (sLine == _T("list const"))
343         {
344                 ListConst(a_Parser);
345                 return 1;
346         }
347         else if (sLine == _T("list exprvar"))
348         {
349                 ListExprVar(a_Parser);
350                 return 1;
351         }
352         else if (sLine == _T("locale de"))
353         {
354                 mu::console() << _T("Setting german locale: ArgSep=';' DecSep=',' ThousandsSep='.'\n");
355                 a_Parser.SetArgSep(';');
356                 a_Parser.SetDecSep(',');
357                 a_Parser.SetThousandsSep('.');
358                 return 1;
359         }
360         else if (sLine == _T("locale en"))
361         {
362                 mu::console() << _T("Setting english locale: ArgSep=',' DecSep='.' ThousandsSep=''\n");
363                 a_Parser.SetArgSep(',');
364                 a_Parser.SetDecSep('.');
365                 a_Parser.SetThousandsSep();
366                 return 1;
367         }
368         else if (sLine == _T("locale reset"))
369         {
370                 mu::console() << _T("Resetting locale\n");
371                 a_Parser.ResetLocale();
372                 return 1;
373         }
374         else if (sLine == _T("test bulk"))
375         {
376                 mu::console() << _T("Testing bulk mode\n");
377                 CalcBulk();
378                 return 1;
379         }
380         else if (sLine == _T("dbg"))
381         {
382                 std::string dbg = R"(6 - 6 ? 4 : "", ? 4 : "", ? 4 : ""), 1)";
383                 a_Parser.SetExpr(dbg);
384                 mu::console() << dbg;
385
386                 int stackSize;
387                 double* v = a_Parser.Eval(stackSize);
388                 mu::console() << *v << std::endl;
389                 return 1;
390         }
391
392         return 0;
393 }
394
395
396 void CalcBulk()
397 {
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];
402
403         try
404         {
405                 for (int i = 0; i < nBulkSize; ++i)
406                 {
407                         x[i] = i;
408                         y[i] = (value_type)i / 10;
409                 }
410                 mu::Parser  parser;
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);
416
417                 for (int i = 0; i < nBulkSize; ++i)
418                 {
419                         mu::console() << _T("Eqn. ") << i << _T(": x=") << x[i] << _T("; y=") << y[i] << _T("; result=") << result[i] << _T("\n");
420                 }
421         }
422         catch (...)
423         {
424                 delete[] x;
425                 delete[] y;
426                 delete[] result;
427                 throw;
428         }
429
430         delete[] x;
431         delete[] y;
432         delete[] result;
433 }
434
435
436 static void Calc()
437 {
438         mu::Parser  parser;
439
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);
449
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);
459
460         parser.DefineOprt(_T("add"), Add, 0);
461         parser.DefineOprt(_T("mul"), Mul, 1);
462
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);
469
470         parser.DefinePostfixOprt(_T("{ft}"), Milli);
471         parser.DefinePostfixOprt(_T("ft"), Milli);
472
473         // Define the variable factory
474         parser.SetVarFactory(AddVariable, &parser);
475
476         for (;;)
477         {
478                 try
479                 {
480                         string_type sLine;
481                         std::getline(mu::console_in(), sLine);
482
483                         switch (CheckKeywords(sLine.c_str(), parser))
484                         {
485                         case  0: break;
486                         case  1: continue;
487                         case -1: return;
488                         }
489
490                         if (!sLine.length())
491                                 continue;
492
493                         parser.SetExpr(sLine);
494                         mu::console() << std::setprecision(12);
495
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 
499                         //     simply use: 
500                         mu::console() << _T("ans=") << parser.Eval() << _T("\n");
501
502                         // 2.) As an alternative you can also retrieve multiple return values using this API:
503                         int nNum = parser.GetNumResults();
504                         if (nNum > 1)
505                         {
506                                 mu::console() << _T("Multiple return values detected! Complete list:\n");
507
508                                 // this is the hard way if you need to retrieve multiple subexpression
509                                 // results
510                                 value_type* v = parser.Eval(nNum);
511                                 mu::console() << std::setprecision(12);
512                                 for (int i = 0; i < nNum; ++i)
513                                 {
514                                         mu::console() << v[i] << _T("\n");
515                                 }
516                         }
517                 }
518                 catch (mu::Parser::exception_type& e)
519                 {
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");
527                 }
528         } // while running
529 }
530
531
532 int main(int, char**)
533 {
534         Splash();
535         SelfTest();
536         Help();
537
538         mu::console() << _T("Enter an expression or a command:\n");
539
540         try
541         {
542                 Calc();
543         }
544         catch (Parser::exception_type& e)
545         {
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;
550                 string_type sBuf;
551                 console_in() >> sBuf;
552         }
553         catch (std::exception& /*exc*/)
554         {
555                 // there is no unicode compliant way to query exc.what()
556                 // i'll leave it for this example.
557                 console() << _T("aborting...\n");
558         }
559
560         return 0;
561 }