⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cctype.c

📁 KCC , a good c compiler, write by Ken Harrenstien
💻 C
📖 第 1 页 / 共 3 页
字号:
    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 + -