muParser API -  1.35
muParserTokenReader.cpp
Go to the documentation of this file.
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 <cstdio>
30 #include <cstring>
31 #include <map>
32 #include <stack>
33 #include <string>
34 
35 #include "muParserTokenReader.h"
36 #include "muParserBase.h"
37 
38 #if defined(_MSC_VER)
39  #pragma warning(push)
40  #pragma warning(disable : 26812)
41 #endif
42 
43 /** \file
44  \brief This file contains the parser token reader implementation.
45 */
46 
47 
48 namespace mu
49 {
50 
51  // Forward declaration
52  class ParserBase;
53 
54  /** \brief Copy constructor.
55 
56  \sa Assign
57  \throw nothrow
58  */
59  ParserTokenReader::ParserTokenReader(const ParserTokenReader& a_Reader)
60  {
61  Assign(a_Reader);
62  }
63 
64 
65  /** \brief Assignment operator.
66 
67  Self assignment will be suppressed otherwise #Assign is called.
68 
69  \param a_Reader Object to copy to this token reader.
70  \throw nothrow
71  */
72  ParserTokenReader& ParserTokenReader::operator=(const ParserTokenReader& a_Reader)
73  {
74  if (&a_Reader != this)
75  Assign(a_Reader);
76 
77  return *this;
78  }
79 
80 
81  /** \brief Assign state of a token reader to this token reader.
82 
83  \param a_Reader Object from which the state should be copied.
84  \throw nothrow
85  */
86  void ParserTokenReader::Assign(const ParserTokenReader& a_Reader)
87  {
88  m_pParser = a_Reader.m_pParser;
89  m_strFormula = a_Reader.m_strFormula;
90  m_iPos = a_Reader.m_iPos;
91  m_iSynFlags = a_Reader.m_iSynFlags;
92 
93  m_UsedVar = a_Reader.m_UsedVar;
94  m_pFunDef = a_Reader.m_pFunDef;
95  m_pConstDef = a_Reader.m_pConstDef;
96  m_pVarDef = a_Reader.m_pVarDef;
97  m_pStrVarDef = a_Reader.m_pStrVarDef;
98  m_pPostOprtDef = a_Reader.m_pPostOprtDef;
99  m_pInfixOprtDef = a_Reader.m_pInfixOprtDef;
100  m_pOprtDef = a_Reader.m_pOprtDef;
101  m_bIgnoreUndefVar = a_Reader.m_bIgnoreUndefVar;
102  m_vIdentFun = a_Reader.m_vIdentFun;
103  m_pFactory = a_Reader.m_pFactory;
104  m_pFactoryData = a_Reader.m_pFactoryData;
105  m_bracketStack = a_Reader.m_bracketStack;
106  m_cArgSep = a_Reader.m_cArgSep;
107  m_fZero = a_Reader.m_fZero;
108  m_lastTok = a_Reader.m_lastTok;
109  }
110 
111 
112  /** \brief Constructor.
113 
114  Create a Token reader and bind it to a parser object.
115 
116  \pre [assert] a_pParser may not be NULL
117  \post #m_pParser==a_pParser
118  \param a_pParent Parent parser object of the token reader.
119  */
121  :m_pParser(a_pParent)
122  , m_strFormula()
123  , m_iPos(0)
124  , m_iSynFlags(0)
125  , m_bIgnoreUndefVar(false)
126  , m_pFunDef(nullptr)
127  , m_pPostOprtDef(nullptr)
128  , m_pInfixOprtDef(nullptr)
129  , m_pOprtDef(nullptr)
130  , m_pConstDef(nullptr)
131  , m_pStrVarDef(nullptr)
132  , m_pVarDef(nullptr)
133  , m_pFactory(nullptr)
134  , m_pFactoryData(nullptr)
135  , m_vIdentFun()
136  , m_UsedVar()
137  , m_fZero(0)
138  , m_bracketStack()
139  , m_lastTok()
140  , m_cArgSep(',')
141  {
142  MUP_ASSERT(m_pParser != nullptr);
143  SetParent(m_pParser);
144  }
145 
146 
147  /** \brief Create instance of a ParserTokenReader identical with this
148  and return its pointer.
149 
150  This is a factory method the calling function must take care of the object destruction.
151 
152  \return A new ParserTokenReader object.
153  \throw nothrow
154  */
156  {
157  std::unique_ptr<ParserTokenReader> ptr(new ParserTokenReader(*this));
158  ptr->SetParent(a_pParent);
159  return ptr.release();
160  }
161 
162 
163  ParserTokenReader::token_type& ParserTokenReader::SaveBeforeReturn(const token_type& tok)
164  {
165  m_lastTok = tok;
166  return m_lastTok;
167  }
168 
169 
170  void ParserTokenReader::AddValIdent(identfun_type a_pCallback)
171  {
172  // Use push_front is used to give user defined callbacks a higher priority than
173  // the built in ones. Otherwise reading hex numbers would not work
174  // since the "0" in "0xff" would always be read first making parsing of
175  // the rest impossible.
176  // reference:
177  // http://sourceforge.net/projects/muparser/forums/forum/462843/topic/4824956
178  m_vIdentFun.push_front(a_pCallback);
179  }
180 
181 
182  void ParserTokenReader::SetVarCreator(facfun_type a_pFactory, void* pUserData)
183  {
184  m_pFactory = a_pFactory;
185  m_pFactoryData = pUserData;
186  }
187 
188 
189  /** \brief Return the current position of the token reader in the formula string.
190 
191  \return #m_iPos
192  \throw nothrow
193  */
195  {
196  return m_iPos;
197  }
198 
199 
200  /** \brief Return a reference to the formula.
201 
202  \return #m_strFormula
203  \throw nothrow
204  */
206  {
207  return m_strFormula;
208  }
209 
210 
211  /** \brief Return a map containing the used variables only. */
213  {
214  return m_UsedVar;
215  }
216 
217 
218  /** \brief Initialize the token Reader.
219 
220  Sets the formula position index to zero and set Syntax flags to default for initial formula parsing.
221  \pre [assert] triggered if a_szFormula==0
222  */
223  void ParserTokenReader::SetFormula(const string_type& a_strFormula)
224  {
225  m_strFormula = a_strFormula;
226  ReInit();
227  }
228 
229 
230  /** \brief Set Flag that controls behaviour in case of undefined variables being found.
231 
232  If true, the parser does not throw an exception if an undefined variable is found.
233  otherwise it does. This variable is used internally only!
234  It suppresses a "undefined variable" exception in GetUsedVar().
235  Those function should return a complete list of variables including
236  those the are not defined by the time of it's call.
237  */
239  {
240  m_bIgnoreUndefVar = bIgnore;
241  }
242 
243 
244  /** \brief Reset the token reader to the start of the formula.
245 
246  The syntax flags will be reset to a value appropriate for the
247  start of a formula.
248  \post #m_iPos==0, #m_iSynFlags = noOPT | noBC | noPOSTOP | noSTR
249  \throw nothrow
250  \sa ESynCodes
251  */
253  {
254  m_iPos = 0;
255  m_iSynFlags = sfSTART_OF_LINE;
256  m_bracketStack = std::stack<int>();
257  m_UsedVar.clear();
258  m_lastTok = token_type();
259  }
260 
261 
262  /** \brief Read the next token from the string. */
264  {
265  MUP_ASSERT(m_pParser != nullptr);
266 
267  const char_type* szExpr = m_strFormula.c_str();
268  token_type tok;
269 
270  // Ignore all non printable characters when reading the expression
271  while (szExpr[m_iPos] > 0 && szExpr[m_iPos] <= 0x20)
272  {
273  // 14-31 are control characters. I donÄt want to have to deal with such strings at all!
274  // (see https://en.cppreference.com/w/cpp/string/byte/isprint)
275  if (szExpr[m_iPos] >= 14 && szExpr[m_iPos] <= 31)
276  Error(ecINVALID_CHARACTERS_FOUND, m_iPos);
277 
278  ++m_iPos;
279  }
280 
281  // Check for end of formula
282  if (IsEOF(tok))
283  return SaveBeforeReturn(tok);
284 
285  // Check for user defined binary operator
286  if (IsOprt(tok))
287  return SaveBeforeReturn(tok);
288 
289  // Check for function token
290  if (IsFunTok(tok))
291  return SaveBeforeReturn(tok);
292 
293  // Check built in operators / tokens
294  if (IsBuiltIn(tok))
295  return SaveBeforeReturn(tok);
296 
297  // Check for function argument separators
298  if (IsArgSep(tok))
299  return SaveBeforeReturn(tok);
300 
301  // Check for values / constant tokens
302  if (IsValTok(tok))
303  return SaveBeforeReturn(tok);
304 
305  // Check for variable tokens
306  if (IsVarTok(tok))
307  return SaveBeforeReturn(tok);
308 
309  // Check for string variables
310  if (IsStrVarTok(tok))
311  return SaveBeforeReturn(tok);
312 
313  // Check for String tokens
314  if (IsString(tok))
315  return SaveBeforeReturn(tok);
316 
317  // Check for unary operators
318  if (IsInfixOpTok(tok))
319  return SaveBeforeReturn(tok);
320 
321  // Check for unary operators
322  if (IsPostOpTok(tok))
323  return SaveBeforeReturn(tok);
324 
325  // Check String for undefined variable token. Done only if a
326  // flag is set indicating to ignore undefined variables.
327  // This is a way to conditionally avoid an error if
328  // undefined variables occur.
329  // (The GetUsedVar function must suppress the error for
330  // undefined variables in order to collect all variable
331  // names including the undefined ones.)
332  if ((m_bIgnoreUndefVar || m_pFactory) && IsUndefVarTok(tok))
333  return SaveBeforeReturn(tok);
334 
335  // Check for unknown token
336  //
337  // !!! From this point on there is no exit without an exception possible...
338  //
339  string_type strTok;
340  auto iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos);
341  if (iEnd != m_iPos)
342  Error(ecUNASSIGNABLE_TOKEN, m_iPos, strTok);
343 
344  Error(ecUNASSIGNABLE_TOKEN, m_iPos, m_strFormula.substr(m_iPos));
345  return token_type(); // never reached
346  }
347 
348 
349  void ParserTokenReader::SetParent(ParserBase* a_pParent)
350  {
351  m_pParser = a_pParent;
352  m_pFunDef = &a_pParent->m_FunDef;
353  m_pOprtDef = &a_pParent->m_OprtDef;
354  m_pInfixOprtDef = &a_pParent->m_InfixOprtDef;
355  m_pPostOprtDef = &a_pParent->m_PostOprtDef;
356  m_pVarDef = &a_pParent->m_VarDef;
357  m_pStrVarDef = &a_pParent->m_StrVarDef;
358  m_pConstDef = &a_pParent->m_ConstDef;
359  }
360 
361 
362  /** \brief Extract all characters that belong to a certain charset.
363 
364  \param a_szCharSet [in] Const char array of the characters allowed in the token.
365  \param a_strTok [out] The string that consists entirely of characters listed in a_szCharSet.
366  \param a_iPos [in] Position in the string from where to start reading.
367  \return The Position of the first character not listed in a_szCharSet.
368  \throw nothrow
369  */
370  int ParserTokenReader::ExtractToken(const char_type* a_szCharSet, string_type& a_sTok, std::size_t a_iPos) const
371  {
372  auto iEnd = m_strFormula.find_first_not_of(a_szCharSet, a_iPos);
373 
374  if (iEnd == string_type::npos)
375  iEnd = m_strFormula.length();
376 
377  // Assign token string if there was something found
378  if (a_iPos != iEnd)
379  a_sTok = string_type(m_strFormula.begin() + a_iPos, m_strFormula.begin() + iEnd);
380 
381  return static_cast<int>(iEnd);
382  }
383 
384 
385  /** \brief Check Expression for the presence of a binary operator token.
386 
387  Userdefined binary operator "++" gives inconsistent parsing result for
388  the equations "a++b" and "a ++ b" if alphabetic characters are allowed
389  in operator tokens. To avoid this this function checks specifically
390  for operator tokens.
391  */
392  int ParserTokenReader::ExtractOperatorToken(string_type& a_sTok, std::size_t a_iPos) const
393  {
394  // Changed as per Issue 6: https://code.google.com/p/muparser/issues/detail?id=6
395  auto iEnd = m_strFormula.find_first_not_of(m_pParser->ValidOprtChars(), a_iPos);
396  if (iEnd == string_type::npos)
397  iEnd = m_strFormula.length();
398 
399  // Assign token string if there was something found
400  if (a_iPos != iEnd)
401  {
402  a_sTok = string_type(m_strFormula.begin() + a_iPos, m_strFormula.begin() + iEnd);
403  return static_cast<int>(iEnd);
404  }
405  else
406  {
407  // There is still the chance of having to deal with an operator consisting exclusively
408  // of alphabetic characters.
409  return ExtractToken(_T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), a_sTok, (std::size_t)a_iPos);
410  }
411  }
412 
413 
414  /** \brief Check if a built in operator or other token can be found
415  \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token.
416  \return true if an operator token has been found.
417  */
418  bool ParserTokenReader::IsBuiltIn(token_type& a_Tok)
419  {
420  const char_type** const pOprtDef = m_pParser->GetOprtDef(),
421  * const szFormula = m_strFormula.c_str();
422 
423  // Compare token with function and operator strings
424  // check string for operator/function
425  for (int i = 0; pOprtDef[i]; i++)
426  {
427  std::size_t len(std::char_traits<char_type>::length(pOprtDef[i]));
428  if (string_type(pOprtDef[i]) == string_type(szFormula + m_iPos, szFormula + m_iPos + len))
429  {
430  switch (i)
431  {
432  case cmLAND:
433  case cmLOR:
434  case cmLT:
435  case cmGT:
436  case cmLE:
437  case cmGE:
438  case cmNEQ:
439  case cmEQ:
440  case cmADD:
441  case cmSUB:
442  case cmMUL:
443  case cmDIV:
444  case cmPOW:
445  case cmASSIGN:
446  // The assignment operator need special treatment
447  if (i == cmASSIGN && m_iSynFlags & noASSIGN)
448  Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]);
449 
450  if (!m_pParser->HasBuiltInOprt()) continue;
451  if (m_iSynFlags & noOPT)
452  {
453  // Maybe its an infix operator not an operator
454  // Both operator types can share characters in
455  // their identifiers
456  if (IsInfixOpTok(a_Tok))
457  return true;
458 
459  Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]);
460  }
461 
462  m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE | noEND;
463  break;
464 
465  case cmBO:
466  if (m_iSynFlags & noBO)
467  Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);
468 
469  if (m_lastTok.GetCode() == cmFUNC)
470  m_iSynFlags = noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE;
471  else
472  m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE;
473 
474  m_bracketStack.push(cmBO);
475  break;
476 
477  case cmBC:
478  if (m_iSynFlags & noBC)
479  Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);
480 
481  m_iSynFlags = noBO | noVAR | noVAL | noFUN | noINFIXOP | noSTR | noASSIGN;
482 
483  if (!m_bracketStack.empty())
484  m_bracketStack.pop();
485  else
486  Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);
487  break;
488 
489  case cmELSE:
490  if (m_iSynFlags & noELSE)
491  Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]);
492 
493  m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE | noSTR;
494  break;
495 
496  case cmIF:
497  if (m_iSynFlags & noIF)
498  Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]);
499 
500  m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE | noSTR;
501  break;
502 
503  default: // The operator is listed in c_DefaultOprt, but not here. This is a bad thing...
504  Error(ecINTERNAL_ERROR);
505  } // switch operator id
506 
507  m_iPos += (int)len;
508  a_Tok.Set((ECmdCode)i, pOprtDef[i]);
509  return true;
510  } // if operator string found
511  } // end of for all operator strings
512 
513  return false;
514  }
515 
516 
517  bool ParserTokenReader::IsArgSep(token_type& a_Tok)
518  {
519  const char_type* szFormula = m_strFormula.c_str();
520 
521  if (szFormula[m_iPos] == m_cArgSep)
522  {
523  // copy the separator into null terminated string
524  char_type szSep[2];
525  szSep[0] = m_cArgSep;
526  szSep[1] = 0;
527 
528  if (m_iSynFlags & noARG_SEP)
529  Error(ecUNEXPECTED_ARG_SEP, m_iPos, szSep);
530 
531  m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN;
532  m_iPos++;
533  a_Tok.Set(cmARG_SEP, szSep);
534  return true;
535  }
536 
537  return false;
538  }
539 
540 
541  /** \brief Check for End of Formula.
542 
543  \return true if an end of formula is found false otherwise.
544  \param a_Tok [out] If an eof is found the corresponding token will be stored there.
545  \throw nothrow
546  \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsString, IsInfixOpTok, IsPostOpTok
547  */
548  bool ParserTokenReader::IsEOF(token_type& a_Tok)
549  {
550  const char_type* szFormula = m_strFormula.c_str();
551 
552  // check for EOF
553  if (!szFormula[m_iPos] /*|| szFormula[m_iPos] == '\n'*/)
554  {
555  if (m_iSynFlags & noEND)
556  Error(ecUNEXPECTED_EOF, m_iPos);
557 
558  if (!m_bracketStack.empty())
559  Error(ecMISSING_PARENS, m_iPos, _T(")"));
560 
561  m_iSynFlags = 0;
562  a_Tok.Set(cmEND);
563  return true;
564  }
565 
566  return false;
567  }
568 
569 
570  /** \brief Check if a string position contains a unary infix operator.
571  \return true if a function token has been found false otherwise.
572  */
573  bool ParserTokenReader::IsInfixOpTok(token_type& a_Tok)
574  {
575  string_type sTok;
576  auto iEnd = ExtractToken(m_pParser->ValidInfixOprtChars(), sTok, (std::size_t)m_iPos);
577  if (iEnd == m_iPos)
578  return false;
579 
580  // iterate over all postfix operator strings
581  funmap_type::const_reverse_iterator it = m_pInfixOprtDef->rbegin();
582  for (; it != m_pInfixOprtDef->rend(); ++it)
583  {
584  if (sTok.find(it->first) != 0)
585  continue;
586 
587  a_Tok.Set(it->second, it->first);
588  m_iPos += (int)it->first.length();
589 
590  if (m_iSynFlags & noINFIXOP)
591  Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString());
592 
593  m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN | noARG_SEP;
594  return true;
595  }
596 
597  return false;
598 
599  /*
600  a_Tok.Set(item->second, sTok);
601  m_iPos = (int)iEnd;
602 
603  if (m_iSynFlags & noINFIXOP)
604  Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString());
605 
606  m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN;
607  return true;
608  */
609  }
610 
611 
612  /** \brief Check whether the token at a given position is a function token.
613  \param a_Tok [out] If a value token is found it will be placed here.
614  \throw ParserException if Syntaxflags do not allow a function at a_iPos
615  \return true if a function token has been found false otherwise.
616  \pre [assert] m_pParser!=0
617  */
618  bool ParserTokenReader::IsFunTok(token_type& a_Tok)
619  {
620  string_type strTok;
621  auto iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos);
622  if (iEnd == m_iPos)
623  return false;
624 
625  funmap_type::const_iterator item = m_pFunDef->find(strTok);
626  if (item == m_pFunDef->end())
627  return false;
628 
629  // Check if the next sign is an opening bracket
630  const char_type* szFormula = m_strFormula.c_str();
631  if (szFormula[iEnd] != '(')
632  return false;
633 
634  a_Tok.Set(item->second, strTok);
635 
636  m_iPos = (int)iEnd;
637  if (m_iSynFlags & noFUN)
638  Error(ecUNEXPECTED_FUN, m_iPos - (int)a_Tok.GetAsString().length(), a_Tok.GetAsString());
639 
640  m_iSynFlags = noANY ^ noBO;
641  return true;
642  }
643 
644 
645  /** \brief Check if a string position contains a binary operator.
646  \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token.
647  \return true if an operator token has been found.
648  */
649  bool ParserTokenReader::IsOprt(token_type& a_Tok)
650  {
651  const char_type* const szExpr = m_strFormula.c_str();
652  string_type strTok;
653 
654  auto iEnd = ExtractOperatorToken(strTok, (std::size_t)m_iPos);
655  if (iEnd == m_iPos)
656  return false;
657 
658  // Check if the operator is a built in operator, if so ignore it here
659  const char_type** const pOprtDef = m_pParser->GetOprtDef();
660  for (int i = 0; m_pParser->HasBuiltInOprt() && pOprtDef[i]; ++i)
661  {
662  if (string_type(pOprtDef[i]) == strTok)
663  return false;
664  }
665 
666  // Note:
667  // All tokens in oprt_bin_maptype are have been sorted by their length
668  // Long operators must come first! Otherwise short names (like: "add") that
669  // are part of long token names (like: "add123") will be found instead
670  // of the long ones.
671  // Length sorting is done with ascending length so we use a reverse iterator here.
672  funmap_type::const_reverse_iterator it = m_pOprtDef->rbegin();
673  for (; it != m_pOprtDef->rend(); ++it)
674  {
675  const string_type& sID = it->first;
676  if (sID == string_type(szExpr + m_iPos, szExpr + m_iPos + sID.length()))
677  {
678  a_Tok.Set(it->second, strTok);
679 
680  // operator was found
681  if (m_iSynFlags & noOPT)
682  {
683  // An operator was found but is not expected to occur at
684  // this position of the formula, maybe it is an infix
685  // operator, not a binary operator. Both operator types
686  // can share characters in their identifiers.
687  if (IsInfixOpTok(a_Tok))
688  return true;
689  else
690  {
691  // nope, no infix operator
692  return false;
693  //Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString());
694  }
695 
696  }
697 
698  m_iPos += (int)sID.length();
699  m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noEND | noASSIGN;
700  return true;
701  }
702  }
703 
704  return false;
705  }
706 
707 
708  /** \brief Check if a string position contains a unary post value operator. */
709  bool ParserTokenReader::IsPostOpTok(token_type& a_Tok)
710  {
711  // <ibg 20110629> Do not check for postfix operators if they are not allowed at
712  // the current expression index.
713  //
714  // This will fix the bug reported here:
715  //
716  // http://sourceforge.net/tracker/index.php?func=detail&aid=3343891&group_id=137191&atid=737979
717  //
718  if (m_iSynFlags & noPOSTOP)
719  return false;
720  // </ibg>
721 
722  // Tricky problem with equations like "3m+5":
723  // m is a postfix operator, + is a valid sign for postfix operators and
724  // for binary operators parser detects "m+" as operator string and
725  // finds no matching postfix operator.
726  //
727  // This is a special case so this routine slightly differs from the other
728  // token readers.
729 
730  // Test if there could be a postfix operator
731  string_type sTok;
732  auto iEnd = ExtractToken(m_pParser->ValidOprtChars(), sTok, (std::size_t)m_iPos);
733  if (iEnd == m_iPos)
734  return false;
735 
736  // iterate over all postfix operator strings
737  funmap_type::const_reverse_iterator it = m_pPostOprtDef->rbegin();
738  for (; it != m_pPostOprtDef->rend(); ++it)
739  {
740  if (sTok.find(it->first) != 0)
741  continue;
742 
743  a_Tok.Set(it->second, sTok);
744  m_iPos += (int)it->first.length();
745 
746  m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noSTR | noASSIGN;
747  return true;
748  }
749 
750  return false;
751  }
752 
753 
754  /** \brief Check whether the token at a given position is a value token.
755 
756  Value tokens are either values or constants.
757 
758  \param a_Tok [out] If a value token is found it will be placed here.
759  \return true if a value token has been found.
760  */
761  bool ParserTokenReader::IsValTok(token_type& a_Tok)
762  {
763  MUP_ASSERT(m_pConstDef != nullptr);
764  MUP_ASSERT(m_pParser != nullptr);
765 
766  string_type strTok;
767  value_type fVal(0);
768 
769  // 2.) Check for user defined constant
770  // Read everything that could be a constant name
771  auto iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos);
772  if (iEnd != m_iPos)
773  {
774  valmap_type::const_iterator item = m_pConstDef->find(strTok);
775  if (item != m_pConstDef->end())
776  {
777  m_iPos = iEnd;
778  a_Tok.SetVal(item->second, strTok);
779 
780  if (m_iSynFlags & noVAL)
781  Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok);
782 
783  m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN;
784  return true;
785  }
786  }
787 
788  // 3.call the value recognition functions provided by the user
789  // Call user defined value recognition functions
790  std::list<identfun_type>::const_iterator item = m_vIdentFun.begin();
791  for (item = m_vIdentFun.begin(); item != m_vIdentFun.end(); ++item)
792  {
793  int iStart = m_iPos;
794  if ((*item)(m_strFormula.c_str() + m_iPos, &m_iPos, &fVal) == 1)
795  {
796  // 2013-11-27 Issue 2: https://code.google.com/p/muparser/issues/detail?id=2
797  strTok.assign(m_strFormula.c_str(), iStart, (std::size_t)m_iPos - iStart);
798 
799  if (m_iSynFlags & noVAL)
800  Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok);
801 
802  a_Tok.SetVal(fVal, strTok);
803  m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN;
804  return true;
805  }
806  }
807 
808  return false;
809  }
810 
811 
812  /** \brief Check wheter a token at a given position is a variable token.
813  \param a_Tok [out] If a variable token has been found it will be placed here.
814  \return true if a variable token has been found.
815  */
816  bool ParserTokenReader::IsVarTok(token_type& a_Tok)
817  {
818  if (m_pVarDef->empty())
819  return false;
820 
821  string_type strTok;
822  auto iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos);
823  if (iEnd == m_iPos)
824  return false;
825 
826  varmap_type::const_iterator item = m_pVarDef->find(strTok);
827  if (item == m_pVarDef->end())
828  return false;
829 
830  if (m_iSynFlags & noVAR)
831  Error(ecUNEXPECTED_VAR, m_iPos, strTok);
832 
833  m_pParser->OnDetectVar(&m_strFormula, m_iPos, iEnd);
834 
835  m_iPos = iEnd;
836  a_Tok.SetVar(item->second, strTok);
837  m_UsedVar[item->first] = item->second; // Add variable to used-var-list
838 
839  m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR;
840 
841  // Zur Info hier die SynFlags von IsVal():
842  // m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN;
843  return true;
844  }
845 
846 
847  bool ParserTokenReader::IsStrVarTok(token_type& a_Tok)
848  {
849  if (!m_pStrVarDef || m_pStrVarDef->empty())
850  return false;
851 
852  string_type strTok;
853  auto iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos);
854  if (iEnd == m_iPos)
855  return false;
856 
857  strmap_type::const_iterator item = m_pStrVarDef->find(strTok);
858  if (item == m_pStrVarDef->end())
859  return false;
860 
861  if (m_iSynFlags & noSTR)
862  Error(ecUNEXPECTED_VAR, m_iPos, strTok);
863 
864  m_iPos = iEnd;
865  if (!m_pParser->m_vStringVarBuf.size())
866  Error(ecINTERNAL_ERROR);
867 
868  a_Tok.SetString(m_pParser->m_vStringVarBuf[item->second], m_pParser->m_vStringVarBuf.size());
869 
870  m_iSynFlags = noANY ^ (noBC | noOPT | noEND | noARG_SEP);
871  return true;
872  }
873 
874 
875 
876  /** \brief Check wheter a token at a given position is an undefined variable.
877 
878  \param a_Tok [out] If a variable tom_pParser->m_vStringBufken has been found it will be placed here.
879  \return true if a variable token has been found.
880  \throw nothrow
881  */
882  bool ParserTokenReader::IsUndefVarTok(token_type& a_Tok)
883  {
884  string_type strTok;
885  auto iEnd(ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos));
886  if (iEnd == m_iPos)
887  return false;
888 
889  if (m_iSynFlags & noVAR)
890  {
891  // <ibg/> 20061021 added token string strTok instead of a_Tok.GetAsString() as the
892  // token identifier.
893  // related bug report:
894  // http://sourceforge.net/tracker/index.php?func=detail&aid=1578779&group_id=137191&atid=737979
895  Error(ecUNEXPECTED_VAR, m_iPos - (int)a_Tok.GetAsString().length(), strTok);
896  }
897 
898  // If a factory is available implicitely create new variables
899  if (m_pFactory)
900  {
901  value_type* fVar = m_pFactory(strTok.c_str(), m_pFactoryData);
902  a_Tok.SetVar(fVar, strTok);
903 
904  // Do not use m_pParser->DefineVar( strTok, fVar );
905  // in order to define the new variable, it will clear the
906  // m_UsedVar array which will kill previously defined variables
907  // from the list
908  // This is safe because the new variable can never override an existing one
909  // because they are checked first!
910  (*m_pVarDef)[strTok] = fVar;
911  m_UsedVar[strTok] = fVar; // Add variable to used-var-list
912  }
913  else
914  {
915  a_Tok.SetVar((value_type*)&m_fZero, strTok);
916  m_UsedVar[strTok] = 0; // Add variable to used-var-list
917  }
918 
919  m_iPos = iEnd;
920 
921  // Call the variable factory in order to let it define a new parser variable
922  m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noINFIXOP | noSTR;
923  return true;
924  }
925 
926 
927 
928  /** \brief Check wheter a token at a given position is a string.
929  \param a_Tok [out] If a variable token has been found it will be placed here.
930  \return true if a string token has been found.
931  \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsEOF, IsInfixOpTok, IsPostOpTok
932  \throw nothrow
933  */
934  bool ParserTokenReader::IsString(token_type& a_Tok)
935  {
936  if (m_strFormula[m_iPos] != '"')
937  return false;
938 
939  string_type strBuf(&m_strFormula[(std::size_t)m_iPos + 1]);
940  std::size_t iEnd(0), iSkip(0);
941 
942  // parser over escaped '\"' end replace them with '"'
943  for (iEnd = (int)strBuf.find(_T('\"')); iEnd != 0 && iEnd != string_type::npos; iEnd = (int)strBuf.find(_T('\"'), iEnd))
944  {
945  if (strBuf[iEnd - 1] != '\\') break;
946  strBuf.replace(iEnd - 1, 2, _T("\""));
947  iSkip++;
948  }
949 
950  if (iEnd == string_type::npos)
951  Error(ecUNTERMINATED_STRING, m_iPos, _T("\""));
952 
953  string_type strTok(strBuf.begin(), strBuf.begin() + iEnd);
954 
955  if (m_iSynFlags & noSTR)
956  Error(ecUNEXPECTED_STR, m_iPos, strTok);
957 
958  m_pParser->m_vStringBuf.push_back(strTok); // Store string in internal buffer
959  a_Tok.SetString(strTok, m_pParser->m_vStringBuf.size());
960 
961  m_iPos += (int)strTok.length() + 2 + (int)iSkip; // +2 for quotes; +iSkip for escape characters
962  m_iSynFlags = noANY ^ (noARG_SEP | noBC | noOPT | noEND);
963 
964  return true;
965  }
966 
967 
968  /** \brief Create an error containing the parse error position.
969 
970  This function will create an Parser Exception object containing the error text and its position.
971 
972  \param a_iErrc [in] The error code of type #EErrorCodes.
973  \param a_iPos [in] The position where the error was detected.
974  \param a_strTok [in] The token string representation associated with the error.
975  \throw ParserException always throws thats the only purpose of this function.
976  */
977  void ParserTokenReader::Error(EErrorCodes a_iErrc, int a_iPos, const string_type& a_sTok) const
978  {
979  m_pParser->Error(a_iErrc, a_iPos, a_sTok);
980  }
981 
982 
983  void ParserTokenReader::SetArgSep(char_type cArgSep)
984  {
985  m_cArgSep = cArgSep;
986  }
987 
988 
989  char_type ParserTokenReader::GetArgSep() const
990  {
991  return m_cArgSep;
992  }
993 } // namespace mu
994 
995 #if defined(_MSC_VER)
996  #pragma warning(pop)
997 #endif
Operator item: closing bracket.
Definition: muParserDef.h:155
void IgnoreUndefVar(bool bIgnore)
Set Flag that controls behaviour in case of undefined variables being found.
#define _T(x)
Activate this option in order to compile with OpenMP support.
Definition: muParserDef.h:69
value_type *(* facfun_type)(const char_type *, void *)
Callback used for variable creation factory functions.
Definition: muParserDef.h:507
An unexpected comma has been found. (Example: "1,23")
Definition: muParserDef.h:232
Token can't be identified.
Definition: muParserDef.h:230
std::map< string_type, value_type * > varmap_type
Type used for storing variables.
Definition: muParserDef.h:316
function argument separator
Definition: muParserDef.h:159
Operator item: y to the power of ...
Definition: muParserDef.h:150
Internal error of any kind.
Definition: muParserDef.h:279
unterminated string constant. (Example: "3*valueof("hello)")
Definition: muParserDef.h:242
Operator item: not equal.
Definition: muParserDef.h:142
For use in the ternary if-then-else operator.
Definition: muParserDef.h:156
const char_type * ValidInfixOprtChars() const
Virtual function that defines the characters allowed in infix operator definitions.
const char_type * ValidOprtChars() const
Virtual function that defines the characters allowed in operator definitions.
varmap_type & GetUsedVar()
Return a map containing the used variables only.
int GetPos() const
Return the current position of the token reader in the formula string.
Unexpected function found. (Example: "sin(8)cos(9)")
Definition: muParserDef.h:241
end of formula
Definition: muParserDef.h:177
ParserTokenReader(ParserBase *a_pParent)
Constructor.
bool HasBuiltInOprt() const
Query status of built in variables.
Code for a generic function item.
Definition: muParserDef.h:170
const char_type * ValidNameChars() const
Virtual function that defines the characters allowed in name identifiers.
An unexpected value token has been found.
Definition: muParserDef.h:234
This file contains the parser token reader definition.
For use in the ternary if-then-else operator.
Definition: muParserDef.h:157
An unexpected variable token has been found.
Definition: muParserDef.h:235
Operator item: subtract.
Definition: muParserDef.h:147
token_type ReadNextToken()
Read the next token from the string.
ECmdCode
Bytecode values.
Definition: muParserDef.h:135
This file contains the class definition of the muparser engine.
Operator item: multiply.
Definition: muParserDef.h:148
void ReInit()
Reset the token reader to the start of the formula.
#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
void SetFormula(const string_type &a_strFormula)
Initialize the token Reader.
Operator item: add.
Definition: muParserDef.h:146
ECmdCode GetCode() const
Return the token type.
Namespace for mathematical applications.
Definition: muParser.cpp:48
Unexpected end of formula. (Example: "2+sin(")
Definition: muParserDef.h:231
Operator item: less than.
Definition: muParserDef.h:144
int(* identfun_type)(const char_type *sExpr, int *nPos, value_type *fVal)
Callback used for functions that identify values in a string.
Definition: muParserDef.h:504
Operator item: greater than.
Definition: muParserDef.h:145
const char_type ** GetOprtDef() const
Get the default symbols used for the built in operators.
string_type::value_type char_type
The character type used by the parser.
Definition: muParserDef.h:308
Token reader for the ParserBase class.
Operator item: equals.
Definition: muParserDef.h:143
ParserTokenReader * Clone(ParserBase *a_pParent) const
Create instance of a ParserTokenReader identical with this and return its pointer.
Operator item: Assignment operator.
Definition: muParserDef.h:153
Unexpected binary operator found.
Definition: muParserDef.h:229
MUP_STRING_TYPE string_type
The stringtype used by the parser.
Definition: muParserDef.h:302
Operator item: less or equal.
Definition: muParserDef.h:140
Unexpected Parenthesis, opening or closing.
Definition: muParserDef.h:236
Operator item: greater or equal.
Definition: muParserDef.h:141
The expression or identifier contains invalid non printable characters.
Definition: muParserDef.h:276
void Error(EErrorCodes a_iErrc, int a_iPos=static_cast< int >(mu::string_type::npos), const string_type &a_strTok=string_type()) const
Create an error containing the parse error position.
EErrorCodes
Error codes.
Definition: muParserDef.h:226
Missing parens. (Example: "3*sin(3")
Definition: muParserDef.h:240
const string_type & GetExpr() const
Return a reference to the formula.
A string has been found at an inapropriate position.
Definition: muParserDef.h:237
Mathematical expressions parser (base parser engine).
Definition: muParserBase.h:68
Operator item: opening bracket.
Definition: muParserDef.h:154