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

📄 get.c

📁 ultraEdit的Ctag标签工具的实现源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
*   $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 + -