Example #1
0
/*
* Returns a string describing the scope in 'list'.
* We record the current scope as a list of entered scopes.
* Scopes corresponding to 'if' statements and the like are
* represented by empty strings. Scopes corresponding to
* modules and classes are represented by the name of the
* module or class.
*/
static vString* stringListToScope (const stringList* list)
{
	unsigned int i;
	unsigned int chunks_output = 0;
	vString* result = vStringNew ();
	const unsigned int max = stringListCount (list);
	for (i = 0; i < max; ++i)
	{
	    vString* chunk = stringListItem (list, i);
	    if (vStringLength (chunk) > 0)
	    {
	        vStringCatS (result, (chunks_output++ > 0) ? "." : "");
	        vStringCatS (result, vStringValue (chunk));
	    }
	}
	return result;
}
Example #2
0
static void makeVhdlTag (tokenInfo * const token, const vhdlKind kind)
{
	if (VhdlKinds[kind].enabled)
	{
		/*
		 * If a scope has been added to the token, change the token
		 * string to include the scope when making the tag.
		 */
		if (vStringLength (token->scope) > 0)
		{
			vString *fulltag = vStringNew ();
			vStringCopy (fulltag, token->scope);
			vStringCatS (fulltag, ".");
			vStringCatS (fulltag, vStringValue (token->string));
			vStringTerminate (fulltag);
			vStringCopy (token->string, fulltag);
			vStringDelete (fulltag);
		}
		makeConstTag (token, kind);
	}
}
Example #3
0
CXXToken * cxxTokenCreateKeyword(int iLineNumber,MIOPos oFilePosition,enum CXXKeyword eKeyword)
{
	CXXToken * pToken = cxxTokenCreate();
	pToken->iLineNumber = iLineNumber;
	pToken->oFilePosition = oFilePosition;
	pToken->eType = CXXTokenTypeKeyword;
	pToken->eKeyword = eKeyword;
	pToken->bFollowedBySpace = TRUE;
	vStringCatS(pToken->pszWord,cxxKeywordName(eKeyword));

	return pToken;
}
Example #4
0
File: main.c Project: att/uwin
static boolean recurseIntoDirectory (const char *const dirName)
{
    boolean resize = FALSE;
    if (isRecursiveLink (dirName))
	verbose ("ignoring \"%s\" (recursive link)\n", dirName);
    else if (! Option.recurse)
	verbose ("ignoring \"%s\" (directory)\n", dirName);
    else
    {
	verbose ("RECURSING into directory \"%s\"\n", dirName);
#if defined (HAVE_OPENDIR)
	resize = recurseUsingOpendir (dirName);
#elif defined (HAVE_FINDFIRST) || defined (HAVE__FINDFIRST)
	{
	    vString *const pattern = vStringNew ();
	    vStringCopyS (pattern, dirName);
	    vStringPut (pattern, OUTPUT_PATH_SEPARATOR);
	    vStringCatS (pattern, "*.*");
	    resize = createTagsForWildcardUsingFindfirst (vStringValue (pattern));
	    vStringDelete (pattern);
	}
#elif defined (AMIGA)
	{
	    vString *const pattern = vStringNew ();
	    if (*dirName != '\0'  &&  strcmp (dirName, ".") != 0)
	    {
		vStringCopyS (pattern, dirName);
		if (dirName [strlen (dirName) - 1] != '/')
		    vStringPut (pattern, '/');
	    }
	    vStringCatS (pattern, "#?");
	    resize = createTagsForAmigaWildcard (vStringValue (pattern));
	    vStringDelete (pattern);
	}
#endif
    }
    return resize;
}
Example #5
0
static void addToScope (tokenInfo *const token, const vString *const extra,
			int kindOfUpperScope)
{
	if (vStringLength (token->scope) > 0)
	{
		const char* sep;

		sep = phpScopeSeparatorFor(token->parentKind,
					   kindOfUpperScope);
		vStringCatS (token->scope, sep);
	}
	vStringCat (token->scope, extra);
	vStringTerminate(token->scope);
}
Example #6
0
static void findAbcTags (void)
{
	vString *name = vStringNew();
	const unsigned char *line;

	while ((line = readLineFromInputFile()) != NULL)
	{
		/*int name_len = vStringLength(name);*/

		/* underlines must be the same length or more */
		/*if (name_len > 0 &&	(line[0] == '=' || line[0] == '-') && issame((const char*) line))
		{
			makeAbcTag(name, TRUE);
		}*/
/*		if (line[1] == '%') {
			vStringClear(name);
			vStringCatS(name, (const char *) line);
			vStringTerminate(name);
			makeAbcTag(name, FALSE);
		}*/
		if (line[0] == 'T') {
			/*vStringClear(name);*/
			vStringCatS(name, " / ");
			vStringCatS(name, (const char *) line);
			vStringTerminate(name);
			makeAbcTag(name, FALSE);
		}
		else {
			vStringClear (name);
			if (! isspace(*line))
				vStringCatS(name, (const char*) line);
			vStringTerminate(name);
		}
	}
	vStringDelete (name);
}
Example #7
0
File: main.c Project: koron/ctags
static boolean createTagsForWildcardEntry (
		const char *const pattern, const size_t dirLength,
		const char *const entryName)
{
	boolean resize = FALSE;
	/* we must not recurse into the directories "." or ".." */
	if (strcmp (entryName, ".") != 0  &&  strcmp (entryName, "..") != 0)
	{
		vString *const filePath = vStringNew ();
		vStringNCopyS (filePath, pattern, dirLength);
		vStringCatS (filePath, entryName);
		resize = createTagsForEntry (vStringValue (filePath));
		vStringDelete (filePath);
	}
	return resize;
}
Example #8
0
static void initPhpEntry (tagEntryInfo *const e, const tokenInfo *const token,
						  const phpKind kind, const accessType access)
{
	int parentKind = -1;

	vStringClear (FullScope);

	if (vStringLength (CurrentNamesapce) > 0)
	{
		parentKind = K_NAMESPACE;
		vStringCat (FullScope, CurrentNamesapce);

	}

	initTagEntry (e, vStringValue (token->string), kind);

	e->lineNumber	= token->lineNumber;
	e->filePosition	= token->filePosition;

	if (access != ACCESS_UNDEFINED)
		e->extensionFields.access = accessToString (access);
	if (vStringLength (token->scope) > 0)
	{
		parentKind = token->parentKind;

		if (vStringLength (FullScope) > 0)
		{
			const char* sep;

			sep = phpScopeSeparatorFor (parentKind,
						    K_NAMESPACE);
			vStringCatS (FullScope, sep);
		}
			vStringCat (FullScope, token->scope);
	}
	if (vStringLength (FullScope) > 0)
	{
		Assert (parentKind >= 0);

		e->extensionFields.scopeKindIndex = parentKind;
		e->extensionFields.scopeName = vStringValue (FullScope);
	}

	if (token->anonymous)
		markTagExtraBit (e, XTAG_ANONYMOUS);
}
Example #9
0
/*
* Returns a string describing the scope in 'nls'.
* We record the current scope as a list of entered scopes.
* Scopes corresponding to 'if' statements and the like are
* represented by empty strings. Scopes corresponding to
* modules and classes are represented by the name of the
* module or class.
*/
static vString* nestingLevelsToScope (const NestingLevels* nls)
{
	int i;
	unsigned int chunks_output = 0;
	vString* result = vStringNew ();
	for (i = 0; i < nls->n; ++i)
	{
	    NestingLevel *nl = nestingLevelsGetNth (nls, i);
	    tagEntryInfo *e = getEntryOfNestingLevel (nl);
	    if (e && strlen (e->name) > 0 && (!e->placeholder))
	    {
	        if (chunks_output++ > 0)
	            vStringPut (result, SCOPE_SEPARATOR);
	        vStringCatS (result, e->name);
	    }
	}
	return result;
}
Example #10
0
/* TODO: parse overlining & underlining as distinct sections. */
static void findRstTags (void)
{
    vString *name = vStringNew ();
    fpos_t filepos;
    const unsigned char *line;

    memset(&filepos, 0, sizeof(fpos_t));
    memset(kindchars, 0, sizeof kindchars);
    nestingLevels = nestingLevelsNew();

    while ((line = readLineFromInputFile ()) != NULL)
    {
        int line_len = strlen((const char*) line);
        int name_len_bytes = vStringLength(name);
        int name_len = utf8_strlen(vStringValue(name), name_len_bytes);

        /* if the name doesn't look like UTF-8, assume one-byte charset */
        if (name_len < 0)
            name_len = name_len_bytes;

        /* underlines must be the same length or more */
        if (line_len >= name_len && name_len > 0 &&
                ispunct(line[0]) && issame((const char*) line))
        {
            char c = line[0];
            int kind = get_kind(c);

            if (kind >= 0)
            {
                makeRstTag(name, kind, filepos);
                continue;
            }
        }
        vStringClear (name);
        if (!isspace(*line))
        {
            vStringCatS(name, (const char*)line);
            filepos = getInputFilePosition();
        }
        vStringTerminate(name);
    }
    vStringDelete (name);
    nestingLevelsFree(nestingLevels);
}
Example #11
0
static void createContext (tokenInfo *const scope)
{
	if (scope)
	{
		vString *contextName = vStringNew ();

		verbose ("Creating new context %s\n", vStringValue (scope->name));
		/* Determine full context name */
		if (currentContext->kind != K_UNDEFINED)
		{
			vStringCopy (contextName, currentContext->name);
			vStringCatS (contextName, ".");
		}
		vStringCat (contextName, scope->name);
		/* Create context */
		currentContext = pushToken (currentContext, scope);
		vStringCopy (currentContext->name, contextName);
		vStringDelete (contextName);
	}
}
Example #12
0
File: main.c Project: koron/ctags
static boolean createTagsForWildcardArg (const char *const arg)
{
	boolean resize = FALSE;
	vString *const pattern = vStringNewInit (arg);
	char *patternS = vStringValue (pattern);

#if defined (HAVE_FINDFIRST) || defined (HAVE__FINDFIRST)
	/*  We must transform the "." and ".." forms into something that can
	 *  be expanded by the findfirst/_findfirst functions.
	 */
	if (Option.recurse  &&
		(strcmp (patternS, ".") == 0  ||  strcmp (patternS, "..") == 0))
	{
		vStringPut (pattern, OUTPUT_PATH_SEPARATOR);
		vStringCatS (pattern, "*.*");
	}
	resize |= createTagsForWildcardUsingFindfirst (patternS);
#endif
	vStringDelete (pattern);
	return resize;
}
Example #13
0
void cxxTokenChainJoinInString(
		CXXTokenChain * tc,
		vString * s,
		const char * szSeparator,
		unsigned int uFlags
	)
{
	if(!tc)
		return;

	if(tc->iCount == 0)
		return;

	CXXToken * t = tc->pHead;

	cxxTokenAppendToString(s,t);

	if(
			(!(uFlags & CXXTokenChainJoinNoTrailingSpaces)) &&
			t->bFollowedBySpace
		)
		vStringPut (s, ' ');

	t = t->pNext;
	while(t)
	{
		if(szSeparator)
			vStringCatS(s,szSeparator);

		cxxTokenAppendToString(s,t);

		if(
				(!(uFlags & CXXTokenChainJoinNoTrailingSpaces)) &&
				t->bFollowedBySpace
			)
			vStringPut (s, ' ');

		t = t->pNext;
	}
}
Example #14
0
File: objc.c Project: simlrh/ctags
static void parseMethodsImplemName (vString * const ident, objcToken what)
{
	switch (what)
	{
	case Tok_PARL:
		toDoNext = &tillToken;
		comeAfter = &parseMethodsImplemName;
		waitedToken = Tok_PARR;
		break;

	case Tok_dpoint:
		vStringCat (fullMethodName, prevIdent);
		vStringCatS (fullMethodName, ":");
		vStringClear (prevIdent);
		break;

	case ObjcIDENTIFIER:
		vStringCopy (prevIdent, ident);
		break;

	case Tok_CurlL:
	case Tok_semi:
		/* method name is not simple */
		if (vStringLength (fullMethodName) != '\0')
		{
			addTag (fullMethodName, methodKind);
			vStringClear (fullMethodName);
		}
		else
			addTag (prevIdent, methodKind);

		toDoNext = &parseImplemMethods;
		parseImplemMethods (ident, what);
		vStringClear (prevIdent);
		break;

	default:
		break;
	}
}
Example #15
0
File: go.c Project: 15ramky/geany
static void makeTag (tokenInfo *const token, const goKind kind,
	tokenInfo *const parent_token, const goKind parent_kind,
	const char *argList, const char *varType)
{
	const char *const name = vStringValue (token->string);

	tagEntryInfo e;
	initTagEntry (&e, name);

	if (!GoKinds [kind].enabled)
		return;

	e.lineNumber = token->lineNumber;
	e.filePosition = token->filePosition;
	e.kindName = GoKinds [kind].name;
	e.kind = GoKinds [kind].letter;
	if (argList)
		e.extensionFields.arglist = argList;
	if (varType)
		e.extensionFields.varType = varType;

	if (parent_kind != GOTAG_UNDEFINED && parent_token != NULL)
	{
		e.extensionFields.scope[0] = GoKinds[parent_kind].name;
		e.extensionFields.scope[1] = vStringValue (parent_token->string);
	}
	makeTagEntry (&e);

	if (scope && Option.include.qualifiedTags)
	{
		vString *qualifiedName = vStringNew ();
		vStringCopy (qualifiedName, scope);
		vStringCatS (qualifiedName, ".");
		vStringCat (qualifiedName, token->string);
		e.name = vStringValue (qualifiedName);
		makeTagEntry (&e);
		vStringDelete (qualifiedName);
	}
}
Example #16
0
static void dropContext (tokenInfo *const token)
{
	verbose ("current context %s; context kind %0d; nest level %0d\n", vStringValue (currentContext->name), currentContext->kind, currentContext->nestLevel);
	vString *endTokenName = vStringNewInit("end");
	if ((currentContext->kind == K_COVERGROUP && strcmp (vStringValue (token->name), "endgroup") == 0) ||
	    (currentContext->kind == K_BLOCK && currentContext->nestLevel == 0 && strcmp (vStringValue (token->name), vStringValue (endTokenName)) == 0)
	    )
	{
		verbose ("Dropping context %s\n", vStringValue (currentContext->name));
		currentContext = popToken (currentContext);
	}
	else
	{
		vStringCatS (endTokenName, kindFromKind (currentContext->kind)->name);
		if (strcmp (vStringValue (token->name), vStringValue (endTokenName)) == 0)
		{
			verbose ("Dropping context %s\n", vStringValue (currentContext->name));
			currentContext = popToken (currentContext);
		}
	}
	vStringDelete(endTokenName);
}
Example #17
0
File: vim.c Project: amosbird/ctags
static void parseFunction (const unsigned char *line)
{
	vString *name = vStringNew ();
	/* boolean inFunction = FALSE; */
	int scope;
	const unsigned char *cp = line;
	int index = CORK_NIL;

	if (*cp == '!')
		++cp;
	if (isspace ((int) *cp))
	{
		while (*cp && isspace ((int) *cp))
			++cp;

		if (*cp)
		{
			cp = skipPrefix (cp, &scope);
			if (isupper ((int) *cp)  ||
					scope == 's'  ||  /* script scope */
					scope == '<'  ||  /* script scope */
					scope == 'd'  ||  /* dictionary */
					scope == 'a')     /* autoload */
			{
				char prefix[3] = { [0] = (char)scope, [1] = ':', [2] = '\0' };
				if (scope == 's')
					vStringCatS (name, prefix);

				do
				{
					vStringPut (name, (int) *cp);
					++cp;
				} while (isalnum ((int) *cp) || *cp == '_' || *cp == '.' || *cp == '#');
				vStringTerminate (name);
				index = makeSimpleTag (name, VimKinds, K_FUNCTION);
				vStringClear (name);
			}
		}
	}
Example #18
0
/* parses namespace declarations
 * 	namespace Foo {}
 * 	namespace Foo\Bar {}
 * 	namespace Foo;
 * 	namespace Foo\Bar;
 * 	namespace;
 * 	napespace {} */
static boolean parseNamespace (tokenInfo *const token)
{
	tokenInfo *nsToken = newToken ();

	vStringClear (CurrentNamesapce);
	copyToken (nsToken, token, FALSE);

	do
	{
		readToken (token);
		if (token->type == TOKEN_IDENTIFIER)
		{
			if (vStringLength (CurrentNamesapce) > 0)
			{
				const char *sep;

				sep = phpScopeSeparatorFor(K_NAMESPACE,
							   K_NAMESPACE);
				vStringCatS (CurrentNamesapce, sep);
			}
			vStringCat (CurrentNamesapce, token->string);
		}
	}
	while (token->type != TOKEN_EOF &&
		   token->type != TOKEN_SEMICOLON &&
		   token->type != TOKEN_OPEN_CURLY);

	vStringTerminate (CurrentNamesapce);
	if (vStringLength (CurrentNamesapce) > 0)
		makeNamespacePhpTag (nsToken, CurrentNamesapce);

	if (token->type == TOKEN_OPEN_CURLY)
		enterScope (token, NULL, -1);

	deleteToken (nsToken);

	return TRUE;
}
Example #19
0
File: go.c Project: Dev0Null/ctags
static void makeTag (tokenInfo *const token, const goKind kind,
	tokenInfo *const parent_token, const goKind parent_kind,
	const char *argList)
{
	const char *const name = vStringValue (token->string);

	tagEntryInfo e;
	initTagEntry (&e, name, &(GoKinds [kind]));

	if (!GoKinds [kind].enabled)
		return;

	e.lineNumber = token->lineNumber;
	e.filePosition = token->filePosition;
	if (argList)
		e.extensionFields.signature = argList;

	if (parent_kind != GOTAG_UNDEFINED && parent_token != NULL)
	{
		e.extensionFields.scopeKind = &(GoKinds[parent_kind]);
		e.extensionFields.scopeName = vStringValue (parent_token->string);
	}
	makeTagEntry (&e);

	if (scope && isXtagEnabled(XTAG_QUALIFIED_TAGS))
	{
		vString *qualifiedName = vStringNew ();
		vStringCopy (qualifiedName, scope);
		vStringCatS (qualifiedName, ".");
		vStringCat (qualifiedName, token->string);
		e.name = vStringValue (qualifiedName);
		markTagExtraBit (&e, XTAG_QUALIFIED_TAGS);
		makeTagEntry (&e);
		vStringDelete (qualifiedName);
	}
}
Example #20
0
void cxxTokenChainJoinRangeInString(
		CXXToken * from,
		CXXToken * to,
		vString * s,
		const char * szSeparator,
		unsigned int uFlags
	)
{
	if(!from)
		return;

	CXXToken * t = from;

	cxxTokenAppendToString(s,t);

	if((!(uFlags & CXXTokenChainJoinNoTrailingSpaces)) && t->bFollowedBySpace)
		vStringPut (s, ' ');

	while(t && (t != to))
	{
		t = t->pNext;
		if(t)
			return;

		if(szSeparator)
			vStringCatS(s,szSeparator);

		cxxTokenAppendToString(s,t);

		if(
				(!(uFlags & CXXTokenChainJoinNoTrailingSpaces)) &&
				t->bFollowedBySpace
			)
			vStringPut (s, ' ');
	}
}
Example #21
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;
}
Example #22
0
File: go.c Project: Dev0Null/ctags
static void readToken (tokenInfo *const token)
{
	int c;
	static tokenType lastTokenType = TOKEN_NONE;
	boolean firstWhitespace = TRUE;
	boolean whitespace;

	token->type = TOKEN_NONE;
	token->keyword = KEYWORD_NONE;
	vStringClear (token->string);

getNextChar:
	do
	{
		c = getcFromInputFile ();
		token->lineNumber = getInputLineNumber ();
		token->filePosition = getInputFilePosition ();
		if (c == '\n' && (lastTokenType == TOKEN_IDENTIFIER ||
						  lastTokenType == TOKEN_STRING ||
						  lastTokenType == TOKEN_OTHER ||
						  lastTokenType == TOKEN_CLOSE_PAREN ||
						  lastTokenType == TOKEN_CLOSE_CURLY ||
						  lastTokenType == TOKEN_CLOSE_SQUARE))
		{
			c = ';';  // semicolon injection
		}
		whitespace = c == '\t'  ||  c == ' ' ||  c == '\r' || c == '\n';
		if (signature && whitespace && firstWhitespace && vStringLength (signature) < MAX_SIGNATURE_LENGTH)
		{
			firstWhitespace = FALSE;
			vStringPut(signature, ' ');
		}
	}
	while (whitespace);

	switch (c)
	{
		case EOF:
			token->type = TOKEN_EOF;
			break;

		case ';':
			token->type = TOKEN_SEMICOLON;
			break;

		case '/':
			{
				boolean hasNewline = FALSE;
				int d = getcFromInputFile ();
				switch (d)
				{
					case '/':
						skipToCharacterInInputFile ('\n');
						/* Line comments start with the
						 * character sequence // and
						 * continue through the next
						 * newline. A line comment acts
						 * like a newline.  */
						ungetcToInputFile ('\n');
						goto getNextChar;
					case '*':
						do
						{
							do
							{
								d = getcFromInputFile ();
								if (d == '\n')
								{
									hasNewline = TRUE;
								}
							} while (d != EOF && d != '*');

							c = getcFromInputFile ();
							if (c == '/')
								break;
							else
								ungetcToInputFile (c);
						} while (c != EOF && c != '\0');

						ungetcToInputFile (hasNewline ? '\n' : ' ');
						goto getNextChar;
					default:
						token->type = TOKEN_OTHER;
						ungetcToInputFile (d);
						break;
				}
			}
			break;

		case '"':
		case '\'':
		case '`':
			token->type = TOKEN_STRING;
			parseString (token->string, c);
			token->lineNumber = getInputLineNumber ();
			token->filePosition = getInputFilePosition ();
			break;

		case '<':
			{
				int d = getcFromInputFile ();
				if (d == '-')
					token->type = TOKEN_LEFT_ARROW;
				else
				{
					ungetcToInputFile (d);
					token->type = TOKEN_OTHER;
				}
			}
			break;

		case '(':
			token->type = TOKEN_OPEN_PAREN;
			break;

		case ')':
			token->type = TOKEN_CLOSE_PAREN;
			break;

		case '{':
			token->type = TOKEN_OPEN_CURLY;
			break;

		case '}':
			token->type = TOKEN_CLOSE_CURLY;
			break;

		case '[':
			token->type = TOKEN_OPEN_SQUARE;
			break;

		case ']':
			token->type = TOKEN_CLOSE_SQUARE;
			break;

		case '*':
			token->type = TOKEN_STAR;
			break;

		case '.':
			token->type = TOKEN_DOT;
			break;

		case ',':
			token->type = TOKEN_COMMA;
			break;

		default:
			if (isStartIdentChar (c))
			{
				parseIdentifier (token->string, c);
				token->lineNumber = getInputLineNumber ();
				token->filePosition = getInputFilePosition ();
				token->keyword = lookupKeyword (vStringValue (token->string), Lang_go);
				if (isKeyword (token, KEYWORD_NONE))
					token->type = TOKEN_IDENTIFIER;
				else
					token->type = TOKEN_KEYWORD;
			}
			else
				token->type = TOKEN_OTHER;
			break;
	}

	if (signature && vStringLength (signature) < MAX_SIGNATURE_LENGTH)
	{
		if (token->type == TOKEN_LEFT_ARROW)
			vStringCatS(signature, "<-");
		else if (token->type == TOKEN_STRING)
		{
			// only struct member annotations can appear in function prototypes
			// so only `` type strings are possible
			vStringPut(signature, '`');
			vStringCat(signature, token->string);
			vStringPut(signature, '`');
		}
		else if (token->type == TOKEN_IDENTIFIER || token->type == TOKEN_KEYWORD)
			vStringCat(signature, token->string);
		else if (c != EOF)
			vStringPut(signature, c);
	}

	lastTokenType = token->type;
}
Example #23
0
/* parse a function
 *
 * if @name is NULL, parses a normal function
 * 	function myfunc($foo, $bar) {}
 * 	function &myfunc($foo, $bar) {}
 * 	function myfunc($foo, $bar) : type {}
 *
 * if @name is not NULL, parses an anonymous function with name @name
 * 	$foo = function($foo, $bar) {}
 * 	$foo = function&($foo, $bar) {}
 * 	$foo = function($foo, $bar) use ($x, &$y) {}
 * 	$foo = function($foo, $bar) use ($x, &$y) : type {} */
static boolean parseFunction (tokenInfo *const token, const tokenInfo *name)
{
	boolean readNext = TRUE;
	accessType access = CurrentStatement.access;
	implType impl = CurrentStatement.impl;
	tokenInfo *nameFree = NULL;

	readToken (token);
	/* skip a possible leading ampersand (return by reference) */
	if (token->type == TOKEN_AMPERSAND)
		readToken (token);

	if (! name)
	{
		if (token->type != TOKEN_IDENTIFIER && token->type != TOKEN_KEYWORD)
			return FALSE;

		name = nameFree = newToken ();
		copyToken (nameFree, token, TRUE);
		readToken (token);
	}

	if (token->type == TOKEN_OPEN_PAREN)
	{
		vString *arglist = vStringNew ();
		int depth = 1;

		vStringPut (arglist, '(');
		do
		{
			readToken (token);

			switch (token->type)
			{
				case TOKEN_OPEN_PAREN:  depth++; break;
				case TOKEN_CLOSE_PAREN: depth--; break;
				default: break;
			}
			/* display part */
			switch (token->type)
			{
				case TOKEN_AMPERSAND:		vStringPut (arglist, '&');		break;
				case TOKEN_CLOSE_CURLY:		vStringPut (arglist, '}');		break;
				case TOKEN_CLOSE_PAREN:		vStringPut (arglist, ')');		break;
				case TOKEN_CLOSE_SQUARE:	vStringPut (arglist, ']');		break;
				case TOKEN_COLON:			vStringPut (arglist, ':');		break;
				case TOKEN_COMMA:			vStringCatS (arglist, ", ");	break;
				case TOKEN_EQUAL_SIGN:		vStringCatS (arglist, " = ");	break;
				case TOKEN_OPEN_CURLY:		vStringPut (arglist, '{');		break;
				case TOKEN_OPEN_PAREN:		vStringPut (arglist, '(');		break;
				case TOKEN_OPEN_SQUARE:		vStringPut (arglist, '[');		break;
				case TOKEN_PERIOD:			vStringPut (arglist, '.');		break;
				case TOKEN_SEMICOLON:		vStringPut (arglist, ';');		break;
				case TOKEN_BACKSLASH:		vStringPut (arglist, '\\');		break;
				case TOKEN_STRING:
				{
					vStringCatS (arglist, "'");	
					vStringCat  (arglist, token->string);
					vStringCatS (arglist, "'");
					break;
				}

				case TOKEN_IDENTIFIER:
				case TOKEN_KEYWORD:
				case TOKEN_VARIABLE:
				{
					switch (vStringLast (arglist))
					{
						case 0:
						case ' ':
						case '{':
						case '(':
						case '[':
						case '.':
						case '\\':
							/* no need for a space between those and the identifier */
							break;

						default:
							vStringPut (arglist, ' ');
							break;
					}
					if (token->type == TOKEN_VARIABLE)
						vStringPut (arglist, '$');
					vStringCat (arglist, token->string);
					break;
				}

				default: break;
			}
		}
		while (token->type != TOKEN_EOF && depth > 0);

		vStringTerminate (arglist);

		makeFunctionTag (name, arglist, access, impl);
		vStringDelete (arglist);

		readToken (token); /* normally it's an open brace or "use" keyword */
	}

	/* skip use(...) */
	if (token->type == TOKEN_KEYWORD && token->keyword == KEYWORD_use)
	{
		readToken (token);
		skipOverParens (token);
	}

	/* PHP7 return type declaration or if parsing Zephir, skip function return
	 * type hint */
	if ((getInputLanguage () == Lang_php && token->type == TOKEN_COLON) ||
	    (getInputLanguage () == Lang_zephir && token->type == TOKEN_OPERATOR))
	{
		do
			readToken (token);
		while (token->type == TOKEN_IDENTIFIER ||
		       token->type == TOKEN_BACKSLASH);
	}

	if (token->type == TOKEN_OPEN_CURLY)
		enterScope (token, name->string, K_FUNCTION);
	else
		readNext = FALSE;

	if (nameFree)
		deleteToken (nameFree);

	return readNext;
}
Example #24
0
/* Algorithm adapted from from GNU etags.
 * Perl support by Bart Robinson <*****@*****.**>
 * Perl sub names: look for /^ [ \t\n]sub [ \t\n]+ [^ \t\n{ (]+/
 */
static void findPerlTags (void)
{
	vString *name = vStringNew ();
	vString *package = NULL;
	boolean skipPodDoc = FALSE;
	const unsigned char *line;

	/* Core modules AutoLoader and SelfLoader support delayed compilation
	 * by allowing Perl code that follows __END__ and __DATA__ tokens,
	 * respectively.  When we detect that one of these modules is used
	 * in the file, we continue processing even after we see the
	 * corresponding token that would usually terminate parsing of the
	 * file.
	 */
	enum {
		RESPECT_END		= (1 << 0),
		RESPECT_DATA	= (1 << 1),
	} respect_token = RESPECT_END | RESPECT_DATA;

	while ((line = fileReadLine ()) != NULL)
	{
		boolean spaceRequired = FALSE;
		boolean qualified = FALSE;
		const unsigned char *cp = line;
		perlKind kind = K_NONE;
		tagEntryInfo e;

		if (skipPodDoc)
		{
			if (strncmp ((const char*) line, "=cut", (size_t) 4) == 0)
				skipPodDoc = FALSE;
			continue;
		}
		else if (line [0] == '=')
		{
			skipPodDoc = isPodWord ((const char*)line + 1);
			continue;
		}
		else if (strcmp ((const char*) line, "__DATA__") == 0)
		{
			if (respect_token & RESPECT_DATA)
				break;
			else
				continue;
		}
		else if (strcmp ((const char*) line, "__END__") == 0)
		{
			if (respect_token & RESPECT_END)
				break;
			else
				continue;
		}
		else if (line [0] == '#')
			continue;

		while (isspace (*cp))
			cp++;

		if (strncmp((const char*) cp, "sub", (size_t) 3) == 0)
		{
			TRACE("this looks like a sub\n");
			cp += 3;
			kind = K_SUBROUTINE;
			spaceRequired = TRUE;
			qualified = TRUE;
		}
		else if (strncmp((const char*) cp, "use", (size_t) 3) == 0)
		{
			cp += 3;
			if (!isspace(*cp))
				continue;
			while (*cp && isspace (*cp))
				++cp;
			if (strncmp((const char*) cp, "AutoLoader", (size_t) 10) == 0) {
				respect_token &= ~RESPECT_END;
				continue;
			}
			if (strncmp((const char*) cp, "SelfLoader", (size_t) 10) == 0) {
				respect_token &= ~RESPECT_DATA;
				continue;
			}
			if (strncmp((const char*) cp, "constant", (size_t) 8) != 0)
				continue;
			cp += 8;
			/* Skip up to the first non-space character, skipping empty
			 * and comment lines.
			 */
			while (isspace(*cp))
				cp++;
			while (!*cp || '#' == *cp) {
				cp = fileReadLine ();
				if (!cp)
					goto END_MAIN_WHILE;
				while (isspace (*cp))
					cp++;
			}
			if ('{' == *cp) {
				++cp;
				if (0 == parseConstantsFromHashRef(cp, name, package)) {
					vStringClear(name);
					continue;
				} else
					goto END_MAIN_WHILE;
			}
			kind = K_CONSTANT;
			spaceRequired = FALSE;
			qualified = TRUE;
		}
		else if (strncmp((const char*) cp, "package", (size_t) 7) == 0 &&
				 ('\0' == cp[7] || isspace(cp[7])))
		{
			cp += 7;
			while (isspace (*cp))
				cp++;
			while (!*cp || '#' == *cp) {
				cp = fileReadLine ();
				if (!cp)
					goto END_MAIN_WHILE;
				while (isspace (*cp))
					cp++;
			}
			if (package == NULL)
				package = vStringNew ();
			else
				vStringClear (package);
			const unsigned char *const first = cp;
			while (*cp && (int) *cp != ';'  &&  !isspace ((int) *cp))
			{
				vStringPut (package, (int) *cp);
				cp++;
			}
			vStringCatS (package, "::");

			cp = first;	 /* Rewind */
			kind = K_PACKAGE;
			spaceRequired = FALSE;
			qualified = TRUE;
		}
		else if (strncmp((const char*) cp, "format", (size_t) 6) == 0)
		{
			cp += 6;
			kind = K_FORMAT;
			spaceRequired = TRUE;
			qualified = TRUE;
		}
		else
		{
			if (isIdentifier1 (*cp))
			{
				const unsigned char *p = cp;
				while (isIdentifier (*p))
					++p;
				while (isspace (*p))
					++p;
				if ((int) *p == ':' && (int) *(p + 1) != ':')
					kind = K_LABEL;
			}
		}
		if (kind != K_NONE)
		{
			TRACE("cp0: %s\n", (const char *) cp);
			if (spaceRequired && *cp && !isspace (*cp))
				continue;

			TRACE("cp1: %s\n", (const char *) cp);
			while (isspace (*cp))
				cp++;

			while (!*cp || '#' == *cp) { /* Gobble up empty lines
				                            and comments */
				cp = fileReadLine ();
				if (!cp)
					goto END_MAIN_WHILE;
				while (isspace (*cp))
					cp++;
			}

			while (isIdentifier (*cp) || (K_PACKAGE == kind && ':' == *cp))
			{
				vStringPut (name, (int) *cp);
				cp++;
			}

			if (K_FORMAT == kind &&
				vStringLength (name) == 0 && /* cp did not advance */
				'=' == *cp)
			{
				/* format's name is optional.  If it's omitted, 'STDOUT'
				   is assumed. */
				vStringCatS (name, "STDOUT");
			}

			vStringTerminate (name);
			TRACE("name: %s\n", name->buffer);

			if (0 == vStringLength(name)) {
				vStringClear(name);
				continue;
			}

			if (K_SUBROUTINE == kind)
			{
				/*
				 * isSubroutineDeclaration() may consume several lines.  So
				 * we record line positions.
				 */
				initTagEntry(&e, vStringValue(name), NULL);

				if (TRUE == isSubroutineDeclaration(cp)) {
					if (TRUE == PerlKinds[K_SUBROUTINE_DECLARATION].enabled) {
						kind = K_SUBROUTINE_DECLARATION;
					} else {
						vStringClear (name);
						continue;
					}
				} else if (! PerlKinds[kind].enabled) {
					continue;
				}

				e.kind     = &(PerlKinds[kind]);

				makeTagEntry(&e);

				if (Option.include.qualifiedTags && qualified &&
					package != NULL  && vStringLength (package) > 0)
				{
					vString *const qualifiedName = vStringNew ();
					vStringCopy (qualifiedName, package);
					vStringCat (qualifiedName, name);
					e.name = vStringValue(qualifiedName);
					makeTagEntry(&e);
					vStringDelete (qualifiedName);
				}
			} else if (vStringLength (name) > 0)
			{
				makeSimpleTag (name, PerlKinds, kind);
				if (Option.include.qualifiedTags && qualified &&
					K_PACKAGE != kind &&
					package != NULL  && vStringLength (package) > 0)
				{
					vString *const qualifiedName = vStringNew ();
					vStringCopy (qualifiedName, package);
					vStringCat (qualifiedName, name);
					makeSimpleTag (qualifiedName, PerlKinds, kind);
					vStringDelete (qualifiedName);
				}
			}
			vStringClear (name);
		}
	}

END_MAIN_WHILE:
	vStringDelete (name);
	if (package != NULL)
		vStringDelete (package);
}
Example #25
0
static boolean loadPathKinds  (xcmdPath *const path, const langType language)
{
	enum pcoprocError r;
	FILE* pp = NULL;
	char * argv[3];
	int status;
	vString * opt;
	char file_kind = getLanguageFileKind (language)->letter;

	opt = vStringNewInit(XCMD_LIST_KIND_OPTION);
	vStringCatS (opt, "=");
	vStringCatS (opt, getLanguageName(language));

	argv[2] = NULL;
	argv[1] = vStringValue (opt);
	argv[0] = vStringValue (path->path);

	errno = 0;

	if (getuid() == 0 || geteuid() == 0)
	{
		verbose ("all xcmd feature is disabled when running ctags in root privilege\n");
		vStringDelete (opt);
		return FALSE;
	}

	if (! isSafeExecutable (argv [0]))
	{
		vStringDelete (opt);
		return FALSE;
	}
	verbose ("loading path kinds of %s from [%s %s]\n", getLanguageName(language), argv[0], argv[1]);
	r = pcoprocOpen (vStringValue (path->path), argv, &pp, NULL);
	switch (r) {
	case PCOPROC_ERROR_WPIPE:
		error (WARNING | PERROR, "failed to make pipe to write to command: [%s %s]",
		       argv[0], argv[1]);
		break;
	case PCOPROC_ERROR_RPIPE:
		error (WARNING | PERROR, "failed to make pipe to read from command: [%s %s]",
		       argv[0], argv[1]);
		break;
	case PCOPROC_ERROR_FORK:
		error (WARNING | PERROR, "failed to do fork: [%s %s]",
		       argv[0], argv[1]);
		break;
	case PCOPROC_SUCCESSFUL:
		break;
	}

	if (pp)
	{
		vString* vline = vStringNew();

		while (readLineRawWithNoSeek (vline, pp))
		{
			char* line;
			char  kind_letter;

			vStringStripNewline (vline);
			line = vStringValue (vline);
			if (!loadPathKind (path, line, argv))
				break;

			kind_letter = path->kinds [path->n_kinds - 1].letter;
			if (kind_letter == file_kind)
				error (FATAL,
				       "Kind letter \'%c\' returned from xcmd %s of %s language is reserved in ctags main",
				       kind_letter,
				       vStringValue (path->path),
				       getLanguageName (language));
		}

		vStringDelete (vline);


		status = pcoprocClose (pp);

		/* TODO: Decode status */
		verbose("	status: %d\n", status);
		if (status != 0)
		{
			if (status > 0
			    && WIFEXITED (status)
			    && (WEXITSTATUS (status) == path->not_available_status))
				verbose ("xcmd: the %s backend is not available\n", argv[0]);
			else
				error (WARNING, "xcmd exits abnormally status(%d): [%s %s]",
				       status, argv[0], argv[1]);
			vStringDelete (opt);
			return FALSE;
		}
	}
	else
	{
		error (WARNING | PERROR, "cannot make pipe to xcmd: [%s %s]",
		       argv[0], argv[1]);
	}

	vStringDelete (opt);
	return path->kinds == NULL? FALSE: TRUE;
}
Example #26
0
/* Adds a name to the end of the scope string */
static void addToScope (vString *scope, vString *name)
{
	if (vStringLength(scope) > 0)
		vStringCatS(scope, "::");
	vStringCat(scope, name);
}
Example #27
0
static vString* ext2ptrnNew (const char *const ext)
{
	vString * ptrn = vStringNewInit ("*.");
	vStringCatS (ptrn, ext);
	return ptrn;
}
Example #28
0
static boolean parseTag (tokenInfo *const token, texKind kind)
{
    tokenInfo *const name = newToken ();
    vString *   fullname;
    boolean     useLongName = TRUE;

    fullname = vStringNew ();
    vStringClear (fullname);

    /*
     * Tex tags are of these formats:
     *   \keyword{any number of words}
     *   \keyword[short desc]{any number of words}
     *   \keyword*[short desc]{any number of words}
     *
     * When a keyword is found, loop through all words within
     * the curly braces for the tag name.
     */

    if (isType (token, TOKEN_KEYWORD))
    {
        copyToken (name, token);
        readToken (token);
    }

    if (isType (token, TOKEN_OPEN_SQUARE))
    {
        useLongName = FALSE;

        readToken (token);
        while (! isType (token, TOKEN_CLOSE_SQUARE) )
        {
            if (isType (token, TOKEN_IDENTIFIER))
            {
                if (fullname->length > 0)
                    vStringCatS (fullname, " ");
                vStringCatS (fullname, vStringValue (token->string));
            }
            readToken (token);
        }
        vStringTerminate (fullname);
        vStringCopy (name->string, fullname);
        makeTexTag (name, kind);
    }

    if (isType (token, TOKEN_STAR))
    {
        readToken (token);
    }

    if (isType (token, TOKEN_OPEN_CURLY))
    {
        readToken (token);
        while (! isType (token, TOKEN_CLOSE_CURLY) )
        {
            if (isType (token, TOKEN_IDENTIFIER) && useLongName)
            {
                if (fullname->length > 0)
                    vStringCatS (fullname, " ");
                vStringCatS (fullname, vStringValue (token->string));
            }
            readToken (token);
        }
        if (useLongName) 
        {
            vStringTerminate (fullname);
            vStringCopy (name->string, fullname);
            makeTexTag (name, kind);
        }
    }

    deleteToken (name);
    vStringDelete (fullname);
    return TRUE;
}
Example #29
0
static void readTokenFull (tokenInfo *const token, boolean include_newlines, vString *const repr)
{
	int c;
	int i;

	token->type			= TOKEN_UNDEFINED;
	token->keyword		= KEYWORD_NONE;
	vStringClear (token->string);

getNextChar:
	i = 0;
	do
	{
		c = fileGetc ();
		i++;
	}
	while (c == '\t'  ||  c == ' ' ||
		   ((c == '\r' || c == '\n') && ! include_newlines));

	token->lineNumber   = getSourceLineNumber ();
	token->filePosition = getInputFilePosition ();

	if (repr)
	{
		if (i > 1)
			vStringPut (repr, ' ');
		vStringPut (repr, c);
	}

	switch (c)
	{
		case EOF: token->type = TOKEN_EOF;					break;
		case '(': token->type = TOKEN_OPEN_PAREN;			break;
		case ')': token->type = TOKEN_CLOSE_PAREN;			break;
		case ';': token->type = TOKEN_SEMICOLON;			break;
		case ',': token->type = TOKEN_COMMA;				break;
		case '.': token->type = TOKEN_PERIOD;				break;
		case ':': token->type = TOKEN_COLON;				break;
		case '{': token->type = TOKEN_OPEN_CURLY;			break;
		case '}': token->type = TOKEN_CLOSE_CURLY;			break;
		case '=': token->type = TOKEN_EQUAL_SIGN;			break;
		case '[': token->type = TOKEN_OPEN_SQUARE;			break;
		case ']': token->type = TOKEN_CLOSE_SQUARE;			break;

		case '+':
		case '-':
			{
				int d = fileGetc ();
				if (d == c) /* ++ or -- */
					token->type = TOKEN_POSTFIX_OPERATOR;
				else
				{
					fileUngetc (d);
					token->type = TOKEN_BINARY_OPERATOR;
				}
				break;
			}

		case '*':
		case '%':
		case '?':
		case '>':
		case '<':
		case '^':
		case '|':
		case '&':
			token->type = TOKEN_BINARY_OPERATOR;
			break;

		case '\r':
		case '\n':
			/* This isn't strictly correct per the standard, but following the
			 * real rules means understanding all statements, and that's not
			 * what the parser currently does.  What we do here is a guess, by
			 * avoiding inserting semicolons that would make the statement on
			 * the left invalid.  Hopefully this should not have false negatives
			 * (e.g. should not miss insertion of a semicolon) but might have
			 * false positives (e.g. it will wrongfully emit a semicolon for the
			 * newline in "foo\n+bar").
			 * This should however be mostly harmless as we only deal with
			 * newlines in specific situations where we know a false positive
			 * wouldn't hurt too bad. */
			switch (LastTokenType)
			{
				/* these cannot be the end of a statement, so hold the newline */
				case TOKEN_EQUAL_SIGN:
				case TOKEN_COLON:
				case TOKEN_PERIOD:
				case TOKEN_FORWARD_SLASH:
				case TOKEN_BINARY_OPERATOR:
				/* and these already end one, no need to duplicate it */
				case TOKEN_SEMICOLON:
				case TOKEN_COMMA:
				case TOKEN_CLOSE_CURLY:
				case TOKEN_OPEN_CURLY:
					include_newlines = FALSE; /* no need to recheck */
					goto getNextChar;
					break;
				default:
					token->type = TOKEN_SEMICOLON;
			}
			break;

		case '\'':
		case '"':
				  token->type = TOKEN_STRING;
				  parseString (token->string, c);
				  token->lineNumber = getSourceLineNumber ();
				  token->filePosition = getInputFilePosition ();
				  if (repr)
				  {
					  vStringCat (repr, token->string);
					  vStringPut (repr, c);
				  }
				  break;

		case '\\':
				  c = fileGetc ();
				  if (c != '\\'  && c != '"'  &&  !isspace (c))
					  fileUngetc (c);
				  token->type = TOKEN_CHARACTER;
				  token->lineNumber = getSourceLineNumber ();
				  token->filePosition = getInputFilePosition ();
				  break;

		case '/':
				  {
					  int d = fileGetc ();
					  if ( (d != '*') &&		/* is this the start of a comment? */
							  (d != '/') )		/* is a one line comment? */
					  {
						  fileUngetc (d);
						  switch (LastTokenType)
						  {
							  case TOKEN_CHARACTER:
							  case TOKEN_IDENTIFIER:
							  case TOKEN_STRING:
							  case TOKEN_CLOSE_CURLY:
							  case TOKEN_CLOSE_PAREN:
							  case TOKEN_CLOSE_SQUARE:
								  token->type = TOKEN_FORWARD_SLASH;
								  break;

							  default:
								  token->type = TOKEN_REGEXP;
								  parseRegExp ();
								  token->lineNumber = getSourceLineNumber ();
								  token->filePosition = getInputFilePosition ();
								  break;
						  }
					  }
					  else
					  {
						  if (repr) /* remove the / we added */
							  repr->buffer[--repr->length] = 0;
						  if (d == '*')
						  {
							  do
							  {
								  skipToCharacter ('*');
								  c = fileGetc ();
								  if (c == '/')
									  break;
								  else
									  fileUngetc (c);
							  } while (c != EOF && c != '\0');
							  goto getNextChar;
						  }
						  else if (d == '/')	/* is this the start of a comment?  */
						  {
							  skipToCharacter ('\n');
							  /* if we care about newlines, put it back so it is seen */
							  if (include_newlines)
								  fileUngetc ('\n');
							  goto getNextChar;
						  }
					  }
					  break;
				  }

		case '#':
				  /* skip shebang in case of e.g. Node.js scripts */
				  if (token->lineNumber > 1)
					  token->type = TOKEN_UNDEFINED;
				  else if ((c = fileGetc ()) != '!')
				  {
					  fileUngetc (c);
					  token->type = TOKEN_UNDEFINED;
				  }
				  else
				  {
					  skipToCharacter ('\n');
					  goto getNextChar;
				  }
				  break;

		default:
				  if (! isIdentChar (c))
					  token->type = TOKEN_UNDEFINED;
				  else
				  {
					  parseIdentifier (token->string, c);
					  token->lineNumber = getSourceLineNumber ();
					  token->filePosition = getInputFilePosition ();
					  token->keyword = analyzeToken (token->string);
					  if (isKeyword (token, KEYWORD_NONE))
						  token->type = TOKEN_IDENTIFIER;
					  else
						  token->type = TOKEN_KEYWORD;
					  if (repr && vStringLength (token->string) > 1)
						  vStringCatS (repr, vStringValue (token->string) + 1);
				  }
				  break;
	}

	LastTokenType = token->type;
}
Example #30
0
boolean cxxParserParseNextToken(void)
{
	CXXToken * t = cxxTokenCreate();

	// The token chain should not be allowed to grow arbitrairly large.
	// The token structures are quite big and it's easy to grow up to
	// 5-6GB or memory usage. However this limit should be large enough
	// to accomodate all the reasonable statements that could have some
	// information in them. This includes multiple function prototypes
	// in a single statement (ImageMagick has some examples) but probably
	// does NOT include large data tables.
	if(g_cxx.pTokenChain->iCount > 16384)
		cxxTokenChainDestroyLast(g_cxx.pTokenChain);

	cxxTokenChainAppend(g_cxx.pTokenChain,t);

	g_cxx.pToken = t;

	cxxParserSkipToNonWhiteSpace();

	// FIXME: this cpp handling is kind of broken:
	// it works only because the moon is in the correct phase.
	cppBeginStatement();

	// This must be done after getting char from input
	t->iLineNumber = getInputLineNumber();
	t->oFilePosition = getInputFilePosition();

	if(g_cxx.iChar == EOF)
	{
		t->eType = CXXTokenTypeEOF;
		t->bFollowedBySpace = FALSE;
		return FALSE;
	}

	unsigned int uInfo = (g_cxx.iChar < 0x80) ? g_aCharTable[g_cxx.iChar].uType : 0;

	//printf("Char %c %02x info %u\n",g_cxx.iChar,g_cxx.iChar,uInfo);

	if(uInfo & CXXCharTypeStartOfIdentifier)
	{
		// word
		t->eType = CXXTokenTypeIdentifier;
		t->bFollowedBySpace = FALSE;

		vStringPut(t->pszWord,g_cxx.iChar);

		// special case for tile, which may actually be an operator
		if(g_cxx.iChar == '~')
		{
			// may be followed by space!
			g_cxx.iChar = cppGetc();
			if(isspace(g_cxx.iChar))
			{
				t->bFollowedBySpace = TRUE;
				g_cxx.iChar = cppGetc();
				while(isspace(g_cxx.iChar))
					g_cxx.iChar = cppGetc();
			}

			// non space
			uInfo = (g_cxx.iChar < 0x80) ? g_aCharTable[g_cxx.iChar].uType : 0;
			if(!(uInfo & CXXCharTypeStartOfIdentifier))
			{
				// this is not an identifier after all
				t->eType = CXXTokenTypeOperator;
				if((!t->bFollowedBySpace) && g_cxx.iChar == '=')
				{
					// make ~= single token so it's not handled as
					// a separate assignment
					vStringPut(t->pszWord,g_cxx.iChar);
					g_cxx.iChar = cppGetc();
					t->bFollowedBySpace = isspace(g_cxx.iChar);
				}
				return TRUE;
			}
		} else {
			g_cxx.iChar = cppGetc();
		}

		for(;;)
		{
			uInfo = (g_cxx.iChar < 0x80) ? g_aCharTable[g_cxx.iChar].uType : 0;
			if(!(uInfo & CXXCharTypePartOfIdentifier))
				break;
			vStringPut(t->pszWord,g_cxx.iChar);
			g_cxx.iChar = cppGetc();
		}

		int iCXXKeyword = lookupKeyword(t->pszWord->buffer,g_cxx.eLanguage);
		if(iCXXKeyword >= 0)
		{
			if(
					(
						(iCXXKeyword == CXXKeywordFINAL) &&
						(!g_cxx.bParsingClassStructOrUnionDeclaration)
					) || (
						(
							(iCXXKeyword == CXXKeywordPUBLIC) ||
							(iCXXKeyword == CXXKeywordPROTECTED) ||
							(iCXXKeyword == CXXKeywordPRIVATE)
						) &&
						(!g_cxx.bEnablePublicProtectedPrivateKeywords)
					)
				)
			{
				t->eType = CXXTokenTypeIdentifier;
			} else {
				t->eType = CXXTokenTypeKeyword;
				t->eKeyword = (enum CXXKeyword)iCXXKeyword;

				if(iCXXKeyword == CXXKeyword__ATTRIBUTE__)
				{
					// special handling for __attribute__
					return cxxParserParseNextTokenCondenseAttribute();
				}
			}
		} else {
			boolean bIgnoreParens = FALSE;
			const char * szReplacement = NULL;
			if(isIgnoreToken(
					vStringValue(t->pszWord),
					&bIgnoreParens,
					&szReplacement
				))
			{
				CXX_DEBUG_PRINT("Ignore token %s",vStringValue(t->pszWord));
				// FIXME: Handle ignore parens!
				if(szReplacement && *szReplacement)
				{
					vStringClear(t->pszWord);
					vStringCatS(t->pszWord,szReplacement);
				} else {
					// skip
					cxxTokenChainDestroyLast(g_cxx.pTokenChain);
					return cxxParserParseNextToken();
				}
			}
		}

		t->bFollowedBySpace = t->bFollowedBySpace | isspace(g_cxx.iChar);

		return TRUE;
	}

	if(g_cxx.iChar == '-')
	{
		// special case for pointer
		vStringPut(t->pszWord,g_cxx.iChar);
		g_cxx.iChar = cppGetc();
		if(g_cxx.iChar == '>')
		{
			t->eType = CXXTokenTypePointerOperator;
			vStringPut(t->pszWord,g_cxx.iChar);
			g_cxx.iChar = cppGetc();
		} else {
			t->eType = CXXTokenTypeOperator;
			if(g_cxx.iChar == '-')
			{
				vStringPut(t->pszWord,g_cxx.iChar);
				g_cxx.iChar = cppGetc();
			}
		}
		t->bFollowedBySpace = isspace(g_cxx.iChar);
		return TRUE;
	}

#if 0
	// As long as we use cppGetc() we don't need this

	if(g_cxx.iChar == '"')
	{
		// special case for strings
		t->eType = CXXTokenTypeStringConstant;
		vStringPut(t->pszWord,g_cxx.iChar);
		// We don't even care of storing the other chars: we don't need
		// them for parsing
		// FIXME: We might need them in signature:() tag.. maybe add
		// them up to a certain length only?
		for(;;)
		{
			g_cxx.iChar = cppGetc();
			if(g_cxx.iChar == EOF)
			{
				t->bFollowedBySpace = FALSE;
				return TRUE;
			}
			if(g_cxx.iChar == '\\')
			{
				// escape
				g_cxx.iChar = cppGetc();
				if(g_cxx.iChar == EOF)
				{
					t->bFollowedBySpace = FALSE;
					return TRUE;
				}
			} else if(g_cxx.iChar == '"')
			{
				g_cxx.iChar = cppGetc();
				break;
			}
		}
		t->bFollowedBySpace = isspace(g_cxx.iChar);
		return TRUE;
	}
#else
	if(g_cxx.iChar == STRING_SYMBOL)
	{
		t->eType = CXXTokenTypeStringConstant;
		vStringPut(t->pszWord,'"');
		vStringPut(t->pszWord,'"');
		g_cxx.iChar = cppGetc();
		t->bFollowedBySpace = isspace(g_cxx.iChar);
		return TRUE;
	}
#endif

#if 0
	// As long as we use cppGetc() we don't need this
	if(g_cxx.iChar == '\'')
	{
		// special case for strings
		t->eType = CXXTokenTypeCharacterConstant;
		vStringPut(t->pszWord,g_cxx.iChar);
		// We don't even care storing the other chars: we don't
		// need them for parsing
		for(;;)
		{
			g_cxx.iChar = cppGetc();
			if(g_cxx.iChar == EOF)
			{
				t->bFollowedBySpace = FALSE;
				return TRUE;
			}
			if(g_cxx.iChar == '\\')
			{
				// escape
				g_cxx.iChar = cppGetc();
				if(g_cxx.iChar == EOF)
				{
					t->bFollowedBySpace = FALSE;
					return TRUE;
				}
			} else if(g_cxx.iChar == '\'')
			{
				g_cxx.iChar = cppGetc();
				break;
			}
		}
		t->bFollowedBySpace = isspace(g_cxx.iChar);
		return TRUE;
	}
#else
	if(g_cxx.iChar == CHAR_SYMBOL)
	{
		t->eType = CXXTokenTypeCharacterConstant;
		vStringPut(t->pszWord,'\'');
		vStringPut(t->pszWord,'\'');
		g_cxx.iChar = cppGetc();
		t->bFollowedBySpace = isspace(g_cxx.iChar);
		return TRUE;
	}
#endif

	if(uInfo & CXXCharTypeDecimalDigit)
	{
		// number
		t->eType = CXXTokenTypeNumber;
		vStringPut(t->pszWord,g_cxx.iChar);

		for(;;)
		{
			g_cxx.iChar = cppGetc();
			uInfo = (g_cxx.iChar < 0x80) ? g_aCharTable[g_cxx.iChar].uType : 0;
			if(!(uInfo & CXXCharTypeValidInNumber))
				break;
			vStringPut(t->pszWord,g_cxx.iChar);
		}

		t->bFollowedBySpace = isspace(g_cxx.iChar);
		return TRUE;
	}

	if(uInfo & CXXCharTypeNamedSingleOrRepeatedCharToken)
	{
		t->eType = g_aCharTable[g_cxx.iChar].uSingleTokenType;
		vStringPut(t->pszWord,g_cxx.iChar);
		int iChar = g_cxx.iChar;
		g_cxx.iChar = cppGetc();
		if(g_cxx.iChar == iChar)
		{
			t->eType = g_aCharTable[g_cxx.iChar].uMultiTokenType;
			// We could signal a syntax error with more than two colons
			// or equal signs...but we're tolerant
			do {
				vStringPut(t->pszWord,g_cxx.iChar);
				g_cxx.iChar = cppGetc();
			} while(g_cxx.iChar == iChar);
		}
		t->bFollowedBySpace = isspace(g_cxx.iChar);
		return TRUE;
	}

	if(uInfo & CXXCharTypeNamedSingleOrOperatorToken)
	{
		t->eType = g_aCharTable[g_cxx.iChar].uSingleTokenType;
		vStringPut(t->pszWord,g_cxx.iChar);
		g_cxx.iChar = cppGetc();
		uInfo = (g_cxx.iChar < 0x80) ? g_aCharTable[g_cxx.iChar].uType : 0;
		if(uInfo & (CXXCharTypeOperator | CXXCharTypeNamedSingleOrOperatorToken))
		{
			t->eType = CXXTokenTypeOperator;
			do {
				vStringPut(t->pszWord,g_cxx.iChar);
				g_cxx.iChar = cppGetc();
				uInfo = (g_cxx.iChar < 0x80) ? g_aCharTable[g_cxx.iChar].uType : 0;
			} while(
					uInfo &
						(CXXCharTypeOperator | CXXCharTypeNamedSingleOrOperatorToken)
				);
		}
		t->bFollowedBySpace = isspace(g_cxx.iChar);
		return TRUE;
	}

	if(uInfo & CXXCharTypeNamedSingleCharToken)
	{
		t->eType = g_aCharTable[g_cxx.iChar].uSingleTokenType;
		vStringPut(t->pszWord,g_cxx.iChar);
		g_cxx.iChar = cppGetc();
		t->bFollowedBySpace = isspace(g_cxx.iChar);
		return TRUE;
	}

	if(uInfo & CXXCharTypeOperator)
	{
		t->eType = CXXTokenTypeOperator;
		vStringPut(t->pszWord,g_cxx.iChar);
		g_cxx.iChar = cppGetc();
		uInfo = (g_cxx.iChar < 0x80) ? g_aCharTable[g_cxx.iChar].uType : 0;
		while(uInfo & CXXCharTypeOperator)
		{
			vStringPut(t->pszWord,g_cxx.iChar);
			g_cxx.iChar = cppGetc();
			uInfo = (g_cxx.iChar < 0x80) ? g_aCharTable[g_cxx.iChar].uType : 0;
		}
		t->bFollowedBySpace = isspace(g_cxx.iChar);
		return TRUE;
	}

	t->eType = CXXTokenTypeUnknown;
	vStringPut(t->pszWord,g_cxx.iChar);
	g_cxx.iChar = cppGetc();
	t->bFollowedBySpace = isspace(g_cxx.iChar);

	return TRUE;
}