📄 cctype.c
字号:
else if (lt == dbltype || rt == dbltype)
convboth(n, dbltype);
/* 2a. If one operand is "float", make both "float".
** Need not do clevel check here as convunary already did that;
** i.e. if clevel isn't ANSI then floats would be doubles by now.
*/
else if (lt == flttype || rt == flttype)
convboth(n, flttype);
/* 3. If one operand is "unsigned long", make both "unsigned long" */
else if (lt == ulongtype || rt == ulongtype)
convboth(n, ulongtype);
/* 4+5. CARM only: If one operand is "long" and other is "unsigned int",
** make both "unsigned long".
** ANSI: if "long" can represent all values of "unsigned int", then use
** "long", else use "unsigned long".
*/
else if (lt == longtype || rt == longtype) {
if ((lt == uinttype || rt == uinttype)
&& (longtype->Tsize <= uinttype->Tsize /* Check type size */
|| (clevel < CLEV_ANSI)))
convboth(n, ulongtype); /* Sigh, use ulong */
else convboth(n, longtype); /* Win, plain long */
}
/* 6. If one operand is "unsigned", then both are made "unsigned" */
else if (lt == uinttype || rt == uinttype)
convboth(n, uinttype);
/* Else should be int, and should have caught the equivalence earlier! */
else int_error("convbinary: operand types escaped!");
n->Ntype = n->Nleft->Ntype; /* Result type is the common type */
return n;
}
/* CONVBOTH and CONVXBOTH - simple auxiliaries just for convbinary().
*/
static void
convboth(n, newtyp)
NODE *n;
TYPE *newtyp;
{
n->Nleft = convxboth(n->Nleft, newtyp); /* Do left side */
n->Nright = convxboth(n->Nright, newtyp); /* then right */
}
static NODE *
convxboth(n, newtyp)
NODE *n;
TYPE *newtyp;
{
if (n->Ntype != newtyp) {
/* Do implicit cast. If casting a cast that's also implicit,
** we avoid overhead by just changing the existing cast op to the
** right thing.
*/
if (n->Nop == N_CAST
&& (n->Nflag & NF_USERCAST)==0) { /* Implicit cast? */
n->Ntype = newtyp; /* Yup, fix it up */
n->Ncast = cast_op(newtyp, n->Nleft->Ntype);
} else /* Casting something else */
n = ndefcast(cast_op(newtyp, n->Ntype), newtyp, n);
}
return n;
}
/* CONVFUNARG - Apply the "function argument conversions" to a node.
** [H&S 6.14]
** Note that a float argument is always converted to a double,
** regardless of whether this conversion is done for unary or binary
** expressions.
** The new type is always unqualified.
*/
NODE *
convfunarg(n)
NODE *n;
{
if (n->Ntype->Tspec == TS_VOID) {
error("Illegal use of void type - function arg");
return ndeficonst(0L);
}
else if (n->Ntype->Tspec == TS_FLOAT) { /* Cast float to double */
return ndefcast(cast_op(dbltype, n->Ntype), dbltype, n);
}
return convunary(n);
}
/* CONVFPARAM - Apply the "function parameter promotions" to a type.
** [H&S 9.4] No explicit casts are possible at this point; we
** simply set the variable type to what actually will be passed as an argument.
** This routine is called by CCDECL when parsing a function declaration
** and is unlike the others in that it returns a TYPE * pointer
** rather than a NODE * pointer.
** Note the difference between ANSI and CARM: ANSI preserves value
** whereas CARM preserves unsignedness. This has the effect of requiring
** ANSI level to return "int" for both signed and unsigned chars/shorts,
** whereas CARM level returns "unsigned int" if the original type was unsigned.
*/
TYPE *
convfparam(t)
TYPE *t; /* Type of function parameter to check */
{
switch (t->Tspec) { /* Apply funct param convs */
case TS_VOID:
error("Function parameter cannot have type void");
break;
case TS_FUNCT: /* "Function of T" => "pointer to function of T" */
if (clevel < CLEV_ANSI) /* If not ANSI, complain */
error("Function parameter cannot have type function");
return findtype(TS_PTR, t);
case TS_ARRAY: /* "Array of T" => "pointer to T" */
return findtype(TS_PTR, t->Tsubt);
case TS_STRUCT:
case TS_UNION:
case TS_PTR:
case TS_ENUM:
break;
case TS_FLOAT: /* float => double, always. */
return dbltype;
case TS_DOUBLE:
case TS_LNGDBL:
break;
case TS_BITF: /* bitfield => int */
case TS_UBITF: /* Ditto for unsigned bitf */
int_error("convfparam: BITF param");
break;
case TS_CHAR: /* char => int */
case TS_UCHAR: /* and unsigned char */
if ((TGSIZ_WORD % tbitsize(t)) != 0)
error("Function param cannot have char size %d",
tbitsize(t));
if (clevel >= CLEV_ANSI) /* If ANSI, */
return inttype; /* chars always promoted to int */
return (t->Tspec == TS_CHAR ? inttype : uinttype);
case TS_SHORT: /* short => int */
return inttype;
case TS_USHORT: /* unsigned short must check for ANSIness */
if (clevel >= CLEV_ANSI)
return inttype;
return uinttype;
case TS_INT:
case TS_LONG:
case TS_UINT:
case TS_ULONG:
break;
default:
int_error("convfparam: bad type: %d", t->Tspec);
}
return t;
}
/* CONVTERNARYT - Do type checking and conversion for operands of
** conditional operator. Returns a type pointer (not a node pointer).
** Operands must have already been run through convbinary(), thus
** they have no type-qualifiers.
** 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).
*/
TYPE *
convternaryt(n)
NODE *n;
{
TYPE *lt, *rt, *t;
INT quals;
if (convisnull(n)) /* Combo of NULL and pointer? */
return n->Nleft->Ntype; /* Yep, done. Both nodes now have the */
/* type of the pointer. */
if (n->Nleft->Ntype->Tspec != TS_PTR || n->Nright->Ntype->Tspec != TS_PTR)
return NULL; /* Not both pointers, gotta give up */
lt = n->Nleft->Ntype->Tsubt;
rt = n->Nright->Ntype->Tsubt;
quals = 0;
if (tisqualif(lt)) { /* Get unqualified subtype */
quals |= lt->Tflag;
lt = findutype(lt);
}
if (tisqualif(rt)) { /* Get unqualified subtype */
quals |= rt->Tflag;
rt = findutype(rt);
}
if (lt->Tspec == TS_VOID) { /* If left is (void *) */
t = lt; /* then convert right to that */
} else if (rt->Tspec == TS_VOID) { /* If right is (void *) */
t = rt; /* then convert left to that */
} else if ((t = tcomposite(lt, rt)) == NULL) /* Comp of unqual subtypes */
return NULL;
t = findtype(TS_PTR, findqtype(t, quals)); /* Combine quals */
/* Now have result type, ensure both left and right are that type. */
n->Nleft = convcast(t, n->Nleft);
n->Nright = convcast(t, n->Nright);
return t;
}
/* Auxiliary miscellaneous routines */
/* CONVVOIDPTR - Converts combination of pointer and (void *) if present,
** else does nothing. Takes a binary op node with left and right
** expressions already crunched through binary conversions.
** Ignores qualifiers.
*/
NODE *
convvoidptr(n)
NODE *n;
{
if (n->Nleft->Ntype->Tspec == TS_PTR
&& n->Nleft->Ntype->Tsubt->Tspec == TS_VOID)
n->Nright = convcast(n->Nleft->Ntype, n->Nright);
else if (n->Nright->Ntype->Tspec == TS_PTR
&& n->Nright->Ntype->Tsubt->Tspec == TS_VOID)
n->Nleft = convcast(n->Nright->Ntype, n->Nleft);
return n;
}
/* CONVNULLCOMB - Converts combination of pointer and NULL if present,
** else does nothing. Takes a binary op node with left and right
** expressions already crunched through binary conversions.
** (thus they have no qualifiers on their types)
*/
NODE *
convnullcomb(n)
NODE *n;
{
(void)convisnull(n); /* Invoke conversion if any, ignore result */
return n;
}
/* CONVISNULL - worker routine for CONVNULLCOMB.
** This is a separate routine so it can be called by CCSTMT's ternary()
** with an indication of conversion success or failure. It does
** the same thing as CONVNULLCOMB but unlike the other CONV routines
** it returns 0 (no conversion done) or 1 (conversion done) instead of
** a node pointer, which is OK because the node pointer is never changed.
** Type-qualifiers are flushed, but they shouldn't exist at this point
** anyway because the operands have been run through convbinary().
*/
static int
convisnull(n)
NODE *n;
{
if (n->Nleft->Ntype->Tspec == TS_PTR && nisnull(&n->Nright))
n->Nright = convcast(n->Nleft->Ntype, n->Nright);
else if (n->Nright->Ntype->Tspec == TS_PTR && nisnull(&n->Nleft))
n->Nleft = convcast(n->Nright->Ntype, n->Nleft);
else return 0;
return 1;
}
/* NISNULL - Given POINTER TO a node pointer, evaluates that node
** to determine if it is a null pointer constant. Updates the pointer
** pointed to (since evaluation can change it), and returns
** TRUE if node is a null pointer constant.
**
** As of 7-Dec-88, the ANSI draft requires that
** a "null pointer constant" be either:
** An integral constant expression with the value 0,
** or such an expression cast to the type (void *).
** Someday, someday, they may come to their senses and flush the second
** possibility. Yeech!
** Note the code here tries to avoid invoking evalexpr() by doing
** some preliminary checks.
*/
static int
nisnull(an)
NODE **an;
{
NODE *n = *an;
if (clevel >= CLEV_ANSI) {
/* Stupid ANSI mistake, but must support (void *)0 */
if (n->Ntype == voidptrtype) { /* If type is (void *) */
if (n->Nop != N_CAST /* see if it's a cast */
|| !tisinteg(n->Ntype)) /* of an integer */
return 0;
n = n->Nleft = evalexpr(n->Nleft); /* Sigh, must eval it */
} else if (tisinteg(n->Ntype) && n->Nop != N_ICONST)
*an = n = evalexpr(n); /* Ensure expr is evaluated */
} else
while (n->Nop == N_EXPRLIST) /* Dig down to real expr */
n = n->Nright;
/* Now check for integer 0 */
return (n->Nop == N_ICONST && n->Niconst == 0);
}
/* NDEFCAST - Makes a N_CAST node and sets its cast operation value.
*/
static NODE *
ndefcast(op, t, n)
TYPE *t;
NODE *n;
{
n = ndeftl(N_CAST, t, n); /* Apply cast to given type */
n->Ncast = op; /* Using this specific cast operation */
return n;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -