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