// // Parse a subchain of input delimited by matching pairs: [],(),{},<> // [WARNING: no other subchain types are recognized!]. This function expects // g_cxx.pToken to point to the initial token of the pair ([{<. // It will parse input until the matching terminator token is found. // Inner parsing is done by cxxParserParseAndCondenseSubchainsUpToOneOf() // so this is actually a recursive subchain nesting algorithm. // boolean cxxParserParseAndCondenseCurrentSubchain( unsigned int uInitialSubchainMarkerTypes, boolean bAcceptEOF ) { CXXTokenChain * pCurrentChain = g_cxx.pTokenChain; g_cxx.pTokenChain = cxxTokenChainCreate(); CXXToken * pInitial = cxxTokenChainTakeLast(pCurrentChain); cxxTokenChainAppend(g_cxx.pTokenChain,pInitial); CXXToken * pChainToken = cxxTokenCreate(); pChainToken->iLineNumber = pInitial->iLineNumber; pChainToken->oFilePosition = pInitial->oFilePosition; // see the declaration of CXXTokenType enum. // Shifting by 8 gives the corresponding chain marker pChainToken->eType = (enum CXXTokenType)(g_cxx.pToken->eType << 8); pChainToken->pChain = g_cxx.pTokenChain; cxxTokenChainAppend(pCurrentChain,pChainToken); // see the declaration of CXXTokenType enum. // Shifting by 4 gives the corresponding closing token type unsigned int uTokenTypes = g_cxx.pToken->eType << 4; if(bAcceptEOF) uTokenTypes |= CXXTokenTypeEOF; boolean bRet = cxxParserParseAndCondenseSubchainsUpToOneOf( uTokenTypes, uInitialSubchainMarkerTypes ); g_cxx.pTokenChain = pCurrentChain; g_cxx.pToken = pCurrentChain->pTail; return bRet; }
// An macro token was encountered and it expects a parameter list. // The routine has to check if there is a following parenthesis // and eventually skip it but it MUST NOT parse the next token // if it is not a parenthesis. This is because the macro token // may have a replacement and is that one that has to be returned // back to the caller from cxxParserParseNextToken(). static bool cxxParserParseNextTokenSkipMacroParenthesis(CXXToken ** ppChain) { CXX_DEBUG_ENTER(); CXX_DEBUG_ASSERT(ppChain,"ppChain should not be null here"); cxxParserSkipToNonWhiteSpace(); if(g_cxx.iChar != '(') { *ppChain = NULL; return true; // no parenthesis } if(!cxxParserParseNextToken()) { CXX_DEBUG_LEAVE_TEXT("No next token after ignored identifier"); return false; } if(!cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeOpeningParenthesis)) { CXX_DEBUG_ASSERT(false,"Should have found an open parenthesis token here!"); CXX_DEBUG_LEAVE_TEXT("Internal error"); return false; } if(!cxxParserParseAndCondenseCurrentSubchain( CXXTokenTypeOpeningParenthesis | CXXTokenTypeOpeningSquareParenthesis | CXXTokenTypeOpeningBracket, false )) { CXX_DEBUG_LEAVE_TEXT("Failed to parse and condense subchains"); return false; } CXX_DEBUG_ASSERT( cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeParenthesisChain), "Should have a parenthesis chain as last token!" ); // Now just kill the chain. *ppChain = cxxTokenChainTakeLast(g_cxx.pTokenChain); CXX_DEBUG_LEAVE(); return true; }
void cxxScopePop(void) { CXX_DEBUG_ASSERT( g_pScope->iCount > 0, "When popping as scope there must be a scope to pop" ); cxxTokenDestroy(cxxTokenChainTakeLast(g_pScope)); g_bScopeNameDirty = true; #ifdef CXX_DO_DEBUGGING const char * szScopeName = cxxScopeGetFullName(); CXX_DEBUG_PRINT("Popped scope: '%s'",szScopeName ? szScopeName : ""); #endif }
void cxxTokenChainTake(CXXTokenChain * tc,CXXToken * t) { if(!tc) return; if(!tc->pHead) return; /* Debug with this: CXXToken * t2 = tc->pHead; while(t2 && (t2 != t)) t2 = t2->pNext; Assert(t2); */ if(t == tc->pHead) { cxxTokenChainTakeFirst(tc); return; } if(t == tc->pTail) { cxxTokenChainTakeLast(tc); return; } // in the middle CXXToken * n = t->pNext; CXXToken * p = t->pPrev; n->pPrev = p; p->pNext = n; tc->iCount--; Assert(tc->iCount > 1); }
// // Parses a template<anything> prefix. // The parsed template parameter definition is stored in a separate token chain. // boolean cxxParserParseTemplatePrefix(void) { CXX_DEBUG_ENTER(); CXX_DEBUG_ASSERT(cxxTokenTypeIs(cxxTokenChainLast(g_cxx.pTokenChain),CXXTokenTypeKeyword),"We should be pointing at the template keyword here"); cxxTokenChainDestroyLast(g_cxx.pTokenChain); // kill the template keyword if(!cxxParserParseUpToOneOf(CXXTokenTypeSmallerThanSign | CXXTokenTypeEOF | CXXTokenTypeSemicolon)) { CXX_DEBUG_LEAVE_TEXT("Failed to parse up to the < sign"); return FALSE; } if(cxxTokenTypeIsOneOf(g_cxx.pToken,CXXTokenTypeEOF | CXXTokenTypeSemicolon)) { CXX_DEBUG_LEAVE_TEXT("Found EOF or semicolon: assuming this is unparseable"); cxxParserNewStatement(); return TRUE; // tolerate syntax error } CXXTokenChain * pSave = g_cxx.pTokenChain; g_cxx.pTokenChain = cxxTokenChainCreate(); cxxTokenChainAppend(g_cxx.pTokenChain,cxxTokenChainTakeLast(pSave)); if(!cxxParserParseTemplatePrefixAngleBrackets()) { CXX_DEBUG_LEAVE_TEXT("Failed to parse angle brackets"); cxxTokenChainDestroy(pSave); return FALSE; } if(g_cxx.pTemplateTokenChain) cxxTokenChainDestroy(g_cxx.pTemplateTokenChain); g_cxx.pTemplateTokenChain = g_cxx.pTokenChain; g_cxx.pTokenChain = pSave; CXX_DEBUG_LEAVE(); return TRUE; }
void cxxParserUngetCurrentToken(void) { CXX_DEBUG_ASSERT( g_cxx.pToken && g_cxx.pTokenChain && (g_cxx.pTokenChain->iCount > 0), "There should be at least one token to unget" ); CXX_DEBUG_ASSERT(!g_cxx.pUngetToken,"The parser supports only one unget token at a time."); if(g_cxx.pUngetToken) cxxTokenDestroy(g_cxx.pUngetToken); g_cxx.pUngetToken = cxxTokenChainTakeLast(g_cxx.pTokenChain); CXX_DEBUG_ASSERT(g_cxx.pUngetToken == g_cxx.pToken,"Oops.. ungot a token that was not the chain tail"); g_cxx.pToken = cxxTokenChainLast(g_cxx.pTokenChain); }
// The __attribute__((...)) sequence complicates parsing quite a lot. // For this reason we attempt to "hide" it from the rest of the parser // at tokenizer level. static bool cxxParserParseNextTokenCondenseAttribute(void) { CXX_DEBUG_ENTER(); CXX_DEBUG_ASSERT( cxxTokenIsKeyword(g_cxx.pToken,CXXKeyword__ATTRIBUTE__), "This function should be called only after we have parsed __attribute__" ); // Kill it cxxTokenDestroy(cxxTokenChainTakeLast(g_cxx.pTokenChain)); // And go ahead. if(!cxxParserParseNextToken()) { CXX_DEBUG_LEAVE_TEXT("No next token after __attribute__"); return false; } if(!cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeOpeningParenthesis)) { CXX_DEBUG_LEAVE_TEXT("Something that is not an opening parenthesis"); return true; } if(!cxxParserParseAndCondenseCurrentSubchain( CXXTokenTypeOpeningParenthesis | CXXTokenTypeOpeningSquareParenthesis | CXXTokenTypeOpeningBracket, false )) { CXX_DEBUG_LEAVE_TEXT("Failed to parse and condense subchains"); return false; } CXX_DEBUG_ASSERT( cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeParenthesisChain), "Should have a parenthesis chain as last token!" ); // Try to make sense of certain kinds of __attribute__. // the proper syntax is __attribute__(()), so look at the inner chain CXXToken * pInner = cxxTokenChainFirst(g_cxx.pToken->pChain); if(pInner) { if(pInner->pNext && cxxTokenTypeIs(pInner->pNext,CXXTokenTypeParenthesisChain)) pInner = cxxTokenChainFirst(pInner->pNext->pChain); while(pInner) { if(cxxTokenTypeIs(pInner,CXXTokenTypeIdentifier)) { CXX_DEBUG_PRINT("Analyzing attribyte %s",vStringValue(pInner->pszWord)); if( (strcmp(vStringValue(pInner->pszWord),"always_inline") == 0) || (strcmp(vStringValue(pInner->pszWord),"__always_inline__") == 0) ) { CXX_DEBUG_PRINT("Found attribute 'always_inline'"); // assume "inline" has been seen. g_cxx.uKeywordState |= CXXParserKeywordStateSeenInline; } else if( (strcmp(vStringValue(pInner->pszWord),"deprecated") == 0) || (strcmp(vStringValue(pInner->pszWord),"__deprecated__") == 0) ) { CXX_DEBUG_PRINT("Found attribute 'deprecated'"); // assume "inline" has been seen. g_cxx.uKeywordState |= CXXParserKeywordStateSeenAttributeDeprecated; } } // If needed, we could attach certain attributes to previous // identifiers. But note that __attribute__ may apply to a // following identifier too. pInner = pInner->pNext; } } // Now just kill the chain. cxxTokenDestroy(cxxTokenChainTakeLast(g_cxx.pTokenChain)); // And finally extract yet another token. CXX_DEBUG_LEAVE(); return cxxParserParseNextToken(); }