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