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 - 2020 Ingo Berg
9 
10  Redistribution and use in source and binary forms, with or without modification, are permitted
11  provided that the following conditions are met:
12 
13  * Redistributions of source code must retain the above copyright notice, this list of
14  conditions and the following disclaimer.
15  * Redistributions in binary form must reproduce the above copyright notice, this list of
16  conditions and the following disclaimer in the documentation and/or other materials provided
17  with the distribution.
18 
19  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
20  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 #include <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* szFormula = m_strFormula.c_str();
268  token_type tok;
269 
270  // Ignore all non printable characters when reading the expression
271  while (szFormula[m_iPos] > 0 && szFormula[m_iPos] <= 0x20)
272  ++m_iPos;
273 
274  // Check for end of formula
275  if (IsEOF(tok))
276  return SaveBeforeReturn(tok);
277 
278  // Check for user defined binary operator
279  if (IsOprt(tok))
280  return SaveBeforeReturn(tok);
281 
282  // Check for function token
283  if (IsFunTok(tok))
284  return SaveBeforeReturn(tok);
285 
286  // Check built in operators / tokens
287  if (IsBuiltIn(tok))
288  return SaveBeforeReturn(tok);
289 
290  // Check for function argument separators
291  if (IsArgSep(tok))
292  return SaveBeforeReturn(tok);
293 
294  // Check for values / constant tokens
295  if (IsValTok(tok))
296  return SaveBeforeReturn(tok);
297 
298  // Check for variable tokens
299  if (IsVarTok(tok))
300  return SaveBeforeReturn(tok);
301 
302  // Check for string variables
303  if (IsStrVarTok(tok))
304  return SaveBeforeReturn(tok);
305 
306  // Check for String tokens
307  if (IsString(tok))
308  return SaveBeforeReturn(tok);
309 
310  // Check for unary operators
311  if (IsInfixOpTok(tok))
312  return SaveBeforeReturn(tok);
313 
314  // Check for unary operators
315  if (IsPostOpTok(tok))
316  return SaveBeforeReturn(tok);
317 
318  // Check String for undefined variable token. Done only if a
319  // flag is set indicating to ignore undefined variables.
320  // This is a way to conditionally avoid an error if
321  // undefined variables occur.
322  // (The GetUsedVar function must suppress the error for
323  // undefined variables in order to collect all variable
324  // names including the undefined ones.)
325  if ((m_bIgnoreUndefVar || m_pFactory) && IsUndefVarTok(tok))
326  return SaveBeforeReturn(tok);
327 
328  // Check for unknown token
329  //
330  // !!! From this point on there is no exit without an exception possible...
331  //
332  string_type strTok;
333  auto iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos);
334  if (iEnd != m_iPos)
335  Error(ecUNASSIGNABLE_TOKEN, m_iPos, strTok);
336 
337  Error(ecUNASSIGNABLE_TOKEN, m_iPos, m_strFormula.substr(m_iPos));
338  return token_type(); // never reached
339  }
340 
341 
342  void ParserTokenReader::SetParent(ParserBase* a_pParent)
343  {
344  m_pParser = a_pParent;
345  m_pFunDef = &a_pParent->m_FunDef;
346  m_pOprtDef = &a_pParent->m_OprtDef;
347  m_pInfixOprtDef = &a_pParent->m_InfixOprtDef;
348  m_pPostOprtDef = &a_pParent->m_PostOprtDef;
349  m_pVarDef = &a_pParent->m_VarDef;
350  m_pStrVarDef = &a_pParent->m_StrVarDef;
351  m_pConstDef = &a_pParent->m_ConstDef;
352  }
353 
354 
355  /** \brief Extract all characters that belong to a certain charset.
356 
357  \param a_szCharSet [in] Const char array of the characters allowed in the token.
358  \param a_strTok [out] The string that consists entirely of characters listed in a_szCharSet.
359  \param a_iPos [in] Position in the string from where to start reading.
360  \return The Position of the first character not listed in a_szCharSet.
361  \throw nothrow
362  */
363  int ParserTokenReader::ExtractToken(const char_type* a_szCharSet, string_type& a_sTok, std::size_t a_iPos) const
364  {
365  auto iEnd = m_strFormula.find_first_not_of(a_szCharSet, a_iPos);
366 
367  if (iEnd == string_type::npos)
368  iEnd = m_strFormula.length();
369 
370  // Assign token string if there was something found
371  if (a_iPos != iEnd)
372  a_sTok = string_type(m_strFormula.begin() + a_iPos, m_strFormula.begin() + iEnd);
373 
374  return iEnd;
375  }
376 
377 
378  /** \brief Check Expression for the presence of a binary operator token.
379 
380  Userdefined binary operator "++" gives inconsistent parsing result for
381  the equations "a++b" and "a ++ b" if alphabetic characters are allowed
382  in operator tokens. To avoid this this function checks specifically
383  for operator tokens.
384  */
385  int ParserTokenReader::ExtractOperatorToken(string_type& a_sTok, std::size_t a_iPos) const
386  {
387  // Changed as per Issue 6: https://code.google.com/p/muparser/issues/detail?id=6
388  auto iEnd = m_strFormula.find_first_not_of(m_pParser->ValidOprtChars(), a_iPos);
389  if (iEnd == string_type::npos)
390  iEnd = m_strFormula.length();
391 
392  // Assign token string if there was something found
393  if (a_iPos != iEnd)
394  {
395  a_sTok = string_type(m_strFormula.begin() + a_iPos, m_strFormula.begin() + iEnd);
396  return iEnd;
397  }
398  else
399  {
400  // There is still the chance of having to deal with an operator consisting exclusively
401  // of alphabetic characters.
402  return ExtractToken("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", a_sTok, (std::size_t)a_iPos);
403  }
404  }
405 
406 
407  /** \brief Check if a built in operator or other token can be found
408  \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token.
409  \return true if an operator token has been found.
410  */
411  bool ParserTokenReader::IsBuiltIn(token_type& a_Tok)
412  {
413  const char_type** const pOprtDef = m_pParser->GetOprtDef(),
414  * const szFormula = m_strFormula.c_str();
415 
416  // Compare token with function and operator strings
417  // check string for operator/function
418  for (int i = 0; pOprtDef[i]; i++)
419  {
420  std::size_t len(std::char_traits<char_type>::length(pOprtDef[i]));
421  if (string_type(pOprtDef[i]) == string_type(szFormula + m_iPos, szFormula + m_iPos + len))
422  {
423  switch (i)
424  {
425  case cmLAND:
426  case cmLOR:
427  case cmLT:
428  case cmGT:
429  case cmLE:
430  case cmGE:
431  case cmNEQ:
432  case cmEQ:
433  case cmADD:
434  case cmSUB:
435  case cmMUL:
436  case cmDIV:
437  case cmPOW:
438  case cmASSIGN:
439  //if (len!=sTok.length())
440  // continue;
441 
442  // The assignment operator need special treatment
443  if (i == cmASSIGN && m_iSynFlags & noASSIGN)
444  Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]);
445 
446  if (!m_pParser->HasBuiltInOprt()) continue;
447  if (m_iSynFlags & noOPT)
448  {
449  // Maybe its an infix operator not an operator
450  // Both operator types can share characters in
451  // their identifiers
452  if (IsInfixOpTok(a_Tok))
453  return true;
454 
455  Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]);
456  }
457 
458  m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE | noEND;
459  break;
460 
461  case cmBO:
462  if (m_iSynFlags & noBO)
463  Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);
464 
465  if (m_lastTok.GetCode() == cmFUNC)
466  m_iSynFlags = noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE;
467  else
468  m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE;
469 
470  m_bracketStack.push(cmBO);
471  break;
472 
473  case cmBC:
474  if (m_iSynFlags & noBC)
475  Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);
476 
477  m_iSynFlags = noBO | noVAR | noVAL | noFUN | noINFIXOP | noSTR | noASSIGN;
478 
479  if (!m_bracketStack.empty())
480  m_bracketStack.pop();
481  else
482  Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);
483  break;
484 
485  case cmELSE:
486  if (m_iSynFlags & noELSE)
487  Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]);
488 
489  m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE | noSTR;
490  break;
491 
492  case cmIF:
493  if (m_iSynFlags & noIF)
494  Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]);
495 
496  m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE | noSTR;
497  break;
498 
499  default: // The operator is listed in c_DefaultOprt, but not here. This is a bad thing...
500  Error(ecINTERNAL_ERROR);
501  } // switch operator id
502 
503  m_iPos += (int)len;
504  a_Tok.Set((ECmdCode)i, pOprtDef[i]);
505  return true;
506  } // if operator string found
507  } // end of for all operator strings
508 
509  return false;
510  }
511 
512 
513  bool ParserTokenReader::IsArgSep(token_type& a_Tok)
514  {
515  const char_type* szFormula = m_strFormula.c_str();
516 
517  if (szFormula[m_iPos] == m_cArgSep)
518  {
519  // copy the separator into null terminated string
520  char_type szSep[2];
521  szSep[0] = m_cArgSep;
522  szSep[1] = 0;
523 
524  if (m_iSynFlags & noARG_SEP)
525  Error(ecUNEXPECTED_ARG_SEP, m_iPos, szSep);
526 
527  m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN;
528  m_iPos++;
529  a_Tok.Set(cmARG_SEP, szSep);
530  return true;
531  }
532 
533  return false;
534  }
535 
536 
537  /** \brief Check for End of Formula.
538 
539  \return true if an end of formula is found false otherwise.
540  \param a_Tok [out] If an eof is found the corresponding token will be stored there.
541  \throw nothrow
542  \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsString, IsInfixOpTok, IsPostOpTok
543  */
544  bool ParserTokenReader::IsEOF(token_type& a_Tok)
545  {
546  const char_type* szFormula = m_strFormula.c_str();
547 
548  // check for EOF
549  if (!szFormula[m_iPos] /*|| szFormula[m_iPos] == '\n'*/)
550  {
551  if (m_iSynFlags & noEND)
552  Error(ecUNEXPECTED_EOF, m_iPos);
553 
554  if (!m_bracketStack.empty())
555  Error(ecMISSING_PARENS, m_iPos, _T(")"));
556 
557  m_iSynFlags = 0;
558  a_Tok.Set(cmEND);
559  return true;
560  }
561 
562  return false;
563  }
564 
565 
566  /** \brief Check if a string position contains a unary infix operator.
567  \return true if a function token has been found false otherwise.
568  */
569  bool ParserTokenReader::IsInfixOpTok(token_type& a_Tok)
570  {
571  string_type sTok;
572  auto iEnd = ExtractToken(m_pParser->ValidInfixOprtChars(), sTok, (std::size_t)m_iPos);
573  if (iEnd == m_iPos)
574  return false;
575 
576  // iterate over all postfix operator strings
577  funmap_type::const_reverse_iterator it = m_pInfixOprtDef->rbegin();
578  for (; it != m_pInfixOprtDef->rend(); ++it)
579  {
580  if (sTok.find(it->first) != 0)
581  continue;
582 
583  a_Tok.Set(it->second, it->first);
584  m_iPos += (int)it->first.length();
585 
586  if (m_iSynFlags & noINFIXOP)
587  Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString());
588 
589  m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN | noARG_SEP;
590  return true;
591  }
592 
593  return false;
594 
595  /*
596  a_Tok.Set(item->second, sTok);
597  m_iPos = (int)iEnd;
598 
599  if (m_iSynFlags & noINFIXOP)
600  Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString());
601 
602  m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN;
603  return true;
604  */
605  }
606 
607 
608  /** \brief Check whether the token at a given position is a function token.
609  \param a_Tok [out] If a value token is found it will be placed here.
610  \throw ParserException if Syntaxflags do not allow a function at a_iPos
611  \return true if a function token has been found false otherwise.
612  \pre [assert] m_pParser!=0
613  */
614  bool ParserTokenReader::IsFunTok(token_type& a_Tok)
615  {
616  string_type strTok;
617  auto iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos);
618  if (iEnd == m_iPos)
619  return false;
620 
621  funmap_type::const_iterator item = m_pFunDef->find(strTok);
622  if (item == m_pFunDef->end())
623  return false;
624 
625  // Check if the next sign is an opening bracket
626  const char_type* szFormula = m_strFormula.c_str();
627  if (szFormula[iEnd] != '(')
628  return false;
629 
630  a_Tok.Set(item->second, strTok);
631 
632  m_iPos = (int)iEnd;
633  if (m_iSynFlags & noFUN)
634  Error(ecUNEXPECTED_FUN, m_iPos - (int)a_Tok.GetAsString().length(), a_Tok.GetAsString());
635 
636  m_iSynFlags = noANY ^ noBO;
637  return true;
638  }
639 
640 
641  /** \brief Check if a string position contains a binary operator.
642  \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token.
643  \return true if an operator token has been found.
644  */
645  bool ParserTokenReader::IsOprt(token_type& a_Tok)
646  {
647  const char_type* const szExpr = m_strFormula.c_str();
648  string_type strTok;
649 
650  auto iEnd = ExtractOperatorToken(strTok, (std::size_t)m_iPos);
651  if (iEnd == m_iPos)
652  return false;
653 
654  // Check if the operator is a built in operator, if so ignore it here
655  const char_type** const pOprtDef = m_pParser->GetOprtDef();
656  for (int i = 0; m_pParser->HasBuiltInOprt() && pOprtDef[i]; ++i)
657  {
658  if (string_type(pOprtDef[i]) == strTok)
659  return false;
660  }
661 
662  // Note:
663  // All tokens in oprt_bin_maptype are have been sorted by their length
664  // Long operators must come first! Otherwise short names (like: "add") that
665  // are part of long token names (like: "add123") will be found instead
666  // of the long ones.
667  // Length sorting is done with ascending length so we use a reverse iterator here.
668  funmap_type::const_reverse_iterator it = m_pOprtDef->rbegin();
669  for (; it != m_pOprtDef->rend(); ++it)
670  {
671  const string_type& sID = it->first;
672  if (sID == string_type(szExpr + m_iPos, szExpr + m_iPos + sID.length()))
673  {
674  a_Tok.Set(it->second, strTok);
675 
676  // operator was found
677  if (m_iSynFlags & noOPT)
678  {
679  // An operator was found but is not expected to occur at
680  // this position of the formula, maybe it is an infix
681  // operator, not a binary operator. Both operator types
682  // can share characters in their identifiers.
683  if (IsInfixOpTok(a_Tok))
684  return true;
685  else
686  {
687  // nope, no infix operator
688  return false;
689  //Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString());
690  }
691 
692  }
693 
694  m_iPos += (int)sID.length();
695  m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noEND | noASSIGN;
696  return true;
697  }
698  }
699 
700  return false;
701  }
702 
703 
704  /** \brief Check if a string position contains a unary post value operator. */
705  bool ParserTokenReader::IsPostOpTok(token_type& a_Tok)
706  {
707  // <ibg 20110629> Do not check for postfix operators if they are not allowed at
708  // the current expression index.
709  //
710  // This will fix the bug reported here:
711  //
712  // http://sourceforge.net/tracker/index.php?func=detail&aid=3343891&group_id=137191&atid=737979
713  //
714  if (m_iSynFlags & noPOSTOP)
715  return false;
716  // </ibg>
717 
718  // Tricky problem with equations like "3m+5":
719  // m is a postfix operator, + is a valid sign for postfix operators and
720  // for binary operators parser detects "m+" as operator string and
721  // finds no matching postfix operator.
722  //
723  // This is a special case so this routine slightly differs from the other
724  // token readers.
725 
726  // Test if there could be a postfix operator
727  string_type sTok;
728  auto iEnd = ExtractToken(m_pParser->ValidOprtChars(), sTok, (std::size_t)m_iPos);
729  if (iEnd == m_iPos)
730  return false;
731 
732  // iterate over all postfix operator strings
733  funmap_type::const_reverse_iterator it = m_pPostOprtDef->rbegin();
734  for (; it != m_pPostOprtDef->rend(); ++it)
735  {
736  if (sTok.find(it->first) != 0)
737  continue;
738 
739  a_Tok.Set(it->second, sTok);
740  m_iPos += (int)it->first.length();
741 
742  m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noSTR | noASSIGN;
743  return true;
744  }
745 
746  return false;
747  }
748 
749 
750  /** \brief Check whether the token at a given position is a value token.
751 
752  Value tokens are either values or constants.
753 
754  \param a_Tok [out] If a value token is found it will be placed here.
755  \return true if a value token has been found.
756  */
757  bool ParserTokenReader::IsValTok(token_type& a_Tok)
758  {
759  MUP_ASSERT(m_pConstDef != nullptr);
760  MUP_ASSERT(m_pParser != nullptr);
761 
762  string_type strTok;
763  value_type fVal(0);
764 
765  // 2.) Check for user defined constant
766  // Read everything that could be a constant name
767  auto iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos);
768  if (iEnd != m_iPos)
769  {
770  valmap_type::const_iterator item = m_pConstDef->find(strTok);
771  if (item != m_pConstDef->end())
772  {
773  m_iPos = iEnd;
774  a_Tok.SetVal(item->second, strTok);
775 
776  if (m_iSynFlags & noVAL)
777  Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok);
778 
779  m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN;
780  return true;
781  }
782  }
783 
784  // 3.call the value recognition functions provided by the user
785  // Call user defined value recognition functions
786  std::list<identfun_type>::const_iterator item = m_vIdentFun.begin();
787  for (item = m_vIdentFun.begin(); item != m_vIdentFun.end(); ++item)
788  {
789  int iStart = m_iPos;
790  if ((*item)(m_strFormula.c_str() + m_iPos, &m_iPos, &fVal) == 1)
791  {
792  // 2013-11-27 Issue 2: https://code.google.com/p/muparser/issues/detail?id=2
793  strTok.assign(m_strFormula.c_str(), iStart, (std::size_t)m_iPos - iStart);
794 
795  if (m_iSynFlags & noVAL)
796  Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok);
797 
798  a_Tok.SetVal(fVal, strTok);
799  m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN;
800  return true;
801  }
802  }
803 
804  return false;
805  }
806 
807 
808  /** \brief Check wheter a token at a given position is a variable token.
809  \param a_Tok [out] If a variable token has been found it will be placed here.
810  \return true if a variable token has been found.
811  */
812  bool ParserTokenReader::IsVarTok(token_type& a_Tok)
813  {
814  if (m_pVarDef->empty())
815  return false;
816 
817  string_type strTok;
818  auto iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos);
819  if (iEnd == m_iPos)
820  return false;
821 
822  varmap_type::const_iterator item = m_pVarDef->find(strTok);
823  if (item == m_pVarDef->end())
824  return false;
825 
826  if (m_iSynFlags & noVAR)
827  Error(ecUNEXPECTED_VAR, m_iPos, strTok);
828 
829  m_pParser->OnDetectVar(&m_strFormula, m_iPos, iEnd);
830 
831  m_iPos = iEnd;
832  a_Tok.SetVar(item->second, strTok);
833  m_UsedVar[item->first] = item->second; // Add variable to used-var-list
834 
835  m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR;
836 
837  // Zur Info hier die SynFlags von IsVal():
838  // m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN;
839  return true;
840  }
841 
842 
843  bool ParserTokenReader::IsStrVarTok(token_type& a_Tok)
844  {
845  if (!m_pStrVarDef || m_pStrVarDef->empty())
846  return false;
847 
848  string_type strTok;
849  auto iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos);
850  if (iEnd == m_iPos)
851  return false;
852 
853  strmap_type::const_iterator item = m_pStrVarDef->find(strTok);
854  if (item == m_pStrVarDef->end())
855  return false;
856 
857  if (m_iSynFlags & noSTR)
858  Error(ecUNEXPECTED_VAR, m_iPos, strTok);
859 
860  m_iPos = iEnd;
861  if (!m_pParser->m_vStringVarBuf.size())
862  Error(ecINTERNAL_ERROR);
863 
864  a_Tok.SetString(m_pParser->m_vStringVarBuf[item->second], m_pParser->m_vStringVarBuf.size());
865 
866  m_iSynFlags = noANY ^ (noBC | noOPT | noEND | noARG_SEP);
867  return true;
868  }
869 
870 
871 
872  /** \brief Check wheter a token at a given position is an undefined variable.
873 
874  \param a_Tok [out] If a variable tom_pParser->m_vStringBufken has been found it will be placed here.
875  \return true if a variable token has been found.
876  \throw nothrow
877  */
878  bool ParserTokenReader::IsUndefVarTok(token_type& a_Tok)
879  {
880  string_type strTok;
881  auto iEnd(ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos));
882  if (iEnd == m_iPos)
883  return false;
884 
885  if (m_iSynFlags & noVAR)
886  {
887  // <ibg/> 20061021 added token string strTok instead of a_Tok.GetAsString() as the
888  // token identifier.
889  // related bug report:
890  // http://sourceforge.net/tracker/index.php?func=detail&aid=1578779&group_id=137191&atid=737979
891  Error(ecUNEXPECTED_VAR, m_iPos - (int)a_Tok.GetAsString().length(), strTok);
892  }
893 
894  // If a factory is available implicitely create new variables
895  if (m_pFactory)
896  {
897  value_type* fVar = m_pFactory(strTok.c_str(), m_pFactoryData);
898  a_Tok.SetVar(fVar, strTok);
899 
900  // Do not use m_pParser->DefineVar( strTok, fVar );
901  // in order to define the new variable, it will clear the
902  // m_UsedVar array which will kill previously defined variables
903  // from the list
904  // This is safe because the new variable can never override an existing one
905  // because they are checked first!
906  (*m_pVarDef)[strTok] = fVar;
907  m_UsedVar[strTok] = fVar; // Add variable to used-var-list
908  }
909  else
910  {
911  a_Tok.SetVar((value_type*)&m_fZero, strTok);
912  m_UsedVar[strTok] = 0; // Add variable to used-var-list
913  }
914 
915  m_iPos = iEnd;
916 
917  // Call the variable factory in order to let it define a new parser variable
918  m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noINFIXOP | noSTR;
919  return true;
920  }
921 
922 
923 
924  /** \brief Check wheter a token at a given position is a string.
925  \param a_Tok [out] If a variable token has been found it will be placed here.
926  \return true if a string token has been found.
927  \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsEOF, IsInfixOpTok, IsPostOpTok
928  \throw nothrow
929  */
930  bool ParserTokenReader::IsString(token_type& a_Tok)
931  {
932  if (m_strFormula[m_iPos] != '"')
933  return false;
934 
935  string_type strBuf(&m_strFormula[(std::size_t)m_iPos + 1]);
936  std::size_t iEnd(0), iSkip(0);
937 
938  // parser over escaped '\"' end replace them with '"'
939  for (iEnd = (int)strBuf.find(_T('\"')); iEnd != 0 && iEnd != string_type::npos; iEnd = (int)strBuf.find(_T('\"'), iEnd))
940  {
941  if (strBuf[iEnd - 1] != '\\') break;
942  strBuf.replace(iEnd - 1, 2, _T("\""));
943  iSkip++;
944  }
945 
946  if (iEnd == string_type::npos)
947  Error(ecUNTERMINATED_STRING, m_iPos, _T("\""));
948 
949  string_type strTok(strBuf.begin(), strBuf.begin() + iEnd);
950 
951  if (m_iSynFlags & noSTR)
952  Error(ecUNEXPECTED_STR, m_iPos, strTok);
953 
954  m_pParser->m_vStringBuf.push_back(strTok); // Store string in internal buffer
955  a_Tok.SetString(strTok, m_pParser->m_vStringBuf.size());
956 
957  m_iPos += (int)strTok.length() + 2 + (int)iSkip; // +2 for quotes; +iSkip for escape characters
958  m_iSynFlags = noANY ^ (noARG_SEP | noBC | noOPT | noEND);
959 
960  return true;
961  }
962 
963 
964  /** \brief Create an error containing the parse error position.
965 
966  This function will create an Parser Exception object containing the error text and its position.
967 
968  \param a_iErrc [in] The error code of type #EErrorCodes.
969  \param a_iPos [in] The position where the error was detected.
970  \param a_strTok [in] The token string representation associated with the error.
971  \throw ParserException always throws thats the only purpose of this function.
972  */
973  void ParserTokenReader::Error(EErrorCodes a_iErrc, int a_iPos, const string_type& a_sTok) const
974  {
975  m_pParser->Error(a_iErrc, a_iPos, a_sTok);
976  }
977 
978 
979  void ParserTokenReader::SetArgSep(char_type cArgSep)
980  {
981  m_cArgSep = cArgSep;
982  }
983 
984 
985  char_type ParserTokenReader::GetArgSep() const
986  {
987  return m_cArgSep;
988  }
989 } // namespace mu
990 
991 #if defined(_MSC_VER)
992  #pragma warning(pop)
993 #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:415
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:314
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.
void Error(EErrorCodes a_iErrc, int a_iPos=(int) mu::string_type::npos, const string_type &a_strTok=string_type()) const
Create an error containing the parse error position.
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:294
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:46
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:412
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:306
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:300
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
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:63
Operator item: opening bracket.
Definition: muParserDef.h:154