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

📄 ccstmt.c

📁 KCC , a good c compiler, write by Ken Harrenstien
💻 C
📖 第 1 页 / 共 5 页
字号:
/*	CCSTMT.C - Statement and Expression Parsing
**
**	(c) Copyright Ken Harrenstien 1989
**		All changes after v.340, 4-Aug-1988
**	(c) Copyright Ken Harrenstien, SRI International 1985, 1986
**		All changes after v.101, 8-Aug-1985
**
**	Original version (C) 1981  K. Chen
*/

#include "cc.h"
#include "cclex.h"	/* For reference to "constant" structure */

/* Imported functions */
extern NODE *debug_node(NODE *, int, int, int);	/* CCDBUG */
extern TYPE *typename(void);	/* CCDECL */
extern SYMBOL *defauto(char *, TYPE *);	/* CCDECL */
extern SYMBOL *funchk(int, int, SYMBOL *, SYMBOL *);	/* CCDECL */
extern TYPE *findtype(int, TYPE *), *findftype(TYPE *, TYPE *),	/* CCSYM */
	*findqtype(TYPE *, INT);
extern INT sizearray(TYPE *), sizeptobj(TYPE *);	/* CCSYM */
extern SYMBOL *newlabel(void);	/* CCSYM */
extern SYMBOL *symqcreat(SYMBOL *);	/* CCSYM */
extern SYMBOL *symflabel(SYMBOL *), *symfmember(SYMBOL *, SYMBOL *);/* CCSYM */
extern void freesym(SYMBOL *);			/* CCSYM */
extern INT sizetype(TYPE *);
extern int cmputype(TYPE *, TYPE *), mapextsym(SYMBOL *);	/* CCSYM */
extern NODE *evalexpr(NODE *), *evaldiscard(NODE *);		/* CCEVAL */
extern NODE *convcast(TYPE *, NODE *), *convarrfn(NODE *),
	*convbinary(NODE *),	/* CCTYPE */
	*convunary(NODE *), *convasgn(TYPE *, NODE *), *convfunarg(NODE *),
	*convnullcomb(NODE *), *convvoidptr(NODE *);
extern NODE *ndeficonst(INT); /* CCNODE */
extern TYPE *convternaryt(NODE *);
extern int nextoken(void);			/* CCLEX */
extern void tokpush(int, SYMBOL *);			/* CCLEX */
extern int expect (int);
extern SYMBOL *beglsym (void);
extern NODE *ldecllist (void);	/* from CCDECL */
extern void endlsym (SYMBOL *);

/* Exported functions */
long pconst(void);			/* For CCDECL and CCINP */
NODE *funstmt(void), *asgnexpr(void);	/* For CCDECL */
NODE *exprconst(void);		/* For CCDECL */

/* Internal functions */
static NODE *statement(void),
	*whilestmt(void), *dostmt(void), *forstmt(void),
	*switchstmt(void), *casestmt(void), *defaultstmt(void),
	*returnstmt(void), *gotostmt(void), *ifstmt(void),
	*compoundstmt(int), *breakstmt(void), *continuestmt(void),
	*exprstmt(void);
static SYMBOL *plabel(SYMBOL *, int);
static NODE *exprcntrl(void);
static NODE *evalifok(NODE *), *ediscifok(NODE *);

static NODE *expression(void),
	*condexpr(void), *binary(int), *unary(void), *primary(void),
	*castexpr(void), *postexpr(void), *sizeexpr(void),
	*pincdec(NODE *, int);
static NODE *ptrapply(NODE *), *chkadd(int, NODE *),
	    *parglist(SYMBOL *, TYPE *);
static NODE *bin_asm(void), *bin_offsetof(void), *bin_muuo(void);
static int cmpatype(TYPE *, TYPE *);
#if 0
static int cmpatype();
static NODE *statement(),
	*whilestmt(), *dostmt(), *forstmt(),
	*switchstmt(), *casestmt(), *defaultstmt(), *returnstmt(),
	*gotostmt(), *ifstmt(), *compoundstmt(), *breakstmt(),
	*continuestmt(), *exprstmt();
static SYMBOL *plabel();
static NODE *exprcntrl();
static NODE *evalifok(), *ediscifok();

static NODE *expression(),
	*condexpr(), *binary(), *unary(), *primary(),
	*castexpr(), *postexpr(), *sizeexpr(),
	*pincdec();
static NODE *ptrapply(), *chkadd(), *parglist();
static NODE *bin_asm(), *bin_offsetof(), *bin_muuo();
#endif

/* Variables global to statement parsing routines */
static int contlevel,		/* Current nesting depth for continue (loop) */
	caselevel,		/* Ditto for case (switch) */
	breaklevel,		/* Ditto for break (either loop or switch) */
	constexpr,		/* flag for parsing constant expression */
	stmt_number;		/* used by external debugger/profiler */

/* Variables pushed/restored by each switch, global during a switch level */
static struct sw		/* Structure for easier push/pop */
    {
    NODE    *swdefault,	/* Default stmt if any seen */
	    *swcases,	/* Head of list of case stmts seen */
	    *swtail;	/* Tail of list */
    int	    swcount;	/* # of case labels in list */
    unsigned INT swrange;	/* AND constant for case range check */
    }
sw;

extern char _ch_cpy;
extern char ra_expr;		/* KAR-11/91, usage before init. flag */
#define fline_off(c)	\
    (debcsi > 0 && (c) != '\n' && (c) != '\r' && (c) != '\v')

/*
** FUNSTMT - Parse function statement.
**	Main entry to statement parser from CCDECL.
**	Returns a statement-list which ends with a Q_RETURN node.
** Entered with current token T_LBRACE ('{').
** Returns with current token T_RBRACE ('}'), unlike most other
** parsing routines.
** Originally this was so that the calling routine can fix up the symtab
** before attempting to read the next token.  See compoundstmt() for more
** explanation.
*/

NODE *
funstmt()
{
    NODE *f, *nreg;
    int offset = 0;


    /* Initialize local vars */
    contlevel = caselevel = breaklevel = 0;


    f = ndefl(N_STATEMENT, debug_node(compoundstmt(1),fline- 1, stmt_number++,
	    FN_ENTRY));
    nreg = ndefop(Q_RETURN);
    nreg->Nreg = _reg_count;
    offset = !fline_off(_ch_cpy);
    f->Nright = ndefl(N_STATEMENT, debug_node(nreg, fline - offset,
		stmt_number++, FN_EXIT));

    if (vrbfun)
	fprintf(outmsgs,"Compiled function %s: ", curfn->Sname);

    return f;
#if 0
    return ndeflr(N_STATEMENT,
		compoundstmt(1),		/* Parse top-level block */
		ndefl(N_STATEMENT,		/* with a RETURN at end */
			ndefop(Q_RETURN)));
#endif
}

/*
** Parse statement
** Ref. [1] A.9
*/

static NODE *
statement()
{
    SYMBOL *sym, *nlabel;
    NODE *s;
    int tokn;
    int stmt_line = fline;
    int stmt_num = stmt_number++;

    switch (token)
	{
	case T_SCOLON:		/* Null statement */

	    if (fline_off(_ch_cpy))
		stmt_line++;

	    nextoken();
	    s = NULL;
	    stmt_line--;
	    break;
	case T_LBRACE:		/* Compound statement */
	    stmt_number--;
	    s = compoundstmt(0);	/* Parse inner block */
	    expect (T_RBRACE);	/* Doesn't set up new token, so do it now */
	    return s;

	case Q_SWITCH:
	    s = switchstmt();
	    break;
	case Q_CASE:
	    stmt_number--;
	    return casestmt();
	case Q_DEFAULT:
	    stmt_number--;
	    return defaultstmt();
	case Q_DO:
	    s = dostmt();
	    break;
	case Q_WHILE:
	    s = whilestmt();
	    break;
	case Q_FOR:
	    s = forstmt();
	    break;
	case Q_GOTO:
	    s = gotostmt();
	    break;
	case Q_IF:
	    s = ifstmt();
	    break;
	case Q_RETURN:
	    s = returnstmt();
	    break;
	case Q_BREAK:
	    s = breakstmt();
	    break;
	case Q_CONTINUE:
	    s = continuestmt();
	    break;

	case Q_IDENT:	/* Check for labeled statement [H&S 8.3] */
	    sym = csymbol;			/* get last symbol if any */
	    tokn = token;			/* and last token */
	    if (nextoken() == T_COLON)	/* it is if followed by colon */
		{
		stmt_number--;
		nextoken();			/* skip over lab: */
		nlabel = plabel(sym, 1);	/* get label symbol number */
		s = ndefl(N_LABEL, statement());	/* make label node */
		s->Nxfsym = nlabel;
		return(s);			/* make no stmt label! */
		}
	    tokpush (tokn, sym);		/* push back token */
					/* and fall through to try expr */
	default:
	    s = exprstmt();			/* Parse expression stmt */
	    break;

	case T_EOF:				/* catch premature EOF */
	    error("Unexpected EOF within function");
	    return NULL;
	}

    if (s->Nop == Q_RETURN)
	s = debug_node(s, stmt_line, stmt_num, FN_EXIT);
    else
	s = debug_node(s, stmt_line, stmt_num, STMT);
    return s;
}

/* COMPOUNDSTMT - Parse compound statement
**	[K&R A.9.2]  [H&S 8.4]
**
** When called, current token is the left-brace opening the compound stmt.
** On return, the current token is either T_EOF or the closing right-brace.
** This is only called from funstmt() at top level, or statement() at
** any inner levels.
**
**	NOTE CAREFULLY: At the end of a compound statement (block)
** any local symbols which were defined within that
** block must be deactivated.  This must be done BEFORE the lexer looks
** at the next token, because the next token might be an identifier and this
** identifier might happen to correspond to a symbol which is about to
** be deactivated!  Typedef symbols are especially vulnerable to this.
**
** Note that this is unlike most other parsing routines which always set up the
** next token after gobbling everything pertinent to their parsing.
** Originally this was to permit CCDECL's funcdef() to properly reset
** the symbol table; this routine could not just call nextoken() after the
** endlsym() because if it was parsing a function body, the terminating
** '}' would end not only the current inner block but also a virtual block
** that enclosed the function parameter definitions.  Ending this virtual
** block at the right level required waiting until control returned to
** CCDECL's funcdef().  This is no longer necessary because ANSI C mandates
** that function parameters have the same scope as if declared at the
** start of the function body's block, and so funcdef() has already set up
** this local symbol block for us.  funstmt() passes the word by setting
** "toplev" TRUE.
*/

static NODE *
compoundstmt(toplev)		/* toplev TRUE if this is function body */
{
    SYMBOL *prevlsym;
    NODE *u, *beg, *n, *nr = NULL;

    prevlsym = toplev ? NULL	/* At top level, block is already set up */
		: beglsym();	/* else start a new symbol block! */

    expect(T_LBRACE);		/* Now get next token after left-brace */

    u = ldecllist();		/* Parse declarations, get list of inits */

    for (beg = n = NULL; token != T_RBRACE && token != T_EOF; n = nr)
	{
	nr = ndefl(N_STATEMENT, statement());
	if (n != NULL)
	    n->Nright = nr;
	else
	    beg = nr;
	}
    if (u)
	u = ndeflr(N_STATEMENT, u, beg);
    else
	u = beg;		/* No declarations, just code */

    endlsym(prevlsym);		/* End local sym block - deactivate syms */
				/* Important that this be done BEFORE reading
				** the next token after the right brace!
				*/
    return u;	/* Return result, with right-brace still current token */
}

/* DOSTMT - Parse DO iterative statement
**	[K&R A.9.5]  [H&S 8.6.2]
*/

static NODE *
dostmt()
{
    NODE *cond, *stmt;

    nextoken();
    contlevel++;
    breaklevel++;
    stmt = statement();
    breaklevel--;
    contlevel--;
    expect(Q_WHILE);
    expect(T_LPAREN);
    cond = exprcntrl();
    expect(T_RPAREN);
    expect(T_SCOLON);
    return ndeflr(Q_DO, cond, stmt);
}

/* WHILESTMT - Parse WHILE iterative statement
**	[K&R A.9.4] [H&S 8.6.1]
*/

static NODE *
whilestmt()
{
    NODE *cond, *stmt;

    nextoken();
    expect(T_LPAREN);
    cond = exprcntrl();
    expect(T_RPAREN);
    breaklevel++;
    contlevel++;
    stmt = statement();
    breaklevel--;
    contlevel--;
    return ndeflr(Q_WHILE, cond, stmt);
}

/* CONTINUESTMT - Parse CONTINUE statement
**	[H&S 8.8]
*/

static NODE *
continuestmt()
{
    if (contlevel == 0)
	error("Continue must be within loop");
    nextoken();
    expect(T_SCOLON);		/* it's followed by a semicolon */
    return ndefop(Q_CONTINUE);
}

/* BREAKSTMT - Parse BREAK statement
**	[H&S 8.8]
*/

static NODE *
breakstmt()
{
    if (breaklevel == 0)
	error("Break must be within loop or switch");
    nextoken();
    expect(T_SCOLON);		/* it's followed by a semicolon */
    return ndefop(Q_BREAK);
}

/* FORSTMT - Parse FOR iterative statement
**	[K&R A.9.6]  [H&S 8.6.3]
*/

static NODE *
forstmt()
{
    NODE *preamble, *e1, *e2, *e3, *s;

    nextoken();
    e1 = e2 = e3 = NULL;
    expect(T_LPAREN);
    if (token != T_SCOLON)		/* Get initialization expr if one */
	e1 = ediscifok(evalifok(expression()));
    expect(T_SCOLON);
    if (token != T_SCOLON)		/* Get control expr if one */
	e2 = exprcntrl();
    expect(T_SCOLON);
    if (token != T_RPAREN)		/* Get incrementation expr if one */
	e3 = ediscifok(evalifok(expression()));
    expect(T_RPAREN);
    contlevel++;
    breaklevel++;
    s = statement();
    breaklevel--;
    contlevel--;
    preamble = ndeflr(N_NODE, e1, e2);
    preamble = ndeflr(N_NODE, preamble, ndefl(N_NODE, e3));
    return ndeflr(Q_FOR, preamble, s);
}

/* IFSTMT - Parse IF conditional statement
**	[K&R A.9.3] [H&S 8.5]
*/
static NODE *
ifstmt()
{
    NODE *cond, *then, *elsec;

    nextoken();
    expect(T_LPAREN);
    cond = exprcntrl();
    expect(T_RPAREN);
    then = statement();
    if (token == T_ELSE)
	{
	nextoken();
	elsec = statement();
	}
    else
	elsec = NULL;

    return ndeflr(Q_IF, cond, ndeflr(N_NODE, then, elsec));
}

/* ----------------------------------------- */
/*	goto statement  Ref.[1]  A.9.11      */
/* ----------------------------------------- */

⌨️ 快捷键说明

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