📄 ccstmt.c
字号:
/* 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 + -