Пример #1
0
unsigned int cxxScopeGetKind(void)
{
	CXX_DEBUG_ASSERT(g_pScope->iCount >= 0,"Must not be called in global scope");

	switch(g_pScope->pTail->uInternalScopeType)
	{
		case CXXScopeTypeNamespace:
			CXX_DEBUG_ASSERT(cxxParserCurrentLanguageIsCPP(),"C++ only");
			return CXXTagCPPKindNAMESPACE;
		case CXXScopeTypeClass:
			CXX_DEBUG_ASSERT(cxxParserCurrentLanguageIsCPP(),"C++ only");
			return CXXTagCPPKindCLASS;
		case CXXScopeTypeEnum:
			return CXXTagKindENUM;
		case CXXScopeTypeFunction:
			return CXXTagKindFUNCTION;
		case CXXScopeTypeStruct:
			return CXXTagKindSTRUCT;
		case CXXScopeTypeUnion:
			return CXXTagKindUNION;
		default:
			CXX_DEBUG_ASSERT(false,"Unhandled scope type!");
			break;
	}

	return CXXTagKindFUNCTION;
}
Пример #2
0
void cxxScopePush(
		CXXToken * t,
		enum CXXScopeType eScopeType,
		enum CXXScopeAccess eInitialAccess
	)
{
	CXX_DEBUG_ASSERT(
			t->eType == CXXTokenTypeIdentifier,
			"The scope name must be an identifer"
		);
	CXX_DEBUG_ASSERT(
			t->pszWord,
			"The scope name should have a text"
		);
	cxxTokenChainAppend(g_pScope,t);
	t->uInternalScopeType = (unsigned char)eScopeType;
	t->uInternalScopeAccess = (unsigned char)eInitialAccess;
	g_bScopeNameDirty = true;

#ifdef CXX_DO_DEBUGGING
	const char * szScopeName = cxxScopeGetFullName();

	CXX_DEBUG_PRINT("Pushed scope: '%s'",szScopeName ? szScopeName : "");
#endif
}
Пример #3
0
static void cxxParserParseNextTokenApplyReplacement(
		const cppMacroInfo * pInfo,
		CXXToken * pParameterChainToken
	)
{
	CXX_DEBUG_ENTER();

	CXX_DEBUG_ASSERT(pInfo,"Info must be not null");
	CXX_DEBUG_ASSERT(pInfo->replacements,"There should be a replacement");

	if(!pInfo->hasParameterList)
	{
		CXX_DEBUG_ASSERT(!pParameterChainToken,"This shouldn't have been extracted");
	}

	CXXTokenChain * pParameters = NULL;
	const char ** aParameters = NULL;
	int iParameterCount = 0;

	if(pInfo->hasParameterList && pParameterChainToken && (pParameterChainToken->pChain->iCount >= 3))
	{
		// kill parenthesis
		cxxTokenChainDestroyFirst(pParameterChainToken->pChain);
		cxxTokenChainDestroyLast(pParameterChainToken->pChain);

		pParameters = cxxTokenChainSplitOnComma(
				pParameterChainToken->pChain
			);

		aParameters = (const char **)eMalloc(sizeof(const char *) * pParameters->iCount);
		CXXToken * pParam = cxxTokenChainFirst(pParameters);
		while(pParam)
		{
			aParameters[iParameterCount] = vStringValue(pParam->pszWord);
			iParameterCount++;
			pParam = pParam->pNext;
		}

		CXX_DEBUG_ASSERT(iParameterCount == pParameters->iCount,"Bad number of parameters found");
	}

	vString * pReplacement = cppBuildMacroReplacement(pInfo,aParameters,iParameterCount);

	if(pParameters)
	{
		cxxTokenChainDestroy(pParameters);
		eFree(aParameters);
	}

	CXX_DEBUG_PRINT("Applying complex replacement '%s'",vStringValue(pReplacement));

	cppUngetString(vStringValue(pReplacement),vStringLength(pReplacement));

	vStringDelete(pReplacement);

	CXX_DEBUG_LEAVE();
}
Пример #4
0
// 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;
}
Пример #5
0
void cxxTagSetCorkQueueField(
		int iIndex,
		unsigned int uField,
		const char * szValue
	)
{
	CXX_DEBUG_ASSERT(
			uField < g_cxx.uFieldOptionCount,
			"The field must be associated to the current language!"
		);

	CXX_DEBUG_ASSERT(g_cxx.pFieldOptions[uField].enabled,"The field must be enabled!");

	attachParserFieldToCorkEntry(iIndex,g_cxx.pFieldOptions[uField].ftype,szValue);
}
Пример #6
0
CXXToken * cxxTokenChainSkipBackToStartOfTemplateAngleBracket(CXXToken * t)
{
	if(!t)
		return NULL;
	CXX_DEBUG_ASSERT(
			t->eType == CXXTokenTypeGreaterThanSign,
			"This function must be called when pointing to a >"
		);
	int iLevel = 1;
	t = t->pPrev;
	while(t)
	{
		if(cxxTokenTypeIs(t,CXXTokenTypeGreaterThanSign))
		{
			iLevel++;
		} else if(cxxTokenTypeIs(t,CXXTokenTypeSmallerThanSign))
		{
			if(iLevel == 1)
				return t;
			iLevel--;
		}
		t = t->pPrev;
	}
	// invalid
	return NULL;
}
Пример #7
0
boolean cxxTagFieldEnabled(unsigned int uField)
{
	CXX_DEBUG_ASSERT(
			uField < g_cxx.uFieldOptionCount,
			"The field must be associated to the current language!"
		);
	return g_cxx.pFieldOptions[uField].enabled;
}
Пример #8
0
boolean cxxTagKindEnabled(unsigned int uKind)
{
	CXX_DEBUG_ASSERT(
			uKind < g_cxx.uKindOptionCount,
			"The kind must be associated to the current language!"
		);
	return g_cxx.pKindOptions[uKind].enabled;
}
Пример #9
0
void cxxTokenChainDestroyRange(CXXTokenChain * pChain,CXXToken * from,CXXToken * to)
{
	if(!from || !to)
		return;
	CXX_DEBUG_ASSERT(from,"Bad from pointer passed to cxxTokenChainDestroyRange");
	CXX_DEBUG_ASSERT(to,"Bad to pointer passed to cxxTokenChainDestroyRange");

	for(;;)
	{
		CXXToken * next = from->pNext;
		cxxTokenChainTake(pChain,from);
		cxxTokenDestroy(from);
		if(from == to) // may be compared even if invalid
			return;
		from = next;
		CXX_DEBUG_ASSERT(from,"Should NOT have found chain termination here");
	}
}
Пример #10
0
//
// This has to be called when pointing at an opening bracket in function scope.
// Returns NULL if it does not look to be a lambda invocation.
// Returns the lambda parameter parenthesis chain token if it DOES look like a
// lambda invocation.
//
CXXToken * cxxParserOpeningBracketIsLambda(void)
{
	// [ capture-list ] ( params ) mutable(opt) exception attr -> ret {} (1)
	// [ capture-list ] ( params ) -> ret { body }	(2)
	// [ capture-list ] ( params ) { body }	(3)
	// [ capture-list ] { body }	(4)

	CXX_DEBUG_ASSERT(cxxParserCurrentLanguageIsCPP(),"C++ only");

	CXXToken * t = g_cxx.pToken->pPrev;

	if(!t)
		return NULL; // not a lambda

	// Check simple cases first

	// case 4
	if(cxxTokenTypeIs(t,CXXTokenTypeSquareParenthesisChain))
	{
		// very likely parameterless lambda
		return t;
	}

	// case 3
	if(cxxTokenTypeIs(t,CXXTokenTypeParenthesisChain))
	{
		t = t->pPrev;
		if(!t)
			return NULL; // can't be

		if(cxxTokenTypeIs(t,CXXTokenTypeSquareParenthesisChain))
			return t->pNext;

		return NULL;
	}

	// Stop also at commas, so in very large structures we will not be searching far
	t = cxxTokenChainPreviousTokenOfType(
			t,
			CXXTokenTypeSquareParenthesisChain |
			CXXTokenTypeComma
		);

	if(!t)
		return NULL;

	if(!cxxTokenTypeIs(t,CXXTokenTypeSquareParenthesisChain))
		return NULL;

	t = t->pNext;

	if(cxxTokenTypeIs(t,CXXTokenTypeParenthesisChain))
		return t;

	return NULL;
}
Пример #11
0
void cxxScopePushTop(CXXToken * t)
{
	CXX_DEBUG_ASSERT(
			t->eType == CXXTokenTypeIdentifier,
			"The scope name must be an identifier"
		);
	CXX_DEBUG_ASSERT(
			t->pszWord,
			"The scope name should have a text"
		);

	cxxTokenChainAppend(g_pScope,t);
	g_bScopeNameDirty = true;

#ifdef CXX_DO_DEBUGGING
	const char * szScopeName = cxxScopeGetFullName();

	CXX_DEBUG_PRINT("Pushed scope: '%s'",szScopeName ? szScopeName : "");
#endif
}
Пример #12
0
void cxxTagSetField(unsigned int uField,const char * szValue)
{
	CXX_DEBUG_ASSERT(
			uField < g_cxx.uFieldOptionCount,
			"The field must be associated to the current language!"
		);

	if(!g_cxx.pFieldOptions[uField].enabled)
		return;

	attachParserField(&g_oCXXTag,g_cxx.pFieldOptions[uField].ftype,szValue);
}
Пример #13
0
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);
}
Пример #14
0
// This is called when we encounter a "public", "protected" or "private" keyword
// that is NOT in the class declaration header line.
boolean cxxParserParseAccessSpecifier(void)
{
	CXX_DEBUG_ENTER();

	enum CXXTagKind eScopeKind = cxxScopeGetKind();

	if(
			(eScopeKind != CXXTagKindCLASS) &&
			(eScopeKind != CXXTagKindSTRUCT) &&
			(eScopeKind != CXXTagKindUNION)
		)
	{
		// this is a syntax error: we're in the wrong scope.
		CXX_DEBUG_LEAVE_TEXT(
				"Access specified in wrong context (%d): "
					"bailing out to avoid reporting broken structure",
				eScopeKind
			);
		return FALSE;
	}

	switch(g_cxx.pToken->eKeyword)
	{
		case CXXKeywordPUBLIC:
			cxxScopeSetAccess(CXXScopeAccessPublic);
		break;
		case CXXKeywordPRIVATE:
			cxxScopeSetAccess(CXXScopeAccessPrivate);
		break;
		case CXXKeywordPROTECTED:
			cxxScopeSetAccess(CXXScopeAccessProtected);
		break;
		default:
			CXX_DEBUG_ASSERT(FALSE,"Bad keyword in cxxParserParseAccessSpecifier!");
		break;
	}

	// skip to the next :, without leaving scope.
	if(!cxxParserParseUpToOneOf(
			CXXTokenTypeSingleColon | CXXTokenTypeSemicolon |
				CXXTokenTypeClosingBracket | CXXTokenTypeEOF
		))
	{
		CXX_DEBUG_LEAVE_TEXT("Failed to parse up to the next ;");
		return FALSE;
	}

	cxxTokenChainClear(g_cxx.pTokenChain);
	CXX_DEBUG_LEAVE();
	return TRUE;
}
Пример #15
0
void cxxTokenChainMoveEntryRange(
		CXXTokenChain * src,
		CXXToken * start,
		CXXToken * end,
		CXXTokenChain * dest
	)
{
	if(!src || !dest || !start || !end)
		return;

	CXX_DEBUG_ASSERT(
			cxxTokenChainFindToken(src,start) >= 0,
			"The start token must be in the source chain!"
		);
	CXX_DEBUG_ASSERT(
			cxxTokenChainFindToken(src,end) >= 0,
			"The end token must be in the source chain!"
		);
	CXX_DEBUG_ASSERT(
			cxxTokenChainFindToken(src,start) <= cxxTokenChainFindToken(src,end),
			"The start token must come before the end token"
		);

	CXXToken * t = start;
	for(;;)
	{
		CXXToken * next = t->pNext;

		cxxTokenChainTake(src,t);
		cxxTokenChainAppend(dest,t);

		if(t == end)
			break;

		t = next;
	}
}
Пример #16
0
CXXToken * cxxTagCheckAndSetTypeField(
		CXXToken * pTypeStart,
		CXXToken * pTypeEnd
	)
{
	CXX_DEBUG_ASSERT(pTypeStart && pTypeEnd,"Non null parameters are expected");

	const char * szTypeRef0;

	// "typename" is debatable since it's not really
	// allowed by C++ for unqualified types. However I haven't been able
	// to come up with something better... so "typename" it is for now.
	static const char * szTypename = "typename";

	if(pTypeStart != pTypeEnd)
	{
		// Note that this does not work for types like "const enum X"
		// But that's not backward compatible anyway, so we live with it.
		if(
				cxxTokenTypeIs(pTypeStart,CXXTokenTypeKeyword) &&
				cxxKeywordIsTypeRefMarker(pTypeStart->eKeyword)
			)
		{
			szTypeRef0 = cxxKeywordName(pTypeStart->eKeyword);
			pTypeStart = pTypeStart->pNext;
		} else {
			szTypeRef0 = szTypename;
		}
	} else {
		szTypeRef0 = szTypename;
	}

	if(!cxxTagCheckTypeField(pTypeStart,pTypeEnd))
	{
		CXX_DEBUG_PRINT("Type name looks suspicious: refusing to emit it");
		return NULL;
	}

	cxxTokenChainNormalizeTypeNameSpacingInRange(pTypeStart,pTypeEnd);
	CXXToken * pTypeName = cxxTokenChainExtractRange(pTypeStart,pTypeEnd,0);

	CXX_DEBUG_PRINT("Type name is '%s'",vStringValue(pTypeName->pszWord));

	g_oCXXTag.extensionFields.typeRef[0] = szTypeRef0;
	g_oCXXTag.extensionFields.typeRef[1] = vStringValue(pTypeName->pszWord);

	return pTypeName;
}
Пример #17
0
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
}
Пример #18
0
void cxxTokenAppendToString(vString * s,CXXToken * t)
{
	switch(t->eType)
	{
		case CXXTokenTypeParenthesisChain:
		case CXXTokenTypeSquareParenthesisChain:
		case CXXTokenTypeBracketChain:
		case CXXTokenTypeAngleBracketChain:
			CXX_DEBUG_ASSERT(t->pChain,"This token should have a nested chain!");
			cxxTokenChainJoinInString(t->pChain,s,NULL,0);
		break;
		default:
			vStringCat(s,t->pszWord);
		break;
	}
}
Пример #19
0
void cxxTokenForceDestroy(CXXToken * t)
{
	if(!t)
		return;

	if(t->pChain)
	{
		cxxTokenChainDestroy(t->pChain);
		t->pChain = NULL;
	}

	CXX_DEBUG_ASSERT(t->pszWord,"There should be a word here");

	vStringDelete(t->pszWord);

	eFree(t);
}
Пример #20
0
void cxxTagInitForLanguage(langType eLanguage)
{
	g_cxx.eLanguage = eLanguage;

	if(g_cxx.eLanguage == g_cxx.eCLanguage)
	{
		g_cxx.pKindOptions = g_aCXXCKinds;
		g_cxx.uKindOptionCount = sizeof(g_aCXXCKinds) / sizeof(kindOption);
		g_cxx.pFieldOptions = g_aCXXCFields;
		g_cxx.uFieldOptionCount = sizeof(g_aCXXCFields) / sizeof(fieldSpec);
	} else if(g_cxx.eLanguage == g_cxx.eCPPLanguage)
	{
		g_cxx.pKindOptions = g_aCXXCPPKinds;
		g_cxx.uKindOptionCount = sizeof(g_aCXXCPPKinds) / sizeof(kindOption);
		g_cxx.pFieldOptions = g_aCXXCPPFields;
		g_cxx.uFieldOptionCount = sizeof(g_aCXXCPPFields) / sizeof(fieldSpec);
	} else {
		CXX_DEBUG_ASSERT(FALSE,"Invalid language passed to cxxTagInitForLanguage()");
	}
}
Пример #21
0
//
// 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;
}
Пример #22
0
//
// Attach the current position of input file as "end" field of
// the specified tag in the cork queue
//
void cxxParserMarkEndLineForTagInCorkQueue(int iCorkQueueIndex)
{
	CXX_DEBUG_ASSERT(iCorkQueueIndex > CORK_NIL,"The cork queue index is not valid");

	char buf[16];

	if(cxxParserCurrentLanguageIsCPP())
	{
		if(!cxxTagCPPFieldEnabled(CXXTagCPPFieldEndLine))
			return;

		sprintf(buf,"%ld",getInputLineNumber());
		cxxTagSetCorkQueueCPPField(iCorkQueueIndex,CXXTagCPPFieldEndLine,buf);
		return;
	}

	if(!cxxTagCFieldEnabled(CXXTagCFieldEndLine))
		return;

	sprintf(buf,"%ld",getInputLineNumber());
	cxxTagSetCorkQueueCField(iCorkQueueIndex,CXXTagCFieldEndLine,buf);
}
Пример #23
0
CXXToken * cxxTokenCreate(void)
{
	CXXToken * t;

	if(g_pTokenPool->iCount > 0)
	{
		t = cxxTokenChainTakeFirst(g_pTokenPool);
		CXX_DEBUG_ASSERT(t->pszWord,"The string shouldn't have been destroyed");
	} else {
		t = xMalloc(sizeof(CXXToken),CXXToken);
		// we almost always want a string, and since this token
		// is being reused..well.. we always want it
		t->pszWord = vStringNew();
	}

	t->bFollowedBySpace = FALSE;

	t->pChain = NULL;
	t->pNext = NULL;
	t->pPrev = NULL;

	return t;
}
Пример #24
0
void cxxTokenDestroy(CXXToken * t)
{
	if(!t)
		return;

	if(t->pChain)
	{
		cxxTokenChainDestroy(t->pChain);
		t->pChain = NULL;
	}

	CXX_DEBUG_ASSERT(t->pszWord,"There should be a word here");

	if(g_pTokenPool->iCount < CXX_TOKEN_POOL_MAXIMUM_SIZE)
	{
		// this won't actually release memory (but we're taking care
		// to do not create very large strings)
		vStringClear(t->pszWord);
		cxxTokenChainAppend(g_pTokenPool,t);
	} else {
		vStringDelete(t->pszWord);
		eFree(t);
	}
}
Пример #25
0
// 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();
}
Пример #26
0
// In case of a lambda without parentheses this is the capture list token.
boolean cxxParserHandleLambda(CXXToken * pParenthesis)
{
	CXX_DEBUG_ENTER();

	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;

		while(
				(pTypeStart != pTypeEnd) &&
				cxxTokenTypeIs(pTypeStart,CXXTokenTypeKeyword) &&
				cxxKeywordExcludeFromTypeNames(pTypeStart->eKeyword)
			)
			pTypeStart = pTypeStart->pNext;
	}

	int iCorkQueueIndex = CORK_NIL;

	if(tag)
	{
		tag->isFileScope = TRUE;

		CXXToken * pTypeName;

		if(pTypeStart)
			pTypeName = cxxTagSetTypeField(pTypeStart,pTypeEnd);
		else
			pTypeName = NULL;

		if(pCaptureList && cxxTagCPPFieldEnabled(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"
				);
			cxxTagSetCPPField(
					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,
			CXXTagKindFUNCTION,
			CXXScopeAccessUnknown
		);

	if(
		pParenthesis &&
		cxxTokenTypeIs(pParenthesis,CXXTokenTypeParenthesisChain) &&
		cxxTagKindEnabled(CXXTagKindPARAMETER)
	)
	{
		CXXFunctionParameterInfo oParamInfo;
		if(cxxParserTokenChainLooksLikeFunctionParameterList(
				pParenthesis->pChain,&oParamInfo
			))
			cxxParserEmitFunctionParameterTags(&oParamInfo);
	}

	boolean 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;
	vStringCatS(t->pszWord,"{");
	cxxTokenChainAppend(pNew,t);

	t = cxxTokenCreate();
	t->eType = CXXTokenTypeClosingBracket;
	vStringCatS(t->pszWord,"}");
	cxxTokenChainAppend(pNew,t);

	CXX_DEBUG_LEAVE();
	return bRet;
}
Пример #27
0
boolean cxxParserParseNamespace(void)
{
	CXX_DEBUG_ENTER();

	CXX_DEBUG_ASSERT(cxxParserCurrentLanguageIsCPP(),"This should be called only in C++");

	/*
		Spec is:

			namespace ns_name { declarations }	(1)
			inline namespace ns_name { declarations }	(2)	(since C++11)
			namespace { declarations }	(3)
			namespace name = qualified-namespace ;	(7)
			namespace ns_name::name	{ (8)	(since C++17)

		Note that the using clauses have their own parsing routine and do not end up here.
	*/

	// namespace <X> {
	// namespace <X>::<Y>::<Z> {
	// namespace <X>::<Y>::<Z>;
	// namespace <X>;
	// namespace;

	unsigned int uProperties = 0;

	if(cxxTagFieldEnabled(CXXTagFieldProperties))
	{
		if(g_cxx.uKeywordState & CXXParserKeywordStateSeenInline)
			uProperties |= CXXTagPropertyInline;
	}

	cxxParserNewStatement(); // always a new statement

	int iScopeCount = 0;

	int i;

	int aCorkQueueIndices[MAX_NESTED_NAMESPACES];

	for(i=0;i<MAX_NESTED_NAMESPACES;i++)
		aCorkQueueIndices[i] = CORK_NIL;

	if(!cxxParserParseNextToken())
	{
		// syntax error, but we tolerate this
		CXX_DEBUG_LEAVE_TEXT("Implicit EOF in cxxParserParseNextToken");
		return TRUE; // EOF
	}

	if(cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeIdentifier))
	{
		// OK, check next token to see what's coming after

		CXX_DEBUG_PRINT("Got identifier %s",g_cxx.pToken->pszWord->buffer);

		CXXToken * pFirstIdentifier = g_cxx.pToken;
		CXXToken * pLastIdentifier = g_cxx.pToken;

		if(!cxxParserParseNextToken())
		{
			// syntax error, but we tolerate this
			CXX_DEBUG_LEAVE_TEXT("EOF in cxxParserParseNextToken");
			return TRUE; // EOF
		}

		switch(g_cxx.pToken->eType)
		{
			case CXXTokenTypeAssignment:
			{
				// probably namespace alias
				CXX_DEBUG_PRINT("Found assignment");

				if(!cxxParserParseNextToken())
				{
					// syntax error, but we tolerate this
					CXX_DEBUG_LEAVE_TEXT("EOF in cxxParserParseNextToken");
					return TRUE; // EOF
				}

				if(!cxxTokenTypeIsOneOf(
						g_cxx.pToken,
						CXXTokenTypeIdentifier | CXXTokenTypeMultipleColons
					))
				{
					CXX_DEBUG_LEAVE_TEXT("Some kind of syntax error here");
					return cxxParserSkipToSemicolonOrEOF();
				}

				CXXToken * pAlias = pFirstIdentifier;
				pFirstIdentifier = g_cxx.pToken;

				if(!cxxParserParseToEndOfQualifedName())
				{
					CXX_DEBUG_LEAVE_TEXT("Failed to parse the aliased name");
					return cxxParserSkipToSemicolonOrEOF();
				}

				pLastIdentifier = g_cxx.pToken->pPrev;

				tagEntryInfo * tag = cxxTagBegin(CXXTagCPPKindALIAS,pAlias);

				if(tag)
				{
					// This is highly questionable but well.. it's how old ctags did, so we do.
					tag->isFileScope = !isInputHeaderFile();

					CXXToken * pAliasedName = cxxTokenChainExtractRange(
							pFirstIdentifier,
							pLastIdentifier,
							CXXTokenChainExtractRangeNoTrailingSpaces
						);

					cxxTagSetField(
							CXXTagCPPFieldAliasedName,
							vStringValue(pAliasedName->pszWord)
						);

					cxxTagCommit();

					cxxTokenDestroy(pAliasedName);
				}

				CXX_DEBUG_LEAVE_TEXT("Finished parsing namespace alias");
				return cxxParserSkipToSemicolonOrEOF();
			}
			break;
			case CXXTokenTypeMultipleColons:
				// multi-namespace
				CXX_DEBUG_PRINT("Found multiple colons");

				if(!cxxParserParseToEndOfQualifedName())
				{
					CXX_DEBUG_LEAVE_TEXT("Failed to parse the namespace name");
					return cxxParserSkipToSemicolonOrEOF();
				}

				pLastIdentifier = g_cxx.pToken->pPrev;

				CXX_DEBUG_ASSERT(
						pFirstIdentifier != pLastIdentifier,
						"We expected multiple identifiers here"
					);

				if(!cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeOpeningBracket))
				{
					if(!cxxParserParseUpToOneOf(
							CXXTokenTypeOpeningBracket | CXXTokenTypeSemicolon | CXXTokenTypeEOF
						))
					{
						CXX_DEBUG_LEAVE_TEXT("Failed to parse up to an opening bracket");
						return FALSE;
					}

					if(!cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeOpeningBracket))
					{
						// tolerate syntax error
						CXX_DEBUG_LEAVE_TEXT("Found semicolon just after namespace declaration");
						return TRUE;
					}

					CXX_DEBUG_LEAVE_TEXT("Was expecting an opening bracket here");
					// FIXME: Maybe we could attempt to recover here?
					return TRUE;
				}
			break;
			case CXXTokenTypeOpeningBracket:
				// single name namespace
				CXX_DEBUG_PRINT("Found opening bracket");
			break;
			case CXXTokenTypeSemicolon:
				// tolerate syntax error
				CXX_DEBUG_LEAVE_TEXT("Found semicolon just after namespace declaration");
				return TRUE;
			break;
			default:
				CXX_DEBUG_LEAVE_TEXT("Some kind of syntax error here");
				return cxxParserSkipToSemicolonOrEOF();
			break;
		}

		CXX_DEBUG_ASSERT(
				cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeOpeningBracket),
				"Should have an opening bracket here!"
			);

		CXX_DEBUG_PRINT("Found regular namespace start");

		CXXToken * t = pFirstIdentifier;

		while(t)
		{
			tagEntryInfo * tag = cxxTagBegin(CXXTagCPPKindNAMESPACE,t);

			if(tag)
			{
				// This is highly questionable but well.. it's how old ctags did, so we do.
				tag->isFileScope = !isInputHeaderFile();

				vString * pszProperties = uProperties ? cxxTagSetProperties(uProperties) : NULL;

				int iCorkQueueIndex = cxxTagCommit();

				if(iScopeCount < MAX_NESTED_NAMESPACES)
					aCorkQueueIndices[iScopeCount] = iCorkQueueIndex;

				if(pszProperties)
					vStringDelete(pszProperties);
			}

			CXXToken * pNext = (t == pLastIdentifier) ? NULL : t->pNext->pNext;

			cxxTokenChainTake(g_cxx.pTokenChain,t);

			cxxScopePush(
					t,
					CXXScopeTypeNamespace,
					CXXScopeAccessUnknown
				);

			iScopeCount++;

			t = pNext;
		}

	} else if(cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeOpeningBracket))
	{
		// anonymous namespace
		CXX_DEBUG_PRINT("Found anonymous namespace start");

		CXXToken * t = cxxTokenCreateAnonymousIdentifier(CXXTagCPPKindNAMESPACE);
		tagEntryInfo * tag = cxxTagBegin(CXXTagCPPKindNAMESPACE,t);
		if(tag)
		{
			tag->isFileScope = !isInputHeaderFile();

			vString * pszProperties = uProperties ? cxxTagSetProperties(uProperties) : NULL;

			aCorkQueueIndices[0] = cxxTagCommit();

			if(pszProperties)
				vStringDelete(pszProperties);
		}
		cxxScopePush(t,CXXScopeTypeNamespace,CXXScopeAccessUnknown);

		iScopeCount++;

	} else {

		CXX_DEBUG_LEAVE_TEXT("Some kind of syntax error after namespace declaration");
		return cxxParserSkipToSemicolonOrEOF();
	}

	CXX_DEBUG_ASSERT(
			cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeOpeningBracket),
			"Should have an opening bracket here!"
		);

	// Here we certainly got an opening bracket: namespace block

	if(!cxxParserParseBlock(TRUE))
	{
		CXX_DEBUG_LEAVE_TEXT("Failed to parse namespace block");
		return FALSE;
	}

	while(iScopeCount > 0)
	{
		cxxScopePop();
		iScopeCount--;

		if(aCorkQueueIndices[iScopeCount] > CORK_NIL)
			cxxParserMarkEndLineForTagInCorkQueue(aCorkQueueIndices[iScopeCount]);
	}

	CXX_DEBUG_LEAVE_TEXT("Finished parsing namespace");
	return TRUE;
}
Пример #28
0
//
// Attempt to extract variable declarations from the chain.
// Returns true if at least one variable was extracted.
// Returns false if a variable declaration could not be identified.
//
// Recognized variable declarations are of the following kinds:
//
//   type var;
//   type var1,var2;
//   type var[];
//   type var(constructor args);
//   type var{list initializer};
//   type var = ...;
//   type (*ident)();
//   type var:bits;
//   type var: range declaration <-- (FIXME: this is only inside for!)
//   very complex type with modifiers() namespace::namespace::var = ...;
//   type<with template> namespace::var[] = {
//   ...
//
// Assumptions:
//  - there is a terminator at the end: either ; or {
//
// Notes:
// - Be aware that if this function returns true then the pChain very likely has been modified
//   (partially destroyed) as part of the type extraction algorithm.
//   If the function returns false the chain has not been modified (and
//   to extract something else from it).
//
// - This function is quite tricky.
//
bool cxxParserExtractVariableDeclarations(CXXTokenChain * pChain,unsigned int uFlags)
{
	CXX_DEBUG_ENTER();

	if(pChain->iCount < 1)
	{
		CXX_DEBUG_LEAVE_TEXT("Chain is empty");
		return false;
	}

#ifdef CXX_DO_DEBUGGING
	vString * pJoinedChain = cxxTokenChainJoin(pChain,NULL,0);
	CXX_DEBUG_PRINT(
			"Looking for variable declarations in '%s'",
			vStringValue(pJoinedChain)
		);
	vStringDelete(pJoinedChain);
#endif

	//
	// Strategy:
	//   - verify that the chain starts with an identifier or keyword (always present)
	//   - run to one of : ; [] () {} = ,
	//   - ensure that the previous token is an identifier (except for special cases)
	//   - go back to skip the eventual scope
	//   - ensure that there is a leading type
	//   - if we are at : [], () or {} then run to the next ; = or ,
	//   - once we have determined that a variable declaration is there
	//     modify the chain to contain only the type name
	//   - emit variable tag
	//   - if we are at , then check if there are more declarations
	//

	CXXToken * t = cxxTokenChainFirst(pChain);

	enum CXXScopeType eScopeType = cxxScopeGetType();

	CXX_DEBUG_ASSERT(t,"There should be an initial token here");

	if(!cxxTokenTypeIsOneOf(t,CXXTokenTypeIdentifier | CXXTokenTypeKeyword))
	{
		CXX_DEBUG_LEAVE_TEXT("Statement does not start with identifier or keyword");
		return false;
	}

	// Handle the special case of delete/new keywords at the beginning
	if(
			cxxTokenTypeIs(t,CXXTokenTypeKeyword) &&
			(
				(t->eKeyword == CXXKeywordDELETE) ||
				(t->eKeyword == CXXKeywordNEW)
			)
		)
	{
		CXX_DEBUG_LEAVE_TEXT("Statement looks like a delete or new call");
		return false;
	}

	bool bGotVariable = false;

	// Loop over the whole statement.

	while(t)
	{
		// Scan up to a notable token: ()[]{}=,;:{

		while(t)
		{
			if(cxxTokenTypeIsOneOf(
						t,
						CXXTokenTypeSingleColon | CXXTokenTypeParenthesisChain |
							CXXTokenTypeSquareParenthesisChain | CXXTokenTypeBracketChain |
							CXXTokenTypeAssignment | CXXTokenTypeComma |
							CXXTokenTypeSemicolon | CXXTokenTypeOpeningBracket
					))
			{
				// Notable token reached.
				break;
			}

			if(
				cxxTokenTypeIsOneOf(
						t,
						CXXTokenTypeOperator | CXXTokenTypeMultipleAnds |
							CXXTokenTypePointerOperator | CXXTokenTypeStringConstant |
							CXXTokenTypeAngleBracketChain | CXXTokenTypeCharacterConstant |
							CXXTokenTypeMultipleDots | CXXTokenTypeClosingBracket |
							CXXTokenTypeClosingParenthesis | CXXTokenTypeClosingSquareParenthesis |
							CXXTokenTypeGreaterThanSign
					)
				)
			{
				// Something that should not appear in a variable declaration
				CXX_DEBUG_LEAVE_TEXT(
						"Found token '%s' of type 0x%02x that should " \
							"not appear in the initial part of a variable declaration",
						vStringValue(t->pszWord),
						t->eType
					);
				return bGotVariable;
			}

			if(t->eType == CXXTokenTypeSmallerThanSign)
			{
				// Must be part of template type name (so properly balanced).
				t = cxxTokenChainSkipToEndOfTemplateAngleBracket(t);
				if(!t)
				{
					CXX_DEBUG_LEAVE_TEXT("Failed to skip past angle bracket chain");
					return bGotVariable;
				}
			}

			t = t->pNext;
		}

		// Notable token reached?

		if(!t)
		{
			CXX_DEBUG_LEAVE_TEXT("Nothing interesting here");
			return bGotVariable;
		}

		CXX_DEBUG_PRINT(
				"Found notable token '%s' of type 0x%02x(%s)",
				vStringValue(t->pszWord),
				t->eType,
				cxxDebugTypeDecode(t->eType)
			);

		// Now before the notable token there MUST be an identifier
		// (eventually hidden in a parenthesis chain) and also a typename.
		if(!t->pPrev)
		{
			CXX_DEBUG_LEAVE_TEXT("Nothing interesting before notable token");
			return bGotVariable;
		}

		CXXToken * pIdentifier = NULL;
		CXXToken * pTokenBefore = NULL;

		// If we have to continue scanning we'll remove the tokens from here
		// so they don't end up being part of the type name.
		// If this is set to NULL then it means that we cannot determine properly
		// what to remove and we should stop scanning after the current variable.
		CXXToken * pRemoveStart = t;

		switch(t->eType)
		{
			case CXXTokenTypeParenthesisChain:
			{
				// At a parenthesis chain we need some additional checks.
				if(
						// check for function pointers or nasty arrays
						// Possible cases:
						//    ret type (*variable)(params)
						//    ret type (* const (variable[4]))(params)
						t->pNext &&
						(
							(
								cxxTokenTypeIs(t->pNext,CXXTokenTypeParenthesisChain) &&
								cxxParserTokenChainLooksLikeFunctionParameterList(
										t->pNext->pChain,
										NULL
									)
							) ||
							cxxTokenTypeIs(t->pNext,CXXTokenTypeSquareParenthesisChain)
						) &&
						(pIdentifier = cxxTokenChainFirstPossiblyNestedTokenOfType(
								t->pChain,
								CXXTokenTypeIdentifier,
								NULL
							)) &&
						// Discard function declarations with function return types
						// like void (*A(B))(C);
						(
							(!pIdentifier->pNext) ||
							(!cxxTokenTypeIs(pIdentifier->pNext,CXXTokenTypeParenthesisChain))
						)
					)
				{
					// A function pointer.
					// There are two parentheses, skip the second too.
					pTokenBefore = t->pPrev;
					t = t->pNext->pNext;
					pRemoveStart = t;
				} else if(
						(t->pChain->iCount == 3) &&
						cxxTokenTypeIs(
								cxxTokenChainAt(t->pChain,1),
								CXXTokenTypeParenthesisChain
							) &&
						t->pPrev &&
						cxxTokenTypeIs(t->pPrev,CXXTokenTypeIdentifier) &&
						t->pPrev->pPrev &&
						cxxTokenTypeIs(t->pPrev->pPrev,CXXTokenTypeIdentifier)
					)
				{
					CXX_DEBUG_LEAVE_TEXT("Parenthesis seems to define an __ARGS style prototype");
					return bGotVariable;
				} else if(
						cxxTokenTypeIs(t->pPrev,CXXTokenTypeIdentifier) &&
						(
							(eScopeType == CXXScopeTypeNamespace) ||
							(eScopeType == CXXScopeTypeFunction)
						) &&
						cxxParserCurrentLanguageIsCPP() &&
						cxxParserTokenChainLooksLikeConstructorParameterSet(t->pChain)
					)
				{
					// ok, *might* be variable instantiation
					pIdentifier = t->pPrev;
					pTokenBefore = pIdentifier->pPrev;
				} else {
					CXX_DEBUG_LEAVE_TEXT("No recognizable parenthesis form for a variable");
					return bGotVariable;
				}
			}
			break;
			case CXXTokenTypeBracketChain:
				if(
						cxxTokenTypeIs(t->pPrev,CXXTokenTypeIdentifier) &&
						cxxParserCurrentLanguageIsCPP() &&
						cxxParserTokenChainLooksLikeConstructorParameterSet(t->pChain)
					)
				{
					// ok, *might* be new C++ style variable initialization
					pIdentifier = t->pPrev;
					pTokenBefore = pIdentifier->pPrev;
				} else {
					CXX_DEBUG_LEAVE_TEXT("Bracket chain that doesn't look like a C++ var init");
					return bGotVariable;
				}
			break;
			case CXXTokenTypeSingleColon:
				// check for bitfield
				if(
						t->pNext &&
						cxxTokenTypeIsOneOf(t->pNext,CXXTokenTypeNumber | CXXTokenTypeIdentifier)
					)
				{
					// ok, looks like a bit field
					if(
							cxxTokenTypeIs(t->pNext,CXXTokenTypeNumber) &&
							t->pNext->pNext &&
							cxxTokenTypeIsOneOf(
									t->pNext->pNext,
									CXXTokenTypeComma | CXXTokenTypeSemicolon |
									CXXTokenTypeAssignment
								)
						)
					{
						// keep bitfield width specification as part of type
						pIdentifier = t->pPrev;
						pTokenBefore = pIdentifier->pPrev;
						t = t->pNext->pNext;
					} else {
						// Too complex: strip width specification (the best we can do)
						pIdentifier = t->pPrev;
						pTokenBefore = pIdentifier->pPrev;
					}
				} else {
					CXX_DEBUG_LEAVE_TEXT("Single colon that doesn't look like a bit field");
					return bGotVariable;
				}
			break;
			case CXXTokenTypeSquareParenthesisChain:
				// check for array
				// Keep the array specifier as part of type

				pIdentifier = t->pPrev;
				pTokenBefore = pIdentifier->pPrev;

				while(t->pNext && cxxTokenTypeIs(t->pNext,CXXTokenTypeSquareParenthesisChain))
					t = t->pNext;

				if(!t->pNext)
				{
					CXX_DEBUG_LEAVE_TEXT("No token after []");
					return bGotVariable;
				}

				// skip identifies attached to the array as attributes
				while(t->pNext && cxxTokenTypeIs(t->pNext, CXXTokenTypeIdentifier))
				{
					t = t->pNext;
					// skip macro argument(s)
					if (t->pNext && cxxTokenTypeIs(t->pNext, CXXTokenTypeParenthesisChain))
						t = t->pNext;
				}

				if (!t->pNext)
				{
					CXX_DEBUG_LEAVE_TEXT("No token after attribute(s) attached to []");
					return bGotVariable;
				}

				if(!cxxTokenTypeIsOneOf(
							t->pNext,
							CXXTokenTypeComma | CXXTokenTypeSemicolon |
							CXXTokenTypeAssignment | CXXTokenTypeBracketChain
							))
				{
					CXX_DEBUG_LEAVE_TEXT("No comma, semicolon, = or {} after [] (\"%s\", %s)",
								vStringValue (t->pNext->pszWord),
								cxxDebugTypeDecode (t->pNext->eType));
					return bGotVariable;
				}

				t = t->pNext;
				pRemoveStart = t;
			break;
			default:
				// Must be identifier
				if(t->pPrev->eType != CXXTokenTypeIdentifier)
				{
					CXX_DEBUG_LEAVE_TEXT("No identifier before the notable token");
					return bGotVariable;
				}

				pIdentifier = t->pPrev;
				pTokenBefore = pIdentifier->pPrev;
			break;
		}

		CXX_DEBUG_ASSERT(pIdentifier,"We should have found an identifier here");

		if(!pTokenBefore)
		{
			CXX_DEBUG_LEAVE_TEXT("Identifier not preceded by a type");

			// Here we can handle yet another one of the gazillion of special cases.
			//
			//    MACRO(whatever) variable;
			//
			if(
					cxxTokenTypeIs(t,CXXTokenTypeParenthesisChain) &&
					t->pNext &&
					cxxTokenTypeIs(t->pNext,CXXTokenTypeIdentifier) &&
					t->pNext->pNext &&
					cxxTokenTypeIs(t->pNext->pNext,CXXTokenTypeSemicolon)
				)
			{
				CXX_DEBUG_PRINT("Looks like the 'MACRO(whatever) variable;' special case");
				pIdentifier = t->pNext;
				pTokenBefore = t;
				t = t->pNext->pNext;
			} else {
				return bGotVariable;
			}
		}

		CXXToken * pScopeEnd = pTokenBefore->pNext;
		CXXToken * pScopeStart = NULL;

		// Skip back to the beginning of the scope, if any
		while(pTokenBefore->eType == CXXTokenTypeMultipleColons)
		{
			if(!cxxParserCurrentLanguageIsCPP())
			{
				CXX_DEBUG_LEAVE_TEXT("Syntax error: found multiple colons in C language");
				return false;
			}

			pTokenBefore = pTokenBefore->pPrev;
			if(!pTokenBefore)
			{
				CXX_DEBUG_LEAVE_TEXT(
						"Identifier preceded by multiple colons " \
							"but not preceded by a type"
					);
				return bGotVariable;
			}

			if(cxxTokenTypeIs(pTokenBefore,CXXTokenTypeGreaterThanSign))
			{
				CXXToken * pAux = cxxTokenChainSkipBackToStartOfTemplateAngleBracket(pTokenBefore);
				if((!pAux) || (!pAux->pPrev))
				{
					CXX_DEBUG_LEAVE_TEXT(
							"Identifier preceded by multiple colons " \
								"and by a >, but failed to skip back to starting <"
						);
					return bGotVariable;
				}

				pTokenBefore = pAux->pPrev;
			}

			if(!cxxTokenTypeIs(pTokenBefore,CXXTokenTypeIdentifier))
			{
				CXX_DEBUG_LEAVE_TEXT(
						"Identifier preceded by multiple colons " \
							"with probable syntax error"
					);
				return bGotVariable;
			}

			pScopeStart = pTokenBefore;

			pTokenBefore = pTokenBefore->pPrev;
			if(!pTokenBefore)
			{
				CXX_DEBUG_LEAVE_TEXT(
						"Identifier preceded by multiple colons " \
							"but not preceded by a type"
					);
				return bGotVariable;
			}
		}

		if(!bGotVariable)
		{
			// now pTokenBefore should be part of a type (either the variable type or return
			// type of a function in case of a function pointer)
			if(!cxxTokenTypeIsOneOf(
					pTokenBefore,
					CXXTokenTypeIdentifier | CXXTokenTypeKeyword |
						CXXTokenTypeStar | CXXTokenTypeAnd
				))
			{
				if(cxxTokenTypeIs(pTokenBefore,CXXTokenTypeGreaterThanSign))
				{
					// the < > must be balanced
					CXXToken * t2 = pTokenBefore->pPrev;
					int iLevel = 1;
					while(t2)
					{
						if(cxxTokenTypeIs(t2,CXXTokenTypeGreaterThanSign))
							iLevel++;
						else if(cxxTokenTypeIs(t2,CXXTokenTypeSmallerThanSign))
							iLevel--;
						t2 = t2->pPrev;
					}
					if(iLevel != 0)
					{
						CXX_DEBUG_LEAVE_TEXT(
								"The > token is unbalanced and does not " \
									"seem to be part of type name"
							);
						return bGotVariable;
					}
				} else if(
						// Still 'MACRO(whatever) variable;' case
						cxxTokenTypeIs(pTokenBefore,CXXTokenTypeParenthesisChain) &&
						pTokenBefore->pPrev &&
						cxxTokenTypeIs(pTokenBefore->pPrev,CXXTokenTypeIdentifier) &&
						!pTokenBefore->pPrev->pPrev
					)
				{
					CXX_DEBUG_PRINT("Type seems to be hidden in a macro");
				} else {
					CXX_DEBUG_LEAVE_TEXT(
							"Token '%s' of type 0x%02x does not seem " \
								"to be part of type name",
							vStringValue(pTokenBefore->pszWord),
							pTokenBefore->eType
						);
					return bGotVariable;
				}
			}

			bGotVariable = true;
		}

		// Goodie. We have an identifier and almost certainly a type here.

		// From now on we start destroying the chain: mark the return value as true
		// so nobody else will try to extract stuff from it

		int iScopesPushed = 0;

		if(pScopeStart)
		{
			// Push the scopes and remove them from the chain so they are not in the way
			while(pScopeStart != pScopeEnd)
			{
				// This is the scope id START. It might contain
				// also other tokens like in ...::A<B>::...

				CXXToken * pPartEnd = cxxTokenChainNextTokenOfType(
						pScopeStart,
						CXXTokenTypeMultipleColons
					);
				CXX_DEBUG_ASSERT(
						pPartEnd,
						"We should have found multiple colons here!"
					);
				CXX_DEBUG_ASSERT(
						pPartEnd->pPrev,
						"And there should be a previous token too"
					);

				CXXToken * pScopeId = cxxTokenChainExtractRange(pScopeStart,pPartEnd->pPrev,0);
				cxxScopePush(
						pScopeId,
						CXXScopeTypeClass,
						// WARNING: We don't know if it's really a class! (FIXME?)
						CXXScopeAccessUnknown
					);

				CXXToken * pAux = pPartEnd->pNext;

				cxxTokenChainDestroyRange(pChain,pScopeStart,pPartEnd);

				pScopeStart = pAux;

				iScopesPushed++;
			}
		}

		bool bKnRStyleParameters =
				(uFlags & CXXExtractVariableDeclarationsKnRStyleParameters);

		tagEntryInfo * tag = cxxTagBegin(
				bKnRStyleParameters ?
					CXXTagKindPARAMETER :
					((g_cxx.uKeywordState & CXXParserKeywordStateSeenExtern) ?
							CXXTagKindEXTERNVAR : cxxScopeGetVariableKind()),
				pIdentifier
			);

		if(tag)
		{
			CXX_DEBUG_ASSERT(t != pIdentifier,"This should not happen");
			// remove the identifier
			cxxTokenChainTakeRecursive(pChain,pIdentifier);

			// Fix square parentheses: if they contain something that is not a numeric
			// constant then empty them up
			CXXToken * pPartOfType = t->pPrev;
			CXX_DEBUG_ASSERT(pPartOfType,"There should be a part of type name here");

			while(pPartOfType && cxxTokenTypeIs(pPartOfType,CXXTokenTypeSquareParenthesisChain))
			{
				CXXTokenChain * pAuxChain = pPartOfType->pChain;

				if(pAuxChain->iCount > 2)
				{
					if(
						(pAuxChain->iCount > 3) ||
						(!cxxTokenTypeIs(cxxTokenChainAt(pAuxChain,1),CXXTokenTypeNumber))
					)
					{
						cxxTokenChainDestroyRange(
								pAuxChain,
								cxxTokenChainFirst(pAuxChain)->pNext,
								cxxTokenChainLast(pAuxChain)->pPrev
							);
					}
				}
				pPartOfType = pPartOfType->pPrev;
			}

			// anything that remains is part of type
			CXXToken * pTypeToken = cxxTagCheckAndSetTypeField(cxxTokenChainFirst(pChain),t->pPrev);

			tag->isFileScope = bKnRStyleParameters ?
					true :
					(
						(
							(eScopeType == CXXScopeTypeNamespace) &&
							(g_cxx.uKeywordState & CXXParserKeywordStateSeenStatic) &&
							(!isInputHeaderFile())
						) ||
						// locals are always hidden
						(eScopeType == CXXScopeTypeFunction) ||
						(
							(eScopeType != CXXScopeTypeNamespace) &&
							(eScopeType != CXXScopeTypeFunction) &&
							(!isInputHeaderFile())
						)
					);

			vString * pszProperties = NULL;

			if(cxxTagFieldEnabled(CXXTagFieldProperties))
			{
				unsigned int uProperties = 0;

				if(g_cxx.uKeywordState & CXXParserKeywordStateSeenStatic)
					uProperties |= CXXTagPropertyStatic;
				if(g_cxx.uKeywordState & CXXParserKeywordStateSeenExtern)
					uProperties |= CXXTagPropertyExtern;
				if(g_cxx.uKeywordState & CXXParserKeywordStateSeenMutable)
					uProperties |= CXXTagPropertyMutable;
				if(g_cxx.uKeywordState & CXXParserKeywordStateSeenAttributeDeprecated)
					uProperties |= CXXTagPropertyDeprecated;
				// Volatile is part of the type, so we don't mark it as a property
				//if(g_cxx.uKeywordState & CXXParserKeywordStateSeenVolatile)
				//	uProperties |= CXXTagPropertyVolatile;

				pszProperties = cxxTagSetProperties(uProperties);
			}

			cxxTagCommit();

			if(pTypeToken)
				cxxTokenDestroy(pTypeToken);
			if(pszProperties)
				vStringDelete(pszProperties);
			cxxTokenDestroy(pIdentifier);
		}

		while(iScopesPushed > 0)
		{
			cxxScopePop();
			iScopesPushed--;
		}

		if(!t)
		{
			CXX_DEBUG_LEAVE_TEXT("Nothing more");
			return bGotVariable;
		}

		if(!cxxTokenTypeIsOneOf(
				t,
				CXXTokenTypeComma | CXXTokenTypeSemicolon | CXXTokenTypeOpeningBracket
			))
		{
			t = cxxTokenChainNextTokenOfType(
					t,
					CXXTokenTypeComma | CXXTokenTypeSemicolon | CXXTokenTypeOpeningBracket
				);
			if(!t)
			{
				CXX_DEBUG_LEAVE_TEXT("Didn't find a comma, semicolon or {");
				return bGotVariable;
			}
		}

		if(cxxTokenTypeIsOneOf(t,CXXTokenTypeSemicolon | CXXTokenTypeOpeningBracket))
		{
			CXX_DEBUG_LEAVE_TEXT("Noting else");
			return bGotVariable;
		}

		// Comma. Might have other declarations here.
		CXX_DEBUG_PRINT("At a comma, might have other declarations here");

		t = t->pNext;

		CXX_DEBUG_ASSERT(t,"There should be something after the comma here!");

		if(!pRemoveStart)
		{
			CXX_DEBUG_LEAVE_TEXT("Could not properly fix type name for next token: stopping here");
			return bGotVariable;
		}

		cxxTokenChainDestroyRange(pChain,pRemoveStart,t->pPrev);
	}

	CXX_DEBUG_LEAVE_TEXT("Reached end");
	return bGotVariable;
}
Пример #29
0
//
// Parses the <parameters> part of the template prefix.
// Here we are pointing at the initial < (but the token chain has been emptied by cxxParserParseTemplatePrefix())
//
static boolean cxxParserParseTemplatePrefixAngleBrackets(void)
{
	CXX_DEBUG_ENTER();

	// Here we have the big prolem of <> characters which may be
	// template argument delimiters, less than/greater than operators, shift left/right operators.
	//
	// A well written code will have parentheses around all the ambiguous cases. We handle that
	// and we permit any kind of syntax inside a parenthesis.
	//
	// Without parentheses we still try to handle the << and >> shift operator cases:
	// - << is always recognized as shift operator
	// - >> is recognized as shift unless it's non-nested. This is what C++11 spec says
	//      and theoretically it should be also pseudo-compatible with C++03 which treats this
	//      case as a syntax error.
	//
	// The 'less-than' and 'greater-than' operators are hopeless in the general case: gcc
	// is smart enough to figure them out by looking at the identifiers around but without
	// proper state (include headers, macro expansion, full type database etc) we simply can't
	// do the same. However, we try to recover if we figure out we (or the programmer?) screwed up.

	int iTemplateLevel = 0;

	for(;;)
	{
		// Within parentheses everything is permitted.
		if(!cxxParserParseAndCondenseSubchainsUpToOneOf(
				CXXTokenTypeGreaterThanSign | CXXTokenTypeSmallerThanSign | CXXTokenTypeOpeningBracket | CXXTokenTypeSemicolon | CXXTokenTypeEOF | CXXTokenTypeAssignment,
				CXXTokenTypeOpeningParenthesis | CXXTokenTypeOpeningSquareParenthesis
			))
		{
			CXX_DEBUG_LEAVE_TEXT("Failed to parse up to '<>{EOF'");
			return FALSE;
		}

evaluate_current_token:
		switch(g_cxx.pToken->eType)
		{
			case CXXTokenTypeSmallerThanSign:
				if(g_cxx.pToken->pPrev && cxxTokenTypeIsOneOf(g_cxx.pToken->pPrev,CXXTokenTypeIdentifier | CXXTokenTypeKeyword))
				{
					if(!cxxParserParseNextToken())
					{
						CXX_DEBUG_LEAVE_TEXT("Syntax error, but tolerate it at this level");
						return TRUE;
					}

					CXX_DEBUG_PRINT("Got token '%s' of type 0x%02x",vStringValue(g_cxx.pToken->pszWord),g_cxx.pToken->eType);

					if(cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeSmallerThanSign))
					{
						// assume it's an operator
						CXX_DEBUG_PRINT("Treating < as shift-left operator");
					} else {
						CXX_DEBUG_PRINT("Increasing template level");
						iTemplateLevel++;

						if(cxxTokenTypeIsOneOf(g_cxx.pToken,CXXTokenTypeOpeningParenthesis | CXXTokenTypeOpeningSquareParenthesis))
						{
							CXX_DEBUG_PRINT("Condensing subchain");
							// hmmm.. must condense as subchain
							if(!cxxParserParseAndCondenseCurrentSubchain(CXXTokenTypeOpeningParenthesis | CXXTokenTypeOpeningSquareParenthesis,TRUE))
							{
								CXX_DEBUG_LEAVE_TEXT("Failed to condense current subchain");
								return TRUE;
							}
							if(cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeEOF))
							{
								CXX_DEBUG_LEAVE_TEXT("Found EOF, syntax error but we tolerate it");
								return TRUE;
							}
						} else {
							// it's ok
							CXX_DEBUG_PRINT("No need to condense subchain");
						}
					}
				} else {
					// assume it's an operator
					CXX_DEBUG_PRINT("Treating < as less-than operator");
				}
			break;
			case CXXTokenTypeGreaterThanSign:
				if(iTemplateLevel == 0)
				{
					// Non-nested > : always a terminator
					cxxTokenChainDestroyLast(g_cxx.pTokenChain);
					CXX_DEBUG_LEAVE_TEXT("Found end of template");
					return TRUE;
				}
				// Nested > : is is a shift operator?

				if(!cxxParserParseNextToken())
				{
					CXX_DEBUG_LEAVE_TEXT("Syntax error, but tolerate it at this level");
					return TRUE;
				}

				CXX_DEBUG_PRINT("Got token '%s' of type 0x%02x",vStringValue(g_cxx.pToken->pszWord),g_cxx.pToken->eType);

				if(cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeGreaterThanSign))
				{
					// assume it's an operator
					CXX_DEBUG_PRINT("Treating > as shift-right operator");
				} else {
					CXX_DEBUG_PRINT("Decreasing template level");
					iTemplateLevel--;

					if(cxxTokenTypeIsOneOf(g_cxx.pToken,CXXTokenTypeOpeningParenthesis | CXXTokenTypeOpeningSquareParenthesis))
					{
						CXX_DEBUG_PRINT("Condensing subchain");
						// hmmm.. must condense as subchain
						if(!cxxParserParseAndCondenseCurrentSubchain(CXXTokenTypeOpeningParenthesis | CXXTokenTypeOpeningSquareParenthesis,TRUE))
						{
							CXX_DEBUG_LEAVE_TEXT("Failed to condense current subchain");
							return TRUE;
						}
						if(cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeEOF))
						{
							CXX_DEBUG_LEAVE_TEXT("Found EOF, syntax error but we tolerate it");
							return TRUE;
						}
					} else {
						// it's ok
						CXX_DEBUG_PRINT("No need to condense subchain");
					}
				}
			break;
			case CXXTokenTypeAssignment:
				CXX_DEBUG_PRINT("Found assignment, trying to skip up to a 'notable' point");
				// try to skip to the next > or , without stopping at < characters.
				if(!cxxParserParseUpToOneOf(
						CXXTokenTypeGreaterThanSign | CXXTokenTypeComma | CXXTokenTypeOpeningBracket | CXXTokenTypeSemicolon | CXXTokenTypeEOF
					))
				{
					CXX_DEBUG_LEAVE_TEXT("Failed to parse up to '}EOF'");
					return FALSE;
				}
				goto evaluate_current_token; // backward jump!
			break;
			case CXXTokenTypeEOF:
				CXX_DEBUG_LEAVE_TEXT("Syntax error, but tolerate it at this level");
				return TRUE;
			break;
			case CXXTokenTypeSemicolon:
				cxxParserNewStatement();
				CXX_DEBUG_LEAVE_TEXT("Broken template arguments, attempting to continue");
				return TRUE;
			break;
			case CXXTokenTypeOpeningBracket:
				CXX_DEBUG_PRINT("Found opening bracket: either syntax error or we screwed up parsing the template parameters (some kind of ugly C++11 syntax?), but we try to recover...");
				// skip the whole bracketed part.
				if(!cxxParserParseUpToOneOf(CXXTokenTypeClosingBracket | CXXTokenTypeEOF))
				{
					CXX_DEBUG_LEAVE_TEXT("Failed to parse up to '}EOF'");
					return FALSE;
				}
				cxxParserNewStatement();
				CXX_DEBUG_LEAVE_TEXT("Broken template arguments recovery complete");
				return TRUE;
			break;
			default:
				CXX_DEBUG_ASSERT(FALSE,"Should not end up here");
				CXX_DEBUG_LEAVE_TEXT("Found unexpected token type 0x%02x",g_cxx.pToken->eType);
				return FALSE;
			break;
		}
	}

	// never reached
	CXX_DEBUG_LEAVE();
	return TRUE;
}
Пример #30
0
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 parameterless 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,
				true
			);

		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;
}