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