Seamly2D
Code documentation
qmuparserbytecode.cpp
Go to the documentation of this file.
1 /***************************************************************************************************
2  **
3  ** Copyright (C) 2013 Ingo Berg
4  **
5  ** Permission is hereby granted, free of charge, to any person obtaining a copy of this
6  ** software and associated documentation files (the "Software"), to deal in the Software
7  ** without restriction, including without limitation the rights to use, copy, modify,
8  ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
9  ** permit persons to whom the Software is furnished to do so, subject to the following conditions:
10  **
11  ** The above copyright notice and this permission notice shall be included in all copies or
12  ** substantial portions of the Software.
13  **
14  ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
15  ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16  ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
17  ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  **
20  ******************************************************************************************************/
21 
22 #include "qmuparserbytecode.h"
23 
24 #include <assert.h>
25 #include <QMessageLogger>
26 #include <QStack>
27 #include <QString>
28 #include <QtDebug>
29 
30 #include "qmudef.h"
31 #include "qmuparsererror.h"
32 #include "../vmisc/vmath.h"
33 
34 namespace qmu
35 {
36 //---------------------------------------------------------------------------------------------------------------------
37 /**
38  * @brief Bytecode default constructor.
39  */
41  :m_iStackPos(0), m_iMaxStackSize(0), m_vRPN(), m_bEnableOptimizer(true)
42 {
43  m_vRPN.reserve(50);
44 }
45 
46 //---------------------------------------------------------------------------------------------------------------------
47 /**
48  * @brief Copy constructor.
49  *
50  * Implemented in Terms of Assign(const QParserByteCode &a_ByteCode)
51  */
53  :m_iStackPos(a_ByteCode.m_iStackPos), m_iMaxStackSize(a_ByteCode.m_iMaxStackSize), m_vRPN(a_ByteCode.m_vRPN),
54  m_bEnableOptimizer(true)
55 {
56  Assign(a_ByteCode);
57 }
58 
59 //---------------------------------------------------------------------------------------------------------------------
60 /**
61  * @brief Assignment operator.
62  *
63  * Implemented in Terms of Assign(const QParserByteCode &a_ByteCode)
64  */
66 {
67  if (this != &a_ByteCode)
68  {
69  Assign(a_ByteCode);
70  }
71  return *this;
72 }
73 
74 //---------------------------------------------------------------------------------------------------------------------
75 /**
76  * @brief Copy state of another object to this.
77  *
78  * @throw nowthrow
79  */
81 {
82  if (this==&a_ByteCode)
83  {
84  return;
85  }
86 
87  m_iStackPos = a_ByteCode.m_iStackPos;
88  m_vRPN = a_ByteCode.m_vRPN;
89  m_iMaxStackSize = a_ByteCode.m_iMaxStackSize;
91 }
92 
93 //---------------------------------------------------------------------------------------------------------------------
94 /**
95  * @brief Add a Variable pointer to bytecode.
96  * @param a_pVar Pointer to be added.
97  * @throw nothrow
98  */
99 void QmuParserByteCode::AddVar(qreal *a_pVar)
100 {
101  ++m_iStackPos;
103 
104  // optimization does not apply
105  SToken tok;
106  tok.Cmd = cmVAR;
107  tok.Val.ptr = a_pVar;
108  tok.Val.data = 1;
109  tok.Val.data2 = 0;
110  m_vRPN.push_back(tok);
111 }
112 
113 //---------------------------------------------------------------------------------------------------------------------
114 /**
115  * @brief Add a Variable pointer to bytecode.
116  *
117  * Value entries in byte code consist of:
118  * <ul>
119  * <li>value array position of the value</li>
120  * <li>the operator code according to ParserToken::cmVAL</li>
121  * <li>the value stored in #mc_iSizeVal number of bytecode entries.</li>
122  * </ul>
123  *
124  * @param a_fVal Value to be added.
125  * @throw nothrow
126  */
127 void QmuParserByteCode::AddVal(qreal a_fVal)
128 {
129  ++m_iStackPos;
131 
132  // If optimization does not apply
133  SToken tok;
134  tok.Cmd = cmVAL;
135  tok.Val.ptr = nullptr;
136  tok.Val.data = 0;
137  tok.Val.data2 = a_fVal;
138  m_vRPN.push_back(tok);
139 }
140 
141 //---------------------------------------------------------------------------------------------------------------------
143 {
144  int sz = m_vRPN.size();
145  qreal &x = m_vRPN[sz-2].Val.data2,
146  &y = m_vRPN[sz-1].Val.data2;
147  switch (a_Oprt)
148  {
149  case cmLAND:
150  x = static_cast<int>(x) && static_cast<int>(y);
151  m_vRPN.pop_back();
152  break;
153  case cmLOR:
154  x = static_cast<int>(x) || static_cast<int>(y);
155  m_vRPN.pop_back();
156  break;
157  case cmLT:
158  x = x < y;
159  m_vRPN.pop_back();
160  break;
161  case cmGT:
162  x = x > y;
163  m_vRPN.pop_back();
164  break;
165  case cmLE:
166  x = x <= y;
167  m_vRPN.pop_back();
168  break;
169  case cmGE:
170  x = x >= y;
171  m_vRPN.pop_back();
172  break;
173  case cmNEQ:
174  x = not QmuFuzzyComparePossibleNulls(x, y);
175  m_vRPN.pop_back();
176  break;
177  case cmEQ:
179  m_vRPN.pop_back();
180  break;
181  case cmADD:
182  x = x + y;
183  m_vRPN.pop_back();
184  break;
185  case cmSUB:
186  x = x - y;
187  m_vRPN.pop_back();
188  break;
189  case cmMUL:
190  x = x * y;
191  m_vRPN.pop_back();
192  break;
193  case cmDIV:
194  #if defined(MUP_MATH_EXCEPTIONS)
195  if (y==0)
196  {
197  throw qmuParserError(ecDIV_BY_ZERO, "0");
198  }
199  #endif
200  x = x / y;
201  m_vRPN.pop_back();
202  break;
203  case cmPOW:
204  x = qPow(x, y);
205  m_vRPN.pop_back();
206  break;
207  default:
208  break;
209  } // switch opcode
210 }
211 
212 QT_WARNING_PUSH
213 QT_WARNING_DISABLE_INTEL(1195)
214 QT_WARNING_DISABLE_MSVC(4826)
215 
216 //---------------------------------------------------------------------------------------------------------------------
217 /**
218  * @brief Add an operator identifier to bytecode.
219  *
220  * Operator entries in byte code consist of:
221  * <ul>
222  * <li>value array position of the result</li>
223  * <li>the operator code according to ParserToken::ECmdCode</li>
224  * </ul>
225  *
226  * @sa ParserToken::ECmdCode
227  */
228 void QmuParserByteCode::AddOp(ECmdCode a_Oprt)
229 {
230  bool bOptimized = false;
231 
232  if (m_bEnableOptimizer)
233  {
234  int sz = m_vRPN.size();
235 
236  // Check for foldable constants like:
237  // cmVAL cmVAL cmADD
238  // where cmADD can stand fopr any binary operator applied to
239  // two constant values.
240  if (sz>=2 && m_vRPN.at(sz-2).Cmd == cmVAL && m_vRPN.at(sz-1).Cmd == cmVAL)
241  {
242  ConstantFolding(a_Oprt);
243  bOptimized = true;
244  }
245  else
246  {
247  switch (a_Oprt)
248  {
249  case cmPOW:
250  // Optimization for ploynomials of low order
251  if (m_vRPN.at(sz-2).Cmd == cmVAR && m_vRPN.at(sz-1).Cmd == cmVAL) //-V807
252  {
253  if (qFuzzyCompare(m_vRPN.at(sz-1).Val.data2, 2)) //-V807
254  {
255  m_vRPN[sz-2].Cmd = cmVARPOW2;
256  }
257  else if (qFuzzyCompare(m_vRPN.at(sz-1).Val.data2, 3))
258  {
259  m_vRPN[sz-2].Cmd = cmVARPOW3;
260  }
261  else if (qFuzzyCompare(m_vRPN.at(sz-1).Val.data2, 4))
262  {
263  m_vRPN[sz-2].Cmd = cmVARPOW4;
264  }
265  else
266  {
267  break;
268  }
269  m_vRPN.pop_back();
270  bOptimized = true;
271  }
272  break;
273 
274  case cmSUB:
275  case cmADD:
276  // Simple optimization based on pattern recognition for a shitload of different
277  // bytecode combinations of addition/subtraction
278  if ( (m_vRPN.at(sz-1).Cmd == cmVAR && m_vRPN.at(sz-2).Cmd == cmVAL) ||
279  (m_vRPN.at(sz-1).Cmd == cmVAL && m_vRPN.at(sz-2).Cmd == cmVAR) ||
280  (m_vRPN.at(sz-1).Cmd == cmVAL && m_vRPN.at(sz-2).Cmd == cmVARMUL) ||
281  (m_vRPN.at(sz-1).Cmd == cmVARMUL && m_vRPN.at(sz-2).Cmd == cmVAL) ||
282  (m_vRPN.at(sz-1).Cmd == cmVAR && m_vRPN.at(sz-2).Cmd == cmVAR &&
283  m_vRPN.at(sz-2).Val.ptr == m_vRPN.at(sz-1).Val.ptr) || //-V807
284  (m_vRPN.at(sz-1).Cmd == cmVAR && m_vRPN.at(sz-2).Cmd == cmVARMUL
285  && m_vRPN.at(sz-2).Val.ptr == m_vRPN.at(sz-1).Val.ptr) ||
286  (m_vRPN.at(sz-1).Cmd == cmVARMUL && m_vRPN.at(sz-2).Cmd == cmVAR &&
287  m_vRPN.at(sz-2).Val.ptr == m_vRPN.at(sz-1).Val.ptr) ||
288  (m_vRPN.at(sz-1).Cmd == cmVARMUL && m_vRPN.at(sz-2).Cmd == cmVARMUL &&
289  m_vRPN.at(sz-2).Val.ptr == m_vRPN.at(sz-1).Val.ptr) )
290  {
291  assert( (m_vRPN.at(sz-2).Val.ptr==nullptr && m_vRPN.at(sz-1).Val.ptr!=nullptr) ||
292  (m_vRPN.at(sz-2).Val.ptr!=nullptr && m_vRPN.at(sz-1).Val.ptr==nullptr) ||
293  (m_vRPN.at(sz-2).Val.ptr == m_vRPN.at(sz-1).Val.ptr) );
294 
295  m_vRPN[sz-2].Cmd = cmVARMUL;
296  m_vRPN[sz-2].Val.ptr = reinterpret_cast<qreal*>( //-V807
297  reinterpret_cast<qlonglong>(m_vRPN.at(sz-2).Val.ptr) |
298  reinterpret_cast<qlonglong>(m_vRPN.at(sz-1).Val.ptr)); // variable
299  m_vRPN[sz-2].Val.data2 += ((a_Oprt==cmSUB) ? -1 : 1) * m_vRPN.at(sz-1).Val.data2; // offset
300  m_vRPN[sz-2].Val.data += ((a_Oprt==cmSUB) ? -1 : 1) * m_vRPN.at(sz-1).Val.data; // multiplikatior
301  m_vRPN.pop_back();
302  bOptimized = true;
303  }
304  break;
305  case cmMUL:
306  if ( (m_vRPN.at(sz-1).Cmd == cmVAR && m_vRPN.at(sz-2).Cmd == cmVAL) ||
307  (m_vRPN.at(sz-1).Cmd == cmVAL && m_vRPN.at(sz-2).Cmd == cmVAR) )
308  {
309  m_vRPN[sz-2].Cmd = cmVARMUL;
310  m_vRPN[sz-2].Val.ptr = reinterpret_cast<qreal*>(
311  reinterpret_cast<qlonglong>(m_vRPN.at(sz-2).Val.ptr) |
312  reinterpret_cast<qlonglong>(m_vRPN.at(sz-1).Val.ptr));
313  m_vRPN[sz-2].Val.data = m_vRPN.at(sz-2).Val.data2 + m_vRPN.at(sz-1).Val.data2;
314  m_vRPN[sz-2].Val.data2 = 0;
315  m_vRPN.pop_back();
316  bOptimized = true;
317  }
318  else if ( (m_vRPN.at(sz-1).Cmd == cmVAL && m_vRPN.at(sz-2).Cmd == cmVARMUL) ||
319  (m_vRPN.at(sz-1).Cmd == cmVARMUL && m_vRPN.at(sz-2).Cmd == cmVAL) )
320  {
321  // Optimization: 2*(3*b+1) or (3*b+1)*2 -> 6*b+2
322  m_vRPN[sz-2].Cmd = cmVARMUL;
323  m_vRPN[sz-2].Val.ptr = reinterpret_cast<qreal*>(
324  reinterpret_cast<qlonglong>(m_vRPN.at(sz-2).Val.ptr) |
325  reinterpret_cast<qlonglong>(m_vRPN.at(sz-1).Val.ptr));
326  if (m_vRPN.at(sz-1).Cmd == cmVAL)
327  {
328  m_vRPN[sz-2].Val.data *= m_vRPN.at(sz-1).Val.data2;
329  m_vRPN[sz-2].Val.data2 *= m_vRPN.at(sz-1).Val.data2;
330  }
331  else
332  {
333  m_vRPN[sz-2].Val.data = m_vRPN.at(sz-1).Val.data * m_vRPN.at(sz-2).Val.data2;
334  m_vRPN[sz-2].Val.data2 = m_vRPN.at(sz-1).Val.data2 * m_vRPN.at(sz-2).Val.data2;
335  }
336  m_vRPN.pop_back();
337  bOptimized = true;
338  }
339  else if (m_vRPN.at(sz-1).Cmd == cmVAR && m_vRPN.at(sz-2).Cmd == cmVAR &&
340  m_vRPN.at(sz-1).Val.ptr == m_vRPN.at(sz-2).Val.ptr)
341  {
342  // Optimization: a*a -> a^2
343  m_vRPN[sz-2].Cmd = cmVARPOW2;
344  m_vRPN.pop_back();
345  bOptimized = true;
346  }
347  break;
348  case cmDIV:
349  if (m_vRPN.at(sz-1).Cmd == cmVAL && m_vRPN.at(sz-2).Cmd == cmVARMUL &&
350  not qFuzzyIsNull(m_vRPN.at(sz-1).Val.data2))
351  {
352  // Optimization: 4*a/2 -> 2*a
353  m_vRPN[sz-2].Val.data /= m_vRPN.at(sz-1).Val.data2;
354  m_vRPN[sz-2].Val.data2 /= m_vRPN.at(sz-1).Val.data2;
355  m_vRPN.pop_back();
356  bOptimized = true;
357  }
358  break;
359  default:
360  break;
361 
362  } // switch a_Oprt
363  }
364  }
365 
366  // If optimization can't be applied just write the value
367  if (bOptimized == false)
368  {
369  --m_iStackPos;
370  SToken tok;
371  tok.Cmd = a_Oprt;
372  m_vRPN.push_back(tok);
373  }
374 }
375 
377 
378 //---------------------------------------------------------------------------------------------------------------------
380 {
381  SToken tok;
382  tok.Cmd = a_Oprt;
383  m_vRPN.push_back(tok);
384 }
385 
386 //---------------------------------------------------------------------------------------------------------------------
387 /**
388  * @brief Add an assignement operator
389  *
390  * Operator entries in byte code consist of:
391  * <ul>
392  * <li>cmASSIGN code</li>
393  * <li>the pointer of the destination variable</li>
394  * </ul>
395  *
396  * @sa ParserToken::ECmdCode
397  */
399 {
400  --m_iStackPos;
401 
402  SToken tok;
403  tok.Cmd = cmASSIGN;
404  tok.Oprt.ptr = a_pVar;
405  m_vRPN.push_back(tok);
406 }
407 
408 //---------------------------------------------------------------------------------------------------------------------
409 /**
410  * @brief Add function to bytecode.
411  *
412  * @param a_iArgc Number of arguments, negative numbers indicate multiarg functions.
413  * @param a_pFun Pointer to function callback.
414  */
416 {
417  if (a_iArgc>=0)
418  {
419  m_iStackPos = m_iStackPos - static_cast<quint32>(a_iArgc) + 1;
420  }
421  else
422  {
423  // function with unlimited number of arguments
424  m_iStackPos = static_cast<quint32>(static_cast<int>(m_iStackPos) + a_iArgc + 1);
425  }
427 
428  SToken tok;
429  tok.Cmd = cmFUNC;
430  tok.Fun.argc = a_iArgc;
431  tok.Fun.ptr = a_pFun;
432  m_vRPN.push_back(tok);
433 }
434 
435 //---------------------------------------------------------------------------------------------------------------------
436 /**
437  * @brief Add a bulk function to bytecode.
438  *
439  * @param a_iArgc Number of arguments, negative numbers indicate multiarg functions.
440  * @param a_pFun Pointer to function callback.
441  */
443 {
444  m_iStackPos = static_cast<quint32>(static_cast<int>(m_iStackPos) - a_iArgc + 1);
446 
447  SToken tok;
448  tok.Cmd = cmFUNC_BULK;
449  tok.Fun.argc = a_iArgc;
450  tok.Fun.ptr = a_pFun;
451  m_vRPN.push_back(tok);
452 }
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, followed by a cmSTRFUNC code, the
460  * function pointer and an index into the string buffer maintained by the parser.
461  */
462 void QmuParserByteCode::AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx)
463 {
464  m_iStackPos = static_cast<quint32>(static_cast<int>(m_iStackPos) - a_iArgc + 1);
465 
466  SToken tok;
467  tok.Cmd = cmFUNC_STR;
468  tok.Fun.argc = a_iArgc;
469  tok.Fun.idx = a_iIdx;
470  tok.Fun.ptr = a_pFun;
471  m_vRPN.push_back(tok);
472 
474 }
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  QStack<int> stIf, stElse;
491  int idx;
492  for (int i=0; i<m_vRPN.size(); ++i)
493  {
494  switch (m_vRPN.at(i).Cmd)
495  {
496  case cmIF:
497  stIf.push(i);
498  break;
499  case cmELSE:
500  stElse.push(i);
501  idx = stIf.pop();
502  m_vRPN[idx].Oprt.offset = i - idx;
503  break;
504  case cmENDIF:
505  idx = stElse.pop();
506  m_vRPN[idx].Oprt.offset = i - idx;
507  break;
508  default:
509  break;
510  }
511  }
512 }
513 
514 //---------------------------------------------------------------------------------------------------------------------
516 {
517  if (m_vRPN.size()==0)
518  {
520  }
521  else
522  {
523  return &m_vRPN.at(0);
524  }
525 }
526 
527 //---------------------------------------------------------------------------------------------------------------------
528 /**
529  * @brief Delete the bytecode.
530  *
531  * @throw nothrow
532  *
533  * The name of this function is a violation of my own coding guidelines but this way it's more in line with the STL
534  * functions thus more intuitive.
535  */
537 {
538  m_vRPN.clear();
539  m_iStackPos = 0;
540  m_iMaxStackSize = 0;
541 }
542 
543 //---------------------------------------------------------------------------------------------------------------------
544 /**
545  * @brief Dump bytecode (for debugging only!).
546  */
548 {
549  if (m_vRPN.size() == false)
550  {
551  qDebug() << "No bytecode available\n";
552  return;
553  }
554 
555  qDebug() << "Number of RPN tokens:" << m_vRPN.size() << "\n";
556  for (int i=0; i<m_vRPN.size() && m_vRPN.at(i).Cmd!=cmEND; ++i)
557  {
558  qDebug() << i << " : \t";
559  switch (m_vRPN.at(i).Cmd)
560  {
561  case cmVAL:
562  qDebug() << "VAL \t" << "[" << m_vRPN.at(i).Val.data2 << "]\n";
563  break;
564  case cmVAR:
565  qDebug() << "VAR \t" << "[ADDR: 0x" << QString::number(*m_vRPN.at(i).Val.ptr, 'f', 16) << "]\n";
566  break;
567  case cmVARPOW2:
568  qDebug() << "VARPOW2 \t" << "[ADDR: 0x" << QString::number(*m_vRPN.at(i).Val.ptr, 'f', 16) << "]\n";
569  break;
570  case cmVARPOW3:
571  qDebug() << "VARPOW3 \t" << "[ADDR: 0x" << QString::number(*m_vRPN.at(i).Val.ptr, 'f', 16) << "]\n";
572  break;
573  case cmVARPOW4:
574  qDebug() << "VARPOW4 \t" << "[ADDR: 0x" << QString::number(*m_vRPN.at(i).Val.ptr, 'f', 16) << "]\n";
575  break;
576  case cmVARMUL:
577  qDebug() << "VARMUL \t" << "[ADDR: 0x" << QString::number(*m_vRPN.at(i).Val.ptr, 'f', 16) << "]" << " * [" //-V807
578  << m_vRPN.at(i).Val.data << "]" << " + [" << m_vRPN.at(i).Val.data2 << "]\n";
579  break;
580  case cmFUNC:
581  qDebug() << "CALL\t" << "[ARG:" << m_vRPN.at(i).Fun.argc << "]" << "[ADDR: 0x" << m_vRPN.at(i).Fun.ptr << "]"
582  << "\n";
583  break;
584  case cmFUNC_STR:
585  qDebug() << "CALL STRFUNC\t" << "[ARG:" << m_vRPN.at(i).Fun.argc << "]" << "[IDX:" << m_vRPN.at(i).Fun.idx //-V807
586  << "]" << "[ADDR: 0x" << m_vRPN.at(i).Fun.ptr << "]\n";
587  break;
588  case cmLT:
589  qDebug() << "LT\n";
590  break;
591  case cmGT:
592  qDebug() << "GT\n";
593  break;
594  case cmLE:
595  qDebug() << "LE\n";
596  break;
597  case cmGE:
598  qDebug() << "GE\n";
599  break;
600  case cmEQ:
601  qDebug() << "EQ\n";
602  break;
603  case cmNEQ:
604  qDebug() << "NEQ\n";
605  break;
606  case cmADD:
607  qDebug() << "ADD\n";
608  break;
609  case cmLAND:
610  qDebug() << "&&\n";
611  break;
612  case cmLOR:
613  qDebug() << "||\n";
614  break;
615  case cmSUB:
616  qDebug() << "SUB\n";
617  break;
618  case cmMUL:
619  qDebug() << "MUL\n";
620  break;
621  case cmDIV:
622  qDebug() << "DIV\n";
623  break;
624  case cmPOW:
625  qDebug() << "POW\n";
626  break;
627  case cmIF:
628  qDebug() << "IF\t" << "[OFFSET:" << m_vRPN.at(i).Oprt.offset << "]\n";
629  break;
630  case cmELSE:
631  qDebug() << "ELSE\t" << "[OFFSET:" << m_vRPN.at(i).Oprt.offset << "]\n";
632  break;
633  case cmENDIF:
634  qDebug() << "ENDIF\n"; break;
635  case cmASSIGN:
636  qDebug() << "ASSIGN\t" << "[ADDR: 0x" << QString::number(*m_vRPN.at(i).Oprt.ptr, 'f', 16) << "]\n";
637  break;
638  case cmBO:
639  case cmBC:
640  case cmARG_SEP:
641  case cmPOW2:
642  case cmFUNC_BULK:
643  case cmSTRING:
644  case cmOPRT_BIN:
645  case cmOPRT_POSTFIX:
646  case cmOPRT_INFIX:
647  case cmEND:
648  case cmUNKNOWN:
649  default:
650  qDebug() << "(unknown code: " << m_vRPN.at(i).Cmd << ")\n";
651  break;
652  } // switch cmdCode
653  } // while bytecode
654 
655  qDebug() << "END";
656 }
657 } // namespace qmu
Bytecode implementation of the Math Parser.
void AddIfElse(ECmdCode a_Oprt)
void ConstantFolding(ECmdCode a_Oprt)
void Finalize()
Add end marker to bytecode.
void AddFun(generic_fun_type a_pFun, int a_iArgc)
Add function to bytecode.
const SToken * GetBase() const
void AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx)
Add Strung function entry to the parser bytecode.
void AddVal(qreal a_fVal)
Add a Variable pointer to bytecode.
unsigned m_iMaxStackSize
Maximum size needed for the stack.
QmuParserByteCode()
Bytecode default constructor.
unsigned m_iStackPos
Position in the Calculation array.
rpn_type m_vRPN
The actual rpn storage.
void AddVar(qreal *a_pVar)
Add a Variable pointer to bytecode.
void clear()
Delete the bytecode.
void Assign(const QmuParserByteCode &a_ByteCode)
Copy state of another object to this.
void AddBulkFun(generic_fun_type a_pFun, int a_iArgc)
Add a bulk function to bytecode.
void AsciiDump()
Dump bytecode (for debugging only!).
QVector< SToken > rpn_type
Token vector for storing the RPN.
QmuParserByteCode & operator=(const QmuParserByteCode &a_ByteCode)
Assignment operator.
void AddAssignOp(qreal *a_pVar)
Add an assignement operator.
Error class of the parser.
Namespace for mathematical applications.
@ ecINTERNAL_ERROR
Internal error of any kind.
@ ecDIV_BY_ZERO
Division by zero (currently unused)
ECmdCode
Bytecode values.
Definition: qmuparserdef.h:99
@ cmVARPOW4
Definition: qmuparserdef.h:129
@ cmOPRT_INFIX
code for infix operators
Definition: qmuparserdef.h:140
@ cmBC
Operator item: closing bracket.
Definition: qmuparserdef.h:118
@ cmLE
Operator item: less or equal.
Definition: qmuparserdef.h:103
@ cmUNKNOWN
uninitialized item
Definition: qmuparserdef.h:142
@ cmSUB
Operator item: subtract.
Definition: qmuparserdef.h:110
@ cmLAND
Definition: qmuparserdef.h:114
@ cmGT
Operator item: greater than.
Definition: qmuparserdef.h:108
@ cmSTRING
Code for a string token.
Definition: qmuparserdef.h:137
@ cmFUNC
Code for a generic function item.
Definition: qmuparserdef.h:134
@ cmVARMUL
Definition: qmuparserdef.h:130
@ cmEND
end of formula
Definition: qmuparserdef.h:141
@ cmFUNC_STR
Code for a function with a string parameter.
Definition: qmuparserdef.h:135
@ cmLT
Operator item: less than.
Definition: qmuparserdef.h:107
@ cmMUL
Operator item: multiply.
Definition: qmuparserdef.h:111
@ cmVARPOW3
Definition: qmuparserdef.h:128
@ cmGE
Operator item: greater or equal.
Definition: qmuparserdef.h:104
@ cmADD
Operator item: add.
Definition: qmuparserdef.h:109
@ cmASSIGN
Operator item: Assignment operator.
Definition: qmuparserdef.h:116
@ cmENDIF
For use in the ternary if-then-else operator.
Definition: qmuparserdef.h:121
@ cmELSE
For use in the ternary if-then-else operator.
Definition: qmuparserdef.h:120
@ cmEQ
Operator item: equals.
Definition: qmuparserdef.h:106
@ cmFUNC_BULK
Special callbacks for Bulk mode with an additional parameter for the bulk index.
Definition: qmuparserdef.h:136
@ cmPOW2
Definition: qmuparserdef.h:131
@ cmARG_SEP
function argument separator
Definition: qmuparserdef.h:122
@ cmPOW
Operator item: y to the power of ...
Definition: qmuparserdef.h:113
@ cmLOR
Definition: qmuparserdef.h:115
@ cmNEQ
Operator item: not equal.
Definition: qmuparserdef.h:105
@ cmVARPOW2
Definition: qmuparserdef.h:127
@ cmOPRT_BIN
user defined binary operator
Definition: qmuparserdef.h:138
@ cmIF
For use in the ternary if-then-else operator.
Definition: qmuparserdef.h:119
@ cmVAL
value item
Definition: qmuparserdef.h:124
@ cmOPRT_POSTFIX
code for postfix operators
Definition: qmuparserdef.h:139
@ cmDIV
Operator item: division.
Definition: qmuparserdef.h:112
@ cmVAR
variable item
Definition: qmuparserdef.h:123
@ cmBO
Operator item: opening bracket.
Definition: qmuparserdef.h:117
qreal(* generic_fun_type)()
Callback type used for functions without arguments.
Definition: qmuparserdef.h:221
QT_WARNING_POP static Q_REQUIRED_RESULT bool QmuFuzzyComparePossibleNulls(double p1, double p2)
Definition: qmudef.h:61
Definition of the parser bytecode class.
This file defines the error class used by the parser.
struct qmu::SToken::@3::@6 Fun
struct qmu::SToken::@3::@5 Val
struct qmu::SToken::@3::@7 Oprt