This is get.c in view mode; [Download] [Up]
/***************************************************************************** * $Id: get.c,v 1.5 1997/04/06 02:13:52 darren Exp $ * * Copyright (c) 1996-1997, Darren Hiebert * * 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, { DRCTV_NONE, FALSE, { 0, 0, "" }, FALSE, 0, {{FALSE,FALSE}} } }; /*============================================================================ = Function prototypes ============================================================================*/ static boolean cppReadDirective __ARGS((int c, char *name)); static boolean cppReadIdentifier __ARGS((int c, tagInfo *const tag)); static boolean pushCppIgnore __ARGS((const boolean ignore, const boolean pathChosen)); static boolean popCppIgnore __ARGS((void)); static boolean prevCppIgnore __ARGS((void)); static boolean setCppIgnore __ARGS((const boolean ignore)); static boolean wasPathChosen __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 ) const char *const name; { boolean opened; opened = fileOpen(name); if (opened) { Cpp.ungetch = '\0'; Cpp.directive.state = DRCTV_NONE; Cpp.directive.accept = TRUE; Cpp.directive.resolve = FALSE; Cpp.directive.level = 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 cppReadDirective( c, name ) int c; char *name; { do { *name++ = c; } while (c = fileGetc(), (c != EOF && isalpha(c))); fileUngetc(c); *name = '\0'; /* null terminate */ return 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 cppReadIdentifier( c, tag ) int c; tagInfo *const tag; { char *name = tag->name; do { *name++ = c; } while (c = fileGetc(), (c != EOF && isident(c))); fileUngetc(c); *name = '\0'; /* null terminate */ tag->location = File.seek; tag->lineNumber = File.lineNumber; return (isspace(c) || c == '('); } /* Pushes one nesting level for an #if directive, indicating whether or not * the path should be ignored and whether a path has already been chosen. */ static boolean pushCppIgnore( ignore, pathChosen ) const boolean ignore; const boolean pathChosen; { if (Cpp.directive.level < CppNestingLevel - 1) { ++Cpp.directive.level; Cpp.directive.ifdef[Cpp.directive.level].ignore = ignore; Cpp.directive.ifdef[Cpp.directive.level].pathChosen = pathChosen; } return cppIgnore(); } /* Pops one nesting level for an #endif directive. */ static boolean popCppIgnore() { if (Cpp.directive.level > 0) --Cpp.directive.level; return cppIgnore(); } /* Returns whether or not the parent of this nesting level was ignored. */ static boolean prevCppIgnore() { boolean ignore; if (Cpp.directive.level <= 0) ignore = FALSE; else ignore = Cpp.directive.ifdef[Cpp.directive.level - 1].ignore; return ignore; } static boolean setCppIgnore( ignore ) const boolean ignore; { return Cpp.directive.ifdef[Cpp.directive.level].ignore = ignore; } static boolean wasPathChosen() { return Cpp.directive.ifdef[Cpp.directive.level].pathChosen; } /* Handles a pre-processor directive whose first character is given by "c". */ static boolean handleDirective( c ) const int c; { char *const name = Cpp.directive.tag.name; const tagScope scope = File.header ? SCOPE_GLOBAL : SCOPE_STATIC; boolean ignore = FALSE; switch (Cpp.directive.state) { case DRCTV_NONE: ignore = cppIgnore(); /* ignore characters until newline */ break; case DRCTV_HASH: cppReadDirective(c, name); if (strcmp(name, "define") == 0) Cpp.directive.state = DRCTV_DEFINE; else if (strncmp(name, "if", (size_t)2) == 0) Cpp.directive.state = DRCTV_IF; else { if (strcmp(name, "endif") == 0) ignore = popCppIgnore(); else if (Cpp.directive.resolve && ! Option.braceFormat) { if (strcmp(name, "elif") == 0) ignore = setCppIgnore(TRUE); else if (strcmp(name, "else") == 0) ignore = setCppIgnore(prevCppIgnore() || wasPathChosen()); } else if (strcmp(name, "elif") == 0 || strcmp(name, "else") == 0) ignore = setCppIgnore(FALSE); Cpp.directive.state = DRCTV_NONE; } break; case DRCTV_DEFINE: cppReadIdentifier(c, &Cpp.directive.tag); makeDefineTag(&Cpp.directive.tag, scope); Cpp.directive.state = DRCTV_NONE; break; case DRCTV_IF: if (Option.braceFormat) ignore = pushCppIgnore(FALSE, TRUE); else if (c == '0') /* special case: avoid first branch */ ignore = pushCppIgnore(TRUE, FALSE); else ignore = pushCppIgnore(cppIgnore(), TRUE); 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) c = 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) c = 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) c = 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() { Comment comment = COMMENT_NONE; boolean directive = FALSE; boolean ignore = FALSE; int c; if (Cpp.ungetch != '\0') { c = Cpp.ungetch; Cpp.ungetch = '\0'; 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 '/': 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) { #ifdef DEBUG const boolean ignore0 = ignore; #endif ignore = handleDirective(c); #ifdef DEBUG if (ignore != ignore0) debugCpp(ignore); #endif } break; } } while (directive || ignore); #ifdef DEBUG debugPutc(c, DEBUG_CPP); #endif return c; } /* vi:set tabstop=8 shiftwidth=4: */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.