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

📄 eiffel.c

📁 ctags-5.5.4.tar.gz,一个很好的代码开发以及编辑源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/**   $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_TOOLstatic const char *FileName;static FILE *File;static int PrintClass;static int PrintReferences;static int SelfReferences;static int Debug;static stringList *GenericNames;static stringList *ReferencedTypes;#elsetypedef 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"}};#endifstatic 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_TOOLstatic 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 ();    switch (c)    {	case 'A':	d = '@';	break;	case 'B':	d = '\b';	break;	case 'C':	d = '^';	break;	case 'D':	d = '$';	break;	case 'F':	d = '\f';	break;	case 'H':	d = '\\';	break;	case 'L':	d = '~';	break;	case 'N':	d = '\n';	break;#ifdef QDOS	case 'Q':	d = 0x9F;	break;#else	case 'Q':	d = '`';	break;#endif	case 'R':	d = '\r';	break;	case 'S':	d = '#';	break;	case 'T':	d = '\t';	break;	case 'U':	d = '\0';	break;	case 'V':	d = '|';	break;	case '%':	d = '%';	break;	case '\'':	d = '\'';	break;	case '"':	d = '"';	break;	case '(':	d = '[';	break;	case ')':	d = ']';	break;	case '<':	d = '{';	break;	case '>':	d = '}';	break;	case '\n': skipToCharacter ('%'); break;	case '/':	{	    vString *string = parseInteger ('\0');	    const char *value = vStringValue (string);	    const unsigned long ascii = atol (value);	    c = fileGetc ();	    if (c == '/'  &&  ascii < 256)		d = ascii;	    break;	}	default: break;    }    return d;}static int parseCharacter (void){    int c = fileGetc ();    int result = c;    if (c == '%')	result = parseEscapedCharacter ();    c = fileGetc ();    if (c != '\'')	skipToCharacter ('\n');    return result;}static void parseString (vString *const string){    boolean verbatim = FALSE;    boolean align = FALSE;    boolean end = FALSE;    vString *verbatimCloser = NULL;    vString *lastLine = NULL;    int prev = '\0';    int c;    while (! end)    {	c = fileGetc ();	if (c == EOF)	    end = TRUE;	else if (c == '"')	{	    if (! verbatim)		end = TRUE;	    else		end = (boolean) (strcmp (vStringValue (lastLine),					 vStringValue (verbatimCloser)) == 0);	}	else if (c == '\n')	{	    if (verbatim)		vStringClear (lastLine);	    if (prev == '[' /* ||  prev == '{' */)	    {		verbatim = TRUE;		verbatimCloser = vStringNew ();		lastLine = vStringNew ();		if (prev == '{')		    vStringPut (verbatimCloser, '}');		else		{		    vStringPut (verbatimCloser, ']');		    align = TRUE;		}		vStringNCat (verbatimCloser, string, vStringLength (string) - 1);		vStringClear (string);	    }	    if (verbatim && align)	    {		do		    c = fileGetc ();		while (isspace (c));	    }	}	else if (c == '%')	    c = parseEscapedCharacter ();	if (! end)	{	    vStringPut (string, c);	    if (verbatim)	    {		vStringPut (lastLine, c);		vStringTerminate (lastLine);	    }	    prev = c;	}    }    vStringTerminate (string);}/*  Read a C identifier beginning with "firstChar" and places it into "name". */static void parseIdentifier (vString *const string, const int firstChar){    int c = firstChar;    do    {	vStringPut (string, c);	c = fileGetc ();    } while (isident (c));    vStringTerminate (string);    if (!isspace (c))	fileUngetc (c);		/* unget non-identifier character */}static void parseFreeOperator (vString *const string, const int firstChar){    int c = firstChar;    do    {	vStringPut (string, c);	c = fileGetc ();    } while (c > ' ');    vStringTerminate (string);    if (!isspace (c))	fileUngetc (c);		/* unget non-identifier character */}static keywordId analyzeToken (vString *const name){    static vString *keyword = NULL;    keywordId id;    if (keyword == NULL)	keyword = vStringNew ();    vStringCopyToLower (keyword, name);    id = (keywordId) lookupKeyword (vStringValue (keyword), Lang_eiffel);    return id;}static void readToken (tokenInfo *const token){    int c;    token->type    = TOKEN_UNDEFINED;    token->keyword = KEYWORD_NONE;    vStringClear (token->string);getNextChar:    do	c = fileGetc ();    while (c == '\t'  ||  c == ' '  ||  c == '\n');    switch (c)    {	case EOF:	longjmp (Exception, (int)ExceptionEOF);	break;	case '!':	token->type = TOKEN_BANG;		break;	case '$':	token->type = TOKEN_DOLLAR;		break;	case '(':	token->type = TOKEN_OPEN_PAREN;		break;	case ')':	token->type = TOKEN_CLOSE_PAREN;	break;	case ',':	token->type = TOKEN_COMMA;		break;	case '.':	token->type = TOKEN_DOT;		break;	case ';':	goto getNextChar;	case '[':	token->type = TOKEN_OPEN_BRACKET;	break;	case ']':	token->type = TOKEN_CLOSE_BRACKET;	break;	case '{':	token->type = TOKEN_OPEN_BRACE;		break;	case '}':	token->type = TOKEN_CLOSE_BRACE;	break;	case '~':	token->type = TOKEN_TILDE;		break;	case '+':	case '*':	case '^':	case '=':	token->type = TOKEN_OPERATOR;		break;	case '-':	    c = fileGetc ();	    if (c == '>')		token->type = TOKEN_CONSTRAINT;	    else if (c == '-')		/* is this the start of a comment? */	    {		skipToCharacter ('\n');		goto getNextChar;	    }	    else

⌨️ 快捷键说明

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