コード例 #1
0
ファイル: cxx_token_chain.c プロジェクト: pjkack/ctags
CXXToken * cxxTokenChainNextKeyword(
		CXXToken * from,
		CXXKeyword eKeyword
	)
{
	if(!from)
		return NULL;

	CXXToken * t = from->pNext;
	while(t)
	{
		if(cxxTokenIsKeyword(t,eKeyword))
			return t;
		t = t->pNext;
	}

	return NULL;
}
コード例 #2
0
ファイル: cxx_token_chain.c プロジェクト: pjkack/ctags
CXXToken * cxxTokenChainPreviousKeyword(
		CXXToken * from,
		CXXKeyword eKeyword
	)
{
	if(!from)
		return NULL;

	CXXToken * t = from->pPrev;
	while(t)
	{
		if(cxxTokenIsKeyword(t,eKeyword))
			return t;
		t = t->pPrev;
	}

	return NULL;
}
コード例 #3
0
ファイル: cxx_token_chain.c プロジェクト: pjkack/ctags
// This is working code but it's unused and coveralls complains.. sigh.
// Remove the #if above if needed.
CXXToken * cxxTokenChainFirstKeyword(
		CXXTokenChain * tc,
		CXXKeyword eKeyword
	)
{
	if(!tc)
		return NULL;
	if(tc->iCount < 1)
		return NULL;

	CXXToken * pToken = tc->pHead;
	while(pToken)
	{
		if(cxxTokenIsKeyword(pToken,eKeyword))
			return pToken;
		pToken = pToken->pNext;
	}

	return NULL;
}
コード例 #4
0
ファイル: cxx_token_chain.c プロジェクト: pjkack/ctags
int cxxTokenChainFirstKeywordIndex(
		CXXTokenChain * tc,
		CXXKeyword eKeyword
	)
{
	if(!tc)
		return -1;
	if(tc->iCount < 1)
		return -1;

	CXXToken * pToken = tc->pHead;
	int idx = 0;
	while(pToken)
	{
		if(cxxTokenIsKeyword(pToken,eKeyword))
			return idx;
		idx++;
		pToken = pToken->pNext;
	}

	return -1;
}
コード例 #5
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();
}
コード例 #6
0
ファイル: cxx_parser_tokenizer.c プロジェクト: lizh06/ctags
//
// 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.
//
// Returns false if it finds an EOF. This is an important invariant required by
// cxxParserParseNextToken(), the only caller.
//
static bool cxxParserParseNextTokenCondenseAttribute(void)
{
	// Since cxxParserParseNextToken() returns false only when it has found
	// an EOF, this function must do the same.
	// This means that any broken input must be discarded here.

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

	// Do NOT accept EOF as a valid terminator as it implies broken input.
	if(!cxxParserParseAndCondenseCurrentSubchain(
			CXXTokenTypeOpeningParenthesis |
				CXXTokenTypeOpeningSquareParenthesis |
				CXXTokenTypeOpeningBracket,
			false,
			false
		))
	{
		// Pasing and/or condensation of the subchain failed. This implies broken
		// input (mismatched parenthesis/bracket, early EOF).

		CXX_DEBUG_LEAVE_TEXT("Failed to parse subchains. The input is broken...");

		// However our invariant (see comment at the beginning of the function)
		// forbids us to return false if we didn't find an EOF. So we attempt
		// to resume parsing anyway. If there is an EOF, cxxParserParseNextToken()
		// will report it.

		// Kill the token chain
		cxxTokenChainDestroyLast(g_cxx.pTokenChain);

		return cxxParserParseNextToken();
	}

	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.
	cxxTokenChainDestroyLast(g_cxx.pTokenChain);

	// And finally extract yet another token.
	CXX_DEBUG_LEAVE();
	return cxxParserParseNextToken();
}
コード例 #7
0
ファイル: cxx_parser_block.c プロジェクト: lizh06/ctags
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) &&
						(
							// case 1
							(!g_cxx.pToken->pPrev->pPrev) ||
							// case 4
							cxxTokenTypeIsOneOf(
									g_cxx.pToken->pPrev->pPrev,
									CXXTokenTypeSingleColon | CXXTokenTypeComma
							) ||
							// cases 1,2,3 but not 4
							(
								// more parts of typename or maybe the "new" keyword before the identifier
								cxxTokenTypeIsOneOf(
										g_cxx.pToken->pPrev->pPrev,
										CXXTokenTypeIdentifier | CXXTokenTypeStar | CXXTokenTypeAnd |
										CXXTokenTypeGreaterThanSign | CXXTokenTypeKeyword
								) &&
								// but no parenthesis (discard things like bool test() Q_DECL_NO_THROW { ... })
								(!(pAux = cxxTokenChainPreviousTokenOfType(
										g_cxx.pToken->pPrev->pPrev,
										CXXTokenTypeParenthesisChain
									))
								)
							)
						) &&
						// "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;
	}

	// In C++ mode check for lambdas
	CXXToken * pParenthesis;

	if(
		bIsCPP &&
		(pParenthesis = cxxParserOpeningBracketIsLambda())
	)
	{
		if(!cxxParserHandleLambda(pParenthesis))
		{
			CXX_DEBUG_LEAVE_TEXT("Lambda handling failed");
			return false;
		}

		// Note that here we're leaving the token chain "alive" so further parsing can be performed.
		CXX_DEBUG_LEAVE_TEXT("Lambda handling succeeded");
		return true;
	}

	int iScopes;
	int iCorkQueueIndex = CORK_NIL;

	CXXFunctionSignatureInfo oInfo;

	if(eScopeType != CXXScopeTypeFunction)
	{
		// very likely a function definition
		// (but may be also a toplevel block, like "extern "C" { ... }")
		iScopes = cxxParserExtractFunctionSignatureBeforeOpeningBracket(&oInfo,&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
		// (note that {}-style initializers have been handled above and thus are excluded)

		iScopes = 0;
	}

	cxxParserNewStatement();

	if(!cxxParserParseBlock(true))
	{
		CXX_DEBUG_LEAVE_TEXT("Failed to parse nested block");
		return false;
	}

	if(iScopes < 1)
	{
		CXX_DEBUG_LEAVE_TEXT("The block was not a function");
		return true;
	}

	unsigned long uEndPosition = getInputLineNumber();

	// If the function contained a "try" keyword before the opening bracket
	// then it's likely to be a function-try-block and should be followed by a catch
	// block that is in the same scope.

	if(oInfo.uFlags & CXXFunctionSignatureInfoFunctionTryBlock)
	{
		// look for the catch blocks.
		CXX_DEBUG_PRINT("The function is a function-try-block: looking for catch blocks");

		for(;;)
		{
			CXX_DEBUG_PRINT("Looking ahead for a catch block...");

			if(!cxxParserParseNextToken())
				break; // EOF

			if(!cxxTokenIsKeyword(g_cxx.pToken,CXXKeywordCATCH))
			{
				// No more catches. Unget and exit.
				CXX_DEBUG_PRINT("No more catch blocks");
				cxxParserUngetCurrentToken();
				break;
			}

			// assume it's a catch block.

			CXX_DEBUG_PRINT("Found catch block");

			if(!cxxParserParseIfForWhileSwitchCatchParenthesis())
			{
				CXX_DEBUG_LEAVE_TEXT("Failed to parse the catch parenthesis");
				return false;
			}

			// the standard requires a bracket here (catch block is always a compound statement).

			cxxParserNewStatement();

			if(!cxxParserParseNextToken())
			{
				CXX_DEBUG_LEAVE_TEXT("Found EOF while looking for catch() block: playing nice");
				break; // EOF (would be a syntax error!)
			}

			if(!cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeOpeningBracket))
			{
				// Aargh...
				CXX_DEBUG_LEAVE_TEXT("Found something unexpected while looking for catch() block: playing nice");
				cxxParserUngetCurrentToken();
				break; // (would be a syntax error!)
			}

			if(!cxxParserParseBlock(true))
				return false;

 			uEndPosition = getInputLineNumber();
 		}
 	}

	if(iCorkQueueIndex > CORK_NIL)
		cxxParserSetEndLineForTagInCorkQueue(iCorkQueueIndex,uEndPosition);

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

	CXX_DEBUG_LEAVE();
	return true;
}