📄 get.c
字号:
/** $Id: get.c,v 1.7 2003/12/14 18:48:38 darren Exp $** Copyright (c) 1996-2002, 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*/#include "general.h" /* must always come first */#include <string.h>#include "debug.h"#include "entry.h"#include "get.h"#include "options.h"#include "read.h"#include "vstring.h"/** MACROS*/#define stringMatch(s1,s2) (strcmp (s1,s2) == 0)#define isspacetab(c) ((c) == SPACE || (c) == TAB)/** DATA DECLARATIONS*/typedef enum { COMMENT_NONE, COMMENT_C, COMMENT_CPLUS } Comment;enum eCppLimits { MaxCppNestingLevel = 20, MaxDirectiveName = 10};/* Defines the one nesting level of a preprocessor conditional. */typedef struct sConditionalInfo { boolean ignoreAllBranches; /* ignoring parent conditional branch */ boolean singleBranch; /* choose only one branch */ boolean branchChosen; /* branch already selected */ boolean ignoring; /* current ignore state */} conditionalInfo;enum eState { DRCTV_NONE, /* no known directive - ignore to end of line */ DRCTV_DEFINE, /* "#define" encountered */ DRCTV_HASH, /* initial '#' read; determine directive */ DRCTV_IF, /* "#if" or "#ifdef" encountered */ DRCTV_PRAGMA, /* #pragma encountered */ DRCTV_UNDEF /* "#undef" encountered */};/* Defines the current state of the pre-processor. */typedef struct sCppState { int ungetch, ungetch2; /* ungotten characters, if any */ boolean resolveRequired; /* must resolve if/else/elif/endif branch */ struct sDirective { enum eState state; /* current directive being processed */ boolean accept; /* is a directive syntatically permitted? */ vString * name; /* macro name */ unsigned int nestLevel; /* level 0 is not used */ conditionalInfo ifdef [MaxCppNestingLevel]; } directive;} cppState;/** DATA DEFINITIONS*//* Use brace formatting to detect end of block. */static boolean BraceFormat = FALSE;static cppState Cpp = { '\0', '\0', /* ungetch characters */ FALSE, /* resolveRequired */ { DRCTV_NONE, /* state */ FALSE, /* accept */ NULL, /* tag name */ 0, /* nestLevel */ { {FALSE,FALSE,FALSE,FALSE} } /* ifdef array */ } /* directive */};/** FUNCTION DEFINITIONS*/extern boolean isBraceFormat (void){ return BraceFormat;}extern unsigned int getDirectiveNestLevel (void){ return Cpp.directive.nestLevel;}extern void cppInit (const boolean state){ BraceFormat = state; Cpp.ungetch = '\0'; Cpp.ungetch2 = '\0'; Cpp.resolveRequired = FALSE; Cpp.directive.state = DRCTV_NONE; Cpp.directive.accept = TRUE; Cpp.directive.nestLevel = 0; Cpp.directive.ifdef [0].ignoreAllBranches = FALSE; Cpp.directive.ifdef [0].singleBranch = FALSE; Cpp.directive.ifdef [0].branchChosen = FALSE; Cpp.directive.ifdef [0].ignoring = FALSE; if (Cpp.directive.name == NULL) Cpp.directive.name = vStringNew (); else vStringClear (Cpp.directive.name);}extern void cppTerminate (void){ if (Cpp.directive.name != NULL) { vStringDelete (Cpp.directive.name); Cpp.directive.name = NULL; }}extern void cppBeginStatement (void){ Cpp.resolveRequired = TRUE;}extern void cppEndStatement (void){ Cpp.resolveRequired = FALSE;}/** Scanning functions** This section handles preprocessor directives. It strips out all* directives and may emit a tag for #define directives.*//* This puts a character back into the input queue for the source File. * Up to two characters may be ungotten. */extern void cppUngetc (const int c){ Assert (Cpp.ungetch2 == '\0'); Cpp.ungetch2 = Cpp.ungetch; Cpp.ungetch = c;}/* Reads a directive, whose first character is given by "c", into "name". */static boolean readDirective (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] = '\0'; /* 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 void readIdentifier (int c, vString *const name){ vStringClear (name); do { vStringPut (name, c); } while (c = fileGetc (), (c != EOF && isident (c))); fileUngetc (c); vStringTerminate (name);}static conditionalInfo *currentConditional (void){ return &Cpp.directive.ifdef [Cpp.directive.nestLevel];}static boolean isIgnore (void){ return Cpp.directive.ifdef [Cpp.directive.nestLevel].ignoring;}static boolean setIgnore (const boolean ignore){ return Cpp.directive.ifdef [Cpp.directive.nestLevel].ignoring = ignore;}static boolean isIgnoreBranch (void){ 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 && ! 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 (void){ if (! 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 (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 && ! BraceFormat && (ifdef->singleBranch || !Option.if0))); ignoreBranch = ifdef->ignoring; } return ignoreBranch;}/* Pops one nesting level for an #endif directive. */static boolean popConditional (void){ if (Cpp.directive.nestLevel > 0) --Cpp.directive.nestLevel; return isIgnore ();}static void makeDefineTag (const char *const name){ const boolean isFileScope = (boolean) (! isHeaderFile ()); if (includingDefineTags () && (! isFileScope || Option.include.fileScope)) { tagEntryInfo e; initTagEntry (&e, name); e.lineNumberEntry = (boolean) (Option.locate != EX_PATTERN); e.isFileScope = isFileScope; e.truncateLine = TRUE; e.kindName = "macro"; e.kind = 'd'; makeTagEntry (&e); }}static void directiveDefine (const int c){ if (isident1 (c)) { readIdentifier (c, Cpp.directive.name); makeDefineTag (vStringValue (Cpp.directive.name)); } Cpp.directive.state = DRCTV_NONE;}static void directivePragma (int c){ if (isident1 (c)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -