📄 ccstmt.c
字号:
error("Comma operator in constant expression");
s = NULL; /* start with chain empty, expr in t */
while (1) /* until we break out with return */
{
e = convarrfn(e);
s = ndef(N_EXPRLIST, e->Ntype, 0, s, e); /* chain expr */
if (token != T_COMMA) /* If no comma, that's it */
break; /* return s */
/* Set flag to indicate that 1st operand of comma expression can
** have its value discarded. This gets set for both the list
** structure node (N_EXPRLIST) and the expression itself.
*/
if ((s->Nright = ediscifok(e)) == NULL) /* If expr flushed, */
{
s = s->Nleft; /* forget structure too. */
}
else
s->Nflag |= NF_DISCARD; /* Else just add flag */
nextoken(); /* pass over comma */
e = asgnexpr(); /* parse another expression */
}
return s;
}
/*
** ASGNEXPR - Parse assignment expression
** Ref. [1] A.9.1
** [H&S 7.2.1]
**
** <assignment-expr> ::= <conditional-expr>
** ::= <unary-expr> <asop> <assignment-expr>
**
** <asop> ::= one of:
** = += -= *= /= %= <<= >>= &= ^= |=
*/
NODE *
asgnexpr()
{
NODE *l, *r, *b;
TYPE *restype;
int op;
b = condexpr(); /* parse lower priority part of expr */
if (tok[token].tktype == TKTY_ASOP) /* if we now have an assignment op */
{
if (constexpr)
error("Assignment op in constant expression");
/* See if left operand is a modifiable lvalue */
if (!(b->Nflag & NF_LVALUE)) /* make sure can asgn to left side */
/* Nope, check for common mistake of (c ? t : f = x) */
{
if (b->Nop == Q_QUERY && !(b->Nflag & NF_INPARENS))
advise("= in 3rd operand of (?:) has lower precedence -- use parentheses");
error("Lvalue required as left operand of assignment");
}
else if (tisconst(b->Ntype) || tisstructiconst(b->Ntype))
error("Left operand of assignment must be modifiable");
else if (b->Ntype->Tspec == TS_ARRAY)
error("Left operand of assignment cannot be array");
else if (sizetype(b->Ntype) == 0)
error("Left operand of assignment cannot be incomplete type");
op = token; /* get the assignment op */
nextoken(); /* and move on in the token world */
r = asgnexpr(); /* parse right side of assignment */
l = b; /* Save ptr to left-hand side */
if (l->Nop == Q_IDENT)
l->Nid->Sinit = 1; /* Set flag to show initialization */
restype = l->Ntype; /* Remember what result type shd be */
b = ndef(op, restype, 0, l, r); /* Set up operator node */
switch (op)
{
case Q_ASPLUS: /* += */
case Q_ASMINUS: /* -= */
/* Left op can be scalar type (arith, pointer, enum) but if
** pointer or enum then right op must be integral.
*/
if (!tisscalar(l->Ntype))
{
error("Left operand must have scalar type");
return ndeficonst(0);
}
if (!tisarith(l->Ntype)) /* Pointer or enum? */
{
if (!tisinteg(r->Ntype))
{
error("Right operand must have integral type");
return ndeficonst(0);
}
b = chkadd(op == Q_ASPLUS ? Q_PLUS : Q_MINUS, b);
}
else if (!tisarith(r->Ntype))
{
error("Right operand must have arithmetic type");
return ndeficonst(0);
}
else
b = convbinary(b); /* Normal binary conversions */
break;
case Q_ASMPLY: /* *= */
case Q_ASDIV: /* /= */
if (!tisarith(l->Ntype) || !tisarith(r->Ntype))
{
error("Operands must have arithmetic type");
return ndeficonst(0);
}
b = convbinary(b); /* Apply binary convs */
break;
case Q_ASMOD: /* %= */
case Q_ASRSH: /* >>= */
case Q_ASLSH: /* <<= */
case Q_ASAND: /* &= */
case Q_ASXOR: /* ^= */
case Q_ASOR: /* |= */
if (!tisinteg(l->Ntype) || !tisinteg(r->Ntype))
{
error("Operands must have integral type");
return ndeficonst(0);
}
b = convbinary(b); /* Apply binary convs */
break;
case Q_ASGN: /* = Simple assignment */
b->Nright = convasgn(restype, r);
break;
default:
int_error("asgnexpr: bad asop %Q", op);
return ndeficonst(0);
}
/* Now see whether an additional type conversion needs to be
** specified when assigning the result to the left operand.
** This is a little bit inefficient but permits code sharing.
*/
b->Nascast = CAST_NONE; /* Default is no conversion */
if (b->Ntype != restype) /* If type isn't what it should be, */
{
b = convasgn(restype, b); /* then apply assignment convs */
if (b->Nop == N_CAST) /* If a cast was done, */
{
b->Nleft->Nascast = b->Ncast; /* remember cast op type */
b = b->Nleft; /* and remove the cast operator. */
b->Ntype = restype; /* and force type to that desired. */
}
}
}
return b;
}
/* CONDEXPR - Parse conditional expression (ternary)
** [H&S 7.7]
** <cond-expr> ::= <binary-expr> '?' <expr> ':' <cond-expr>
**
** One of the following must apply:
** Both operands have arithmetic type
** Both have compatible struct or union type
** Both have void type
** Both are pointers to {un}qualified versions of compatible types
** One is a pointer and the other is a null ptr constant
** One is a pointer and the other is a ptr to {un}qualified (void).
*/
static NODE *
condexpr()
{
NODE *c, *n;
c = binary(1); /* Should check out this precedence */
if (token != Q_QUERY)
return c; /* Not a conditional expression */
/* Conditional expression, have the conditional. Check it. */
nextoken();
if (!tisscalar(c->Ntype))
{
error("First operand of (?:) must have scalar type");
c = ndeficonst(0);
}
/* Get "true" expression */
n = expression();
if (n->Nop == N_EXPRLIST && !(n->Nflag & NF_INPARENS))
advise("Comma inside (?:) has lower precedence -- use parentheses");
expect(T_COLON);
/* Now get "false" expression, bind together */
n = ndeflr(N_NODE, n, condexpr());
/* Now fix up types. Things are REAL hairy for this operator.
*/
n = convbinary(n); /* First apply binary conversions. */
if (n->Nleft->Ntype == n->Nright->Ntype) /* Types OK? */
n->Ntype = n->Nleft->Ntype; /* Yep, use that type */
else
{
if ((n->Ntype = convternaryt(n)) == NULL) /* Try pointer hackery */
/* Failed. Maybe later do more checking and just warn instead if
** it is possible to do an implicit conversion -- but to
** which type, left-hand or right-hand??
*/
{
error("Operands of (?:) have incompatible types");
n->Ntype = n->Nleft->Ntype; /* Use type of left */
n->Nleft = n->Nright = ndeficonst(0);
}
}
return ndef(Q_QUERY, n->Ntype, 0, c, n);
}
/* BINARY - Parse binary (or logical) expression
** Ref.[1] A.18.1
** [H&S 7.5, 7.6]
**
** <binary-expr> ::= <cast-expr> {<op> <binary-expr>}
**
** where <op> is one of:
** Optypes Convs Result Lvalue
** Multiplicative: * / arith bin cvops no
** % integ bin cvops no
** Additive: + - * bin * no
** Shift: << >> integ un,sep cvlftop no
** Inequality: < <= > >= * bin int(0/1) no
** Equality: == != * bin int(0/1) no
** Bitwise: & | ^ integ bin cvops no
** and <logical-op> is:
** Logical: && || scalar * int(0/1) no
*/
static NODE *
binary(prec)
{
int nprec, op, typ;
NODE *lx, *rx, *bx; /* Left, right, and binary expressions */
lx = castexpr(); /* First get a left-hand <cast-expr> expression */
/* Then, if a binary operator follows it, handle the binary expression */
while ((typ = tok[token].tktype) == TKTY_BINOP || typ == TKTY_BOOLOP)
{
if ((nprec = tok[token].tkprec) <= prec)
break; /* New op has lower prec than current, stop */
op = token; /* Save op */
nextoken();
rx = binary(nprec); /* Now get right-hand side of expression */
bx = ndef(op, voidtype, 0, lx, rx); /* No type, must set */
switch (op)
{
default:
int_error("binary: illegal op %Q", op);
return ndeficonst(0);
case Q_LAND: /* && Logical AND */
case Q_LOR: /* || Logical OR */
/* Check to ensure operands are scalar */
lx = convarrfn(lx); /* Apply array/funct convs */
rx = convarrfn(rx);
if (!tisscalar(lx->Ntype) || !tisscalar(rx->Ntype))
{
error("Operands of && or || must have scalar type");
lx = ndeficonst(0);
continue; /* Skip rest of stuff, restart loop */
}
/* Technically no further conversions are required.
** However, it makes life easier for the code generation if
** it only has to deal with full integers.
** If the code generation is beefed up then these two calls
** can be removed.
*/
bx->Nleft = convunary(lx); /* Apply promotions if any */
bx->Nright = convunary(rx);
bx->Ntype = inttype;
break;
case Q_EQUAL:
case Q_NEQ:
/* Operands must have same type, and must be one of
** arith, pointer, or enum (i.e. scalar)
** EXCEPT for case where one is ptr and other is 0.
** ANSI also allows comparing any ptr to a (void *) ptr.
*/
case Q_LEQ:
case Q_GEQ:
case Q_LESS:
case Q_GREAT:
/* Operands must have same type, and must be one of
** arith, pointer, or enum (i.e. scalar)
*/
bx = convbinary(bx); /* Apply binary convs */
if (op == Q_EQUAL || op == Q_NEQ)
{
bx = convnullcomb(bx); /* Also check ptr + null */
bx = convvoidptr(bx); /* Also check ptr + void* */
}
if (!tisscalar(bx->Ntype))
{
error("Operands of comparison must have scalar type");
lx = ndeficonst(0);
continue;
}
/* If types not now same, this is only okay if both are
** pointers to compatible unqualified types.
*/
if (bx->Nleft->Ntype != bx->Nright->Ntype /* Not same? */
&& ( bx->Nleft->Ntype->Tspec == TS_PTR /* L ptr? */
&& bx->Nright->Ntype->Tspec == TS_PTR /* R ptr? */
&& !cmputype(bx->Nleft->Ntype->Tsubt, /* Compat? */
bx->Nright->Ntype->Tsubt)))
{
error("Operands of comparison must have same type");
lx = ndeficonst(0);
continue;
}
bx->Ntype = inttype; /* OK, type of result is always int */
break;
case Q_MPLY:
case Q_DIV:
bx = convbinary(bx); /* Apply usual binary convs */
if (!tisarith(bx->Ntype)
|| bx->Nleft->Ntype != bx->Nright->Ntype)
{
error("Mult/div operands must have arithmetic type");
lx = ndeficonst(0);
continue;
}
break;
case Q_MOD:
bx = convbinary(bx); /* Apply usual binary convs */
if (!tisinteg(bx->Ntype)
|| bx->Nleft->Ntype != bx->Nright->Ntype)
{
error("Remainder operands must have integral type");
lx = ndeficonst(0);
continue;
}
break;
case Q_PLUS:
case Q_MINUS:
bx = chkadd(op, bx); /* Do heavy checking */
break;
case Q_LSHFT:
case Q_RSHFT:
/* Not the usual binary conversions!! */
bx->Nleft = convunary(lx);
bx->Nright = convunary(rx);
if (!tisinteg(bx->Nleft->Ntype)
|| !tisinteg(bx->Nright->Ntype))
{
error("Shift operands must have integral type");
lx = ndeficonst(0);
continue;
}
bx->Ntype = bx->Nleft->Ntype; /* Type is whatever left is */
break;
case Q_ANDT:
case Q_XORT:
case Q_OR:
bx = convbinary(bx);
if (!tisinteg(bx->Ntype)
|| bx->Nleft->Ntype != bx->Nright->Ntype)
{
error("Bitwise operands must have integral type");
lx = ndeficonst(0);
continue;
}
break; /* Type already set up OK */
}
lx = bx->Nleft; /* For more convenient checking below */
rx = bx->Nright;
if (lx->Ntype->Tspec == TS_VOID || rx->Ntype->Tspec == TS_VOID)
{
error("Binary operand cannot have void type");
lx->Ntype = rx->Ntype = bx->Ntype = inttype;
}
if (typ == TKTY_BOOLOP) /* stack is safe from comparisons */
{
if (lx->Nflag & NF_STKREF)
stackrefs--;
if (rx->Nflag & NF_STKREF)
stackrefs--;
bx->Nflag |= NF_WASCOMP; /* remember comparison */
}
if ((bx->Nop == Q_ANDT || bx->Nop == Q_OR) &&
(((lx->Nflag & NF_WASCOMP) && !(lx->Nflag & NF_INPARENS)) ||
((rx->Nflag & NF_WASCOMP) && !(rx->Nflag & NF_INPARENS))))
/* likely lossage with & precedence */
advise("Bitwise operation on result of comparison -- use parentheses");
lx = bx; /* Binary expr becomes new left-hand operand */
}
return lx;
}
/* CASTEXPR and UNARY - Parse cast and unary expressions
**
** [H&S 7.4] Note that the BNF in the text of H&S 7.4 is faulty.
** The following revised BNF corresponds to the LALR(1) grammar in Appendix C,
** and should be correct. Note in particular:
** (1) All unary operators have equal precedence, except for the
** postfix operators (which have a special BNF definition).
** (2) A special check is made in the code for the case of
** "sizeof(<type-name>)" in order to parse it on the spot and remove
** a possible ambiguity (referred to by H&S 7.4.2). This is not reflected
** in the BNF, although H&S App. C deals with it by moving the syntax to
** primary-expression level.
**
** <unary-expr> ::= <cast-expr>
** | <prefix-expr>
**
** <cast-expr> ::= '(' <type-name> ')' <unary-expr>
**
** <prefix-expr> ::= <postfix-expr>
** | <sizeof-expr>
** | '-' <unary-expr> (unary minus)
** | '!' <unary-expr> (logical negation)
** | '~' <unary-expr> (bitwise negation)
** | '&' <unary-expr> (address operator)
** | '*' <unary-expr> (indirection)
** | '++' <unary-expr> (preincrement)
** | '--' <unary-expr> (predecrement)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -