get.c
资源名称:vim53src.zip [点击查看]
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:13k
源码类别:
编辑器/阅读器
开发平台:
DOS
- /*****************************************************************************
- * $Id: get.c,v 6.2 1998/07/15 04:15:51 darren Exp $
- *
- * Copyright (c) 1996-1998, Darren Hiebert
- *
- * This source code is released for free distribution under the terms of the
- * GNU General Public License.
- *
- * This module contains the high level source read functions (preprocessor
- * directives are handled within this level).
- *****************************************************************************/
- /*============================================================================
- = Include files
- ============================================================================*/
- #ifdef HAVE_CONFIG_H
- # include <config.h>
- #endif
- #include "ctags.h"
- /*============================================================================
- = Data declarations
- ============================================================================*/
- typedef enum { COMMENT_NONE, COMMENT_C, COMMENT_CPLUS } Comment;
- /*============================================================================
- = Data definitions
- ============================================================================*/
- cppState Cpp = {
- 0, /* ungetch */
- FALSE, /* resolveRequired */
- {
- DRCTV_NONE, /* state */
- FALSE, /* accept */
- { 0, 0, "" }, /* tag info */
- 0, /* nestLevel */
- { {FALSE,FALSE,FALSE,FALSE} } /* ifdef array */
- } /* directive */
- };
- /*============================================================================
- = Function prototypes
- ============================================================================*/
- static boolean readDirective __ARGS((int c, char *const name, unsigned int maxLength));
- static boolean readDefineTag __ARGS((int c, tagInfo *const tag, boolean *const parameterized));
- static conditionalInfo *currentConditional __ARGS((void));
- static boolean isIgnore __ARGS((void));
- static boolean setIgnore __ARGS((const boolean ignore));
- static boolean isIgnoreBranch __ARGS((void));
- static void chooseBranch __ARGS((void));
- static boolean pushConditional __ARGS((const boolean firstBranchChosen));
- static boolean popConditional __ARGS((void));
- static boolean handleDirective __ARGS((const int c));
- static Comment isComment __ARGS((void));
- static int skipOverCComment __ARGS((void));
- static int skipOverCplusComment __ARGS((void));
- static int skipToEndOfString __ARGS((void));
- static int skipToEndOfChar __ARGS((void));
- /*============================================================================
- = Function definitions
- ============================================================================*/
- /*----------------------------------------------------------------------------
- * Scanning functions
- *
- * This section handles preprocessor directives. It strips out all
- * directives and may emit a tag for #define directives.
- *--------------------------------------------------------------------------*/
- extern boolean cppOpen( name, language, isHeader )
- const char *const name;
- const langType language;
- const boolean isHeader;
- {
- boolean opened;
- opened = fileOpen(name, language, isHeader);
- if (opened)
- {
- Cpp.ungetch = ' ';
- Cpp.resolveRequired = FALSE;
- Cpp.directive.state = DRCTV_NONE;
- Cpp.directive.accept = TRUE;
- Cpp.directive.nestLevel = 0;
- }
- return opened;
- }
- extern void cppClose()
- {
- fileClose();
- }
- /* This puts a character back into the input queue for the source File.
- */
- extern void cppUngetc( c )
- const int c;
- {
- Cpp.ungetch = c;
- }
- /* Reads a directive, whose first character is given by "c", into "name".
- */
- static boolean readDirective( c, name, maxLength )
- int c;
- char *const name;
- unsigned int maxLength;
- {
- unsigned int i;
- for (i = 0 ; i < maxLength - 1 ; ++i)
- {
- if (i > 0)
- {
- c = fileGetc();
- if (c == EOF || ! isalpha(c))
- {
- fileUngetc(c);
- break;
- }
- }
- name[i] = c;
- }
- name[i] = ' '; /* null terminate */
- return (boolean)isspacetab(c);
- }
- /* Reads an identifier, whose first character is given by "c", into "tag",
- * together with the file location and corresponding line number.
- */
- static boolean readDefineTag( c, tag, parameterized )
- int c;
- tagInfo *const tag;
- boolean *const parameterized;
- {
- char *name = tag->name;
- do
- {
- *name++ = c;
- } while (c = fileGetc(), (c != EOF && isident(c)));
- fileUngetc(c);
- *name = ' '; /* null terminate */
- tag->location = File.seek;
- tag->lineNumber = File.lineNumber;
- *parameterized = (boolean)(c == '(');
- return (boolean)(isspace(c) || c == '(');
- }
- static conditionalInfo *currentConditional()
- {
- return &Cpp.directive.ifdef[Cpp.directive.nestLevel];
- }
- static boolean isIgnore()
- {
- return Cpp.directive.ifdef[Cpp.directive.nestLevel].ignoring;
- }
- static boolean setIgnore( ignore )
- const boolean ignore;
- {
- return Cpp.directive.ifdef[Cpp.directive.nestLevel].ignoring = ignore;
- }
- static boolean isIgnoreBranch()
- {
- conditionalInfo *const ifdef = currentConditional();
- /* Force a single branch if an incomplete statement is discovered
- * en route. This may have allowed earlier branches containing complete
- * statements to be followed, but we must follow no further branches.
- */
- if (Cpp.resolveRequired && ! Option.braceFormat)
- ifdef->singleBranch = TRUE;
- /* We will ignore this branch in the following cases:
- *
- * 1. We are ignoring all branches (conditional was within an ignored
- * branch of the parent conditional)
- * 2. A branch has already been chosen and either of:
- * a. A statement was incomplete upon entering the conditional
- * b. A statement is incomplete upon encountering a branch
- */
- return (boolean)(ifdef->ignoreAllBranches ||
- (ifdef->branchChosen && ifdef->singleBranch));
- }
- static void chooseBranch()
- {
- if (! Option.braceFormat)
- {
- conditionalInfo *const ifdef = currentConditional();
- ifdef->branchChosen = (boolean)(ifdef->singleBranch ||
- Cpp.resolveRequired);
- }
- }
- /* Pushes one nesting level for an #if directive, indicating whether or not
- * the branch should be ignored and whether a branch has already been chosen.
- */
- static boolean pushConditional( firstBranchChosen )
- const boolean firstBranchChosen;
- {
- const boolean ignoreAllBranches = isIgnore(); /* current ignore */
- boolean ignoreBranch = FALSE;
- if (Cpp.directive.nestLevel < (unsigned int)MaxCppNestingLevel - 1)
- {
- conditionalInfo *ifdef;
- ++Cpp.directive.nestLevel;
- ifdef = currentConditional();
- /* We take a snapshot of whether there is an incomplete statement in
- * progress upon encountering the preprocessor conditional. If so,
- * then we will flag that only a single branch of the conditional
- * should be followed.
- */
- ifdef->ignoreAllBranches= ignoreAllBranches;
- ifdef->singleBranch = Cpp.resolveRequired;
- ifdef->branchChosen = firstBranchChosen;
- ifdef->ignoring = (boolean)(ignoreAllBranches || (
- !firstBranchChosen && !Option.braceFormat &&
- (ifdef->singleBranch || !Option.if0)));
- ignoreBranch = ifdef->ignoring;
- }
- return ignoreBranch;
- }
- /* Pops one nesting level for an #endif directive.
- */
- static boolean popConditional()
- {
- if (Cpp.directive.nestLevel > 0)
- --Cpp.directive.nestLevel;
- return isIgnore();
- }
- /* Handles a pre-processor directive whose first character is given by "c".
- */
- static boolean handleDirective( c )
- const int c;
- {
- enum { maxDirectiveName = 10 };
- char directive[maxDirectiveName];
- const tagScope scope = File.isHeader ? SCOPE_GLOBAL : SCOPE_STATIC;
- boolean ignore = FALSE;
- DebugStatement( const boolean ignore0 = isIgnore(); )
- switch (Cpp.directive.state)
- {
- case DRCTV_NONE: /* used to ignore rest of line past interesting part*/
- ignore = isIgnore();
- break;
- case DRCTV_HASH: /* '#' read; determine directive */
- readDirective(c, directive, maxDirectiveName);
- if (stringMatch(directive, "define"))
- Cpp.directive.state = DRCTV_DEFINE;
- else if (strncmp(directive, "if", (size_t)2) == 0)
- Cpp.directive.state = DRCTV_IF;
- else if (stringMatch(directive, "elif") ||
- stringMatch(directive, "else"))
- {
- ignore = setIgnore(isIgnoreBranch());
- if (! ignore && stringMatch(directive, "else"))
- chooseBranch();
- Cpp.directive.state = DRCTV_NONE;
- DebugStatement( if (ignore != ignore0) debugCppIgnore(ignore); )
- }
- else if (stringMatch(directive, "endif"))
- {
- DebugStatement( debugCppNest(FALSE, Cpp.directive.nestLevel); )
- ignore = popConditional();
- Cpp.directive.state = DRCTV_NONE;
- DebugStatement( if (ignore != ignore0) debugCppIgnore(ignore); )
- }
- else /* "pragma", etc. */
- Cpp.directive.state = DRCTV_NONE;
- break;
- case DRCTV_IF: /* "if" or "ifdef" detected */
- ignore = pushConditional((boolean)(c != '0'));
- Cpp.directive.state = DRCTV_NONE;
- DebugStatement( debugCppNest(TRUE, Cpp.directive.nestLevel);
- if (ignore != ignore0) debugCppIgnore(ignore); )
- break;
- case DRCTV_DEFINE: /* "define" detected: generate tag */
- {
- boolean parameterized;
- readDefineTag(c, &Cpp.directive.tag, ¶meterized);
- if (! isIgnoreToken(Cpp.directive.tag.name))
- makeDefineTag(&Cpp.directive.tag, scope, parameterized);
- }
- Cpp.directive.state = DRCTV_NONE;
- break;
- }
- return ignore;
- }
- /* Called upon reading of a slash ('/') characters, determines whether a
- * comment is encountered, and its type.
- */
- static Comment isComment()
- {
- Comment comment;
- const int next = fileGetc();
- if (next == '*')
- comment = COMMENT_C;
- else if (next == '/')
- comment = COMMENT_CPLUS;
- else
- {
- fileUngetc(next);
- comment = COMMENT_NONE;
- }
- return comment;
- }
- /* Skips over a C style comment. According to ANSI specification a comment
- * is treated as white space, so we perform this subsitution.
- */
- static int skipOverCComment()
- {
- int c = fileGetc();
- while (c != EOF)
- {
- if (c != '*')
- c = fileGetc();
- else
- {
- const int next = fileGetc();
- if (next != '/')
- c = next;
- else
- {
- c = ' '; /* replace comment with space */
- break;
- }
- }
- }
- return c;
- }
- /* Skips over a C++ style comment.
- */
- static int skipOverCplusComment()
- {
- int c;
- while ((c = fileGetc()) != EOF)
- {
- if (c == BACKSLASH)
- fileGetc(); /* throw away next character, too */
- else if (c == NEWLINE)
- break;
- }
- return c;
- }
- /* Skips to the end of a string, returning a special character to
- * symbolically represent a generic string.
- */
- static int skipToEndOfString()
- {
- int c;
- while ((c = fileGetc()) != EOF)
- {
- if (c == BACKSLASH)
- fileGetc(); /* throw away next character, too */
- else if (c == DOUBLE_QUOTE)
- break;
- else if (c == NEWLINE)
- {
- fileUngetc(c);
- break;
- }
- }
- return STRING_SYMBOL; /* symbolic representation of string */
- }
- /* Skips to the end of the three (possibly four) 'c' sequence, returning a
- * special character to symbolically represent a generic character.
- */
- static int skipToEndOfChar()
- {
- int c;
- while ((c = fileGetc()) != EOF)
- {
- if (c == BACKSLASH)
- fileGetc(); /* throw away next character, too */
- else if (c == SINGLE_QUOTE)
- break;
- else if (c == NEWLINE)
- {
- fileUngetc(c);
- break;
- }
- }
- return CHAR_SYMBOL; /* symbolic representation of character */
- }
- /* This function returns the next character, stripping out comments,
- * C pre-processor directives, and the contents of single and double
- * quoted strings. In short, strip anything which places a burden upon
- * the tokenizer.
- */
- extern int cppGetc()
- {
- boolean directive = FALSE;
- boolean ignore = FALSE;
- int c;
- if (Cpp.ungetch != ' ')
- {
- c = Cpp.ungetch;
- Cpp.ungetch = ' ';
- return c; /* return here to avoid re-calling debugPutc() */
- }
- else do
- {
- c = fileGetc();
- switch (c)
- {
- case EOF:
- ignore = FALSE;
- directive = FALSE;
- break;
- case TAB:
- case SPACE:
- break; /* ignore most white space */
- case NEWLINE:
- if (directive && ! ignore)
- directive = FALSE;
- Cpp.directive.accept = TRUE;
- break;
- case DOUBLE_QUOTE:
- Cpp.directive.accept = FALSE;
- c = skipToEndOfString();
- break;
- case '#':
- if (Cpp.directive.accept)
- {
- directive = TRUE;
- Cpp.directive.state = DRCTV_HASH;
- Cpp.directive.accept = FALSE;
- }
- break;
- case SINGLE_QUOTE:
- Cpp.directive.accept = FALSE;
- c = skipToEndOfChar();
- break;
- case '/':
- {
- const Comment comment = isComment();
- if (comment == COMMENT_C)
- c = skipOverCComment();
- else if (comment == COMMENT_CPLUS)
- {
- c = skipOverCplusComment();
- if (c == NEWLINE)
- fileUngetc(c);
- }
- else
- Cpp.directive.accept = FALSE;
- break;
- }
- default:
- Cpp.directive.accept = FALSE;
- if (directive)
- ignore = handleDirective(c);
- break;
- }
- } while (directive || ignore);
- DebugStatement( debugPutc(c, DEBUG_CPP); )
- return c;
- }
- /* vi:set tabstop=8 shiftwidth=4: */