muParser API -  1.35
Public Member Functions | List of all members
mu::ParserByteCode Class Referencefinal

Bytecode implementation of the Math Parser. More...

#include <muParserBytecode.h>

Public Member Functions

 ParserByteCode ()
 Bytecode default constructor.
 
 ParserByteCode (const ParserByteCode &a_ByteCode)
 Copy constructor. More...
 
ParserByteCodeoperator= (const ParserByteCode &a_ByteCode)
 Assignment operator. More...
 
void Assign (const ParserByteCode &a_ByteCode)
 Copy state of another object to this. More...
 
void AddVar (value_type *a_pVar)
 Add a Variable pointer to bytecode. More...
 
void AddVal (value_type a_fVal)
 Add a Variable pointer to bytecode. More...
 
void AddOp (ECmdCode a_Oprt)
 Add an operator identifier to bytecode. More...
 
void AddIfElse (ECmdCode a_Oprt)
 
void AddAssignOp (value_type *a_pVar)
 Add an assignment operator. More...
 
void AddFun (generic_callable_type a_pFun, int a_iArgc, bool isOptimizable)
 Add function to bytecode. More...
 
void AddBulkFun (generic_callable_type a_pFun, int a_iArgc)
 Add a bulk function to bytecode. More...
 
void AddStrFun (generic_callable_type a_pFun, int a_iArgc, int a_iIdx)
 Add Strung function entry to the parser bytecode. More...
 
void EnableOptimizer (bool bStat)
 
void Finalize ()
 Add end marker to bytecode. More...
 
void clear ()
 Delete the bytecode. More...
 
std::size_t GetMaxStackSize () const
 
std::size_t GetSize () const
 
const STokenGetBase () const
 
void StoreEnvironment (string_type expr, stringbuf_type const &strBuf)
 
std::tuple< string_type, stringbuf_type > RestoreEnvironment () const
 
void AsciiDump () const
 Dump bytecode (for debugging only!).
 

Detailed Description

Bytecode implementation of the Math Parser.

The bytecode contains the formula converted to revers polish notation stored in a continious memory area. Associated with this data are operator codes, variable pointers, constant values and function pointers. Those are necessary in order to calculate the result. All those data items will be casted to the underlying datatype of the bytecode.

Definition at line 87 of file muParserBytecode.h.

Constructor & Destructor Documentation

mu::ParserByteCode::ParserByteCode ( const ParserByteCode a_ByteCode)

Copy constructor.

Implemented in Terms of Assign(const ParserByteCode &a_ByteCode)

Definition at line 67 of file muParserBytecode.cpp.

68  {
69  Assign(a_ByteCode);
70  }
void Assign(const ParserByteCode &a_ByteCode)
Copy state of another object to this.

Member Function Documentation

void mu::ParserByteCode::AddAssignOp ( value_type a_pVar)

Add an assignment operator.

Operator entries in byte code consist of:

  • cmASSIGN code
  • the pointer of the destination variable
See also
ParserToken::ECmdCode

Definition at line 363 of file muParserBytecode.cpp.

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  }
Operator item: Assignment operator.
Definition: muParserDef.h:153
void mu::ParserByteCode::AddBulkFun ( generic_callable_type  a_pFun,
int  a_iArgc 
)

Add a bulk function to bytecode.

Parameters
a_iArgcNumber of arguments, negative numbers indicate multiarg functions.
a_pFunPointer to function callback.

Definition at line 453 of file muParserBytecode.cpp.

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  }
Special callbacks for Bulk mode with an additional parameter for the bulk index.
Definition: muParserDef.h:172
void mu::ParserByteCode::AddFun ( generic_callable_type  a_pFun,
int  a_iArgc,
bool  isFunctionOptimizable 
)

Add function to bytecode.

Parameters
a_iArgcNumber of arguments, negative numbers indicate multiarg functions.
a_pFunPointer to function callback.

Definition at line 379 of file muParserBytecode.cpp.

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
388  if (a_pFun == generic_callable_type{(erased_fun_type)&MathImpl<value_type>::UnaryPlus, nullptr})
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
420  throw ParserError(ecINTERNAL_ERROR);
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  }
Internal error of any kind.
Definition: muParserDef.h:279
Code for a generic function item.
Definition: muParserDef.h:170
MUP_BASETYPE value_type
The numeric datatype used by the parser.
Definition: muParserDef.h:296
value item
Definition: muParserDef.h:161
void(* erased_fun_type)()
Function type used to erase type. Voluntarily needs explicit cast with all other fun_type.
Definition: muParserDef.h:327
void mu::ParserByteCode::AddOp ( ECmdCode  a_Oprt)

Add an operator identifier to bytecode.

Operator entries in byte code consist of:

  • value array position of the result
  • the operator code according to ParserToken::ECmdCode
See also
ParserToken::ECmdCode

Definition at line 199 of file muParserBytecode.cpp.

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  }
Operator item: y to the power of ...
Definition: muParserDef.h:150
Operator item: subtract.
Definition: muParserDef.h:147
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
value item
Definition: muParserDef.h:161
variable item
Definition: muParserDef.h:160
void mu::ParserByteCode::AddStrFun ( generic_callable_type  a_pFun,
int  a_iArgc,
int  a_iIdx 
)

Add Strung function entry to the parser bytecode.

Exceptions
nothrowA string function entry consists of the stack position of the return value, followed by a cmSTRFUNC code, the function pointer and an index into the string buffer maintained by the parser.

Definition at line 473 of file muParserBytecode.cpp.

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  }
Code for a function with a string parameter.
Definition: muParserDef.h:171
void mu::ParserByteCode::AddVal ( value_type  a_fVal)

Add a Variable pointer to bytecode.

Value entries in byte code consist of:

  • value array position of the value
  • the operator code according to ParserToken::cmVAL
  • the value stored in #mc_iSizeVal number of bytecode entries.
Parameters
a_pValValue to be added.
Exceptions
nothrow

Definition at line 140 of file muParserBytecode.cpp.

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  }
value item
Definition: muParserDef.h:161
void mu::ParserByteCode::AddVar ( value_type a_pVar)

Add a Variable pointer to bytecode.

Parameters
a_pVarPointer to be added.
Exceptions
nothrow

Definition at line 113 of file muParserBytecode.cpp.

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  }
variable item
Definition: muParserDef.h:160
void mu::ParserByteCode::Assign ( const ParserByteCode a_ByteCode)

Copy state of another object to this.

Exceptions
nowthrow

Definition at line 94 of file muParserBytecode.cpp.

Referenced by operator=(), and ParserByteCode().

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  }
void mu::ParserByteCode::clear ( )

Delete the bytecode.

Exceptions
nothrowThe name of this function is a violation of my own coding guidelines but this way it's more in line with the STL functions thus more intuitive.

Definition at line 544 of file muParserBytecode.cpp.

545  {
546  m_vRPN.clear();
547  m_iStackPos = 0;
548  m_iMaxStackSize = 0;
549  }
void mu::ParserByteCode::Finalize ( )

Add end marker to bytecode.

Exceptions
nothrow

Definition at line 492 of file muParserBytecode.cpp.

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  }
For use in the ternary if-then-else operator.
Definition: muParserDef.h:156
end of formula
Definition: muParserDef.h:177
For use in the ternary if-then-else operator.
Definition: muParserDef.h:157
For use in the ternary if-then-else operator.
Definition: muParserDef.h:158
ParserByteCode & mu::ParserByteCode::operator= ( const ParserByteCode a_ByteCode)

Assignment operator.

Implemented in Terms of Assign(const ParserByteCode &a_ByteCode)

Definition at line 77 of file muParserBytecode.cpp.

78  {
79  Assign(a_ByteCode);
80  return *this;
81  }
void Assign(const ParserByteCode &a_ByteCode)
Copy state of another object to this.

The documentation for this class was generated from the following files: