boolean cxxParserParseEnum(void) { CXX_DEBUG_ENTER(); // may be cleared below boolean bParsingTypedef = (g_cxx.uKeywordState & CXXParserKeywordStateSeenTypedef); /* Spec is: enum-key attr(optional) identifier(optional) enum-base(optional) { enumerator-list(optional) } (1) enum-key attr(optional) identifier enum-base(optional) ; (2) (since C++11) */ // Skip attr and class-head-name if(!cxxParserParseUpToOneOf( CXXTokenTypeEOF | CXXTokenTypeSemicolon | CXXTokenTypeParenthesisChain | CXXTokenTypeOpeningBracket )) { CXX_DEBUG_LEAVE_TEXT("Could not parse enum name"); return FALSE; } if(cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeParenthesisChain)) { // probably a function declaration/prototype // something like enum x func().... // do not clear statement CXX_DEBUG_LEAVE_TEXT("Probably a function declaration!"); return TRUE; } // FIXME: This block is duplicated in struct/union/class if(cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeSemicolon)) { if(g_cxx.pTokenChain->iCount > 3) { // [typedef] struct X Y; <-- typedef has been removed! if(g_cxx.uKeywordState & CXXParserKeywordStateSeenTypedef) cxxParserExtractTypedef(g_cxx.pTokenChain,TRUE); else cxxParserExtractVariableDeclarations(g_cxx.pTokenChain,0); } cxxParserNewStatement(); CXX_DEBUG_LEAVE(); return TRUE; } if(cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeEOF)) { // tolerate EOF, treat as forward declaration cxxParserNewStatement(); CXX_DEBUG_LEAVE_TEXT("EOF before enum block: treating as forward declaration"); return TRUE; } // semicolon or opening bracket // check if we can extract a class name identifier CXXToken * pEnumName = cxxTokenChainLastTokenOfType( g_cxx.pTokenChain, CXXTokenTypeIdentifier ); int iPushedScopes = 0; if(pEnumName) { // good. // It may be qualified though. CXXToken * pNamespaceBegin = pEnumName; CXXToken * pPrev = pEnumName->pPrev; while(pPrev) { if(!cxxTokenTypeIs(pPrev,CXXTokenTypeMultipleColons)) break; pPrev = pPrev->pPrev; if(!pPrev) break; if(!cxxTokenTypeIs(pPrev,CXXTokenTypeIdentifier)) break; pNamespaceBegin = pPrev; pPrev = pPrev->pPrev; } while(pNamespaceBegin != pEnumName) { CXXToken * pNext = pNamespaceBegin->pNext; cxxTokenChainTake(g_cxx.pTokenChain,pNamespaceBegin); // FIXME: We don't really know if it's a class! cxxScopePush(pNamespaceBegin,CXXTagKindCLASS,CXXScopeAccessUnknown); iPushedScopes++; pNamespaceBegin = pNext->pNext; } CXX_DEBUG_PRINT("Enum name is %s",vStringValue(pEnumName->pszWord)); cxxTokenChainTake(g_cxx.pTokenChain,pEnumName); } else { pEnumName = cxxTokenCreateAnonymousIdentifier(CXXTagKindENUM); CXX_DEBUG_PRINT( "Enum name is %s (anonymous)", vStringValue(pEnumName->pszWord) ); } tagEntryInfo * tag = cxxTagBegin(CXXTagKindENUM,pEnumName); int iCorkQueueIndex = CORK_NIL; if(tag) { // FIXME: this is debatable tag->isFileScope = !isInputHeaderFile(); iCorkQueueIndex = cxxTagCommit(); } cxxScopePush(pEnumName,CXXTagKindENUM,CXXScopeAccessPublic); iPushedScopes++; vString * pScopeName = cxxScopeGetFullNameAsString(); // Special kind of block for(;;) { cxxTokenChainClear(g_cxx.pTokenChain); if(!cxxParserParseUpToOneOf( CXXTokenTypeComma | CXXTokenTypeClosingBracket | CXXTokenTypeEOF )) { CXX_DEBUG_LEAVE_TEXT("Failed to parse enum contents"); if(pScopeName) vStringDelete(pScopeName); return FALSE; } CXXToken * pFirst = cxxTokenChainFirst(g_cxx.pTokenChain); // enumerator. if( (g_cxx.pTokenChain->iCount > 1) && cxxTokenTypeIs(pFirst,CXXTokenTypeIdentifier) ) { tag = cxxTagBegin(CXXTagKindENUMERATOR,pFirst); if(tag) { tag->isFileScope = !isInputHeaderFile(); cxxTagCommit(); } } if(cxxTokenTypeIsOneOf( g_cxx.pToken, CXXTokenTypeEOF | CXXTokenTypeClosingBracket )) break; } if(iCorkQueueIndex > CORK_NIL) cxxParserMarkEndLineForTagInCorkQueue(iCorkQueueIndex); while(iPushedScopes > 0) { cxxScopePop(); iPushedScopes--; } boolean bRet = cxxParserParseEnumStructClassOrUnionFullDeclarationTrailer( bParsingTypedef, CXXKeywordENUM, CXXTagKindENUM, vStringValue(pScopeName) ); if(pScopeName) vStringDelete(pScopeName); cxxParserNewStatement(); CXX_DEBUG_LEAVE(); return bRet; };
bool cxxParserParseBlockHandleOpeningBracket(void) { CXX_DEBUG_ENTER(); CXX_DEBUG_ASSERT( g_cxx.pToken->eType == CXXTokenTypeOpeningBracket, "This must be called when pointing at an opening bracket!" ); enum CXXScopeType eScopeType = cxxScopeGetType(); bool bIsCPP = cxxParserCurrentLanguageIsCPP(); CXXToken * pAux; if( ( // something = {...} (g_cxx.pToken->pPrev) && cxxTokenTypeIs(g_cxx.pToken->pPrev,CXXTokenTypeAssignment) && ( (eScopeType == CXXScopeTypeFunction) || (eScopeType == CXXScopeTypeNamespace) ) ) || ( bIsCPP && (g_cxx.pToken->pPrev) && ( ( // T { arg1, arg2, ... } (1) // T object { arg1, arg2, ... } (2) // new T { arg1, arg2, ... } (3) // Class::Class() : member { arg1, arg2, ... } { (4) cxxTokenTypeIs(g_cxx.pToken->pPrev,CXXTokenTypeIdentifier) && ( (!g_cxx.pToken->pPrev->pPrev) || (cxxTokenTypeIsOneOf( g_cxx.pToken->pPrev->pPrev, CXXTokenTypeIdentifier | CXXTokenTypeStar | CXXTokenTypeAnd | CXXTokenTypeGreaterThanSign | CXXTokenTypeKeyword | // FIXME: This check could be made stricter? CXXTokenTypeSingleColon | CXXTokenTypeComma )) ) && // "override" is handled as identifier since it's a keyword only after function signatures (strcmp(vStringValue(g_cxx.pToken->pPrev->pszWord),"override") != 0) ) || ( // type var[][][]..[] { ... } // (but not '[] { ... }' which is a parameterelss lambda) cxxTokenTypeIs(g_cxx.pToken->pPrev,CXXTokenTypeSquareParenthesisChain) && ( pAux = cxxTokenChainPreviousTokenNotOfType( g_cxx.pToken->pPrev, CXXTokenTypeSquareParenthesisChain ) ) && cxxTokenTypeIs(pAux,CXXTokenTypeIdentifier) ) ) ) || ( // return { } (!g_cxx.pToken->pPrev) && (g_cxx.uKeywordState & CXXParserKeywordStateSeenReturn) ) ) { // array or list-like initialisation bool bRet = cxxParserParseAndCondenseCurrentSubchain( CXXTokenTypeOpeningBracket | CXXTokenTypeOpeningParenthesis | CXXTokenTypeOpeningSquareParenthesis, false ); CXX_DEBUG_LEAVE_TEXT("Handled array or list-like initialisation or return"); return bRet; } int iScopes; // FIXME: Why the invalid cork queue entry index is CORK_NIL? int iCorkQueueIndex = CORK_NIL; if(eScopeType != CXXScopeTypeFunction) { // very likely a function definition iScopes = cxxParserExtractFunctionSignatureBeforeOpeningBracket(&iCorkQueueIndex); // FIXME: Handle syntax (5) of list initialization: // Class::Class() : member { arg1, arg2, ... } {... } else { // some kind of other block: // - anonymous block // - block after for(),while(),foreach(),if() and other similar stuff // - lambda // check for lambdas CXXToken * pParenthesis; if( bIsCPP && (pParenthesis = cxxParserOpeningBracketIsLambda()) ) { CXX_DEBUG_LEAVE_TEXT("Will handle lambda"); return cxxParserHandleLambda(pParenthesis); } iScopes = 0; } cxxParserNewStatement(); if(!cxxParserParseBlock(true)) { CXX_DEBUG_LEAVE_TEXT("Failed to parse nested block"); return false; } if(iCorkQueueIndex > CORK_NIL) cxxParserMarkEndLineForTagInCorkQueue(iCorkQueueIndex); while(iScopes > 0) { cxxScopePop(); iScopes--; } CXX_DEBUG_LEAVE(); return true; }
// In case of a lambda without parentheses this is the capture list token. bool cxxParserHandleLambda(CXXToken * pParenthesis) { CXX_DEBUG_ENTER(); CXX_DEBUG_ASSERT(cxxParserCurrentLanguageIsCPP(),"C++ only"); CXXToken * pIdentifier = cxxTokenCreateAnonymousIdentifier(CXXTagKindFUNCTION); CXXTokenChain * pSave = g_cxx.pTokenChain; CXXTokenChain * pNew = cxxTokenChainCreate(); g_cxx.pTokenChain = pNew; tagEntryInfo * tag = cxxTagBegin(CXXTagKindFUNCTION,pIdentifier); CXXToken * pAfterParenthesis = pParenthesis ? pParenthesis->pNext : NULL; CXXToken * pCaptureList = NULL; if(pParenthesis) { if(cxxTokenTypeIs(pParenthesis,CXXTokenTypeSquareParenthesisChain)) { // form (4) of lambda (see cxxParserOpeningBracketIsLambda()). pCaptureList = pParenthesis; } else if( pParenthesis->pPrev && cxxTokenTypeIs(pParenthesis->pPrev,CXXTokenTypeSquareParenthesisChain) ) { // other forms of lambda (see cxxParserOpeningBracketIsLambda()). pCaptureList = pParenthesis->pPrev; } } if( pAfterParenthesis && cxxTokenTypeIs(pAfterParenthesis,CXXTokenTypeKeyword) && (pAfterParenthesis->eKeyword == CXXKeywordCONST) ) pAfterParenthesis = pAfterParenthesis->pNext; CXXToken * pTypeStart = NULL; CXXToken * pTypeEnd; if( pAfterParenthesis && cxxTokenTypeIs(pAfterParenthesis,CXXTokenTypePointerOperator) && pAfterParenthesis->pNext && !cxxTokenTypeIs(pAfterParenthesis->pNext,CXXTokenTypeOpeningBracket) ) { pTypeStart = pAfterParenthesis->pNext; pTypeEnd = pTypeStart; while( pTypeEnd->pNext && (!cxxTokenTypeIs(pTypeEnd->pNext,CXXTokenTypeOpeningBracket)) ) pTypeEnd = pTypeEnd->pNext; #if 0 while( (pTypeStart != pTypeEnd) && cxxTokenTypeIs(pTypeStart,CXXTokenTypeKeyword) && cxxKeywordExcludeFromTypeNames(pTypeStart->eKeyword) ) pTypeStart = pTypeStart->pNext; #endif } int iCorkQueueIndex = CORK_NIL; if(tag) { tag->isFileScope = true; CXXToken * pTypeName; markTagExtraBit (tag, XTAG_ANONYMOUS); if(pTypeStart) pTypeName = cxxTagCheckAndSetTypeField(pTypeStart,pTypeEnd); else pTypeName = NULL; if(pCaptureList && cxxTagFieldEnabled(CXXTagCPPFieldLambdaCaptureList)) { CXX_DEBUG_ASSERT(pCaptureList->pChain,"The capture list must be a chain"); cxxTokenChainCondense(pCaptureList->pChain,0); CXX_DEBUG_ASSERT( cxxTokenChainFirst(pCaptureList->pChain), "Condensation should have created a single token in the chain" ); cxxTagSetField( CXXTagCPPFieldLambdaCaptureList, vStringValue(cxxTokenChainFirst(pCaptureList->pChain)->pszWord) ); } // FIXME: Properties? vString * pszSignature = NULL; if(cxxTokenTypeIs(pParenthesis,CXXTokenTypeParenthesisChain)) pszSignature = cxxTokenChainJoin(pParenthesis->pChain,NULL,0); if(pszSignature) tag->extensionFields.signature = vStringValue(pszSignature); iCorkQueueIndex = cxxTagCommit(); if(pTypeName) cxxTokenDestroy(pTypeName); if(pszSignature) vStringDelete(pszSignature); } cxxScopePush( pIdentifier, CXXScopeTypeFunction, CXXScopeAccessUnknown ); if( pParenthesis && cxxTokenTypeIs(pParenthesis,CXXTokenTypeParenthesisChain) && cxxTagKindEnabled(CXXTagKindPARAMETER) ) { CXXFunctionParameterInfo oParamInfo; if(cxxParserTokenChainLooksLikeFunctionParameterList( pParenthesis->pChain,&oParamInfo )) cxxParserEmitFunctionParameterTags(&oParamInfo); } bool bRet = cxxParserParseBlock(true); if(iCorkQueueIndex > CORK_NIL) cxxParserMarkEndLineForTagInCorkQueue(iCorkQueueIndex); cxxScopePop(); pNew = g_cxx.pTokenChain; // May have been destroyed and re-created g_cxx.pTokenChain = pSave; g_cxx.pToken = pSave->pTail; // change the type of token so following parsing code is not confused too much g_cxx.pToken->eType = CXXTokenTypeAngleBracketChain; g_cxx.pToken->pChain = pNew; cxxTokenChainClear(pNew); CXXToken * t = cxxTokenCreate(); t->eType = CXXTokenTypeOpeningBracket; vStringPut (t->pszWord, '{'); cxxTokenChainAppend(pNew,t); t = cxxTokenCreate(); t->eType = CXXTokenTypeClosingBracket; vStringPut (t->pszWord, '}'); cxxTokenChainAppend(pNew,t); CXX_DEBUG_LEAVE(); return bRet; }
static bool cxxParserParseBlockInternal(bool bExpectClosingBracket) { CXX_DEBUG_ENTER(); //char * szScopeName = cxxScopeGetFullName(); //CXX_DEBUG_PRINT("Scope name is '%s'",szScopeName ? szScopeName : ""); cxxParserNewStatement(); if(bExpectClosingBracket) { // FIXME: this cpp handling is kind of broken: // it works only because the moon is in the correct phase. cppBeginStatement(); } for(;;) { if(!cxxParserParseNextToken()) { found_eof: if(bExpectClosingBracket) { CXX_DEBUG_LEAVE_TEXT( "Syntax error: found EOF in block but a closing " \ "bracket was expected!" ); return false; } CXX_DEBUG_LEAVE_TEXT("EOF in main block"); return true; // EOF } process_token: CXX_DEBUG_PRINT( "Token '%s' of type 0x%02x", vStringValue(g_cxx.pToken->pszWord), g_cxx.pToken->eType ); switch(g_cxx.pToken->eType) { case CXXTokenTypeKeyword: { switch(g_cxx.pToken->eKeyword) { case CXXKeywordNAMESPACE: { if(cxxScopeGetType() == CXXScopeTypeNamespace || cxxScopeGetType() == CXXScopeTypeFunction) { // namespaces can be nested only within themselves if(!cxxParserParseNamespace()) { CXX_DEBUG_LEAVE_TEXT("Failed to parse namespace"); return false; } } else { // hm... syntax error? CXX_DEBUG_LEAVE_TEXT( "Found namespace in a wrong place: we're probably out of sync" ); return false; } cxxParserNewStatement(); } break; case CXXKeywordTEMPLATE: if(!cxxParserParseTemplatePrefix()) { CXX_DEBUG_LEAVE_TEXT("Failed to parse template"); return false; } // Here we are just after the "template<parameters>" prefix. break; case CXXKeywordTYPEDEF: // Mark the next declaration as a typedef g_cxx.uKeywordState |= CXXParserKeywordStateSeenTypedef; cxxTokenChainClear(g_cxx.pTokenChain); break; case CXXKeywordENUM: if(!cxxParserParseEnum()) { CXX_DEBUG_LEAVE_TEXT("Failed to parse enum"); return false; } break; case CXXKeywordCLASS: if(!cxxParserParseClassStructOrUnion(CXXKeywordCLASS,CXXTagCPPKindCLASS,CXXScopeTypeClass)) { CXX_DEBUG_LEAVE_TEXT("Failed to parse class/struct/union"); return false; } break; case CXXKeywordSTRUCT: if(!cxxParserParseClassStructOrUnion(CXXKeywordSTRUCT,CXXTagKindSTRUCT,CXXScopeTypeStruct)) { CXX_DEBUG_LEAVE_TEXT("Failed to parse class/struct/union"); return false; } break; case CXXKeywordUNION: if(!cxxParserParseClassStructOrUnion(CXXKeywordUNION,CXXTagKindUNION,CXXScopeTypeUnion)) { CXX_DEBUG_LEAVE_TEXT("Failed to parse class/struct/union"); return false; } break; case CXXKeywordPUBLIC: case CXXKeywordPROTECTED: case CXXKeywordPRIVATE: // Note that the class keyword has its own handler // so the only possibility here is an access specifier if(!cxxParserParseAccessSpecifier()) { CXX_DEBUG_LEAVE_TEXT("Failed to parse access specifier"); return false; } break; case CXXKeywordUSING: if(!cxxParserParseUsingClause()) { CXX_DEBUG_LEAVE_TEXT("Failed to parse using clause"); return false; } cxxParserNewStatement(); break; case CXXKeywordIF: case CXXKeywordFOR: case CXXKeywordWHILE: case CXXKeywordSWITCH: if(!cxxParserParseIfForWhileSwitch()) { CXX_DEBUG_LEAVE_TEXT("Failed to parse if/for/while/switch"); return false; } cxxParserNewStatement(); // Force the cpp preprocessor to think that we're in the middle of a statement. cppBeginStatement(); break; case CXXKeywordTRY: case CXXKeywordELSE: case CXXKeywordDO: // parse as normal statement/block cxxParserNewStatement(); // Force the cpp preprocessor to think that we're in the middle of a statement. cppBeginStatement(); break; case CXXKeywordRETURN: if(cxxParserCurrentLanguageIsCPP()) { // may be followed by a lambda, otherwise it's not interesting. cxxParserNewStatement(); g_cxx.uKeywordState |= CXXParserKeywordStateSeenReturn; } else { // ignore if(!cxxParserParseUpToOneOf(CXXTokenTypeSemicolon | CXXTokenTypeEOF)) { CXX_DEBUG_LEAVE_TEXT("Failed to parse return"); return false; } cxxParserNewStatement(); } break; case CXXKeywordCONTINUE: case CXXKeywordBREAK: case CXXKeywordGOTO: // ignore if(!cxxParserParseUpToOneOf(CXXTokenTypeSemicolon | CXXTokenTypeEOF)) { CXX_DEBUG_LEAVE_TEXT("Failed to parse continue/break/goto"); return false; } cxxParserNewStatement(); break; case CXXKeywordTHROW: // ignore when inside a function if(cxxScopeGetType() == CXXScopeTypeFunction) { if(!cxxParserParseUpToOneOf(CXXTokenTypeSemicolon | CXXTokenTypeEOF)) { CXX_DEBUG_LEAVE_TEXT("Failed to parse return/continue/break"); return false; } cxxParserNewStatement(); } break; case CXXKeywordCASE: // ignore if(!cxxParserParseUpToOneOf( CXXTokenTypeSemicolon | CXXTokenTypeEOF | CXXTokenTypeSingleColon )) { CXX_DEBUG_LEAVE_TEXT("Failed to parse case keyword"); return false; } cxxParserNewStatement(); break; case CXXKeywordEXTERN: g_cxx.uKeywordState |= CXXParserKeywordStateSeenExtern; cxxTokenChainDestroyLast(g_cxx.pTokenChain); if(!cxxParserParseNextToken()) goto found_eof; if(cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeStringConstant)) { // assume extern "language" // Strictly speaking this is a C++ only syntax. // However we allow it also in C as it doesn't really hurt. cxxTokenChainDestroyLast(g_cxx.pTokenChain); // Note that extern "C" may be followed by a block with declarations // // extern "C" { ... } // // However in this case the declarations are ALSO definitions // and extern "C" is used only to specify the name mangling mode. // // extern "C" int x; <-- a declaration and not a definition // extern "C" { int x; } <-- a declaration and definition: x IS defined // here and is NOT extern. // // A variable in an extern "C" block has to be re-declared extern again // to be really treated as declaration only. // // extern "C" { extern int x; } // // So in this case we do NOT treat the inner declarations as extern // and we don't need specific handling code for this case. } else { // something else: handle it the normal way goto process_token; } break; case CXXKeywordSTATIC: g_cxx.uKeywordState |= CXXParserKeywordStateSeenStatic; cxxTokenChainDestroyLast(g_cxx.pTokenChain); break; case CXXKeywordINLINE: case CXXKeyword__INLINE: case CXXKeyword__INLINE__: case CXXKeyword__FORCEINLINE: case CXXKeyword__FORCEINLINE__: g_cxx.uKeywordState |= CXXParserKeywordStateSeenInline; cxxTokenChainDestroyLast(g_cxx.pTokenChain); break; case CXXKeywordEXPLICIT: g_cxx.uKeywordState |= CXXParserKeywordStateSeenExplicit; cxxTokenChainDestroyLast(g_cxx.pTokenChain); break; case CXXKeywordOPERATOR: g_cxx.uKeywordState |= CXXParserKeywordStateSeenOperator; break; case CXXKeywordVIRTUAL: g_cxx.uKeywordState |= CXXParserKeywordStateSeenVirtual; cxxTokenChainDestroyLast(g_cxx.pTokenChain); break; case CXXKeywordMUTABLE: g_cxx.uKeywordState |= CXXParserKeywordStateSeenMutable; cxxTokenChainDestroyLast(g_cxx.pTokenChain); break; // "const" and "volatile" are part of the type. Don't treat them specially // and don't attempt to extract an eventual typedef yet, // as there might be a struct/class/union keyword following. case CXXKeywordVOLATILE: g_cxx.uKeywordState |= CXXParserKeywordStateSeenVolatile; break; case CXXKeywordCONST: g_cxx.uKeywordState |= CXXParserKeywordStateSeenConst; break; default: if(g_cxx.uKeywordState & CXXParserKeywordStateSeenTypedef) { g_cxx.uKeywordState &= ~CXXParserKeywordStateSeenTypedef; if(!cxxParserParseGenericTypedef()) { CXX_DEBUG_LEAVE_TEXT("Failed to parse generic typedef"); return false; } cxxParserNewStatement(); } break; } } break; case CXXTokenTypeSemicolon: { if( (g_cxx.eLangType == g_cxx.eCLangType) && cxxScopeIsGlobal() && (!(g_cxx.uKeywordState & CXXParserKeywordStateSeenExtern)) && (!(g_cxx.uKeywordState & CXXParserKeywordStateSeenTypedef)) ) { // Special handling of K&R style function declarations. // We might be in the following situation: // // type whatever fname(par1,par2) int par1; int par2; { // ^ // int iCorkQueueIndex = CORK_NIL; switch(cxxParserMaybeExtractKnRStyleFunctionDefinition(&iCorkQueueIndex)) { case 1: // got K&R style function definition, one scope was pushed. cxxParserNewStatement(); if(!cxxParserParseBlock(true)) { CXX_DEBUG_LEAVE_TEXT("Failed to parse nested block"); return false; } if(iCorkQueueIndex > CORK_NIL) cxxParserMarkEndLineForTagInCorkQueue(iCorkQueueIndex); cxxScopePop(); break; case 0: // something else cxxParserAnalyzeOtherStatement(); break; default: CXX_DEBUG_LEAVE_TEXT("Failed to check for K&R style function definition"); return false; break; } } else { // K&R style function declarations not allowed here. cxxParserAnalyzeOtherStatement(); } cxxParserNewStatement(); } break; case CXXTokenTypeSingleColon: { // label ? if( (g_cxx.pTokenChain->iCount == 2) && cxxTokenTypeIs( cxxTokenChainFirst(g_cxx.pTokenChain), CXXTokenTypeIdentifier ) ) { CXXToken * pFirst = cxxTokenChainFirst(g_cxx.pTokenChain); // assume it's label tagEntryInfo * tag = cxxTagBegin(CXXTagKindLABEL,pFirst); if(tag) { tag->isFileScope = true; cxxTagCommit(); } } else { // what is this? (default: and similar things have been handled at keyword level) } } break; case CXXTokenTypeOpeningBracket: if(!cxxParserParseBlockHandleOpeningBracket()) { CXX_DEBUG_LEAVE_TEXT("Failed to handle opening bracket"); return false; } break; case CXXTokenTypeClosingBracket: // scope finished if(!bExpectClosingBracket) { CXX_DEBUG_LEAVE_TEXT( "Found unexpected closing bracket: probably preprocessing problem" ); return false; } CXX_DEBUG_LEAVE_TEXT("Closing bracket!"); cxxParserNewStatement(); return true; break; case CXXTokenTypeOpeningParenthesis: case CXXTokenTypeOpeningSquareParenthesis: if(!cxxParserParseAndCondenseCurrentSubchain( CXXTokenTypeOpeningBracket | CXXTokenTypeOpeningParenthesis | CXXTokenTypeOpeningSquareParenthesis, true )) { CXX_DEBUG_LEAVE_TEXT("Parsing the parenthesis failed"); return false; } if(cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeEOF)) { if(bExpectClosingBracket) { CXX_DEBUG_LEAVE_TEXT( "Syntax error: found EOF in block but a closing bracket was expected!" ); return false; } return true; // EOF } break; case CXXTokenTypeIdentifier: if(g_cxx.uKeywordState & CXXParserKeywordStateSeenTypedef) { g_cxx.uKeywordState &= ~CXXParserKeywordStateSeenTypedef; if(!cxxParserParseGenericTypedef()) { CXX_DEBUG_LEAVE_TEXT("Failed to parse generic typedef"); return false; } cxxParserNewStatement(); } break; default: // something else we didn't handle break; } } CXX_DEBUG_LEAVE_TEXT("WARNING: Not reached"); return true; }