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

📄 eiffel.c

📁 ultraEdit的Ctag标签工具的实现源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
*   $Id: eiffel.c,v 1.16 2003/07/17 03:08:23 darren Exp $
*
*   Copyright (c) 1998-2002, Darren Hiebert
*
*   This source code is released for free distribution under the terms of the
*   GNU General Public License.
*
*   This module contains functions for generating tags for Eiffel language
*   files.
*/

/*
*   INCLUDE FILES
*/
#include "general.h"	/* must always come first */

#ifdef TYPE_REFERENCE_TOOL
#include <stdio.h>
#endif
#include <string.h>
#include <limits.h>
#include <ctype.h>	/* to define tolower () */
#include <setjmp.h>

#include "debug.h"
#include "keyword.h"
#include "routines.h"
#include "vstring.h"
#ifndef TYPE_REFERENCE_TOOL
#include "entry.h"
#include "options.h"
#include "parse.h"
#include "read.h"
#endif

/*
*   MACROS
*/
#define isident(c)		(isalnum(c) || (c) == '_')
#define isFreeOperatorChar(c)	((c) == '@' || (c) == '#' || \
				 (c) == '|' || (c) == '&')
#define isType(token,t)		(boolean) ((token)->type == (t))
#define isKeyword(token,k)	(boolean) ((token)->keyword == (k))

/*
*   DATA DECLARATIONS
*/

typedef enum eException { ExceptionNone, ExceptionEOF } exception_t;

/*  Used to specify type of keyword.
 */
typedef enum eKeywordId {
    KEYWORD_NONE = -1,
    KEYWORD_alias, KEYWORD_all, KEYWORD_and, KEYWORD_as, KEYWORD_check,
    KEYWORD_class, KEYWORD_create, KEYWORD_creation, KEYWORD_Current,
    KEYWORD_debug, KEYWORD_deferred, KEYWORD_do, KEYWORD_else,
    KEYWORD_elseif, KEYWORD_end, KEYWORD_ensure, KEYWORD_expanded,
    KEYWORD_export, KEYWORD_external, KEYWORD_false, KEYWORD_feature,
    KEYWORD_from, KEYWORD_frozen, KEYWORD_if, KEYWORD_implies,
    KEYWORD_indexing, KEYWORD_infix, KEYWORD_inherit, KEYWORD_inspect,
    KEYWORD_invariant, KEYWORD_is, KEYWORD_like, KEYWORD_local,
    KEYWORD_loop, KEYWORD_not, KEYWORD_obsolete, KEYWORD_old, KEYWORD_once,
    KEYWORD_or, KEYWORD_prefix, KEYWORD_redefine, KEYWORD_rename,
    KEYWORD_require, KEYWORD_rescue, KEYWORD_Result, KEYWORD_retry,
    KEYWORD_select, KEYWORD_separate, KEYWORD_strip, KEYWORD_then,
    KEYWORD_true, KEYWORD_undefine, KEYWORD_unique, KEYWORD_until,
    KEYWORD_variant, KEYWORD_when, KEYWORD_xor
} keywordId;

/*  Used to determine whether keyword is valid for the token language and
 *  what its ID is.
 */
typedef struct sKeywordDesc {
    const char *name;
    keywordId id;
} keywordDesc;

typedef enum eTokenType {
    TOKEN_UNDEFINED,
    TOKEN_BANG,
    TOKEN_CHARACTER,
    TOKEN_CLOSE_BRACE,
    TOKEN_CLOSE_BRACKET,
    TOKEN_CLOSE_PAREN,
    TOKEN_COLON,
    TOKEN_COMMA,
    TOKEN_CONSTRAINT,
    TOKEN_DOT,
    TOKEN_DOLLAR,
    TOKEN_IDENTIFIER,
    TOKEN_KEYWORD,
    TOKEN_NUMERIC,
    TOKEN_OPEN_BRACE,
    TOKEN_OPEN_BRACKET,
    TOKEN_OPEN_PAREN,
    TOKEN_OPERATOR,
    TOKEN_OTHER,
    TOKEN_SEPARATOR,
    TOKEN_STRING,
    TOKEN_TILDE
} tokenType;

typedef struct sTokenInfo {
    tokenType	type;
    keywordId	keyword;
    boolean	isExported;
    vString *	string;
    vString *	className;
    vString *	featureName;
} tokenInfo;

/*
*   DATA DEFINITIONS
*/

static langType Lang_eiffel;

#ifdef TYPE_REFERENCE_TOOL

static const char *FileName;
static FILE *File;
static int PrintClass;
static int PrintReferences;
static int SelfReferences;
static int Debug;
static stringList *GenericNames;
static stringList *ReferencedTypes;

#else

typedef enum {
    EKIND_CLASS, EKIND_FEATURE, EKIND_LOCAL, EKIND_QUALIFIED_TAGS
} eiffelKind;

static kindOption EiffelKinds [] = {
    { TRUE,  'c', "class",   "classes"},
    { TRUE,  'f', "feature", "features"},
    { FALSE, 'l', "local",   "local entities"}
};

#endif

static langType Lang_eiffel;

static jmp_buf Exception;

static const keywordDesc EiffelKeywordTable [] = {
    /* keyword		keyword ID */
    { "alias",		KEYWORD_alias		},
    { "all",		KEYWORD_all		},
    { "and",		KEYWORD_and		},
    { "as",		KEYWORD_as		},
    { "check",		KEYWORD_check		},
    { "class",		KEYWORD_class		},
    { "create",		KEYWORD_create		},
    { "creation",	KEYWORD_creation	},
    { "current",	KEYWORD_Current		},
    { "debug",		KEYWORD_debug		},
    { "deferred",	KEYWORD_deferred	},
    { "do",		KEYWORD_do		},
    { "else",		KEYWORD_else		},
    { "elseif",		KEYWORD_elseif		},
    { "end",		KEYWORD_end		},
    { "ensure",		KEYWORD_ensure		},
    { "expanded",	KEYWORD_expanded	},
    { "export",		KEYWORD_export		},
    { "external",	KEYWORD_external	},
    { "false",		KEYWORD_false		},
    { "feature",	KEYWORD_feature		},
    { "from",		KEYWORD_from		},
    { "frozen",		KEYWORD_frozen		},
    { "if",		KEYWORD_if		},
    { "implies",	KEYWORD_implies		},
    { "indexing",	KEYWORD_indexing	},
    { "infix",		KEYWORD_infix		},
    { "inherit",	KEYWORD_inherit		},
    { "inspect",	KEYWORD_inspect		},
    { "invariant",	KEYWORD_invariant	},
    { "is",		KEYWORD_is		},
    { "like",		KEYWORD_like		},
    { "local",		KEYWORD_local		},
    { "loop",		KEYWORD_loop		},
    { "not",		KEYWORD_not		},
    { "obsolete",	KEYWORD_obsolete	},
    { "old",		KEYWORD_old		},
    { "once",		KEYWORD_once		},
    { "or",		KEYWORD_or		},
    { "prefix",		KEYWORD_prefix		},
    { "redefine",	KEYWORD_redefine	},
    { "rename",		KEYWORD_rename		},
    { "require",	KEYWORD_require		},
    { "rescue",		KEYWORD_rescue		},
    { "result",		KEYWORD_Result		},
    { "retry",		KEYWORD_retry		},
    { "select",		KEYWORD_select		},
    { "separate",	KEYWORD_separate	},
    { "strip",		KEYWORD_strip		},
    { "then",		KEYWORD_then		},
    { "true",		KEYWORD_true		},
    { "undefine",	KEYWORD_undefine	},
    { "unique",		KEYWORD_unique		},
    { "until",		KEYWORD_until		},
    { "variant",	KEYWORD_variant		},
    { "when",		KEYWORD_when		},
    { "xor",		KEYWORD_xor		}
};

/*
*   FUNCTION DEFINITIONS
*/

static void buildEiffelKeywordHash (void)
{
    const size_t count = sizeof (EiffelKeywordTable) /
			 sizeof (EiffelKeywordTable [0]);
    size_t i;
    for (i = 0  ;  i < count  ;  ++i)
    {
	const keywordDesc* const p = &EiffelKeywordTable [i];
	addKeyword (p->name, Lang_eiffel, (int) p->id);
    }
}

#ifdef TYPE_REFERENCE_TOOL

static void addGenericName (tokenInfo *const token)
{
    if (vStringLength (token->string) > 0)
	stringListAdd (GenericNames, vStringNewCopy (token->string));
}

static boolean isGeneric (tokenInfo *const token)
{
    return (boolean) stringListHasInsensitive (
	GenericNames, vStringValue (token->string));
}

static void reportType (tokenInfo *const token)
{
    if (vStringLength (token->string) > 0  && ! isGeneric (token)  &&
	(SelfReferences || strcasecmp (vStringValue (
	    token->string), vStringValue (token->className)) != 0) &&
	! stringListHasInsensitive (
	    ReferencedTypes, vStringValue (token->string)))
    {
	printf ("%s\n", vStringValue (token->string));
	stringListAdd (ReferencedTypes, vStringNewCopy (token->string));
    }
}

static int fileGetc (void)
{
    int c = getc (File);
    if (c == '\r')
    {
	c = getc (File);
	if (c != '\n')
	{
	    ungetc (c, File);
	    c = '\n';
	}
    }
    if (Debug > 0  &&  c != EOF)
	putc (c, errout);
    return c;
}

static int fileUngetc (c)
{
    return ungetc (c, File);
}

extern char *readLine (vString *const vLine, FILE *const fp)
{
    return NULL;
}

#else

/*
*   Tag generation functions
*/

static void makeEiffelClassTag (tokenInfo *const token)
{
    if (EiffelKinds [EKIND_CLASS].enabled)
    {
	const char *const name = vStringValue (token->string);
	tagEntryInfo e;

	initTagEntry (&e, name);

	e.kindName = EiffelKinds [EKIND_CLASS].name;
	e.kind     = EiffelKinds [EKIND_CLASS].letter;

	makeTagEntry (&e);
    }
    vStringCopy (token->className, token->string);
}

static void makeEiffelFeatureTag (tokenInfo *const token)
{
    if (EiffelKinds [EKIND_FEATURE].enabled  &&
	(token->isExported  ||  Option.include.fileScope))
    {
	const char *const name = vStringValue (token->string);
	tagEntryInfo e;

	initTagEntry (&e, name);

	e.isFileScope	= (boolean) (! token->isExported);
	e.kindName	= EiffelKinds [EKIND_FEATURE].name;
	e.kind		= EiffelKinds [EKIND_FEATURE].letter;
	e.extensionFields.scope [0] = EiffelKinds [EKIND_CLASS].name;
	e.extensionFields.scope [1] = vStringValue (token->className);

	makeTagEntry (&e);

	if (Option.include.qualifiedTags)
	{
	    vString* qualified = vStringNewInit (vStringValue (token->className));
	    vStringPut (qualified, '.');
	    vStringCat (qualified, token->string);
	    e.name = vStringValue (qualified);
	    makeTagEntry (&e);
	    vStringDelete (qualified);
	}
    }
    vStringCopy (token->featureName, token->string);
}

static void makeEiffelLocalTag (tokenInfo *const token)
{
    if (EiffelKinds [EKIND_LOCAL].enabled && Option.include.fileScope)
    {
	const char *const name = vStringValue (token->string);
	vString* scope = vStringNew ();
	tagEntryInfo e;

	initTagEntry (&e, name);

	e.isFileScope	= TRUE;
	e.kindName	= EiffelKinds [EKIND_LOCAL].name;
	e.kind		= EiffelKinds [EKIND_LOCAL].letter;

	vStringCopy (scope, token->className);
	vStringPut (scope, '.');
	vStringCat (scope, token->featureName);

	e.extensionFields.scope [0] = EiffelKinds [EKIND_FEATURE].name;
	e.extensionFields.scope [1] = vStringValue (scope);

	makeTagEntry (&e);
	vStringDelete (scope);
    }
}

#endif

/*
*   Parsing functions
*/

static int skipToCharacter (const int c)
{
    int d;

    do
    {
	d = fileGetc ();
    } while (d != EOF  &&  d != c);

    return d;
}

/*  If a numeric is passed in 'c', this is used as the first digit of the
 *  numeric being parsed.
 */
static vString *parseInteger (int c)
{
    static vString *string = NULL;

    if (string == NULL)
	string = vStringNew ();
    vStringClear (string);

    if (c == '\0')
	c = fileGetc ();
    if (c == '-')
    {
	vStringPut (string, c);
	c = fileGetc ();
    }
    else if (! isdigit (c))
	c = fileGetc ();
    while (c != EOF  &&  (isdigit (c)  ||  c == '_'))
    {
	vStringPut (string, c);
	c = fileGetc ();
    }
    vStringTerminate (string);
    fileUngetc (c);

    return string;
}

static vString *parseNumeric (int c)
{
    static vString *string = NULL;

    if (string == NULL)
	string = vStringNew ();
    vStringCopy (string, parseInteger (c));

    c = fileGetc ();
    if (c == '.')
    {
	vStringPut (string, c);
	vStringCat (string, parseInteger ('\0'));
	c = fileGetc ();
    }
    if (tolower (c) == 'e')
    {
	vStringPut (string, c);
	vStringCat (string, parseInteger ('\0'));
    }
    else if (!isspace (c))
	fileUngetc (c);

    vStringTerminate (string);

    return string;
}

static int parseEscapedCharacter (void)
{
    int d = '\0';
    int c = fileGetc ();

⌨️ 快捷键说明

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