⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 c.c

📁 ultraEdit的Ctag标签工具的实现源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
    else if (isLanguage (Lang_vera))
	result = VeraKinds [veraTagKind (type)].enabled;
    else
	result = CKinds [cTagKind (type)].enabled;
    return result;
}

static tagType declToTagType (const declType declaration)
{
    tagType type = TAG_UNDEFINED;

    switch (declaration)
    {
	case DECL_CLASS:	type = TAG_CLASS;	break;
	case DECL_ENUM:		type = TAG_ENUM;	break;
	case DECL_EVENT:	type = TAG_EVENT;	break;
	case DECL_FUNCTION:	type = TAG_FUNCTION;	break;
	case DECL_INTERFACE:	type = TAG_INTERFACE;	break;
	case DECL_NAMESPACE:	type = TAG_NAMESPACE;	break;
	case DECL_PROGRAM:	type = TAG_PROGRAM;	break;
	case DECL_TASK:		type = TAG_TASK;	break;
	case DECL_STRUCT:	type = TAG_STRUCT;	break;
	case DECL_UNION:	type = TAG_UNION;	break;

	default: Assert ("Unexpected declaration" == NULL); break;
    }
    return type;
}

static const char* accessField (const statementInfo *const st)
{
    const char* result = NULL;
    if (isLanguage (Lang_cpp)  &&  st->scope == SCOPE_FRIEND)
	result = "friend";
    else if (st->member.access != ACCESS_UNDEFINED)
	result = accessString (st->member.access);
    return result;
}

static void addOtherFields (tagEntryInfo* const tag, const tagType type,
			    const statementInfo *const st, vString *const scope)
{
    /*  For selected tag types, append an extension flag designating the
     *  parent object in which the tag is defined.
     */
    switch (type)
    {
	default: break;

	case TAG_FUNCTION:
	case TAG_METHOD:
	case TAG_PROTOTYPE:
	    if (vStringLength (Signature) > 0)
		tag->extensionFields.signature = vStringValue (Signature);
	case TAG_CLASS:
	case TAG_ENUM:
	case TAG_ENUMERATOR:
	case TAG_EVENT:
	case TAG_FIELD:
	case TAG_INTERFACE:
	case TAG_MEMBER:
	case TAG_NAMESPACE:
	case TAG_PROPERTY:
	case TAG_STRUCT:
	case TAG_TASK:
	case TAG_TYPEDEF:
	case TAG_UNION:
	    if (vStringLength (scope) > 0  &&
		(isMember (st) || st->parent->declaration == DECL_NAMESPACE))
	    {
		if (isType (st->context, TOKEN_NAME))
		    tag->extensionFields.scope [0] = tagName (TAG_CLASS);
		else
		    tag->extensionFields.scope [0] =
			tagName (declToTagType (parentDecl (st)));
		tag->extensionFields.scope [1] = vStringValue (scope);
	    }
	    if ((type == TAG_CLASS  ||  type == TAG_INTERFACE  ||
		 type == TAG_STRUCT) && vStringLength (st->parentClasses) > 0)
	    {

		tag->extensionFields.inheritance =
			vStringValue (st->parentClasses);
	    }
	    if (st->implementation != IMP_DEFAULT &&
		(isLanguage (Lang_cpp) || isLanguage (Lang_csharp) ||
		 isLanguage (Lang_java)))
	    {
		tag->extensionFields.implementation =
			implementationString (st->implementation);
	    }
	    if (isMember (st))
	    {
		tag->extensionFields.access = accessField (st);
	    }
	    break;
    }
}

static void addContextSeparator (vString *const scope)
{
    if (isLanguage (Lang_c)  ||  isLanguage (Lang_cpp))
	vStringCatS (scope, "::");
    else if (isLanguage (Lang_java) || isLanguage (Lang_csharp))
	vStringCatS (scope, ".");
}

static void findScopeHierarchy (vString *const string,
				const statementInfo *const st)
{
    const char* const anon = "<anonymous>";
    boolean nonAnonPresent = FALSE;

    vStringClear (string);
    if (isType (st->context, TOKEN_NAME))
    {
	vStringCopy (string, st->context->name);
	nonAnonPresent = TRUE;
    }
    if (st->parent != NULL)
    {
	vString *temp = vStringNew ();
	const statementInfo *s;

	for (s = st->parent  ;  s != NULL  ;  s = s->parent)
	{
	    if (isContextualStatement (s) ||
		s->declaration == DECL_NAMESPACE ||
		s->declaration == DECL_PROGRAM)
	    {
		vStringCopy (temp, string);
		vStringClear (string);
		if (isType (s->blockName, TOKEN_NAME))
		{
		    if (isType (s->context, TOKEN_NAME) &&
			vStringLength (s->context->name) > 0)
		    {
			vStringCat (string, s->context->name);
			addContextSeparator (string);
		    }
		    vStringCat (string, s->blockName->name);
		    nonAnonPresent = TRUE;
		}
		else
		    vStringCopyS (string, anon);
		if (vStringLength (temp) > 0)
		    addContextSeparator (string);
		vStringCat (string, temp);
	    }
	}
	vStringDelete (temp);

	if (! nonAnonPresent)
	    vStringClear (string);
    }
}

static void makeExtraTagEntry (const tagType type, tagEntryInfo *const e,
			       vString *const scope)
{
    if (Option.include.qualifiedTags  &&
	scope != NULL  &&  vStringLength (scope) > 0)
    {
	vString *const scopedName = vStringNew ();

	if (type != TAG_ENUMERATOR)
	    vStringCopy (scopedName, scope);
	else
	{
	    /* remove last component (i.e. enumeration name) from scope */
	    const char* const sc = vStringValue (scope);
	    const char* colon = strrchr (sc, ':');
	    if (colon != NULL)
	    {
		while (*colon == ':'  &&  colon > sc)
		    --colon;
		vStringNCopy (scopedName, scope, colon + 1 - sc);
	    }
	}
	if (vStringLength (scopedName) > 0)
	{
	    addContextSeparator (scopedName);
	    vStringCatS (scopedName, e->name);
	    e->name = vStringValue (scopedName);
	    makeTagEntry (e);
	}
	vStringDelete (scopedName);
    }
}

static void makeTag (const tokenInfo *const token,
		     const statementInfo *const st,
		     boolean isFileScope, const tagType type)
{
    /*  Nothing is really of file scope when it appears in a header file.
     */
    isFileScope = (boolean) (isFileScope && ! isHeaderFile ());

    if (isType (token, TOKEN_NAME)  &&  vStringLength (token->name) > 0  &&
	includeTag (type, isFileScope))
    {
	vString *scope = vStringNew ();
	tagEntryInfo e;

	initTagEntry (&e, vStringValue (token->name));

	e.lineNumber	= token->lineNumber;
	e.filePosition	= token->filePosition;
	e.isFileScope	= isFileScope;
	e.kindName	= tagName (type);
	e.kind		= tagLetter (type);

	findScopeHierarchy (scope, st);
	addOtherFields (&e, type, st, scope);

	makeTagEntry (&e);
	makeExtraTagEntry (type, &e, scope);
	vStringDelete (scope);
    }
}

static boolean isValidTypeSpecifier (const declType declaration)
{
    boolean result;
    switch (declaration)
    {
	case DECL_BASE:
	case DECL_CLASS:
	case DECL_ENUM:
	case DECL_EVENT:
	case DECL_STRUCT:
	case DECL_UNION:
	    result = TRUE;
	    break;

	default:
	    result = FALSE;
	    break;
    }
    return result;
}

static void qualifyEnumeratorTag (const statementInfo *const st,
				  const tokenInfo *const nameToken)
{
    if (isType (nameToken, TOKEN_NAME))
	makeTag (nameToken, st, TRUE, TAG_ENUMERATOR);
}

static void qualifyFunctionTag (const statementInfo *const st,
				const tokenInfo *const nameToken)
{
    if (isType (nameToken, TOKEN_NAME))
    {
	tagType type;
	const boolean isFileScope =
			(boolean) (st->member.access == ACCESS_PRIVATE ||
			(!isMember (st)  &&  st->scope == SCOPE_STATIC));
	if (isLanguage (Lang_java) || isLanguage (Lang_csharp))
	    type = TAG_METHOD;
	else if (isLanguage (Lang_vera)  &&  st->declaration == DECL_TASK)
	    type = TAG_TASK;
	else
	    type = TAG_FUNCTION;
	makeTag (nameToken, st, isFileScope, type);
    }
}

static void qualifyFunctionDeclTag (const statementInfo *const st,
				    const tokenInfo *const nameToken)
{
    if (! isType (nameToken, TOKEN_NAME))
	;
    else if (isLanguage (Lang_java) || isLanguage (Lang_csharp))
	qualifyFunctionTag (st, nameToken);
    else if (st->scope == SCOPE_TYPEDEF)
	makeTag (nameToken, st, TRUE, TAG_TYPEDEF);
    else if (isValidTypeSpecifier (st->declaration) && ! isLanguage (Lang_csharp))
	makeTag (nameToken, st, TRUE, TAG_PROTOTYPE);
}

static void qualifyCompoundTag (const statementInfo *const st,
				const tokenInfo *const nameToken)
{
    if (isType (nameToken, TOKEN_NAME))
    {
	const tagType type = declToTagType (st->declaration);
	const boolean fileScoped = (boolean)
		(!(isLanguage (Lang_java) ||
		   isLanguage (Lang_csharp) ||
		   isLanguage (Lang_vera)));

	if (type != TAG_UNDEFINED)
	    makeTag (nameToken, st, fileScoped, type);
    }
}

static void qualifyBlockTag (statementInfo *const st,
			     const tokenInfo *const nameToken)
{
    switch (st->declaration)
    {
	case DECL_CLASS:
	case DECL_ENUM:
	case DECL_INTERFACE:
	case DECL_NAMESPACE:
	case DECL_PROGRAM:
	case DECL_STRUCT:
	case DECL_UNION:
	    qualifyCompoundTag (st, nameToken);
	    break;
	default: break;
    }
}

static void qualifyVariableTag (const statementInfo *const st,
				const tokenInfo *const nameToken)
{
    /*	We have to watch that we do not interpret a declaration of the
     *	form "struct tag;" as a variable definition. In such a case, the
     *	token preceding the name will be a keyword.
     */
    if (! isType (nameToken, TOKEN_NAME))
	;
    else if (st->scope == SCOPE_TYPEDEF)
	makeTag (nameToken, st, TRUE, TAG_TYPEDEF);
    else if (st->declaration == DECL_EVENT)
	makeTag (nameToken, st, (boolean) (st->member.access == ACCESS_PRIVATE),
		TAG_EVENT);
    else if (st->declaration == DECL_PACKAGE)
	makeTag (nameToken, st, FALSE, TAG_PACKAGE);
    else if (isValidTypeSpecifier (st->declaration))
    {
	if (st->notVariable)
	    ;
	else if (isMember (st))
	{
	    if (isLanguage (Lang_java) || isLanguage (Lang_csharp))
		makeTag (nameToken, st,
			(boolean) (st->member.access == ACCESS_PRIVATE), TAG_FIELD);
	    else if (st->scope == SCOPE_GLOBAL  ||  st->scope == SCOPE_STATIC)
		makeTag (nameToken, st, TRUE, TAG_MEMBER);
	}
	else
	{
	    if (st->scope == SCOPE_EXTERN  ||  ! st->haveQualifyingName)
		makeTag (nameToken, st, FALSE, TAG_EXTERN_VAR);
	    else if (st->inFunction)
		makeTag (nameToken, st, (boolean) (st->scope == SCOPE_STATIC),
			TAG_LOCAL);
	    else
		makeTag (nameToken, st, (boolean) (st->scope == SCOPE_STATIC),
			TAG_VARIABLE);
	}
    }
}

/*
*   Parsing functions
*/

static int skipToOneOf (const char *const chars)
{
    int c;
    do
	c = cppGetc ();
    while (c != EOF  &&  c != '\0'  &&  strchr (chars, c) == NULL);
    return c;
}

/*  Skip to the next non-white character.
 */
static int skipToNonWhite (void)
{
    boolean found = FALSE;
    int c;

#if 0
    do
	c = cppGetc ();
    while (isspace (c));
#else
    while (1)
    {
	c = cppGetc ();
	if (isspace (c))
	    found = TRUE;
	else
	    break;
    }
    if (CollectingSignature && found)
	vStringPut (Signature, ' ');
#endif

    return c;
}

/*  Skips to the next brace in column 1. This is intended for cases where
 *  preprocessor constructs result in unbalanced braces.
 */
static void skipToFormattedBraceMatch (void)
{
    int c, next;

    c = cppGetc ();
    next = cppGetc ();
    while (c != EOF  &&  (c != '\n'  ||  next != '}'))
    {
	c = next;
	next = cppGetc ();
    }
}

/*  Skip to the matching character indicated by the pair string. If skipping
 *  to a matching brace and any brace is found within a different level of a
 *  #if conditional statement while brace formatting is in effect, we skip to
 *  the brace matched by its formatting. It is assumed that we have already
 *  read the character which starts the group (i.e. the first character of
 *  "pair").
 */
static void skipToMatch (const char *const pair)
{
    const boolean braceMatching = (boolean) (strcmp ("{}", pair) == 0);
    const boolean braceFormatting = (boolean) (isBraceFormat () && braceMatching);
    const unsigned int initialLevel = getDirectiveNestLevel ();
    const int begin = pair [0], end = pair [1];
    const unsigned long inputLineNumber = getInputLineNumber ();
    int matchLevel = 1;
    int c = '\0';

    while (matchLevel > 0  &&  (c = skipToNonWhite ()) != EOF)
    {
	if (CollectingSignature)
	    vStringPut (Signature, c);
	if (c == begin)
	{
	    ++matchLevel;
	    if (braceFormatting  &&  getDirectiveNestLevel () != initialLevel)
	    {
		skipToFormattedBraceMatch ();
		break;
	    }
	}
	else if (c == end)
	{
	    --matchLevel;
	    if (braceFormatting  &&  getDirectiveNestLevel () != initialLevel)
	    {
		skipToFormattedBraceMatch ();
		break;
	    }
	}
    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -