📄 ccstmt.c
字号:
**
** <postfix-expr> ::= <postfix-expr> '++' (postincrement operator)
** | <postfix-expr> '--' (postdecrement operator)
** | <primary-expr>
**
** <sizeof-expr> ::= 'sizeof' '(' <type-name> ')'
** | 'sizeof' <prefix-expr> (*)
**
** (*) = the reason this is <prefix-expr> instead of <unary-expr> is
** to reflect the fact that a cast expression cannot be used there since
** it would be interpreted as the other kind of sizeof expression.
**
** Notes on unary expr ops:
** Operand Convs Result Lvalue result
** Cast any any any no
** Sizeof any - int no
** Unary minus: -() arith unary = no
** Logical negate: !() scalar unary int(0/1) no
** Bitwise negate: ~() integ unary = no
** Address: &() lvalue - *() no
** Indirect: *() ptr unary obj yes
** Prefix inc/dec: ++ -- scalar bin = no
** Postfix inc/dec: ++ -- scalar bin = no
*/
static NODE *
castexpr()
{
NODE *n;
TYPE *t;
if (token != T_LPAREN)
return unary();
nextoken(); /* Peek at next token */
if (csymbol && (tok[token].tktype == TKTY_RWTYPE
|| csymbol->Sclass == SC_TYPEDEF))
{
t = typename(); /* Parse the type-name */
expect(T_RPAREN);
n = convcast(t, convarrfn(castexpr()));
/* Get expression, apply cast */
n->Nflag |= NF_USERCAST; /* Say this was explicit user cast */
return n;
}
tokpush(T_LPAREN, (SYMBOL *)NULL); /* Not a cast, push token back */
return unary(); /* and parse unary-expr instead! */
}
static NODE *
unary()
{
NODE *n;
int op;
switch (token)
{
default:
return postexpr(); /* Parse <postfix-expr> */
case T_SIZEOF:
return sizeexpr(); /* Parse <sizeof-expr> */
case T_INC:
nextoken(); /* ++() Prefix increment */
return pincdec(unary(), N_PREINC);
case T_DEC:
nextoken(); /* --() Prefix decrement */
return pincdec(unary(), N_PREDEC);
case Q_COMPL:
op = Q_COMPL;
break; /* ~() Bitwise not */
case Q_NOT:
op = Q_NOT;
break; /* !() Logical not */
case Q_PLUS:
op = Q_PLUS;
break; /* +() Unary plus */
case Q_MINUS:
op = N_NEG;
break; /* -() Arithmetic negation */
/* KAR-11/91, changed value of ra_expr for this case */
/* to 20 if ra_expr is 0 and 21 if ra_expr is 1 */
case Q_ANDT:
op = N_ADDR; /* &() Address of */
if (ra_expr)
ra_expr = 21;
else
ra_expr = 20;
break;
case Q_MPLY:
op = N_PTR;
break; /* *() Indirection */
}
nextoken(); /* Have a prefix op, move on to next token */
n = castexpr(); /* and parse cast-expr following the op */
if (n->Ntype->Tspec == TS_VOID)
error("Unary operand cannot have void type");
switch (op)
{
case N_PREINC: /* ++() Prefix increment */
case N_PREDEC: /* --() Prefix decrement */
n = pincdec(n, op);
break;
case Q_COMPL: /* ~() Bitwise not */
if (!tisinteg(n->Ntype)) /* Check for integral type */
{
error("Operand of ~ must have integral type");
return ndeficonst(0);
}
n = convunary(n); /* Convert if needed */
return ndef(op, n->Ntype, 0, n, (NODE*)NULL); /* Result has converted type */
case Q_NOT: /* !() Logical not */
n = convunary(n); /* Apply conversions */
if (!tisscalar(n->Ntype)) /* Check for scalar type */
{
error("Operand of ! must have scalar type");
return ndeficonst(0);
}
/* Note result type is always int! */
return ndef(op, inttype, 0, n, (NODE*)NULL);
case Q_PLUS: /* +() Unary plus */
if (!tisarith(n->Ntype)) /* Check for arithmetic type */
{
error("Operand of + must have arithmetic type");
return ndeficonst(0);
}
return convunary(n); /* Apply integral promotions */
case N_NEG: /* -() Arithmetic negation */
if (!tisarith(n->Ntype)) /* Check for arithmetic type */
{
error("Operand of - must have arithmetic type");
return ndeficonst(0);
}
/* Apply the usual unary conversions */
n = convunary(n); /* Convert if needed */
return ndef(op, n->Ntype, 0, n, (NODE*)NULL); /* Result has cvted type */
case N_ADDR: /* &() Address of */
/* No unary conversions apply here. Only check for lvalue.
** Application to functions and arrays is tricky.
** Level &(fun of T) &(array of T)
** ----- ----------- -------------
** base: error error
** carm: warn (ptr to fun of T) warn (ptr to T)
** ansi: OK (ptr to fun of T) OK (ptr to array of T)
*/
if (n->Ntype->Tspec == TS_FUNCT || n->Ntype->Tspec == TS_ARRAY)
{
switch (clevel)
{
default:
case CLEV_BASE:
error("& applied to array or function");
return convarrfn(n);
case CLEV_CARM:
case CLEV_ANSI:
warn("& applied to array or function");
return convarrfn(n); /* Let this convert to addr */
case CLEV_STDC:
if (n->Ntype->Tspec == TS_FUNCT)
return convarrfn(n);
break; /* For array, drop thru. */
}
}
if (!(n->Nflag & NF_LVALUE)) /* Operand must be lvalue */
error("Operand of & must be lvalue");
if (n->Nop == Q_IDENT)
if (n->Nid->Sclass == SC_RAUTO || n->Nid->Sclass == SC_RARG)
#if 0
if (clevel < CLEV_STRICT)
warn("& applied to register variable: non-portable!");
else
#endif
error("& applied to register variable");
if (tisbitf(n->Ntype))
#if 0
if (clevel < CLEV_STRICT)
warn("& applied to bitfield: non-portable!");
else
#endif
error("& applied to bitfield");
n = ndef(N_ADDR, n->Ntype, 0, n, (NODE*)NULL);
if (!(n->Nleft->Nflag & NF_GLOBAL)) /* If object has local extent */
{
stackrefs++; /* then count it as a */
n->Nflag |= NF_STKREF; /* stack reference */
}
n->Ntype = findtype(TS_PTR, n->Ntype); /* add ref to type */
break;
case N_PTR: /* *() Indirection */
return ptrapply(n); /* Use common routine */
default:
; /* do nothing */
}
return n;
}
/* PTRAPPLY - Apply "*" operator to an expression.
** This is a common subroutine rather than part of unary() because
** array subscripting wants to invoke "*" as well.
*/
static NODE *
ptrapply(n)
NODE *n;
{
n = convunary(n); /* Apply usual unary conversions */
if (n->Ntype->Tspec != TS_PTR)
{
error("Operand of * must have pointer type");
n->Ntype = findtype(TS_PTR, n->Ntype); /* patch up */
}
if (n->Ntype->Tsubt->Tspec == TS_VOID)
{
error("Operand of * cannot be ptr to void");
return ndeficonst(0);
}
n = ndef(N_PTR, n->Ntype->Tsubt, 0, n, (NODE*)NULL);
if (debcsi == KCC_DBG_NULL)
{
n->sfline = fline;
n->Nflag |= NF_USENPD;
}
if (n->Nleft->Nflag & NF_STKREF) /* If addr was on stack, */
stackrefs--; /* "*" cancels existence of addr. */
else
n->Nflag |= NF_GLOBAL; /* Not stack addr so must be global */
if (n->Ntype->Tspec != TS_FUNCT)
n->Nflag |= NF_LVALUE; /* Result is lvalue unless function */
return n;
}
/* SIZEEXPR - Handle "sizeof" operator.
** Note that the size is always in terms of TGSIZ_CHAR size bytes,
** rather than the actual # bits used by a "char" type; the latter can vary
** (mainly if -x=ch7 was specified), but by fiat we always measure objects
** in terms of 9-bit bytes so that everything will divide evenly and not
** confuse library routines and so forth.
** The exception is arrays; char arrays always return the number of
** elements (chars) in the array, regardless of the size of a char.
** Similarly, the size of a char is always 1, regardless of the actual # of
** bits it uses.
*/
static NODE *
sizeexpr(void)
{
TYPE *t;
NODE *n, *e;
int saveconst = constexpr; /* save state of constexpr flag */
/*
* Suspend restrictions on parsing of constant expressions
*/
constexpr = 0;
n = ndeft(N_ICONST, siztype); /* Get node for integer constant */
/* Use special type for "sizeof" */
t = NULL;
if (nextoken() == T_LPAREN) /* Check for possible type-name */
{
nextoken();
if(csymbol && (tok[token].tktype == TKTY_RWTYPE
|| csymbol->Sclass == SC_TYPEDEF))
{
t = typename();
expect(T_RPAREN);
}
else /* Not a reserved-word type or typedef, push paren back. */
tokpush(T_LPAREN, (SYMBOL *)NULL);
}
if (t == NULL) /* If no type-name seen, get a prefix-expression. */
{
e = unary(); /* Get expr, without fun/arr convs */
t = e->Ntype; /* and use type of the expression */
/* Special check for string constant, which normally doesn't
** have the size set in its type.
*/
if (e->Nop == N_SCONST) /* Is it string constant? */
{
n->Niconst = e->Nsclen; /* Yes, return length! */
constexpr = saveconst; /* restore state of flag */
return n;
}
}
/* Have type, now determine its size */
n->Niconst = 0; /* Clear in case of error */
switch (t->Tspec)
{
case TS_VOID:
warn("Operand of sizeof has void type");
break;
case TS_FUNCT:
error("Operand of sizeof has function type");
break;
case TS_ARRAY:
if (t->Tsize == 0)
{
error("Size of array not known");
n->Niconst = 0;
break;
}
if (tischararray(t)) /* If char array, */
{
n->Niconst = sizearray(t); /* size is # of elements */
break;
}
/* 8/91 ensure short s[1] is size 2 NOT 4 (SPR 9578) */
if (t->Tsubt->Tspec == TS_SHORT ||
t->Tsubt->Tspec == TS_USHORT)
{
n->Niconst = sizearray(t)*2;
break;
}
/* Drop through */
case TS_STRUCT:
case TS_UNION: /* (size in wds)*(chars per word) */
n->Niconst = sizetype(t) * (TGSIZ_WORD/TGSIZ_CHAR);
break;
case TS_CHAR:
case TS_UCHAR:
n->Niconst = 1; /* char always takes one byte */
break;
case TS_BITF:
case TS_UBITF:
error("Operand of sizeof has bitfield type");
/* Drop through */
/* Anything left had better be a scalar type! */
default:
if (!tisscalar(t))
int_error("sizeexpr: invalid type: %d", t->Tspec);
n->Niconst = (tbitsize(t) + TGSIZ_CHAR-1) / TGSIZ_CHAR;
break;
}
constexpr = saveconst; /* restore state of constexpr flag */
return n; /* return the filled in const node */
}
/* POSTEXPR - Parse postfix expression
** [dpANS 3.3.2]
**
** <postfix-expr> ::= <primary-expr>
** | <postfix-expr> '[' <expr> ']' Array subscript
** | <postfix-expr> '(' {arg-expr-list} ')' Function call
** | <postfix-expr> '.' <ident> Direct component sel
** | <postfix-expr> "->" <ident> Indirect component sel
** | <postfix-expr> "++" Post-increment
** | <postfix-expr> "--" Post-decrement
**
** Current token is 1st token of a postfix expression.
** On return, current token is the next one after the expression.
*/
static NODE *
postexpr()
{
int op;
INT off;
NODE *n;
TYPE *tp, *mt;
SYMBOL *sy;
n = primary(); /* First get primary expression */
for (;;)
switch (token) /* Loop to handle all postfixes */
{
case T_LPAREN:
/* Parse function call ::= <postfix-expr> '(' {arg-expr-list} ')'
** [dpANS 3.3.2.2]
*/
tp = n->Ntype; /* Remember function type */
sy = n->Nop == Q_IDENT ? n->Nid : NULL; /* Get ident if one */
switch (tp->Tspec)
{
case TS_FUNCT:
break; /* Should be this */
case TS_PTR: /* OK to be this */
sy = NULL;
if (tp->Tsubt->Tspec == TS_FUNCT)
{
if (clevel < CLEV_ANSI)
warn("Assuming ptr to function is function");
tp = tp->Tsubt;
if (n->Nop == N_ADDR) /* Simplify &f() to f() */
{
n = n->Nleft;
sy = n->Nop == Q_IDENT ? n->Nid : NULL;
}
else /* Use addr */
{
n = ndef(N_PTR, tp, 0, n, (NODE*)NULL);
if (debcsi == KCC_DBG_NULL)
{
n->sfline = fline;
n->Nflag |= NF_USENPD;
}
}
break;
}
/* Else fall thru to fail */
default:
error("Call to non-function");
n = ndeft(N_UNDEF, tp = findftype(tp, (TYPE *)NULL));
}
n = ndef(N_FNCALL, tp->Tsubt, 0, n, (NODE*)NULL);
/* Hack for returning structures -- see if internal auto
** struct is needed to hold return value, and allocate if so.
*/
if (sizetype(n->Ntype) > 2)
{
static int cntr = 0;
char temp[20];
if (n->Ntype->Tspec != TS_STRUCT && n->Ntype->Tspec !=TS_UNION)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -