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

📄 parse.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 3 页
字号:
    return ok;
}

static void initParenInfo( paren )
    parenInfo *const paren;
{
    DebugStatement( clearString(paren->name, MaxNameLength); )
    paren->gotName	= FALSE;
    paren->location	= 0;
    paren->lineNumber	= 0;
}

static boolean saveParenInfo( paren, c )
    parenInfo *const paren;
    int c;
{
    boolean ok = TRUE;

    readIdentifier(c, paren->name);
    c = skipToNonWhite();
    if (c == ')')		/* saved if only identifier in parentheses */
    {
	paren->gotName    = TRUE;
	paren->location   = File.seek;
	paren->lineNumber = File.lineNumber;
    }
    else
    {
	if (c == '(')
	    cppUngetc(c);
	ok = skipToMatch("()");
    }
    return ok;
}

static boolean doubleParens( st )
    statementInfo *const st;
{
    /*	A double parenthesis almost certainly means one of those conditional
     *	prototype macro thingies (e.g. __ARGS((void)) ). If found, we will use
     *	the previous name, if it is not empty.
     */
    if (st->gotName  &&  *st->tag[!st->buf1].name != '\0')
	swapNameBuffers(st);

    cppUngetc('(');			/* put back for skipToMatch() */
    return skipToMatch("()");
}

/*  Analyzes the context and contents of parentheses.
 */
static boolean analyzeParens( st )
    statementInfo *const st;
{
    boolean ok = TRUE;
    int c;

    c = skipToNonWhite();
    if (c == '*')				/* this is a function pointer */
    {
	st->gotName	= FALSE;		/* invalidate previous name */
	st->isFuncPtr	= TRUE;
	st->token	= TOK_IGNORE;
    }
    if (! st->gotName)
    {
	st->token = TOK_IGNORE;
	cppUngetc(c);
    }
    else
    {
	boolean terminate = FALSE, emptyArgList = FALSE;
	parenInfo paren;

	initParenInfo(&paren);
	if (isident1(c))
	    ok = saveParenInfo(&paren, c);
	else if (c == '(')
	    ok = doubleParens(st);
	else if (c == ')')			/* empty parentheses... */
	    emptyArgList = TRUE;
	else
	{
	    /*	This is an invalid character to be inside a paren in this
	     *	context. This must be a macro call. After we read to the
	     *	end of the parenthesis seqence, force a termination of the
	     *	current statement,
	     */
	    st->token	= TOK_NONE;
	    st->gotName	= FALSE;
	    terminate	= TRUE;
	    ok = skipToMatch("()");
	}
	if (ok  &&  ! terminate)
	    ok = analyzePostParens(st, &paren, emptyArgList);
    }
    return ok;
}

/*  Analyzes the identifier contained in a statement described by the
 *  statement structure and adjusts the structure according the significance
 *  of the identifier.
 */
static void analyzeIdentifier( st )
    statementInfo *const st;
{
    tagInfo *const tag = &activeTag(st);
    char *const name = tag->name;

    if (isIgnoreToken(name))
	st->token = TOK_IGNORE;
    else
	processKeyword(st, analyzeKeyword(name));

    if (st->token == TOK_IGNORE)
	name[0] = '\0';
}

static void processIdentifier( st, c )
    statementInfo *const st;
    const int c;
{
    if (st->gotName)
	swapNameBuffers(st);
    readIdentifier(c, activeName(st));
    analyzeIdentifier(st);
    if (st->gotName  &&  st->token == TOK_IGNORE)
	swapNameBuffers(st);
}

static void processColon( st )
    statementInfo *const st;
{
    if (st->declaration != DECL_CLASS)
    {
	const int c = skipToNonWhite();

	if (c == ':')	/* this is a method or static member definition */
	{
	    st->member.type = MEMBER_CLASS;
	    strcpy(st->member.parent, activeName(st));
	    st->member.persistent = FALSE;
	}
	else
	{
	    cppUngetc(c);
	    st->token = TOK_IGNORE;
	}
    }
}

/*  Skips over any initializing value which may follow a '=' character in a
 *  variable definition.
 */
static int skipInitializer( enumInitializer )
    const boolean enumInitializer;
{
    boolean done = FALSE;
    int c;

    do
    {
	c = cppGetc();

	if (c != EOF) switch (c)
	{
	    case ',':
	    case ';':   done = TRUE; break;

	    case '[':   if (! skipToMatch("[]"))
			    c = EOF;
			break;
	    case '(':   if (! skipToMatch("()"))
			    c = EOF;
			break;
	    case '{':   if (! skipToMatch("{}"))
			    c = EOF;
			break;
	    case '}':   if (enumInitializer)
			{
			    cppUngetc(c);
			    done = TRUE;
			}
			else if (! Option.braceFormat)
			    c = EOF;
			break;

	    default:    break;
	}
    } while (! done  &&  c != EOF);

    return c;
}

static boolean processInitializer( st )
    statementInfo *const st;
{
    boolean ok = TRUE;
    const int c = skipInitializer(st->inEnumBody);

    if (c == EOF)
	ok = FALSE;
    else if (c == ';')
	st->token = TOK_SEMICOLON;
    else if (c == ',')
	st->token = TOK_COMMA;
    else if ('}'  &&  st->inEnumBody)
	st->token = TOK_COMMA;

    if (st->scope == SCOPE_EXTERN)
	st->scope = SCOPE_GLOBAL;

    return ok;
}

static boolean processArray( st )
    statementInfo *const st;
{
    st->token = TOK_IGNORE;
    return skipToMatch("[]");
}

static boolean processTemplate( st )
    statementInfo *const st;
{
    st->token = TOK_IGNORE;
    return skipToMatch("<>");
}

static boolean beginBlock( st, nesting )
    statementInfo *const st;
    const unsigned int nesting;
{
    const tagScope declScope = (File.isHeader || File.language == LANG_JAVA) ?
				SCOPE_GLOBAL : SCOPE_STATIC;
    tagInfo *const tag = &activeTag(st);
    boolean ok;

    switch (st->declaration)
    {
	case DECL_CLASS:
	    qualifyBlockTag(st, &st->class, declScope);
	    ok = createTags(nesting + 1, st);
	    break;

	case DECL_ENUM:
	case DECL_INTERFACE:
	case DECL_NAMESPACE:
	case DECL_STRUCT:
	case DECL_UNION:
	    qualifyBlockTag(st, tag, declScope);
	    ok = createTags(nesting + 1, st);
	    break;

	case DECL_NOMANGLE:
	    ok = createTags(nesting + 1, st);
	    break;

	default:
	    ok = skipToMatch("{}");
    }
    st->token = TOK_BODY;

    return ok;
}

static boolean endBlock( st, nesting )
    statementInfo *const st;
    const unsigned int nesting;
{
    boolean ok = TRUE;

    if (nesting > 0)
	st->token = TOK_EOF;		/* fake out */
    else
    {
	st->token = TOK_IGNORE;
	ok = FALSE;
    }
    return ok;
}

/*  Reads characters from the pre-processor and assembles tokens, setting
 *  the current statement state.
 */
static boolean nextToken( st, nesting )
    statementInfo *const st;
    const unsigned int nesting;
{
    int c;
    boolean ok = TRUE;

    do
    {
	c = cppGetc();

	switch (c)
	{
	    case EOF:   st->token = TOK_EOF;		break;
	    case '(':   ok = analyzeParens(st);		break;
	    case '*':   st->gotName = FALSE;		break;
	    case ',':   st->token = TOK_COMMA;		break;
	    case ':':   processColon(st);		break;
	    case ';':   st->token = TOK_SEMICOLON;	break;
	    case '=':   ok = processInitializer(st);	break;
	    case '[':   ok = processArray(st);		break;
	    case '{':   ok = beginBlock(st, nesting);	break;
	    case '}':   ok = endBlock(st, nesting);	break;
	    case '<':   ok = processTemplate(st);	break;

	    default:
		if (isident1(c))
		    processIdentifier(st, c);
		else if (isExternCDecl(st, c))
		{
		    st->declaration = DECL_NOMANGLE;
		    st->scope = SCOPE_GLOBAL;
		}
		else
		    st->token = TOK_IGNORE;
	}
    } while (ok  &&  st->token == TOK_IGNORE);

    return ok;
}

/*----------------------------------------------------------------------------
*-	Scanning functions
----------------------------------------------------------------------------*/

/*  Parses the current file and decides whether to write out and tags that
 *  are discovered.
 */
extern boolean createTags( nesting, parent )
    const unsigned int nesting;
    const void *const parent;
{
    const tagScope declScope = File.isHeader ? SCOPE_GLOBAL : SCOPE_STATIC;
    statementInfo *st;
    boolean ok;

    DebugStatement( if (nesting > 0) debugParseNest(TRUE, nesting); )
    st = (statementInfo *)malloc(sizeof(statementInfo));
    if (st == NULL)
	error(FATAL | PERROR, "cannot allocate statement info");
    initStatement(st, (const statementInfo *)parent);

    while ((ok = nextToken(st, nesting)))
    {
	tagInfo *const tag = &activeTag(st);

	if (st->token == TOK_EOF)
	    break;
	else if (! st->gotName)
	    ;
	else if (st->inEnumBody)
	    qualifyEnumeratorTag(st, tag, declScope);
	else if (st->token == TOK_BODY  &&  st->prev[0] == TOK_ARGS)
	    qualifyFunctionTag(st, tag);
	else if (st->token == TOK_SEMICOLON  ||  st->token == TOK_COMMA)
	{
	    if (st->scope == SCOPE_TYPEDEF)
		makeTag(tag, &st->member, declScope, TAG_TYPEDEF);
	    else if (st->prev[0] == TOK_NAME  ||  st->isFuncPtr)
		qualifyVariableTag(st, tag);
	    else if (st->prev[0] == TOK_ARGS)
		qualifyFunctionDeclTag(st, tag);
	}

	/*  Reset after a semicolon, or BODY preceeded by ARGS (a function),
	 *  a namspace definition, or an "extern" block.
	 */
	if (st->token == TOK_SEMICOLON  ||  (st->token == TOK_BODY  &&
	     (st->declaration == DECL_NAMESPACE  ||
	      st->declaration == DECL_NOMANGLE   ||
	      st->prev[0] == TOK_ARGS)))
	{
	    DebugStatement( if (debug(DEBUG_PARSE)) printf("<ES>"); )
	    reinitStatement(st);
	    Cpp.resolveRequired = FALSE;	/* end of statement */
	}
	else
	    Cpp.resolveRequired = TRUE;		/* in middle of statement */

	st->prev[1] = st->prev[0];
	st->prev[0] = st->token;
    }
    DebugStatement( if (nesting > 0) debugParseNest(FALSE, nesting - 1); )
    free(st);
    return ok;
}

extern void buildKeywordHash()
{
    int lastInitialChar = '\0';
    size_t i;

    /*  Clear all hash entries.
     */
    for (i = 0  ;  i < sizeof(KeywordHash)/sizeof(KeywordHash[0])  ;  ++i)
	KeywordHash[i] = -1;

    /*  Set those hash entries corresponding to keywords.
     */
    for (i = 0  ;  i < KeywordTableSize  ;  ++i)
    {
	const unsigned char initialChar = KeywordTable[i].name[0];

	if (initialChar != lastInitialChar)
	{
	    KeywordHash[hashIndex(initialChar)] = i;
	    lastInitialChar = initialChar;
	}
    }
}

/* vi:set tabstop=8 shiftwidth=4: */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -