/** \brief Check if a string position contains a binary operator. */ bool TokenReader::IsOprt(ptr_tok_type &a_Tok) { string_type sTok; int iEnd = ExtractToken(m_pParser->ValidOprtChars(), sTok, m_nPos); if (iEnd == m_nPos) return false; oprt_bin_maptype::reverse_iterator item; try { // Note: // All tokens in oprt_bin_maptype are have been sorted by their length // Long operators must come first! Otherwise short names (like: "add") that // are part of long token names (like: "add123") will be found instead // of the long ones. // Length sorting is done with ascending length so we use a reverse iterator here. for (item = m_pOprtDef->rbegin(); item != m_pOprtDef->rend(); ++item) { if (sTok.find(item->first) != 0) continue; // operator found, check if we expect one... if (m_nSynFlags & noOPT) { // An operator was found but is not expected to occur at // this position of the formula, maybe it is an infix // operator, not a binary operator. Both operator types // can use the same characters in their identifiers. if (IsInfixOpTok(a_Tok)) return true; // nope, it's no infix operator and we dont expect // an operator throw ecUNEXPECTED_OPERATOR; } else { a_Tok = ptr_tok_type(item->second->Clone()); m_nPos += (int)a_Tok->GetIdent().length(); m_nSynFlags = noBC | noIO | noIC | noOPT | noCOMMA | noEND | noNEWLINE | noPFX | noIF | noELSE; return true; } } return false; } catch (EErrorCodes e) { ErrorContext err; err.Errc = e; err.Pos = m_nPos; // - (int)item->first.length(); err.Ident = item->first; err.Expr = m_sExpr; throw ParserError(err); } }
/** \brief Check if a string position contains a binary operator. \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token. \return true if an operator token has been found. */ bool ParserTokenReader::IsOprt(token_type &a_Tok) { const char_type *const szExpr = m_strFormula.c_str(); string_type strTok; int iEnd = ExtractOperatorToken(strTok, m_iPos); if (iEnd==m_iPos) return false; // Check if the operator is a built in operator, if so ignore it here const char_type **const pOprtDef = m_pParser->GetOprtDef(); for (int i=0; m_pParser->HasBuiltInOprt() && pOprtDef[i]; ++i) { if (string_type(pOprtDef[i])==strTok) return false; } // Note: // All tokens in oprt_bin_maptype are have been sorted by their length // Long operators must come first! Otherwise short names (like: "add") that // are part of long token names (like: "add123") will be found instead // of the long ones. // Length sorting is done with ascending length so we use a reverse iterator here. funmap_type::const_reverse_iterator it = m_pOprtDef->rbegin(); for ( ; it!=m_pOprtDef->rend(); ++it) { const string_type &sID = it->first; if ( sID == string_type(szExpr + m_iPos, szExpr + m_iPos + sID.length()) ) { a_Tok.Set(it->second, strTok); // operator was found if (m_iSynFlags & noOPT) { // An operator was found but is not expected to occur at // this position of the formula, maybe it is an infix // operator, not a binary operator. Both operator types // can share characters in their identifiers. if ( IsInfixOpTok(a_Tok) ) return true; else { // nope, no infix operator return false; //Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); } } m_iPos += (int)sID.length(); m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noEND | noBC | noASSIGN; return true; } } return false; }
/** \brief Read the next token from the string. */ ParserTokenReader::token_type ParserTokenReader::ReadNextToken() { assert(m_pParser); std::stack<int> FunArgs; const char_type *szFormula = m_strFormula.c_str(); token_type tok; // Ignore all non printable characters when reading the expression while (szFormula[m_iPos]>0 && szFormula[m_iPos]<=0x20) ++m_iPos; if ( IsEOF(tok) ) return SaveBeforeReturn(tok); // Check for end of formula if ( IsOprt(tok) ) return SaveBeforeReturn(tok); // Check for user defined binary operator if ( IsFunTok(tok) ) return SaveBeforeReturn(tok); // Check for function token if ( IsBuiltIn(tok) ) return SaveBeforeReturn(tok); // Check built in operators / tokens if ( IsArgSep(tok) ) return SaveBeforeReturn(tok); // Check for function argument separators if ( IsValTok(tok) ) return SaveBeforeReturn(tok); // Check for values / constant tokens if ( IsVarTok(tok) ) return SaveBeforeReturn(tok); // Check for variable tokens if ( IsStrVarTok(tok) ) return SaveBeforeReturn(tok); // Check for string variables if ( IsString(tok) ) return SaveBeforeReturn(tok); // Check for String tokens if ( IsInfixOpTok(tok) ) return SaveBeforeReturn(tok); // Check for unary operators if ( IsPostOpTok(tok) ) return SaveBeforeReturn(tok); // Check for unary operators // Check String for undefined variable token. Done only if a // flag is set indicating to ignore undefined variables. // This is a way to conditionally avoid an error if // undefined variables occur. // (The GetUsedVar function must suppress the error for // undefined variables in order to collect all variable // names including the undefined ones.) if ( (m_bIgnoreUndefVar || m_pFactory) && IsUndefVarTok(tok) ) return SaveBeforeReturn(tok); // Check for unknown token // // !!! From this point on there is no exit without an exception possible... // string_type strTok; int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); if (iEnd!=m_iPos) Error(ecUNASSIGNABLE_TOKEN, m_iPos, strTok); Error(ecUNASSIGNABLE_TOKEN, m_iPos, m_strFormula.substr(m_iPos)); return token_type(); // never reached }
/** \brief Read the next token from the string. */ ptr_tok_type TokenReader::ReadNextToken() { assert(m_pParser); SkipCommentsAndWhitespaces(); int token_pos = m_nPos; ptr_tok_type pTok; // Check for end of expression if (IsEOF(pTok)) return Store(pTok, token_pos); if (IsNewline(pTok)) return Store(pTok, token_pos); if (!(m_nSynFlags & noOPT) && IsOprt(pTok)) return Store(pTok, token_pos); // Check for user defined binary operator if (!(m_nSynFlags & noIFX) && IsInfixOpTok(pTok)) return Store(pTok, token_pos); // Check for unary operators if (IsValTok(pTok)) return Store(pTok, token_pos); // Check for values / constant tokens if (IsBuiltIn(pTok)) return Store(pTok, token_pos); // Check built in operators / tokens if (IsVarOrConstTok(pTok)) return Store(pTok, token_pos); // Check for variable tokens if (IsFunTok(pTok)) return Store(pTok, token_pos); if (!(m_nSynFlags & noPFX) && IsPostOpTok(pTok)) return Store(pTok, token_pos); // Check for unary operators // 2.) We have found no token, maybe there is a token that we don't expect here. // Again call the Identifier functions but this time only those we don't expect // to find. if ((m_nSynFlags & noOPT) && IsOprt(pTok)) return Store(pTok, token_pos); // Check for user defined binary operator if ((m_nSynFlags & noIFX) && IsInfixOpTok(pTok)) return Store(pTok, token_pos); // Check for unary operators if ((m_nSynFlags & noPFX) && IsPostOpTok(pTok)) return Store(pTok, token_pos); // Check for unary operators // </ibg> // Now we are in trouble because there is something completely unknown.... // Check the string for an undefined variable token. This is done // only if a flag is set indicating to ignore undefined variables. // This is a way to conditionally avoid an error if undefined variables // occur. The GetExprVar function must supress the error for undefined // variables in order to collect all variable names including the // undefined ones. if ((m_pParser->m_bIsQueryingExprVar || m_pParser->m_bAutoCreateVar) && IsUndefVarTok(pTok)) return Store(pTok, token_pos); // Check for unknown token // // !!! From this point on there is no exit without an exception possible... // string_type sTok; int iEnd = ExtractToken(m_pParser->ValidNameChars(), sTok, m_nPos); ErrorContext err; err.Errc = ecUNASSIGNABLE_TOKEN; err.Expr = m_sExpr; err.Pos = m_nPos; if (iEnd != m_nPos) err.Ident = sTok; else err.Ident = m_sExpr.substr(m_nPos); throw ParserError(err); }
/** \brief Check if a built in operator or other token can be found \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token. \return true if an operator token has been found. */ bool ParserTokenReader::IsBuiltIn(token_type &a_Tok) { const char_type **const pOprtDef = m_pParser->GetOprtDef(), *const szFormula = m_strFormula.c_str(); // Compare token with function and operator strings // check string for operator/function for (int i=0; pOprtDef[i]; i++) { std::size_t len( std::char_traits<char_type>::length(pOprtDef[i]) ); if ( string_type(pOprtDef[i]) == string_type(szFormula + m_iPos, szFormula + m_iPos + len) ) { switch(i) { //case cmAND: //case cmOR: //case cmXOR: case cmLAND: case cmLOR: case cmLT: case cmGT: case cmLE: case cmGE: case cmNEQ: case cmEQ: case cmADD: case cmSUB: case cmMUL: case cmDIV: case cmPOW: case cmASSIGN: //if (len!=sTok.length()) // continue; // The assignement operator need special treatment if (i==cmASSIGN && m_iSynFlags & noASSIGN) Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]); if (!m_pParser->HasBuiltInOprt()) continue; if (m_iSynFlags & noOPT) { // Maybe its an infix operator not an operator // Both operator types can share characters in // their identifiers if ( IsInfixOpTok(a_Tok) ) return true; Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]); } m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE; m_iSynFlags |= ( (i != cmEND) && ( i != cmBC) ) ? noEND : 0; break; case cmBO: if (m_iSynFlags & noBO) Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); if (m_lastTok.GetCode()==cmFUNC) m_iSynFlags = noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE; else m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN| noIF | noELSE; ++m_iBrackets; break; case cmBC: if (m_iSynFlags & noBC) Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); m_iSynFlags = noBO | noVAR | noVAL | noFUN | noINFIXOP | noSTR | noASSIGN; if (--m_iBrackets<0) Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); break; case cmELSE: if (m_iSynFlags & noELSE) Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]); m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE; break; case cmIF: if (m_iSynFlags & noIF) Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]); m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE; break; default: // The operator is listed in c_DefaultOprt, but not here. This is a bad thing... Error(ecINTERNAL_ERROR); } // switch operator id m_iPos += (int)len; a_Tok.Set( (ECmdCode)i, pOprtDef[i] ); return true; } // if operator string found } // end of for all operator strings return false; }