OpcUaCanOpen
CANopen OPC-UA server
muParserBytecode.cpp
Go to the documentation of this file.
1 /*
2  __________
3  _____ __ __\______ \_____ _______ ______ ____ _______
4  / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
5  | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
6  |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
7  \/ \/ \/ \/
8  Copyright (C) 2011 Ingo Berg
9 
10  Permission is hereby granted, free of charge, to any person obtaining a copy of this
11  software and associated documentation files (the "Software"), to deal in the Software
12  without restriction, including without limitation the rights to use, copy, modify,
13  merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
14  permit persons to whom the Software is furnished to do so, subject to the following conditions:
15 
16  The above copyright notice and this permission notice shall be included in all copies or
17  substantial portions of the Software.
18 
19  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
20  NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25 
26 #include "muParserBytecode.h"
27 
28 #include <algorithm>
29 #include <cassert>
30 #include <string>
31 #include <stack>
32 #include <vector>
33 #include <iostream>
34 
35 #include "muParserDef.h"
36 #include "muParserError.h"
37 #include "muParserToken.h"
38 #include "muParserStack.h"
39 #include "muParserTemplateMagic.h"
40 
41 
42 namespace mu
43 {
44  //---------------------------------------------------------------------------
47  :m_iStackPos(0)
48  ,m_iMaxStackSize(0)
49  ,m_vRPN()
50  ,m_bEnableOptimizer(true)
51  {
52  m_vRPN.reserve(50);
53  }
54 
55  //---------------------------------------------------------------------------
61  {
62  Assign(a_ByteCode);
63  }
64 
65  //---------------------------------------------------------------------------
71  {
72  Assign(a_ByteCode);
73  return *this;
74  }
75 
76  //---------------------------------------------------------------------------
78  {
79  m_bEnableOptimizer = bStat;
80  }
81 
82  //---------------------------------------------------------------------------
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;
96  }
97 
98  //---------------------------------------------------------------------------
104  {
105  ++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  //---------------------------------------------------------------------------
131  {
132  ++m_iStackPos;
134 
135  // If optimization does not apply
136  SToken tok;
137  tok.Cmd = cmVAL;
138  tok.Val.ptr = NULL;
139  tok.Val.data = 0;
140  tok.Val.data2 = a_fVal;
141  m_vRPN.push_back(tok);
142  }
143 
144  //---------------------------------------------------------------------------
146  {
147  std::size_t sz = m_vRPN.size();
148  value_type &x = m_vRPN[sz-2].Val.data2,
149  &y = m_vRPN[sz-1].Val.data2;
150  switch (a_Oprt)
151  {
152  case cmLAND: x = (int)x && (int)y; m_vRPN.pop_back(); break;
153  case cmLOR: x = (int)x || (int)y; m_vRPN.pop_back(); break;
154  case cmLT: x = x < y; m_vRPN.pop_back(); break;
155  case cmGT: x = x > y; m_vRPN.pop_back(); break;
156  case cmLE: x = x <= y; m_vRPN.pop_back(); break;
157  case cmGE: x = x >= y; m_vRPN.pop_back(); break;
158  case cmNEQ: x = x != y; m_vRPN.pop_back(); break;
159  case cmEQ: x = x == y; m_vRPN.pop_back(); break;
160  case cmADD: x = x + y; m_vRPN.pop_back(); break;
161  case cmSUB: x = x - y; m_vRPN.pop_back(); break;
162  case cmMUL: x = x * y; m_vRPN.pop_back(); break;
163  case cmDIV:
164 
165 #if defined(MUP_MATH_EXCEPTIONS)
166  if (y==0)
167  throw ParserError(ecDIV_BY_ZERO, _T("0"));
168 #endif
169 
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  //---------------------------------------------------------------------------
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==2)
220  m_vRPN[sz-2].Cmd = cmVARPOW2;
221  else if (m_vRPN[sz-1].Val.data2==3)
222  m_vRPN[sz-2].Cmd = cmVARPOW3;
223  else if (m_vRPN[sz-1].Val.data2==4)
224  m_vRPN[sz-2].Cmd = cmVARPOW4;
225  else
226  break;
227 
228  m_vRPN.pop_back();
229  bOptimized = true;
230  }
231  break;
232 
233  case cmSUB:
234  case cmADD:
235  // Simple optimization based on pattern recognition for a shitload of different
236  // bytecode combinations of addition/subtraction
237  if ( (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAL) ||
238  (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVAR) ||
239  (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL) ||
240  (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAL) ||
241  (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ||
242  (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ||
243  (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ||
244  (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) )
245  {
246  assert( (m_vRPN[sz-2].Val.ptr==NULL && m_vRPN[sz-1].Val.ptr!=NULL) ||
247  (m_vRPN[sz-2].Val.ptr!=NULL && m_vRPN[sz-1].Val.ptr==NULL) ||
248  (m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) );
249 
250  m_vRPN[sz-2].Cmd = cmVARMUL;
251  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
252  m_vRPN[sz-2].Val.data2 += ((a_Oprt==cmSUB) ? -1 : 1) * m_vRPN[sz-1].Val.data2; // offset
253  m_vRPN[sz-2].Val.data += ((a_Oprt==cmSUB) ? -1 : 1) * m_vRPN[sz-1].Val.data; // multiplicand
254  m_vRPN.pop_back();
255  bOptimized = true;
256  }
257  break;
258 
259  case cmMUL:
260  if ( (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAL) ||
261  (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVAR) )
262  {
263  m_vRPN[sz-2].Cmd = cmVARMUL;
264  m_vRPN[sz-2].Val.ptr = (value_type*)((long long)(m_vRPN[sz-2].Val.ptr) | (long long)(m_vRPN[sz-1].Val.ptr));
265  m_vRPN[sz-2].Val.data = m_vRPN[sz-2].Val.data2 + m_vRPN[sz-1].Val.data2;
266  m_vRPN[sz-2].Val.data2 = 0;
267  m_vRPN.pop_back();
268  bOptimized = true;
269  }
270  else if ( (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL) ||
271  (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAL) )
272  {
273  // Optimization: 2*(3*b+1) or (3*b+1)*2 -> 6*b+2
274  m_vRPN[sz-2].Cmd = cmVARMUL;
275  m_vRPN[sz-2].Val.ptr = (value_type*)((long long)(m_vRPN[sz-2].Val.ptr) | (long long)(m_vRPN[sz-1].Val.ptr));
276  if (m_vRPN[sz-1].Cmd == cmVAL)
277  {
278  m_vRPN[sz-2].Val.data *= m_vRPN[sz-1].Val.data2;
279  m_vRPN[sz-2].Val.data2 *= m_vRPN[sz-1].Val.data2;
280  }
281  else
282  {
283  m_vRPN[sz-2].Val.data = m_vRPN[sz-1].Val.data * m_vRPN[sz-2].Val.data2;
284  m_vRPN[sz-2].Val.data2 = m_vRPN[sz-1].Val.data2 * m_vRPN[sz-2].Val.data2;
285  }
286  m_vRPN.pop_back();
287  bOptimized = true;
288  }
289  else if (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAR &&
290  m_vRPN[sz-1].Val.ptr == m_vRPN[sz-2].Val.ptr)
291  {
292  // Optimization: a*a -> a^2
293  m_vRPN[sz-2].Cmd = cmVARPOW2;
294  m_vRPN.pop_back();
295  bOptimized = true;
296  }
297  break;
298 
299  case cmDIV:
300  if (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-1].Val.data2!=0)
301  {
302  // Optimization: 4*a/2 -> 2*a
303  m_vRPN[sz-2].Val.data /= m_vRPN[sz-1].Val.data2;
304  m_vRPN[sz-2].Val.data2 /= m_vRPN[sz-1].Val.data2;
305  m_vRPN.pop_back();
306  bOptimized = true;
307  }
308  break;
309  default:
310  // no optimization for other opcodes
311  break;
312  } // switch a_Oprt
313  }
314  }
315 
316  // If optimization can't be applied just write the value
317  if (!bOptimized)
318  {
319  --m_iStackPos;
320  SToken tok;
321  tok.Cmd = a_Oprt;
322  m_vRPN.push_back(tok);
323  }
324  }
325 
326  //---------------------------------------------------------------------------
328  {
329  SToken tok;
330  tok.Cmd = a_Oprt;
331  m_vRPN.push_back(tok);
332  }
333 
334  //---------------------------------------------------------------------------
346  {
347  --m_iStackPos;
348 
349  SToken tok;
350  tok.Cmd = cmASSIGN;
351  tok.Oprt.ptr = a_pVar;
352  m_vRPN.push_back(tok);
353  }
354 
355  //---------------------------------------------------------------------------
362  {
363  if (a_iArgc>=0)
364  {
365  m_iStackPos = m_iStackPos - a_iArgc + 1;
366  }
367  else
368  {
369  // function with unlimited number of arguments
370  m_iStackPos = m_iStackPos + a_iArgc + 1;
371  }
373 
374  SToken tok;
375  tok.Cmd = cmFUNC;
376  tok.Fun.argc = a_iArgc;
377  tok.Fun.ptr = a_pFun;
378  m_vRPN.push_back(tok);
379  }
380 
381  //---------------------------------------------------------------------------
388  {
389  m_iStackPos = m_iStackPos - a_iArgc + 1;
391 
392  SToken tok;
393  tok.Cmd = cmFUNC_BULK;
394  tok.Fun.argc = a_iArgc;
395  tok.Fun.ptr = a_pFun;
396  m_vRPN.push_back(tok);
397  }
398 
399  //---------------------------------------------------------------------------
407  void ParserByteCode::AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx)
408  {
409  m_iStackPos = m_iStackPos - a_iArgc + 1;
410 
411  SToken tok;
412  tok.Cmd = cmFUNC_STR;
413  tok.Fun.argc = a_iArgc;
414  tok.Fun.idx = a_iIdx;
415  tok.Fun.ptr = a_pFun;
416  m_vRPN.push_back(tok);
417 
419  }
420 
421  //---------------------------------------------------------------------------
427  {
428  SToken tok;
429  tok.Cmd = cmEND;
430  m_vRPN.push_back(tok);
431  rpn_type(m_vRPN).swap(m_vRPN); // shrink bytecode vector to fit
432 
433  // Determine the if-then-else jump offsets
434  ParserStack<int> stIf, stElse;
435  int idx;
436  for (int i=0; i<(int)m_vRPN.size(); ++i)
437  {
438  switch(m_vRPN[i].Cmd)
439  {
440  case cmIF:
441  stIf.push(i);
442  break;
443 
444  case cmELSE:
445  stElse.push(i);
446  idx = stIf.pop();
447  m_vRPN[idx].Oprt.offset = i - idx;
448  break;
449 
450  case cmENDIF:
451  idx = stElse.pop();
452  m_vRPN[idx].Oprt.offset = i - idx;
453  break;
454 
455  default:
456  break;
457  }
458  }
459  }
460 
461  //---------------------------------------------------------------------------
463  {
464  if (m_vRPN.size()==0)
466  else
467  return &m_vRPN[0];
468  }
469 
470  //---------------------------------------------------------------------------
472  {
473  return m_iMaxStackSize+1;
474  }
475 
476  //---------------------------------------------------------------------------
478  std::size_t ParserByteCode::GetSize() const
479  {
480  return m_vRPN.size();
481  }
482 
483  //---------------------------------------------------------------------------
493  {
494  m_vRPN.clear();
495  m_iStackPos = 0;
496  m_iMaxStackSize = 0;
497  }
498 
499  //---------------------------------------------------------------------------
502  {
503  if (!m_vRPN.size())
504  {
505  mu::console() << _T("No bytecode available\n");
506  return;
507  }
508 
509  mu::console() << _T("Number of RPN tokens:") << (int)m_vRPN.size() << _T("\n");
510  for (std::size_t i=0; i<m_vRPN.size() && m_vRPN[i].Cmd!=cmEND; ++i)
511  {
512  mu::console() << std::dec << i << _T(" : \t");
513  switch (m_vRPN[i].Cmd)
514  {
515  case cmVAL: mu::console() << _T("VAL \t");
516  mu::console() << _T("[") << m_vRPN[i].Val.data2 << _T("]\n");
517  break;
518 
519  case cmVAR: mu::console() << _T("VAR \t");
520  mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]\n");
521  break;
522 
523  case cmVARPOW2: mu::console() << _T("VARPOW2 \t");
524  mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]\n");
525  break;
526 
527  case cmVARPOW3: mu::console() << _T("VARPOW3 \t");
528  mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]\n");
529  break;
530 
531  case cmVARPOW4: mu::console() << _T("VARPOW4 \t");
532  mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]\n");
533  break;
534 
535  case cmVARMUL: mu::console() << _T("VARMUL \t");
536  mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]");
537  mu::console() << _T(" * [") << m_vRPN[i].Val.data << _T("]");
538  mu::console() << _T(" + [") << m_vRPN[i].Val.data2 << _T("]\n");
539  break;
540 
541  case cmFUNC: mu::console() << _T("CALL\t");
542  mu::console() << _T("[ARG:") << std::dec << m_vRPN[i].Fun.argc << _T("]");
543  mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Fun.ptr << _T("]");
544  mu::console() << _T("\n");
545  break;
546 
547  case cmFUNC_STR:
548  mu::console() << _T("CALL STRFUNC\t");
549  mu::console() << _T("[ARG:") << std::dec << m_vRPN[i].Fun.argc << _T("]");
550  mu::console() << _T("[IDX:") << std::dec << m_vRPN[i].Fun.idx << _T("]");
551  mu::console() << _T("[ADDR: 0x") << m_vRPN[i].Fun.ptr << _T("]\n");
552  break;
553 
554  case cmLT: mu::console() << _T("LT\n"); break;
555  case cmGT: mu::console() << _T("GT\n"); break;
556  case cmLE: mu::console() << _T("LE\n"); break;
557  case cmGE: mu::console() << _T("GE\n"); break;
558  case cmEQ: mu::console() << _T("EQ\n"); break;
559  case cmNEQ: mu::console() << _T("NEQ\n"); break;
560  case cmADD: mu::console() << _T("ADD\n"); break;
561  case cmLAND: mu::console() << _T("&&\n"); break;
562  case cmLOR: mu::console() << _T("||\n"); break;
563  case cmSUB: mu::console() << _T("SUB\n"); break;
564  case cmMUL: mu::console() << _T("MUL\n"); break;
565  case cmDIV: mu::console() << _T("DIV\n"); break;
566  case cmPOW: mu::console() << _T("POW\n"); break;
567 
568  case cmIF: mu::console() << _T("IF\t");
569  mu::console() << _T("[OFFSET:") << std::dec << m_vRPN[i].Oprt.offset << _T("]\n");
570  break;
571 
572  case cmELSE: mu::console() << _T("ELSE\t");
573  mu::console() << _T("[OFFSET:") << std::dec << m_vRPN[i].Oprt.offset << _T("]\n");
574  break;
575 
576  case cmENDIF: mu::console() << _T("ENDIF\n"); break;
577 
578  case cmASSIGN:
579  mu::console() << _T("ASSIGN\t");
580  mu::console() << _T("[ADDR: 0x") << m_vRPN[i].Oprt.ptr << _T("]\n");
581  break;
582 
583  default: mu::console() << _T("(unknown code: ") << m_vRPN[i].Cmd << _T(")\n");
584  break;
585  } // switch cmdCode
586  } // while bytecode
587 
588  mu::console() << _T("END") << std::endl;
589  }
590 } // namespace mu