📄 ccstmt.c
字号:
static NODE *
gotostmt()
{
NODE *n;
SYMBOL *s;
nextoken();
s = csymbol;
expect(Q_IDENT); /* goto lab */
n = ndefop(Q_GOTO);
n->Nxfsym = plabel(s, 0);
expect(T_SCOLON); /* goto lab; */
return n;
}
/* PLABEL - Handle label identifier
*/
static SYMBOL *
plabel(osym, defp)
SYMBOL *osym;
{
SYMBOL *sym;
if (osym == NULL)
return 0; /* already lost, don't barf twice */
if ((sym = symflabel(osym)) != NULL) /* See if this is a label sym */
{
if (osym->Sclass == SC_UNDEF) /* Yes! If original was undefined */
freesym(osym); /* then flush it */
}
else /* No existing label sym, make one */
{
sym = symqcreat(osym); /* Make new local sym from this one */
sym->Sflags |= SF_LABEL; /* Now mark as a label sym! */
sym->Sclass = SC_ULABEL;
sym->Ssym = newlabel(); /* give it a real label number */
if (!defp) /* If not defining the label, */
sym->Srefs++; /* then this is a reference */
}
if (defp)
{
if (sym->Sclass == SC_LABEL) /* previously defined? */
error("Label %S already defined", sym);
else
sym->Sclass = SC_LABEL; /* if being defined, remember so */
}
return sym->Ssym; /* return the label symbol */
}
/* SWITCHSTMT - Parse SWITCH statement
** [K&R A.9.7] [H&S 8.7]
*/
static NODE *
switchstmt()
{
NODE *cond, *stmt, *n;
struct sw savesw; /* Saved state of case stmt collection */
nextoken();
expect(T_LPAREN);
cond = expression();
expect(T_RPAREN);
/* Must fix up this check to reflect what we are capable of compiling.
** Aggregate, pointer and floating-point types are not allowed.
** Perhaps this could be set in the runtime table.
*/
if (!tisinteg(cond->Ntype))
{
error("Switch expression must be of integral type");
cond = ndeficonst(0);
}
else /* Apply usual unary conversions */
cond = evalifok(convunary(cond));
caselevel++;
breaklevel++;
savesw = sw; /* Save current level's variables */
sw.swdefault = sw.swcases = sw.swtail = NULL;
sw.swcount = 0; /* No case stmts seen yet */
sw.swrange = (unsigned long) ~0; /* Range is all bits for now */ // FW KCC-NT
if (cond->Nop == Q_ANDT) /* but check for const AND */
{
if (cond->Nleft->Nop == N_ICONST)
sw.swrange &= cond->Nleft->Niconst;
if (cond->Nright->Nop == N_ICONST)
sw.swrange &= cond->Nright->Niconst;
}
stmt = statement();
caselevel--;
breaklevel--;
n = ndeflr(Q_SWITCH, cond, stmt);
if (sw.swdefault) /* Put default at start of list, */
{
sw.swdefault->Nright = sw.swcases;
n->Nxswlist = sw.swdefault;
}
else
n->Nxswlist = sw.swcases; /* and point to head of result */
sw = savesw; /* Restore vars for previous level */
return n;
}
/* CASESTMT - Parse CASE labeled statement
** [K&R A.9.7] [H&S 8.7]
*/
static NODE *
casestmt()
{
NODE *n, *this, *old;
nextoken();
n = exprconst(); /* parse constant expr for this case */
if (caselevel == 0) /* make sure in switch stmt */
{
error("Case label outside switch statement"); /* nope */
n = NULL; /* disable further checks */
}
this = ndefop(Q_CASE);
/* Need to fix up the case constant-expression value further.
** It must be a constant expression and of the same type as the
** switch control-expression. We fold in case convunary produces a cast.
*/
if (n != NULL)
n = evalexpr(convunary(n));
/*
** Perform various checks on the new case value.
**
** If it's NULL, then there was some error that's already been reported.
** Otherwise, it must be a constant, and one that hasn't been seen before
** in this switch(). We also make sure that, if the value being tested
** is a bitwise AND with a constant, the case value can happen as a result.
*/
if (n == NULL)
; /* already complained, don't redo */
else if (n->Nop != N_ICONST)
error("Case label must be integral constant expr");
else /* Yes, can perform further checks */
{
for (old = sw.swcases; old != NULL; old = old->Nright) /* go through */
if (old->Nxfint == n->Niconst) /* checking for same value */
{
error("Switch statement has duplicate case labels: %ld",
(INT) n->Niconst); /* complain if duplicate */
break; /* but only complain once */
}
if (old == NULL) /* do this unless it was a dup */
{
if ((n->Niconst & (long) sw.swrange) != n->Niconst) /* check range */
advise("Case label outside range of AND in switch -- %ld",
(INT) n->Niconst);
this->Nxfint = n->Niconst; /* now safe to set case value */
if (sw.swtail) /* add to list of known cases */
sw.swtail->Nright = this;
else
sw.swcases = this;
sw.swtail = this;
if (++sw.swcount > MAXCASE) /* Bump count of known cases */
error("Too many case statements (%d; max is %d)",
sw.swcount, MAXCASE);
}
}
/* checked value and set in list of cases, parse rest of case statement */
expect (T_COLON); /* colon comes after expression */
this->Nleft = statement(); /* only parse after setting swcases */
return this; /* return with whole of case stmt */
}
/* DEFAULTSTMT - Parse DEFAULT labeled statement
** [K&R A.9.7] [H&S 8.7]
*/
static NODE *
defaultstmt()
{
NODE *n;
nextoken();
if (caselevel == 0)
error("Case label outside switch statement");
else if (sw.swdefault != NULL) /* Err if already have default stmt */
error("Switch statement has multiple \"default\" labels");
expect(T_COLON);
sw.swdefault = n = ndefop(Q_DEFAULT);
n->Nleft = statement();
return n;
}
/* RETURNSTMT - Parse RETURN statement
** [K&R A.9.10] [H&S 8.9 and 9.8]
*/
static NODE *
returnstmt()
{
NODE *e, *nreg;
TYPE *t;
t = curfn->Stype->Tsubt; /* Get type of function return val */
if (nextoken() == T_SCOLON)
{
/* No return value. Should check to see whether return type is
** specified for function and give warning if so.
** Not error, for backwards compatibility. See H&S 9.8.
*/
e = NULL;
if (t->Tspec != TS_VOID && t->Tspec != TS_INT)
warn("No return value for value-returning function");
}
else
{
/* Parse expression, apply assignment conversions, and optimize */
if (t->Tspec != TS_VOID)
e = evalifok(convasgn(t, expression()));
else
{
error("Return expression illegal in function returning void");
(void)expression(); /* Parse and ignore expr */
e = NULL;
}
}
expect(T_SCOLON);
nreg = ndeflr(Q_RETURN, (NODE *)NULL, e);
nreg->Nreg = _reg_count;
return nreg;
}
/* EXPRSTMT - Expression statement
** [H&S 8.2]
** The result value of the expression will be thrown away, so
** some optimization can be attempted by flushing anything that has no
** side effects. This is performed by evaldiscard().
*/
static NODE *
exprstmt(void)
{
NODE *n;
n = ediscifok(evalifok(expression())); /* Parse expr list */
expect(T_SCOLON); /* followed by semicolon */
return n;
}
#if 0
EXPRESSION PARSER
Here is some information about how the expression parser works. It is
not complete nor guaranteed to be correct. See the INTERN.DOC file for
a better overview.
About NF_STKREF and
stackrefs:
The global "stackrefs" is used only to decide whether some
optimizations (in CCCSE and CCOPT) should be attempted. If non-zero,
they aren't. The flag NF_STKREF is only used here in CCSTMT for
the sole purpose of incrementing or decrementing "stackrefs".
The meaning of this variable appears to be "number of stack-address
values floating around the function". If an expression such as
"&foo" is used in the function, and foo is an auto var, then the
code generator/optimizer has to be avoid doing things which would
wipe out the part of the stack that the address references, since
there is no way to tell what parts of the local-variable stack area are
actually being used once such an address value is created.
The NF_STKREF flag appears to only be set (and stackrefs bumped)
for N_ADDR nodes (i.e. the & address operator)
. Thus stackrefs would
simply amount to a count of the number of N_ADDRs in the function which
have an auto operand. However, there are a few situations where an
& address value is used immediately and then thrown away. These places
test their operands for the NF_STKREF flag, and if it exists then they
decrement stackrefs. These places appear to
be:
(1) operands to && and ||
(2) The * indirection operator eg "*(&foo)"
(3) Some kinds of array refs (where the * op is implicitly used)
(4) The -> struct member operator, eg "(&foo)->"
There is probably no reason why the stackrefs variable could not be computed
after the parse tree was finished, rather than doing it during parsing.
It is better to err on the side of bumping it up than down since the worst
that will happen if the count is too high is that some optimizations will
not be done.
#endif
/* This page contains functions which provide an interface between
** the statement parsing routines and the expression parsing routines.
*/
/* EXPRCNTRL - Parse a statement control expression
** (for IF, WHILE, DO, FOR) [H&S 8.1.2]
** Checks the parsed <expr> for validity as a logical or control expr
** and returns a node pointer.
*/
static NODE *
exprcntrl()
{
NODE *e;
e = expression(); /* Parse expression */
switch (e->Nop)
{
case Q_ASGN:
case Q_ASPLUS:
case Q_ASMINUS:
case Q_ASMPLY:
case Q_ASDIV:
case Q_ASMOD:
case Q_ASRSH:
case Q_ASLSH:
case Q_ASAND:
case Q_ASXOR:
case Q_ASOR:
warn("Assignment in control expression instead of equality");
default:
break;
}
if (!tisscalar(e->Ntype))
{
error("Control expression must be scalar type");
return ndeficonst(0);
}
return evalifok(e);
}
/* PCONST - parse for a constant integral expression
**
** Optimization is always enabled for constant parsing, since we
** need to be able to fully resolve all constant arithmetic ops and
** the like.
*/
long
pconst()
{
NODE *e;
e = exprconst(); /* Get fully optimized expression */
if (e->Nop != N_ICONST)
{
error("Integral constant expected");
return 0;
}
return e->Niconst;
}
/* EXPRCONST - Parse for a "constant" expression.
** This basically just means always evaluating the parse result.
** This also enforces the restriction that comma and assignment ops
** are not parsed.
*/
NODE *
exprconst()
{
NODE *e;
constexpr = 1;
e = evalexpr(condexpr()); /* Get fully optimized expression */
constexpr = 0;
return e;
}
/* EVALIFOK(e) - Optimize and evaluate an expression if OK.
** Unless optimization is turned off, this should be called
** to crunch a parsed expression.
*/
static NODE *
evalifok(e)
NODE *e;
{
return (optpar ? evalexpr(e) : e);
}
static NODE *
ediscifok(e)
NODE *e;
{
if (optpar)
return evaldiscard(e);
if (e)
e->Nflag |= NF_DISCARD; /* just set flag for top-level node */
return e;
}
/*
** EXPRESSION - Parse expression.
** [H&S 7.2.1, 7.9]
**
** <expr> ::= <comma-expr> (lowest precedence = 1)
** | <no-comma-expr> (higher precedence)
**
** <comma-expr> ::= <expr> ',' <expr>
**
** <no-comma-expr> ::= <assignment-expr> (precedence = 2)
** | <conditional-expr> (ternary, prec = 3)
** | <logical-expr>
** | <binary-expr>
** | <unary-expr>
** | <primary-expr>
*/
/*
** Parse <expr> - either a <no-comma-expr> or a <comma-expr> (expression list)
** Ref. [1] A.7.1
*/
static NODE *
expression(void)
{
NODE *s, *e;
e = asgnexpr(); /* Get first expression */
if (token != T_COMMA)
return e; /* if no comma, that's it */
/*
** We have an expression followed by a comma, parse the whole list.
** Note array/function conversions are applied in this context.
**
** We terminate it with a NULL (as with LISP lists) to distinguish
** ((1, 2), 3) from (1, 2, 3).
** The type of the last expression becomes the result type.
*/
if (constexpr)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -