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