📄 ccstmt.c
字号:
int_error("postexpr: Fn retval too large");
/* Make unique ident and then a local variable for type */
sprintf(temp,"%cstruct%d", SPC_IAUTO, ++cntr);
n->Nretstruct = defauto(temp, n->Ntype);
}
else
n->Nretstruct = NULL;
ra_expr = 1; /* Turn on checking mechanism for */
/* usage before init. */
/* Parse argument list if any */
n->Nright = parglist(sy, tp); /* Get arglist (may be NULL) */
break; /* Results aren't checked further. */
case T_LBRACK:
/*
** Parse array subscript ::= <postfix-expr> '[' <expr> ']'
**
** This is implemented by converting it into
** *(<postfix-expr> + <expr>)
*/
nextoken(); /* Move on to expr */
n = ndeflr(Q_PLUS, expression(), n);
n = chkadd(Q_PLUS, n); /* Do type checking etc */
tp = n->Ntype; /* get type back, make sure ptr */
if (tp->Tspec != TS_PTR)
error("Array or pointer type required");
expect(T_RBRACK);
/* Propagate flags (global & stkref only) */
n->Nflag = (n->Nleft->Nflag | n->Nright->Nflag)
& (NF_STKREF | NF_GLOBAL);
/* Now apply *() to the result, unless it will be an array.
** If the result of the * is going to be an array (ie it will
** remain a pointer) then skip this step to save the overhead
** of a pointless pair of "*" and "&" nodes, and put the result
** type directly into the Q_PLUS node.
*/
if (tp->Tsubt->Tspec == TS_ARRAY)
{
n->Ntype = tp->Tsubt; /* Make result be that array */
#if 0
n->Nflag &= ~NF_LVALUE; /* Make sure not an lvalue */
#else
n->Nflag |= NF_LVALUE; /* Make sure not an lvalue */
#endif
}
else
n = ptrapply(n); /* Not array, apply * to result */
break;
case Q_DOT:
case Q_MEMBER:
/* Parse struct/union component selection
** ::= <postfix-expr> '.' <ident>
** | <postfix-expr> "->" <ident>
**
** For ".", the first operand must be a qualified
** or unqualified struct/union type, and the second operand
** must name a member of that type.
** The result is an lvalue if the first expression is, and has
** the type of the member with the struct's qualifiers added.
**
** For "->", the first operand must be a pointer (quals are flushed
** by standard lvalue mungage, [dpANS 3.2.2.1]) to the same thing
** as ".", ditto second operand.
** The result is always an lvalue, and the type is as for ".".
*/
op = token; /* Remember which kind of selection it is */
/* Check that type of preceding expr is correct */
n = convarrfn(n); /* Apply array/funct convs if any */
tp = n->Ntype; /* (if no conv, qualifiers intact!) */
if (op == Q_MEMBER)
{
if (tp->Tspec != TS_PTR || (tp=tp->Tsubt) == NULL
|| (tp->Tspec != TS_STRUCT && tp->Tspec != TS_UNION))
{
error("Left operand of -> must be pointer to struct or union");
if ((tp=n->Ntype)->Tspec == TS_STRUCT || tp->Tspec == TS_UNION)
{
op = Q_DOT; /* Pretend "." seen instead */
}
else
tp = NULL;
}
}
else if (tp->Tspec != TS_STRUCT && tp->Tspec != TS_UNION)
{
error("Left operand of . must be struct or union");
if (tp->Tspec == TS_PTR && (tp=tp->Tsubt) == NULL
&& (tp->Tspec == TS_STRUCT || tp->Tspec == TS_UNION))
{
op = Q_MEMBER; /* Pretend "->" seen instead */
}
else
tp = NULL;
}
if (nextoken() != Q_IDENT)
{
error("Struct or union member expected");
break; /* Give up now, leave expr as is */
}
/* Check that component name is OK */
/* look up member name in symbol table */
/* Get right name for a member identifier by adding prefix */
sy = symfmember(csymbol, (tp ? tp->Tsmtag : NULL));
if (sy == NULL) /* Not a known member? */
{
error("Unknown struct/union component %S", csymbol);
off = 0; /* No offset for missing symbol */
mt = deftype; /* Use default (int) type of result */
}
else
{
off = sy->Ssmoff;
mt = sy->Stype;
}
if (csymbol->Sclass == SC_UNDEF)
freesym(csymbol);
/* Now ensure that any type qualifiers for the struct are also
** applied to the type of the member we just selected.
** If the struct/union was not an lvalue (as can happen for Q_DOT)
** then all qualifiers will be flushed by whatever uses this
** expression farther on.
*/
if (tp && tisqualif(tp)) /* Add any type qualifiers needed */
mt = findqtype(mt, tp->Tflag & TF_QUALS);
/* The flags remain the same for Q_DOT - this is how lvalueness is
** passed on.
** Q_MEMBER, however, involves
** a deferencing and so can undo a stackref or make a
** non-stackref safe from future address-taking.
*/
n = ndef(op, mt, n->Nflag, n, (NODE*)NULL);
n->Nxoff = off;
if (op == Q_MEMBER)
{
n->Nflag |= NF_LVALUE; /* addr of a->b can be taken */
if (n->Nflag & NF_STKREF)
{
stackrefs--; /* (&x)->y for x on stack */
n->Nflag &=~ NF_STKREF; /* dereferences address op */
}
else
n->Nflag |= NF_GLOBAL; /* otherwise not on stack */
if (debcsi == KCC_DBG_NULL)
{
n->sfline = fline;
n->Nflag |= NF_USENPD;
}
}
#if 0
/*
** Do special handling for member type == TS_ARRAY
**
** If the struct was returned from some function,
** we can't take the addresses of parts of it.
** It should be legal to do foo().x[i] even
** though we can't do foo().x, but it's too hard
** to do right, so we don't do it at all.
** Hopefully the ANSI C standard will clarify this.
**
** If the struct is local, we have to adjust stackrefs.
*/
if (tp->Tspec == TS_ARRAY)
{
if (!(n->Nflag & NF_LVALUE))
{
error("Lvalue required as array ref in struct");
}
n->Nflag &= ~NF_LVALUE; /* Array is never lvalue */
}
#endif
nextoken(); /* Done, now safe to skip over token! */
break;
case T_INC:
case T_DEC:
/*
** Parse post(inc/dec)rement ::= <postfix-expr> ["++" | "--"]
** The operand must have qualified or unqualified scalar type
** and must be a modifiable lvalue.
*/
n = pincdec(n, token == T_INC ? N_POSTINC : N_POSTDEC);
nextoken();
break;
default: /* If token not a postfix operator, */
return n; /* just return what we have so far. */
} /* End of switch and suffix loop */
}
/* PINCDEC - common auxiliary to handle postfix/prefix increment/decrement.
**
** The operand must have qualified or unqualified scalar type
** and must be a modifiable lvalue.
**
** Conversions are tricky here, since result value may not be
** of right type. See H&S 7.4.8.
** "the type of the result is that of the operand before conversion".
** This is one of the rare instances where we let the code generation
** worry about conversions rather than telling it what to do.
*/
static NODE *
pincdec(n, op)
NODE *n; /* Operand expression */
int op; /* Operator (N_PREINC, N_PREDEC, N_POSTINC, N_POSTDEC) */
{
if (constexpr)
error("++ or -- in constant expression");
if (!(n->Nflag&NF_LVALUE))
error("Operand of ++ or -- must be lvalue");
else if (!tisscalar(n->Ntype))
error("Operand of ++ or -- must have scalar type");
else if (tisconst(n->Ntype))
error("Operand of ++ or -- cannot be const-qualified");
else if (n->Ntype->Tspec == TS_PTR && n->Ntype->Tsubt->Tspec == TS_VOID)
error("Operand of ++ or -- cannot be ptr to void");
else if (n->Ntype->Tspec == TS_PTR && sizeptobj(n->Ntype) == 0)
error("Pointer operand of ++ or -- must point to object of known size");
else
{
if ((n->Nop == Q_IDENT) && !(n->Nid->Sinit))
switch (n->Nid->Sclass)
{
case SC_AUTO:
case SC_RAUTO:
case SC_ISTATIC:
warn("Possible usage before initialization: %s", n->Nid->Sname);
n->Nid->Sinit = 1;
break;
default:
break;
}
/* n->Nid->Sused = 1; */
return ndef(op, n->Ntype, 0, n, (NODE*)NULL); /* Success! */
}
/* Failure, return a suitable placeholder */
return ndeficonst(0); /* For now, later match type better? */
}
/* PRIMARY - Parse primary expression
** [dpANS 3.3.1]
**
** <primary-expr> ::= <ident>
** | <constant>
** | <string-literal>
** | '(' <expr> ')'
** KCC EXTENSION: | <asm-expr>
** | <muuo-expr> - KAR 1/91
**
** A <ident> must be either an object (of some type) or a function.
** The former is an lvalue, the latter a function designator.
** Note special case of enum constant, which is also an <ident>.
** A <constant> has a type and value as per syntax (CCLEX, [dpANS 3.1.3])
** It is not an lvalue.
** A <string-literal> is an lvalue, normally with type "array of char",
** per [dpANS 3.1.4].
**
** Current token must be the first token of a valid primary expression.
** On return, current token is the next one after the expression.
*/
static NODE *
primary()
{
NODE *n;
SYMBOL *s, d;
switch (token)
{
case Q_IDENT:
/*
** Parse <ident>
** This may be an enum constant as well as an object or function.
** This is where we check for handling calls to undeclared functs.
*/
s = csymbol; /* Remember pointer to identifier symbol */
nextoken(); /* then flush token, set up next */
switch (s->Sclass)
{
case SC_ENUM: /* If <ident> is Enumeration constant */
/* it evaluates into an integer constant */
return ndeficonst(s->Svalue); /* Note not lvalue! */
case SC_UNDEF: /* Undefined identifier may be function call */
if (token != T_LPAREN) /* Check for function-call case */
/* Undefined, complain */
{
error("Undefined identifier: %S", s);
freesym(s); /* Flush losing symbol */
return ndeft(N_UNDEF, deftype);
/* Returns special undef node so can continue processing */
}
/* Pretend we declared this identifier as
** "extern int ident();" in current block.
*/
note("Call to undeclared function %S", s);
d.Sclass = SC_EXTREF; /* Storage class as if "extern" */
d.Stype = findftype(inttype, (TYPE *)NULL); /* Set type */
s = funchk(0, SC_EXTREF, &d, s); /* Perform funct declaration */
s->Srefs++; /* Say referenced by call */
/* Now can drop through to handle normally */
default:
/* Normal variable or function name */
n = ndefident(s); /* Make Q_IDENT node */
/* Now set appropriate flags for this node. Note Nflag
** was initialized to 0 by the ndefident() above.
*/
if ( s->Sclass != SC_AUTO && s->Sclass != SC_RAUTO
&& s->Sclass != SC_ARG && s->Sclass != SC_RARG)
n->Nflag |= NF_GLOBAL; /* Var has static extent */
if (n->Ntype->Tspec != TS_FUNCT) /* If not a function, */
n->Nflag |= NF_LVALUE; /* then is an lvalue! */
}
break;
/* Constants and literals [H&S 2.7] [dpANS 3.1.3]
** The lexer has already parsed the constant into a T_*CONST token,
** and left information about the constant type and value in the
** global struct "constant".
*/
case T_ICONST: /* Handle integer constant */
case T_CCONST: /* Handle character constant */
n = ndeft(N_ICONST, constant.ctype);
n->Niconst = constant.cvalue;
nextoken();
break;
case T_FCONST: /* Handle floating-point constant */
n = ndeft(N_FCONST, constant.ctype);
switch (constant.ctype->Tspec)
{
case TS_FLOAT:
n->Nfconst = constant.Cfloat;
break;
case TS_DOUBLE:
n->Nfconst = constant.Cdouble;
break;
case TS_LNGDBL:
n->Nfconst = constant.Clngdbl;
break;
default:
int_error ("primary: invalide float const %d",
constant.ctype->Tspec);
}
nextoken();
break;
case T_SCONST: /* Handle <string-literal> */
n = ndeft(N_SCONST, constant.ctype);
n->Nsconst = constant.csptr; /* get pointer */
n->Nsclen = constant.cslen; /* and num chars including null */
nextoken();
break;
case T_LPAREN:
/*
** Parse parenthesized expression ::= '(' <expr> ')'
*/
nextoken(); /* Advance past left-paren */
n = expression(); /* Get expr list in parens */
n->Nflag |= NF_INPARENS; /* Remember it was paren-enclosed */
expect(T_RPAREN); /* followed by close paren */
break;
case Q_MUUO:
return bin_muuo(); /* Handle "muuo" built-in, KAR 1/91 */
case Q_ASM: /* Handle "asm" built-in */
return bin_asm();
case T_OFFSET: /* Handle "_KCC_offsetof" built-in */
return bin_offsetof();
case T_ELSE:
advise("Orphan 'else'");
default: /* Bad token... */
error("Primary expr expected"); /* Complain and return dummy */
return ndeft(N_UNDEF, deftype);
}
return n;
}
/* Parsing for various built-in expressions */
/* "asm" - handle built-in for assembly code inclusion
**
** <asm-expr> ::= "asm" '(' <exprlist> ')'
**
** This is a KCC-specific feature and can only happen if
** "asm" was initialized as a keyword by CCSYM on startup.
*/
static NODE *
bin_asm()
{
NODE *n;
if (nextoken() != T_LPAREN)
{
error("Bad syntax for \"asm\" - no left paren");
return primary(); /* Try again on this token */
}
n = parglist(NULL, NULL); /* Parse args as if function call */
/* Check out against currently supported syntax.
** This must be a single string literal after constant optimization.
*/
if (!n || n->Nleft || (n = evalexpr(n->Nright)) ==NULL
|| n->Nop != N_SCONST)
error("Arg to \"asm\" must be a single string literal");
return ndef(Q_ASM, voidtype, 0, n, (NODE*)NULL);
}
#define param1 temp->Nleft->Nleft->Nright
#define param2 temp->Nleft
#define param3 temp->Nright
#define param4 n->Nle
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -