📄 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 + -