muParser API -  1.35
muParserBytecode.cpp
1 /*
2 
3  _____ __ _____________ _______ ______ ___________
4  / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \
5  | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/
6  |__|_| /____/| __(____ /__| /____ >\___ >__|
7  \/ |__| \/ \/ \/
8  Copyright (C) 2004 - 2022 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 "muParserBytecode.h"
30 
31 #include <algorithm>
32 #include <string>
33 #include <stack>
34 #include <vector>
35 #include <iostream>
36 
37 #include "muParserDef.h"
38 #include "muParserError.h"
39 #include "muParserToken.h"
40 #include "muParserTemplateMagic.h"
41 
42 #if defined(_MSC_VER)
43  #pragma warning(push)
44  #pragma warning(disable : 26812)
45 #endif
46 
47 
48 namespace mu
49 {
50  /** \brief Bytecode default constructor. */
52  : m_iStackPos(0)
53  , m_stringBuffer()
54  , m_expr()
55  , m_iMaxStackSize(0)
56  , m_vRPN()
57  , m_bEnableOptimizer(true)
58  {
59  m_vRPN.reserve(50);
60  }
61 
62 
63  /** \brief Copy constructor.
64 
65  Implemented in Terms of Assign(const ParserByteCode &a_ByteCode)
66  */
68  {
69  Assign(a_ByteCode);
70  }
71 
72 
73  /** \brief Assignment operator.
74 
75  Implemented in Terms of Assign(const ParserByteCode &a_ByteCode)
76  */
78  {
79  Assign(a_ByteCode);
80  return *this;
81  }
82 
83 
84  void ParserByteCode::EnableOptimizer(bool bStat)
85  {
86  m_bEnableOptimizer = bStat;
87  }
88 
89 
90  /** \brief Copy state of another object to this.
91 
92  \throw nowthrow
93  */
94  void ParserByteCode::Assign(const ParserByteCode& a_ByteCode)
95  {
96  if (this == &a_ByteCode)
97  return;
98 
99  m_iStackPos = a_ByteCode.m_iStackPos;
100  m_vRPN = a_ByteCode.m_vRPN;
101  m_iMaxStackSize = a_ByteCode.m_iMaxStackSize;
102  m_bEnableOptimizer = a_ByteCode.m_bEnableOptimizer;
103 
104  m_stringBuffer = a_ByteCode.m_stringBuffer;
105  m_expr = a_ByteCode.m_expr;
106  }
107 
108 
109  /** \brief Add a Variable pointer to bytecode.
110  \param a_pVar Pointer to be added.
111  \throw nothrow
112  */
114  {
115  ++m_iStackPos;
116  m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos);
117 
118  // optimization does not apply
119  SToken tok;
120  tok.Cmd = cmVAR;
121  tok.Val.ptr = a_pVar;
122  tok.Val.data = 1;
123  tok.Val.data2 = 0;
124  m_vRPN.push_back(tok);
125  }
126 
127 
128  /** \brief Add a Variable pointer to bytecode.
129 
130  Value entries in byte code consist of:
131  <ul>
132  <li>value array position of the value</li>
133  <li>the operator code according to ParserToken::cmVAL</li>
134  <li>the value stored in #mc_iSizeVal number of bytecode entries.</li>
135  </ul>
136 
137  \param a_pVal Value to be added.
138  \throw nothrow
139  */
141  {
142  ++m_iStackPos;
143  m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos);
144 
145  // If optimization does not apply
146  SToken tok;
147  tok.Cmd = cmVAL;
148  tok.Val.ptr = nullptr;
149  tok.Val.data = 0;
150  tok.Val.data2 = a_fVal;
151  m_vRPN.push_back(tok);
152  }
153 
154 
155  void ParserByteCode::ConstantFolding(ECmdCode a_Oprt)
156  {
157  std::size_t sz = m_vRPN.size();
158  value_type& x = m_vRPN[sz - 2].Val.data2;
159  value_type& y = m_vRPN[sz - 1].Val.data2;
160 
161  switch (a_Oprt)
162  {
163  case cmLAND: x = (int)x && (int)y; m_vRPN.pop_back(); break;
164  case cmLOR: x = (int)x || (int)y; m_vRPN.pop_back(); break;
165  case cmLT: x = x < y; m_vRPN.pop_back(); break;
166  case cmGT: x = x > y; m_vRPN.pop_back(); break;
167  case cmLE: x = x <= y; m_vRPN.pop_back(); break;
168  case cmGE: x = x >= y; m_vRPN.pop_back(); break;
169  case cmNEQ: x = x != y; m_vRPN.pop_back(); break;
170  case cmEQ: x = x == y; m_vRPN.pop_back(); break;
171  case cmADD: x = x + y; m_vRPN.pop_back(); break;
172  case cmSUB: x = x - y; m_vRPN.pop_back(); break;
173  case cmMUL: x = x * y; m_vRPN.pop_back(); break;
174  case cmDIV:
175  x = x / y;
176  m_vRPN.pop_back();
177  break;
178 
179  case cmPOW: x = MathImpl<value_type>::Pow(x, y);
180  m_vRPN.pop_back();
181  break;
182 
183  default:
184  break;
185  } // switch opcode
186  }
187 
188 
189  /** \brief Add an operator identifier to bytecode.
190 
191  Operator entries in byte code consist of:
192  <ul>
193  <li>value array position of the result</li>
194  <li>the operator code according to ParserToken::ECmdCode</li>
195  </ul>
196 
197  \sa ParserToken::ECmdCode
198  */
200  {
201  bool bOptimized = false;
202 
203  if (m_bEnableOptimizer)
204  {
205  std::size_t sz = m_vRPN.size();
206 
207  // Check for foldable constants like:
208  // cmVAL cmVAL cmADD
209  // where cmADD can stand fopr any binary operator applied to
210  // two constant values.
211  if (sz >= 2 && m_vRPN[sz - 2].Cmd == cmVAL && m_vRPN[sz - 1].Cmd == cmVAL)
212  {
213  ConstantFolding(a_Oprt);
214  bOptimized = true;
215  }
216  else
217  {
218  switch (a_Oprt)
219  {
220  case cmPOW:
221  // Optimization for polynomials of low order
222  if (m_vRPN[sz - 2].Cmd == cmVAR && m_vRPN[sz - 1].Cmd == cmVAL)
223  {
224  if (m_vRPN[sz - 1].Val.data2 == 0)
225  {
226  m_vRPN[sz - 2].Cmd = cmVAL;
227  m_vRPN[sz - 2].Val.ptr = nullptr;
228  m_vRPN[sz - 2].Val.data = 0;
229  m_vRPN[sz - 2].Val.data2 = 1;
230  }
231  else if (m_vRPN[sz - 1].Val.data2 == 1)
232  m_vRPN[sz - 2].Cmd = cmVAR;
233  else if (m_vRPN[sz - 1].Val.data2 == 2)
234  m_vRPN[sz - 2].Cmd = cmVARPOW2;
235  else if (m_vRPN[sz - 1].Val.data2 == 3)
236  m_vRPN[sz - 2].Cmd = cmVARPOW3;
237  else if (m_vRPN[sz - 1].Val.data2 == 4)
238  m_vRPN[sz - 2].Cmd = cmVARPOW4;
239  else
240  break;
241 
242  m_vRPN.pop_back();
243  bOptimized = true;
244  }
245  break;
246 
247  case cmSUB:
248  case cmADD:
249  // Simple optimization based on pattern recognition for a shitload of different
250  // bytecode combinations of addition/subtraction
251  if ((m_vRPN[sz - 1].Cmd == cmVAR && m_vRPN[sz - 2].Cmd == cmVAL) ||
252  (m_vRPN[sz - 1].Cmd == cmVAL && m_vRPN[sz - 2].Cmd == cmVAR) ||
253  (m_vRPN[sz - 1].Cmd == cmVAL && m_vRPN[sz - 2].Cmd == cmVARMUL) ||
254  (m_vRPN[sz - 1].Cmd == cmVARMUL && m_vRPN[sz - 2].Cmd == cmVAL) ||
255  (m_vRPN[sz - 1].Cmd == cmVAR && m_vRPN[sz - 2].Cmd == cmVAR && m_vRPN[sz - 2].Val.ptr == m_vRPN[sz - 1].Val.ptr) ||
256  (m_vRPN[sz - 1].Cmd == cmVAR && m_vRPN[sz - 2].Cmd == cmVARMUL && m_vRPN[sz - 2].Val.ptr == m_vRPN[sz - 1].Val.ptr) ||
257  (m_vRPN[sz - 1].Cmd == cmVARMUL && m_vRPN[sz - 2].Cmd == cmVAR && m_vRPN[sz - 2].Val.ptr == m_vRPN[sz - 1].Val.ptr) ||
258  (m_vRPN[sz - 1].Cmd == cmVARMUL && m_vRPN[sz - 2].Cmd == cmVARMUL && m_vRPN[sz - 2].Val.ptr == m_vRPN[sz - 1].Val.ptr))
259  {
260  MUP_ASSERT(
261  (m_vRPN[sz - 2].Val.ptr == nullptr && m_vRPN[sz - 1].Val.ptr != nullptr) ||
262  (m_vRPN[sz - 2].Val.ptr != nullptr && m_vRPN[sz - 1].Val.ptr == nullptr) ||
263  (m_vRPN[sz - 2].Val.ptr == m_vRPN[sz - 1].Val.ptr));
264 
265  m_vRPN[sz - 2].Cmd = cmVARMUL;
266  m_vRPN[sz - 2].Val.ptr = (value_type*)((long long)(m_vRPN[sz - 2].Val.ptr) | (long long)(m_vRPN[sz - 1].Val.ptr)); // variable
267  m_vRPN[sz - 2].Val.data2 += ((a_Oprt == cmSUB) ? -1 : 1) * m_vRPN[sz - 1].Val.data2; // offset
268  m_vRPN[sz - 2].Val.data += ((a_Oprt == cmSUB) ? -1 : 1) * m_vRPN[sz - 1].Val.data; // multiplicand
269  m_vRPN.pop_back();
270  bOptimized = true;
271  }
272  break;
273 
274  case cmMUL:
275  if ((m_vRPN[sz - 1].Cmd == cmVAR && m_vRPN[sz - 2].Cmd == cmVAL) ||
276  (m_vRPN[sz - 1].Cmd == cmVAL && m_vRPN[sz - 2].Cmd == cmVAR))
277  {
278  m_vRPN[sz - 2].Cmd = cmVARMUL;
279  m_vRPN[sz - 2].Val.ptr = (value_type*)((long long)(m_vRPN[sz - 2].Val.ptr) | (long long)(m_vRPN[sz - 1].Val.ptr));
280  m_vRPN[sz - 2].Val.data = m_vRPN[sz - 2].Val.data2 + m_vRPN[sz - 1].Val.data2;
281  m_vRPN[sz - 2].Val.data2 = 0;
282  m_vRPN.pop_back();
283  bOptimized = true;
284  }
285  else if (
286  (m_vRPN[sz - 1].Cmd == cmVAL && m_vRPN[sz - 2].Cmd == cmVARMUL) ||
287  (m_vRPN[sz - 1].Cmd == cmVARMUL && m_vRPN[sz - 2].Cmd == cmVAL))
288  {
289  // Optimization: 2*(3*b+1) or (3*b+1)*2 -> 6*b+2
290  m_vRPN[sz - 2].Cmd = cmVARMUL;
291  m_vRPN[sz - 2].Val.ptr = (value_type*)((long long)(m_vRPN[sz - 2].Val.ptr) | (long long)(m_vRPN[sz - 1].Val.ptr));
292  if (m_vRPN[sz - 1].Cmd == cmVAL)
293  {
294  m_vRPN[sz - 2].Val.data *= m_vRPN[sz - 1].Val.data2;
295  m_vRPN[sz - 2].Val.data2 *= m_vRPN[sz - 1].Val.data2;
296  }
297  else
298  {
299  m_vRPN[sz - 2].Val.data = m_vRPN[sz - 1].Val.data * m_vRPN[sz - 2].Val.data2;
300  m_vRPN[sz - 2].Val.data2 = m_vRPN[sz - 1].Val.data2 * m_vRPN[sz - 2].Val.data2;
301  }
302  m_vRPN.pop_back();
303  bOptimized = true;
304  }
305  else if (
306  m_vRPN[sz - 1].Cmd == cmVAR && m_vRPN[sz - 2].Cmd == cmVAR &&
307  m_vRPN[sz - 1].Val.ptr == m_vRPN[sz - 2].Val.ptr)
308  {
309  // Optimization: a*a -> a^2
310  m_vRPN[sz - 2].Cmd = cmVARPOW2;
311  m_vRPN.pop_back();
312  bOptimized = true;
313  }
314  break;
315 
316  case cmDIV:
317  if (m_vRPN[sz - 1].Cmd == cmVAL && m_vRPN[sz - 2].Cmd == cmVARMUL && m_vRPN[sz - 1].Val.data2 != 0)
318  {
319  // Optimization: 4*a/2 -> 2*a
320  m_vRPN[sz - 2].Val.data /= m_vRPN[sz - 1].Val.data2;
321  m_vRPN[sz - 2].Val.data2 /= m_vRPN[sz - 1].Val.data2;
322  m_vRPN.pop_back();
323  bOptimized = true;
324  }
325  break;
326 
327  // no optimization for other opcodes
328  default:
329  break;
330  } // switch a_Oprt
331  }
332  }
333 
334  // If optimization can't be applied just write the value
335  if (!bOptimized)
336  {
337  --m_iStackPos;
338  SToken tok;
339  tok.Cmd = a_Oprt;
340  m_vRPN.push_back(tok);
341  }
342  }
343 
344 
345  void ParserByteCode::AddIfElse(ECmdCode a_Oprt)
346  {
347  SToken tok;
348  tok.Cmd = a_Oprt;
349  m_vRPN.push_back(tok);
350  }
351 
352 
353  /** \brief Add an assignment operator
354 
355  Operator entries in byte code consist of:
356  <ul>
357  <li>cmASSIGN code</li>
358  <li>the pointer of the destination variable</li>
359  </ul>
360 
361  \sa ParserToken::ECmdCode
362  */
364  {
365  --m_iStackPos;
366 
367  SToken tok;
368  tok.Cmd = cmASSIGN;
369  tok.Oprt.ptr = a_pVar;
370  m_vRPN.push_back(tok);
371  }
372 
373 
374  /** \brief Add function to bytecode.
375 
376  \param a_iArgc Number of arguments, negative numbers indicate multiarg functions.
377  \param a_pFun Pointer to function callback.
378  */
379  void ParserByteCode::AddFun(generic_callable_type a_pFun, int a_iArgc, bool isFunctionOptimizable)
380  {
381  std::size_t sz = m_vRPN.size();
382  bool optimize = false;
383 
384  // only optimize functions with fixed number of more than a single arguments
385  if (isFunctionOptimizable && m_bEnableOptimizer && a_iArgc > 0)
386  {
387  // <ibg 2020-06-10/> Unary Plus is a no-op
389  return;
390 
391  optimize = true;
392 
393  for (int i = 0; i < std::abs(a_iArgc); ++i)
394  {
395  if (m_vRPN[sz - i - 1].Cmd != cmVAL)
396  {
397  optimize = false;
398  break;
399  }
400  }
401  }
402 
403  if (optimize)
404  {
405  value_type val = 0;
406  switch (a_iArgc)
407  {
408  case 1: val = a_pFun.call_fun<1>(m_vRPN[sz - 1].Val.data2); break;
409  case 2: val = a_pFun.call_fun<2>(m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break;
410  case 3: val = a_pFun.call_fun<3>(m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break;
411  case 4: val = a_pFun.call_fun<4>(m_vRPN[sz - 4].Val.data2, m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break;
412  case 5: val = a_pFun.call_fun<5>(m_vRPN[sz - 5].Val.data2, m_vRPN[sz - 4].Val.data2, m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break;
413  case 6: val = a_pFun.call_fun<6>(m_vRPN[sz - 6].Val.data2, m_vRPN[sz - 5].Val.data2, m_vRPN[sz - 4].Val.data2, m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break;
414  case 7: val = a_pFun.call_fun<7>(m_vRPN[sz - 7].Val.data2, m_vRPN[sz - 6].Val.data2, m_vRPN[sz - 5].Val.data2, m_vRPN[sz - 4].Val.data2, m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break;
415  case 8: val = a_pFun.call_fun<8>(m_vRPN[sz - 8].Val.data2, m_vRPN[sz - 7].Val.data2, m_vRPN[sz - 6].Val.data2, m_vRPN[sz - 5].Val.data2, m_vRPN[sz - 4].Val.data2, m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break;
416  case 9: val = a_pFun.call_fun<9>(m_vRPN[sz - 9].Val.data2, m_vRPN[sz - 8].Val.data2, m_vRPN[sz - 7].Val.data2, m_vRPN[sz - 6].Val.data2, m_vRPN[sz - 5].Val.data2, m_vRPN[sz - 4].Val.data2, m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break;
417  case 10: val = a_pFun.call_fun<10>(m_vRPN[sz - 10].Val.data2, m_vRPN[sz - 9].Val.data2, m_vRPN[sz - 8].Val.data2, m_vRPN[sz - 7].Val.data2, m_vRPN[sz - 6].Val.data2, m_vRPN[sz - 5].Val.data2, m_vRPN[sz - 4].Val.data2, m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break;
418  default:
419  // For now functions with unlimited number of arguments are not optimized
421  }
422 
423  // remove the folded values
424  m_vRPN.erase(m_vRPN.end() - a_iArgc, m_vRPN.end());
425 
426  SToken tok;
427  tok.Cmd = cmVAL;
428  tok.Val.data = 0;
429  tok.Val.data2 = val;
430  tok.Val.ptr = nullptr;
431  m_vRPN.push_back(tok);
432  }
433  else
434  {
435  SToken tok;
436  tok.Cmd = cmFUNC;
437  tok.Fun.argc = a_iArgc;
438  tok.Fun.cb = a_pFun;
439  m_vRPN.push_back(tok);
440  }
441 
442  m_iStackPos = m_iStackPos - std::abs(a_iArgc) + 1;
443  m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos);
444 
445  }
446 
447 
448  /** \brief Add a bulk function to bytecode.
449 
450  \param a_iArgc Number of arguments, negative numbers indicate multiarg functions.
451  \param a_pFun Pointer to function callback.
452  */
454  {
455  m_iStackPos = m_iStackPos - a_iArgc + 1;
456  m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos);
457 
458  SToken tok;
459  tok.Cmd = cmFUNC_BULK;
460  tok.Fun.argc = a_iArgc;
461  tok.Fun.cb = a_pFun;
462  m_vRPN.push_back(tok);
463  }
464 
465 
466  /** \brief Add Strung function entry to the parser bytecode.
467  \throw nothrow
468 
469  A string function entry consists of the stack position of the return value,
470  followed by a cmSTRFUNC code, the function pointer and an index into the
471  string buffer maintained by the parser.
472  */
473  void ParserByteCode::AddStrFun(generic_callable_type a_pFun, int a_iArgc, int a_iIdx)
474  {
475  m_iStackPos = m_iStackPos - a_iArgc + 1;
476 
477  SToken tok;
478  tok.Cmd = cmFUNC_STR;
479  tok.Fun.argc = a_iArgc;
480  tok.Fun.idx = a_iIdx;
481  tok.Fun.cb = a_pFun;
482  m_vRPN.push_back(tok);
483 
484  m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos);
485  }
486 
487 
488  /** \brief Add end marker to bytecode.
489 
490  \throw nothrow
491  */
493  {
494  SToken tok;
495  tok.Cmd = cmEND;
496  m_vRPN.push_back(tok);
497  rpn_type(m_vRPN).swap(m_vRPN); // shrink bytecode vector to fit
498 
499  // Determine the if-then-else jump offsets
500  std::stack<int> stIf, stElse;
501  int idx;
502  for (int i = 0; i < (int)m_vRPN.size(); ++i)
503  {
504  switch (m_vRPN[i].Cmd)
505  {
506  case cmIF:
507  stIf.push(i);
508  break;
509 
510  case cmELSE:
511  stElse.push(i);
512  idx = stIf.top();
513  stIf.pop();
514  m_vRPN[idx].Oprt.offset = i - idx;
515  break;
516 
517  case cmENDIF:
518  idx = stElse.top();
519  stElse.pop();
520  m_vRPN[idx].Oprt.offset = i - idx;
521  break;
522 
523  default:
524  break;
525  }
526  }
527  }
528 
529 
530  std::size_t ParserByteCode::GetMaxStackSize() const
531  {
532  return m_iMaxStackSize + 1;
533  }
534 
535 
536  /** \brief Delete the bytecode.
537 
538  \throw nothrow
539 
540  The name of this function is a violation of my own coding guidelines
541  but this way it's more in line with the STL functions thus more
542  intuitive.
543  */
545  {
546  m_vRPN.clear();
547  m_iStackPos = 0;
548  m_iMaxStackSize = 0;
549  }
550 
551 
552  /** \brief Dump bytecode (for debugging only!). */
554  {
555  if (!m_vRPN.size())
556  {
557  mu::console() << _T("No bytecode available\n");
558  return;
559  }
560 
561  mu::console() << _T("Number of RPN tokens:") << (int)m_vRPN.size() << _T("\n");
562  for (std::size_t i = 0; i < m_vRPN.size() && m_vRPN[i].Cmd != cmEND; ++i)
563  {
564  mu::console() << std::dec << i << _T(" : \t");
565  switch (m_vRPN[i].Cmd)
566  {
567  case cmVAL: mu::console() << _T("VAL \t");
568  mu::console() << _T("[") << m_vRPN[i].Val.data2 << _T("]\n");
569  break;
570 
571  case cmVAR: mu::console() << _T("VAR \t");
572  mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]\n");
573  break;
574 
575  case cmVARPOW2: mu::console() << _T("VARPOW2 \t");
576  mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]\n");
577  break;
578 
579  case cmVARPOW3: mu::console() << _T("VARPOW3 \t");
580  mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]\n");
581  break;
582 
583  case cmVARPOW4: mu::console() << _T("VARPOW4 \t");
584  mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]\n");
585  break;
586 
587  case cmVARMUL: mu::console() << _T("VARMUL \t");
588  mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]");
589  mu::console() << _T(" * [") << m_vRPN[i].Val.data << _T("]");
590  mu::console() << _T(" + [") << m_vRPN[i].Val.data2 << _T("]\n");
591  break;
592 
593  case cmFUNC: mu::console() << _T("CALL\t");
594  mu::console() << _T("[ARG:") << std::dec << m_vRPN[i].Fun.argc << _T("]");
595  mu::console() << _T("[ADDR: 0x") << std::hex << reinterpret_cast<void*>(m_vRPN[i].Fun.cb._pRawFun) << _T("]");
596  mu::console() << _T("[USERDATA: 0x") << std::hex << reinterpret_cast<void*>(m_vRPN[i].Fun.cb._pUserData) << _T("]");
597  mu::console() << _T("\n");
598  break;
599 
600  case cmFUNC_STR:
601  mu::console() << _T("CALL STRFUNC\t");
602  mu::console() << _T("[ARG:") << std::dec << m_vRPN[i].Fun.argc << _T("]");
603  mu::console() << _T("[IDX:") << std::dec << m_vRPN[i].Fun.idx << _T("=\"") << m_stringBuffer[m_vRPN[i].Fun.idx] << ("\"]");
604  mu::console() << _T("[ADDR: 0x") << std::hex << reinterpret_cast<void*>(m_vRPN[i].Fun.cb._pRawFun) << _T("]");
605  mu::console() << _T("[USERDATA: 0x") << std::hex << reinterpret_cast<void*>(m_vRPN[i].Fun.cb._pUserData) << _T("]");
606  mu::console() << _T("\n");
607  break;
608 
609  case cmLT: mu::console() << _T("LT\n"); break;
610  case cmGT: mu::console() << _T("GT\n"); break;
611  case cmLE: mu::console() << _T("LE\n"); break;
612  case cmGE: mu::console() << _T("GE\n"); break;
613  case cmEQ: mu::console() << _T("EQ\n"); break;
614  case cmNEQ: mu::console() << _T("NEQ\n"); break;
615  case cmADD: mu::console() << _T("ADD\n"); break;
616  case cmLAND: mu::console() << _T("&&\n"); break;
617  case cmLOR: mu::console() << _T("||\n"); break;
618  case cmSUB: mu::console() << _T("SUB\n"); break;
619  case cmMUL: mu::console() << _T("MUL\n"); break;
620  case cmDIV: mu::console() << _T("DIV\n"); break;
621  case cmPOW: mu::console() << _T("POW\n"); break;
622 
623  case cmIF: mu::console() << _T("IF\t");
624  mu::console() << _T("[OFFSET:") << std::dec << m_vRPN[i].Oprt.offset << _T("]\n");
625  break;
626 
627  case cmELSE: mu::console() << _T("ELSE\t");
628  mu::console() << _T("[OFFSET:") << std::dec << m_vRPN[i].Oprt.offset << _T("]\n");
629  break;
630 
631  case cmENDIF: mu::console() << _T("ENDIF\n"); break;
632 
633  case cmASSIGN:
634  mu::console() << _T("ASSIGN\t");
635  mu::console() << _T("[ADDR: 0x") << m_vRPN[i].Oprt.ptr << _T("]\n");
636  break;
637 
638  default: mu::console() << _T("(unknown code: ") << m_vRPN[i].Cmd << _T(")\n");
639  break;
640  } // switch cmdCode
641  } // while bytecode
642 
643  mu::console() << _T("END") << std::endl;
644  }
645 } // namespace mu
646 
647 #if defined(_MSC_VER)
648  #pragma warning(pop)
649 #endif
Definition of the parser bytecode class.
#define _T(x)
Activate this option in order to compile with OpenMP support.
Definition: muParserDef.h:69
void AddStrFun(generic_callable_type a_pFun, int a_iArgc, int a_iIdx)
Add Strung function entry to the parser bytecode.
void AsciiDump() const
Dump bytecode (for debugging only!).
std::ostream & console()
Encapsulate cout.
Definition: muParserDef.h:115
Operator item: y to the power of ...
Definition: muParserDef.h:150
Internal error of any kind.
Definition: muParserDef.h:279
void AddAssignOp(value_type *a_pVar)
Add an assignment operator.
Operator item: not equal.
Definition: muParserDef.h:142
For use in the ternary if-then-else operator.
Definition: muParserDef.h:156
end of formula
Definition: muParserDef.h:177
void Assign(const ParserByteCode &a_ByteCode)
Copy state of another object to this.
Code for a generic function item.
Definition: muParserDef.h:170
void AddOp(ECmdCode a_Oprt)
Add an operator identifier to bytecode.
ParserByteCode()
Bytecode default constructor.
For use in the ternary if-then-else operator.
Definition: muParserDef.h:157
void AddBulkFun(generic_callable_type a_pFun, int a_iArgc)
Add a bulk function to bytecode.
Operator item: subtract.
Definition: muParserDef.h:147
void AddVal(value_type a_fVal)
Add a Variable pointer to bytecode.
Error class of the parser.
Definition: muParserError.h:74
For use in the ternary if-then-else operator.
Definition: muParserDef.h:158
void AddFun(generic_callable_type a_pFun, int a_iArgc, bool isOptimizable)
Add function to bytecode.
ECmdCode
Bytecode values.
Definition: muParserDef.h:135
Operator item: multiply.
Definition: muParserDef.h:148
#define MUP_ASSERT(COND)
An assertion that does not kill the program.
Definition: muParserDef.h:77
MUP_BASETYPE value_type
The numeric datatype used by the parser.
Definition: muParserDef.h:296
Operator item: division.
Definition: muParserDef.h:149
Operator item: add.
Definition: muParserDef.h:146
A template class for providing wrappers for essential math functions.
Namespace for mathematical applications.
Definition: muParser.cpp:48
Operator item: less than.
Definition: muParserDef.h:144
value item
Definition: muParserDef.h:161
Operator item: greater than.
Definition: muParserDef.h:145
Special callbacks for Bulk mode with an additional parameter for the bulk index.
Definition: muParserDef.h:172
Code for a function with a string parameter.
Definition: muParserDef.h:171
Operator item: equals.
Definition: muParserDef.h:143
Operator item: Assignment operator.
Definition: muParserDef.h:153
void(* erased_fun_type)()
Function type used to erase type. Voluntarily needs explicit cast with all other fun_type.
Definition: muParserDef.h:327
Bytecode implementation of the Math Parser.
This file contains the parser token definition.
void clear()
Delete the bytecode.
void AddVar(value_type *a_pVar)
Add a Variable pointer to bytecode.
Operator item: less or equal.
Definition: muParserDef.h:140
variable item
Definition: muParserDef.h:160
Operator item: greater or equal.
Definition: muParserDef.h:141
ParserByteCode & operator=(const ParserByteCode &a_ByteCode)
Assignment operator.
void Finalize()
Add end marker to bytecode.
This file defines the error class used by the parser.
This file contains standard definitions used by the parser.