Build internal muparser more simply
[alexxy/gromacs.git] / src / external / muparser / src / muParserTokenReader.cpp
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         */
120         ParserTokenReader::ParserTokenReader(ParserBase* a_pParent)
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         */
155         ParserTokenReader* ParserTokenReader::Clone(ParserBase* a_pParent) const
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         */
194         int ParserTokenReader::GetPos() const
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         */
205         const string_type& ParserTokenReader::GetExpr() const
206         {
207                 return m_strFormula;
208         }
209
210
211         /** \brief Return a map containing the used variables only. */
212         varmap_type& ParserTokenReader::GetUsedVar()
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         */
238         void ParserTokenReader::IgnoreUndefVar(bool bIgnore)
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         */
252         void ParserTokenReader::ReInit()
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. */
263         ParserTokenReader::token_type ParserTokenReader::ReadNextToken()
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 int(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 int(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