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