3 _____ __ _____________ _______ ______ ___________
4 / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \
5 | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/
6 |__|_| /____/| __(____ /__| /____ >\___ >__|
8 Copyright (C) 2004 - 2020 Ingo Berg
10 Redistribution and use in source and binary forms, with or without modification, are permitted
11 provided that the following conditions are met:
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.
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.
35 #include "muParserTokenReader.h"
36 #include "muParserBase.h"
40 #pragma warning(disable : 26812)
44 \brief This file contains the parser token reader implementation.
51 // Forward declaration
54 /** \brief Copy constructor.
59 ParserTokenReader::ParserTokenReader(const ParserTokenReader& a_Reader)
65 /** \brief Assignment operator.
67 Self assignment will be suppressed otherwise #Assign is called.
69 \param a_Reader Object to copy to this token reader.
72 ParserTokenReader& ParserTokenReader::operator=(const ParserTokenReader& a_Reader)
74 if (&a_Reader != this)
81 /** \brief Assign state of a token reader to this token reader.
83 \param a_Reader Object from which the state should be copied.
86 void ParserTokenReader::Assign(const ParserTokenReader& a_Reader)
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;
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;
112 /** \brief Constructor.
114 Create a Token reader and bind it to a parser object.
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.
120 ParserTokenReader::ParserTokenReader(ParserBase* a_pParent)
121 :m_pParser(a_pParent)
125 , m_bIgnoreUndefVar(false)
127 , m_pPostOprtDef(nullptr)
128 , m_pInfixOprtDef(nullptr)
129 , m_pOprtDef(nullptr)
130 , m_pConstDef(nullptr)
131 , m_pStrVarDef(nullptr)
133 , m_pFactory(nullptr)
134 , m_pFactoryData(nullptr)
142 MUP_ASSERT(m_pParser != nullptr);
143 SetParent(m_pParser);
147 /** \brief Create instance of a ParserTokenReader identical with this
148 and return its pointer.
150 This is a factory method the calling function must take care of the object destruction.
152 \return A new ParserTokenReader object.
155 ParserTokenReader* ParserTokenReader::Clone(ParserBase* a_pParent) const
157 std::unique_ptr<ParserTokenReader> ptr(new ParserTokenReader(*this));
158 ptr->SetParent(a_pParent);
159 return ptr.release();
163 ParserTokenReader::token_type& ParserTokenReader::SaveBeforeReturn(const token_type& tok)
170 void ParserTokenReader::AddValIdent(identfun_type a_pCallback)
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.
177 // http://sourceforge.net/projects/muparser/forums/forum/462843/topic/4824956
178 m_vIdentFun.push_front(a_pCallback);
182 void ParserTokenReader::SetVarCreator(facfun_type a_pFactory, void* pUserData)
184 m_pFactory = a_pFactory;
185 m_pFactoryData = pUserData;
189 /** \brief Return the current position of the token reader in the formula string.
194 int ParserTokenReader::GetPos() const
200 /** \brief Return a reference to the formula.
202 \return #m_strFormula
205 const string_type& ParserTokenReader::GetExpr() const
211 /** \brief Return a map containing the used variables only. */
212 varmap_type& ParserTokenReader::GetUsedVar()
218 /** \brief Initialize the token Reader.
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
223 void ParserTokenReader::SetFormula(const string_type& a_strFormula)
225 m_strFormula = a_strFormula;
230 /** \brief Set Flag that controls behaviour in case of undefined variables being found.
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.
238 void ParserTokenReader::IgnoreUndefVar(bool bIgnore)
240 m_bIgnoreUndefVar = bIgnore;
244 /** \brief Reset the token reader to the start of the formula.
246 The syntax flags will be reset to a value appropriate for the
248 \post #m_iPos==0, #m_iSynFlags = noOPT | noBC | noPOSTOP | noSTR
252 void ParserTokenReader::ReInit()
255 m_iSynFlags = sfSTART_OF_LINE;
256 m_bracketStack = std::stack<int>();
258 m_lastTok = token_type();
262 /** \brief Read the next token from the string. */
263 ParserTokenReader::token_type ParserTokenReader::ReadNextToken()
265 MUP_ASSERT(m_pParser != nullptr);
267 const char_type* szFormula = m_strFormula.c_str();
270 // Ignore all non printable characters when reading the expression
271 while (szFormula[m_iPos] > 0 && szFormula[m_iPos] <= 0x20)
274 // Check for end of formula
276 return SaveBeforeReturn(tok);
278 // Check for user defined binary operator
280 return SaveBeforeReturn(tok);
282 // Check for function token
284 return SaveBeforeReturn(tok);
286 // Check built in operators / tokens
288 return SaveBeforeReturn(tok);
290 // Check for function argument separators
292 return SaveBeforeReturn(tok);
294 // Check for values / constant tokens
296 return SaveBeforeReturn(tok);
298 // Check for variable tokens
300 return SaveBeforeReturn(tok);
302 // Check for string variables
303 if (IsStrVarTok(tok))
304 return SaveBeforeReturn(tok);
306 // Check for String tokens
308 return SaveBeforeReturn(tok);
310 // Check for unary operators
311 if (IsInfixOpTok(tok))
312 return SaveBeforeReturn(tok);
314 // Check for unary operators
315 if (IsPostOpTok(tok))
316 return SaveBeforeReturn(tok);
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);
328 // Check for unknown token
330 // !!! From this point on there is no exit without an exception possible...
333 auto iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos);
335 Error(ecUNASSIGNABLE_TOKEN, m_iPos, strTok);
337 Error(ecUNASSIGNABLE_TOKEN, m_iPos, m_strFormula.substr(m_iPos));
338 return token_type(); // never reached
342 void ParserTokenReader::SetParent(ParserBase* a_pParent)
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;
355 /** \brief Extract all characters that belong to a certain charset.
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.
363 int ParserTokenReader::ExtractToken(const char_type* a_szCharSet, string_type& a_sTok, std::size_t a_iPos) const
365 auto iEnd = m_strFormula.find_first_not_of(a_szCharSet, a_iPos);
367 if (iEnd == string_type::npos)
368 iEnd = m_strFormula.length();
370 // Assign token string if there was something found
372 a_sTok = string_type(m_strFormula.begin() + a_iPos, m_strFormula.begin() + iEnd);
378 /** \brief Check Expression for the presence of a binary operator token.
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
385 int ParserTokenReader::ExtractOperatorToken(string_type& a_sTok, std::size_t a_iPos) const
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();
392 // Assign token string if there was something found
395 a_sTok = string_type(m_strFormula.begin() + a_iPos, m_strFormula.begin() + iEnd);
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);
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.
411 bool ParserTokenReader::IsBuiltIn(token_type& a_Tok)
413 const char_type** const pOprtDef = m_pParser->GetOprtDef(),
414 * const szFormula = m_strFormula.c_str();
416 // Compare token with function and operator strings
417 // check string for operator/function
418 for (int i = 0; pOprtDef[i]; i++)
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))
439 //if (len!=sTok.length())
442 // The assignment operator need special treatment
443 if (i == cmASSIGN && m_iSynFlags & noASSIGN)
444 Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]);
446 if (!m_pParser->HasBuiltInOprt()) continue;
447 if (m_iSynFlags & noOPT)
449 // Maybe its an infix operator not an operator
450 // Both operator types can share characters in
452 if (IsInfixOpTok(a_Tok))
455 Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]);
458 m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE | noEND;
462 if (m_iSynFlags & noBO)
463 Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);
465 if (m_lastTok.GetCode() == cmFUNC)
466 m_iSynFlags = noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE;
468 m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE;
470 m_bracketStack.push(cmBO);
474 if (m_iSynFlags & noBC)
475 Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);
477 m_iSynFlags = noBO | noVAR | noVAL | noFUN | noINFIXOP | noSTR | noASSIGN;
479 if (!m_bracketStack.empty())
480 m_bracketStack.pop();
482 Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);
486 if (m_iSynFlags & noELSE)
487 Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]);
489 m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE | noSTR;
493 if (m_iSynFlags & noIF)
494 Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]);
496 m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE | noSTR;
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
504 a_Tok.Set((ECmdCode)i, pOprtDef[i]);
506 } // if operator string found
507 } // end of for all operator strings
513 bool ParserTokenReader::IsArgSep(token_type& a_Tok)
515 const char_type* szFormula = m_strFormula.c_str();
517 if (szFormula[m_iPos] == m_cArgSep)
519 // copy the separator into null terminated string
521 szSep[0] = m_cArgSep;
524 if (m_iSynFlags & noARG_SEP)
525 Error(ecUNEXPECTED_ARG_SEP, m_iPos, szSep);
527 m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN;
529 a_Tok.Set(cmARG_SEP, szSep);
537 /** \brief Check for End of Formula.
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.
542 \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsString, IsInfixOpTok, IsPostOpTok
544 bool ParserTokenReader::IsEOF(token_type& a_Tok)
546 const char_type* szFormula = m_strFormula.c_str();
549 if (!szFormula[m_iPos] /*|| szFormula[m_iPos] == '\n'*/)
551 if (m_iSynFlags & noEND)
552 Error(ecUNEXPECTED_EOF, m_iPos);
554 if (!m_bracketStack.empty())
555 Error(ecMISSING_PARENS, m_iPos, _T(")"));
566 /** \brief Check if a string position contains a unary infix operator.
567 \return true if a function token has been found false otherwise.
569 bool ParserTokenReader::IsInfixOpTok(token_type& a_Tok)
572 auto iEnd = ExtractToken(m_pParser->ValidInfixOprtChars(), sTok, (std::size_t)m_iPos);
576 // iterate over all postfix operator strings
577 funmap_type::const_reverse_iterator it = m_pInfixOprtDef->rbegin();
578 for (; it != m_pInfixOprtDef->rend(); ++it)
580 if (sTok.find(it->first) != 0)
583 a_Tok.Set(it->second, it->first);
584 m_iPos += (int)it->first.length();
586 if (m_iSynFlags & noINFIXOP)
587 Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString());
589 m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN | noARG_SEP;
596 a_Tok.Set(item->second, sTok);
599 if (m_iSynFlags & noINFIXOP)
600 Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString());
602 m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN;
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
614 bool ParserTokenReader::IsFunTok(token_type& a_Tok)
617 auto iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos);
621 funmap_type::const_iterator item = m_pFunDef->find(strTok);
622 if (item == m_pFunDef->end())
625 // Check if the next sign is an opening bracket
626 const char_type* szFormula = m_strFormula.c_str();
627 if (szFormula[iEnd] != '(')
630 a_Tok.Set(item->second, strTok);
633 if (m_iSynFlags & noFUN)
634 Error(ecUNEXPECTED_FUN, m_iPos - (int)a_Tok.GetAsString().length(), a_Tok.GetAsString());
636 m_iSynFlags = noANY ^ noBO;
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.
645 bool ParserTokenReader::IsOprt(token_type& a_Tok)
647 const char_type* const szExpr = m_strFormula.c_str();
650 auto iEnd = ExtractOperatorToken(strTok, (std::size_t)m_iPos);
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)
658 if (string_type(pOprtDef[i]) == strTok)
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
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)
671 const string_type& sID = it->first;
672 if (sID == string_type(szExpr + m_iPos, szExpr + m_iPos + sID.length()))
674 a_Tok.Set(it->second, strTok);
676 // operator was found
677 if (m_iSynFlags & noOPT)
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))
687 // nope, no infix operator
689 //Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString());
694 m_iPos += (int)sID.length();
695 m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noEND | noASSIGN;
704 /** \brief Check if a string position contains a unary post value operator. */
705 bool ParserTokenReader::IsPostOpTok(token_type& a_Tok)
707 // <ibg 20110629> Do not check for postfix operators if they are not allowed at
708 // the current expression index.
710 // This will fix the bug reported here:
712 // http://sourceforge.net/tracker/index.php?func=detail&aid=3343891&group_id=137191&atid=737979
714 if (m_iSynFlags & noPOSTOP)
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.
723 // This is a special case so this routine slightly differs from the other
726 // Test if there could be a postfix operator
728 auto iEnd = ExtractToken(m_pParser->ValidOprtChars(), sTok, (std::size_t)m_iPos);
732 // iterate over all postfix operator strings
733 funmap_type::const_reverse_iterator it = m_pPostOprtDef->rbegin();
734 for (; it != m_pPostOprtDef->rend(); ++it)
736 if (sTok.find(it->first) != 0)
739 a_Tok.Set(it->second, sTok);
740 m_iPos += (int)it->first.length();
742 m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noSTR | noASSIGN;
750 /** \brief Check whether the token at a given position is a value token.
752 Value tokens are either values or constants.
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.
757 bool ParserTokenReader::IsValTok(token_type& a_Tok)
759 MUP_ASSERT(m_pConstDef != nullptr);
760 MUP_ASSERT(m_pParser != nullptr);
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);
770 valmap_type::const_iterator item = m_pConstDef->find(strTok);
771 if (item != m_pConstDef->end())
774 a_Tok.SetVal(item->second, strTok);
776 if (m_iSynFlags & noVAL)
777 Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok);
779 m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN;
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)
790 if ((*item)(m_strFormula.c_str() + m_iPos, &m_iPos, &fVal) == 1)
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);
795 if (m_iSynFlags & noVAL)
796 Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok);
798 a_Tok.SetVal(fVal, strTok);
799 m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN;
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.
812 bool ParserTokenReader::IsVarTok(token_type& a_Tok)
814 if (m_pVarDef->empty())
818 auto iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos);
822 varmap_type::const_iterator item = m_pVarDef->find(strTok);
823 if (item == m_pVarDef->end())
826 if (m_iSynFlags & noVAR)
827 Error(ecUNEXPECTED_VAR, m_iPos, strTok);
829 m_pParser->OnDetectVar(&m_strFormula, m_iPos, iEnd);
832 a_Tok.SetVar(item->second, strTok);
833 m_UsedVar[item->first] = item->second; // Add variable to used-var-list
835 m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR;
837 // Zur Info hier die SynFlags von IsVal():
838 // m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN;
843 bool ParserTokenReader::IsStrVarTok(token_type& a_Tok)
845 if (!m_pStrVarDef || m_pStrVarDef->empty())
849 auto iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos);
853 strmap_type::const_iterator item = m_pStrVarDef->find(strTok);
854 if (item == m_pStrVarDef->end())
857 if (m_iSynFlags & noSTR)
858 Error(ecUNEXPECTED_VAR, m_iPos, strTok);
861 if (!m_pParser->m_vStringVarBuf.size())
862 Error(ecINTERNAL_ERROR);
864 a_Tok.SetString(m_pParser->m_vStringVarBuf[item->second], m_pParser->m_vStringVarBuf.size());
866 m_iSynFlags = noANY ^ (noBC | noOPT | noEND | noARG_SEP);
872 /** \brief Check wheter a token at a given position is an undefined variable.
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.
878 bool ParserTokenReader::IsUndefVarTok(token_type& a_Tok)
881 auto iEnd(ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos));
885 if (m_iSynFlags & noVAR)
887 // <ibg/> 20061021 added token string strTok instead of a_Tok.GetAsString() as the
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);
894 // If a factory is available implicitely create new variables
897 value_type* fVar = m_pFactory(strTok.c_str(), m_pFactoryData);
898 a_Tok.SetVar(fVar, strTok);
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
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
911 a_Tok.SetVar((value_type*)&m_fZero, strTok);
912 m_UsedVar[strTok] = 0; // Add variable to used-var-list
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;
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
930 bool ParserTokenReader::IsString(token_type& a_Tok)
932 if (m_strFormula[m_iPos] != '"')
935 string_type strBuf(&m_strFormula[(std::size_t)m_iPos + 1]);
936 std::size_t iEnd(0), iSkip(0);
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))
941 if (strBuf[iEnd - 1] != '\\') break;
942 strBuf.replace(iEnd - 1, 2, _T("\""));
946 if (iEnd == string_type::npos)
947 Error(ecUNTERMINATED_STRING, m_iPos, _T("\""));
949 string_type strTok(strBuf.begin(), strBuf.begin() + iEnd);
951 if (m_iSynFlags & noSTR)
952 Error(ecUNEXPECTED_STR, m_iPos, strTok);
954 m_pParser->m_vStringBuf.push_back(strTok); // Store string in internal buffer
955 a_Tok.SetString(strTok, m_pParser->m_vStringBuf.size());
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);
964 /** \brief Create an error containing the parse error position.
966 This function will create an Parser Exception object containing the error text and its position.
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.
973 void ParserTokenReader::Error(EErrorCodes a_iErrc, int a_iPos, const string_type& a_sTok) const
975 m_pParser->Error(a_iErrc, a_iPos, a_sTok);
979 void ParserTokenReader::SetArgSep(char_type cArgSep)
985 char_type ParserTokenReader::GetArgSep() const
991 #if defined(_MSC_VER)