442 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			442 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | |
|  * See the copyright notice in the ACK home directory, in the file "Copyright".
 | |
|  */
 | |
| /* $Id$ */
 | |
| /*	S E M A N T I C   A N A L Y S I S -- C H A P T E R  7 RM	*/
 | |
| 
 | |
| #include	"lint.h"
 | |
| #include	"nofloat.h"
 | |
| #include	"debug.h"
 | |
| #include	"nobitfield.h"
 | |
| #include	"idf.h"
 | |
| #include	"arith.h"
 | |
| #include	"type.h"
 | |
| #include	"struct.h"
 | |
| #include	"label.h"
 | |
| #include	"expr.h"
 | |
| #include	"def.h"
 | |
| #include	"Lpars.h"
 | |
| #include	"assert.h"
 | |
| 
 | |
| extern char options[];
 | |
| extern char *symbol2str();
 | |
| 
 | |
| /*	Most expression-handling routines have a pointer to a
 | |
| 	(struct type *) as first parameter. The object under the pointer
 | |
| 	gets updated in the process.
 | |
| */
 | |
| 
 | |
| ch7sel(expp, oper, idf)
 | |
| 	struct expr **expp;
 | |
| 	struct idf *idf;
 | |
| {
 | |
| 	/*	The selector idf is applied to *expp; oper may be '.' or
 | |
| 		ARROW.
 | |
| 	*/
 | |
| 	register struct expr *exp;
 | |
| 	register struct type *tp;
 | |
| 	register struct sdef *sd;
 | |
| 
 | |
| 	any2opnd(expp, oper);
 | |
| 	exp = *expp;
 | |
| 	tp = exp->ex_type;
 | |
| 	if (oper == ARROW)	{
 | |
| 		if (tp->tp_fund == POINTER &&
 | |
| 		    ( tp->tp_up->tp_fund == STRUCT ||
 | |
| 		      tp->tp_up->tp_fund == UNION))	/* normal case */
 | |
| 			tp = tp->tp_up;
 | |
| 		else {	/* constructions like "12->selector" and
 | |
| 				"char c; c->selector"
 | |
| 			*/
 | |
| 			switch (tp->tp_fund)	{
 | |
| 			case INT:
 | |
| 			case LONG:
 | |
| 				/* Allowed by RM 14.1 */
 | |
| 				ch7cast(expp, CAST, pa_type);
 | |
| 				sd = idf2sdef(idf, tp);
 | |
| 				tp = sd->sd_stype;
 | |
| 				break;
 | |
| 			case POINTER:
 | |
| 				break;
 | |
| 			default:
 | |
| 				expr_error(exp, "-> applied to %s",
 | |
| 					symbol2str(tp->tp_fund));
 | |
| 			case ERRONEOUS:
 | |
| 				exp->ex_type = error_type;
 | |
| 				return;
 | |
| 			}
 | |
| 		}
 | |
| 	} /* oper == ARROW */
 | |
| 	else { /* oper == '.' */
 | |
| 		/* filter out illegal expressions "non_lvalue.sel" */
 | |
| 		if (!exp->ex_lvalue) {
 | |
| 			expr_error(exp, "dot requires lvalue");
 | |
| 			return;
 | |
| 		}
 | |
| 	}
 | |
| 	exp = *expp;
 | |
| 	switch (tp->tp_fund)	{
 | |
| 	case POINTER:	/* for int *p;	p->next = ...	*/
 | |
| 	case STRUCT:
 | |
| 	case UNION:
 | |
| 		break;
 | |
| 	case INT:
 | |
| 	case LONG:
 | |
| 		/* warning will be given by idf2sdef() */
 | |
| 		break;
 | |
| 	default:
 | |
| 		if (!is_anon_idf(idf))
 | |
| 			expr_error(exp, "selector %s applied to %s",
 | |
| 				idf->id_text, symbol2str(tp->tp_fund));
 | |
| 	case ERRONEOUS:
 | |
| 		exp->ex_type = error_type;
 | |
| 		return;
 | |
| 	}
 | |
| 	sd = idf2sdef(idf, tp);
 | |
| 	if (oper == '.')	{
 | |
| 		/*	there are 3 cases in which the selection can be
 | |
| 			performed compile-time: 
 | |
| 			I:	n.sel (n either an identifier or a constant)
 | |
| 			II:	(e.s1).s2 (transformed into (e.(s1+s2)))
 | |
| 			III:	(e->s1).s2 (transformed into (e->(s1+s2)))
 | |
| 				The code performing these conversions is
 | |
| 				extremely obscure.
 | |
| 		*/
 | |
| 		if (exp->ex_class == Value)	{
 | |
| 			/*	It is an object we know the address of; so
 | |
| 				we can calculate the address of the
 | |
| 				selected member 
 | |
| 			*/
 | |
| 			exp->VL_VALUE += sd->sd_offset;
 | |
| 			exp->ex_type = sd->sd_type;
 | |
| 			if (exp->ex_type == error_type)
 | |
| 				exp->ex_flags |= EX_ERROR;
 | |
| 		}
 | |
| 		else
 | |
| 		if (exp->ex_class == Oper)	{
 | |
| 			struct oper *op = &(exp->ex_object.ex_oper);
 | |
| 			
 | |
| 			if (op->op_oper == '.' || op->op_oper == ARROW)	{
 | |
| 				ASSERT(is_cp_cst(op->op_right));
 | |
| 				op->op_right->VL_VALUE += sd->sd_offset;
 | |
| 				exp->ex_type = sd->sd_type;
 | |
| 				if (exp->ex_type == error_type)
 | |
| 					exp->ex_flags |= EX_ERROR;
 | |
| 			}
 | |
| 			else
 | |
| 				exp = new_oper(sd->sd_type, exp, '.',
 | |
| 						intexpr(sd->sd_offset, INT));
 | |
| 		}
 | |
| 	}
 | |
| 	else /* oper == ARROW */
 | |
| 		exp = new_oper(sd->sd_type,
 | |
| 			exp, oper, intexpr(sd->sd_offset, INT));
 | |
| 	exp->ex_lvalue = (sd->sd_type->tp_fund != ARRAY);
 | |
| 	*expp = exp;
 | |
| }
 | |
| 
 | |
| ch7incr(expp, oper)
 | |
| 	struct expr **expp;
 | |
| {
 | |
| 	/*	The monadic prefix/postfix incr/decr operator oper is
 | |
| 		applied to *expp.
 | |
| 	*/
 | |
| 	ch7asgn(expp, oper, intexpr((arith)1, INT));
 | |
| }
 | |
| 
 | |
| ch7cast(expp, oper, tp)
 | |
| 	register struct expr **expp;
 | |
| 	register struct type *tp;
 | |
| {
 | |
| 	/*	The expression *expp is cast to type tp; the cast is
 | |
| 		caused by the operator oper.  If the cast has
 | |
| 		to be passed on to run time, its left operand will be an
 | |
| 		expression of class Type.
 | |
| 	*/
 | |
| 	register struct type *oldtp;
 | |
| 
 | |
| 	if ((*expp)->ex_type->tp_fund == FUNCTION)
 | |
| 		function2pointer(*expp);
 | |
| 	if ((*expp)->ex_type->tp_fund == ARRAY)
 | |
| 		array2pointer(*expp);
 | |
| 	if ((*expp)->ex_class == String)
 | |
| 		string2pointer(*expp);
 | |
| 	oldtp = (*expp)->ex_type;
 | |
| 
 | |
| #ifndef NOBITFIELD
 | |
| 	if (oldtp->tp_fund == FIELD)	{
 | |
| 		field2arith(expp);
 | |
| 		ch7cast(expp, oper, tp);
 | |
| 	}
 | |
| 	else
 | |
| 	if (tp->tp_fund == FIELD) {
 | |
| 		ch7cast(expp, oper, tp->tp_up);
 | |
| 	}
 | |
| 	else
 | |
| #endif /* NOBITFIELD */
 | |
| 	if (oldtp == tp) {
 | |
| 		/* life is easy */
 | |
| 	}
 | |
| 	else
 | |
| 	if (tp->tp_fund == VOID) {
 | |
| 		/* Easy again */
 | |
| 		(*expp)->ex_type = void_type;
 | |
| 	}
 | |
| 	else
 | |
| 	if (is_arith_type(oldtp) && is_arith_type(tp))	{
 | |
| 		int oldi = is_integral_type(oldtp);
 | |
| 		int i = is_integral_type(tp);
 | |
| 
 | |
| 		if (oldi && i)	{
 | |
| 			if (	oper != CAST
 | |
| 			&&	(	tp->tp_fund == ENUM
 | |
| 				||	oldtp->tp_fund == ENUM
 | |
| 				)
 | |
| 			) {
 | |
| 				expr_warning(*expp,
 | |
| 					"dubious %s on enum",
 | |
| 					symbol2str(oper));
 | |
| 			}
 | |
| #ifdef	LINT
 | |
| 			if (oper == CAST)
 | |
| 				(*expp)->ex_type = tp;
 | |
| 			else
 | |
| 				int2int(expp, tp);
 | |
| #else	/* LINT */
 | |
| 			int2int(expp, tp);
 | |
| #endif	/* LINT */
 | |
| 		}
 | |
| #ifndef NOFLOAT
 | |
| 		else
 | |
| 		if (oldi && !i)	{
 | |
| 			if (oldtp->tp_fund == ENUM && oper != CAST)
 | |
| 				expr_warning(*expp,
 | |
| 					"conversion of enum to %s\n",
 | |
| 					symbol2str(tp->tp_fund));
 | |
| #ifdef	LINT
 | |
| 			if (oper == CAST)
 | |
| 				(*expp)->ex_type = tp;
 | |
| 			else
 | |
| 				int2float(expp, tp);
 | |
| #else	/* LINT */
 | |
| 			int2float(expp, tp);
 | |
| #endif	/* LINT */
 | |
| 		}
 | |
| 		else
 | |
| 		if (!oldi && i) {
 | |
| #ifdef	LINT
 | |
| 			if (oper == CAST)
 | |
| 				(*expp)->ex_type = tp;
 | |
| 			else
 | |
| 				float2int(expp, tp);
 | |
| #else	/* LINT */
 | |
| 			float2int(expp, tp);
 | |
| #endif	/* LINT */
 | |
| 		}
 | |
| 		else {
 | |
| 			/* !oldi && !i */
 | |
| #ifdef	LINT
 | |
| 			if (oper == CAST)
 | |
| 				(*expp)->ex_type = tp;
 | |
| 			else
 | |
| 				float2float(expp, tp);
 | |
| #else	/* LINT */
 | |
| 			float2float(expp, tp);
 | |
| #endif	/* LINT */
 | |
| 		}
 | |
| #else /* NOFLOAT */
 | |
| 		else {
 | |
| 			crash("(ch7cast) floats not implemented\n");
 | |
| 			/*NOTREACHED*/
 | |
| 		}
 | |
| #endif /* NOFLOAT */
 | |
| 	}
 | |
| 	else
 | |
| 	if (oldtp->tp_fund == POINTER && tp->tp_fund == POINTER)	{
 | |
| 		if (oper != CAST)
 | |
| 			expr_warning(*expp, "incompatible pointers in %s",
 | |
| 							symbol2str(oper));
 | |
| #ifdef	LINT
 | |
| 		if (oper != CAST)
 | |
| 			lint_ptr_conv(oldtp->tp_up->tp_fund, tp->tp_up->tp_fund);
 | |
| #endif	/* LINT */
 | |
| 		(*expp)->ex_type = tp;	/* free conversion */
 | |
| 	}
 | |
| 	else
 | |
| 	if (oldtp->tp_fund == POINTER && is_integral_type(tp))	{
 | |
| 		/* from pointer to integral */
 | |
| 		if (oper != CAST)
 | |
| 			expr_warning(*expp,
 | |
| 				"illegal conversion of pointer to %s",
 | |
| 				symbol2str(tp->tp_fund));
 | |
| 		if (oldtp->tp_size > tp->tp_size)
 | |
| 			expr_warning(*expp,
 | |
| 				"conversion of pointer to %s loses accuracy",
 | |
| 				symbol2str(tp->tp_fund));
 | |
| 		if (oldtp->tp_size != tp->tp_size)
 | |
| 			int2int(expp, tp);
 | |
| 		else
 | |
| 			(*expp)->ex_type = tp;
 | |
| 	}
 | |
| 	else
 | |
| 	if (tp->tp_fund == POINTER && is_integral_type(oldtp))	{
 | |
| 		/* from integral to pointer */
 | |
| 		switch (oper)	{
 | |
| 		case CAST:
 | |
| 			break;
 | |
| 		case EQUAL:
 | |
| 		case NOTEQUAL:
 | |
| 		case ':':
 | |
| 		case '=':
 | |
| 		case RETURN:
 | |
| 			if (is_cp_cst(*expp) && (*expp)->VL_VALUE == (arith)0)
 | |
| 				break;
 | |
| 		default:
 | |
| 			expr_warning(*expp,
 | |
| 				"dubious conversion of %s to pointer",
 | |
| 				symbol2str(oldtp->tp_fund));
 | |
| 			break;
 | |
| 		}
 | |
| 		if (oldtp->tp_size > tp->tp_size)
 | |
| 			expr_warning(*expp,
 | |
| 				"conversion of %s to pointer loses accuracy",
 | |
| 				symbol2str(oldtp->tp_fund));
 | |
| 		if (oldtp->tp_size != tp->tp_size)
 | |
| 			int2int(expp, tp);
 | |
| 		else
 | |
| 			(*expp)->ex_type = tp;
 | |
| 	}
 | |
| 	else
 | |
| 	if (oldtp->tp_fund == ERRONEOUS) {
 | |
| 		/* we just won't look */
 | |
| 		(*expp)->ex_type = tp;	/* brute force */
 | |
| 	}
 | |
| 	else
 | |
| 	if (oldtp->tp_size == tp->tp_size && oper == CAST)	{
 | |
| 		expr_warning(*expp, "dubious conversion based on equal size");
 | |
| 		(*expp)->ex_type = tp;		/* brute force */
 | |
| 	}
 | |
| 	else	{
 | |
| 		if (oldtp->tp_fund != ERRONEOUS && tp->tp_fund != ERRONEOUS)
 | |
| 			expr_error(*expp, "cannot convert %s to %s",
 | |
| 				symbol2str(oldtp->tp_fund),
 | |
| 				symbol2str(tp->tp_fund)
 | |
| 			);
 | |
| 		(*expp)->ex_type = tp;		/* brute force */
 | |
| 	}
 | |
| }
 | |
| 
 | |
| ch7asgn(expp, oper, expr)
 | |
| 	struct expr **expp;
 | |
| 	struct expr *expr;
 | |
| {
 | |
| 	/*	The assignment operators.
 | |
| 		"f op= e" should be interpreted as
 | |
| 		"f = (typeof f)((typeof (f op e))f op (typeof (f op e))e)"
 | |
| 		and not as "f = f op (typeof f)e".
 | |
| 		Consider, for example, (i == 10) i *= 0.9; (i == 9), where
 | |
| 		typeof i == int.
 | |
| 		The resulting expression tree becomes:
 | |
| 				op=
 | |
| 				/ \
 | |
| 			       /   \
 | |
| 			      f     (typeof (f op e))e
 | |
| 		EVAL should however take care of evaluating (typeof (f op e))f
 | |
| 	*/
 | |
| 	register struct expr *exp = *expp;
 | |
| 	int fund = exp->ex_type->tp_fund;
 | |
| 	struct type *tp;
 | |
| 
 | |
| 	/* We expect an lvalue */
 | |
| 	if (!exp->ex_lvalue)	{
 | |
| 		expr_error(exp, "no lvalue in lhs of %s", symbol2str(oper));
 | |
| 		exp->ex_depth = 99;	/* no direct store/load at EVAL() */
 | |
| 			/* what is 99 ??? DG */
 | |
| 	}
 | |
| 	if (oper == '=') {
 | |
| 		ch7cast(&expr, oper, exp->ex_type);
 | |
| 		tp = expr->ex_type;
 | |
| 	}
 | |
| 	else {	/* turn e into e' where typeof(e') = typeof (f op e) */
 | |
| 		struct expr *extmp = intexpr((arith)0, INT);
 | |
| 
 | |
| 		/* this is really $#@&*%$# ! */
 | |
| 		/* if you correct this, please correct lint_new_oper() too */
 | |
| 		extmp->ex_lvalue = 1;
 | |
| 		extmp->ex_type = exp->ex_type;
 | |
| 		ch7bin(&extmp, oper, expr);
 | |
| 		/* Note that ch7bin creates a tree of the expression
 | |
| 			((typeof (f op e))f op (typeof (f op e))e),
 | |
| 		   where f ~ extmp and e ~ expr.
 | |
| 		   We want to use (typeof (f op e))e.
 | |
| 		   Ch7bin does not create a tree if both operands
 | |
| 		   were illegal or constants!
 | |
| 		*/
 | |
| 		tp = extmp->ex_type;	/* perform the arithmetic in type tp */
 | |
| 		if (extmp->ex_class == Oper) {
 | |
| 			expr = extmp->OP_RIGHT;
 | |
| 			extmp->OP_RIGHT = NILEXPR;
 | |
| 			free_expression(extmp);
 | |
| 		}
 | |
| 		else
 | |
| 			expr = extmp;
 | |
| 	}
 | |
| #ifndef NOBITFIELD
 | |
| 	if (fund == FIELD)
 | |
| 		exp = new_oper(exp->ex_type->tp_up, exp, oper, expr);
 | |
| 	else
 | |
| 		exp = new_oper(exp->ex_type, exp, oper, expr);
 | |
| #else /* NOBITFIELD */
 | |
| 	exp = new_oper(exp->ex_type, exp, oper, expr);
 | |
| #endif /* NOBITFIELD */
 | |
| 	exp->OP_TYPE = tp;	/* for EVAL() */
 | |
| 	exp->ex_flags |= EX_SIDEEFFECTS;
 | |
| 	*expp = exp;
 | |
| }
 | |
| 
 | |
| /*	Some interesting (?) questions answered.
 | |
| */
 | |
| int
 | |
| is_integral_type(tp)
 | |
| 	register struct type *tp;
 | |
| {
 | |
| 	switch (tp->tp_fund)	{
 | |
| 	case CHAR:
 | |
| 	case SHORT:
 | |
| 	case INT:
 | |
| 	case LONG:
 | |
| 	case ENUM:
 | |
| 		return 1;
 | |
| #ifndef NOBITFIELD
 | |
| 	case FIELD:
 | |
| 		return is_integral_type(tp->tp_up);
 | |
| #endif /* NOBITFIELD */
 | |
| 	default:
 | |
| 		return 0;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int
 | |
| is_arith_type(tp)
 | |
| 	register struct type *tp;
 | |
| {
 | |
| 	switch (tp->tp_fund)	{
 | |
| 	case CHAR:
 | |
| 	case SHORT:
 | |
| 	case INT:
 | |
| 	case LONG:
 | |
| 	case ENUM:
 | |
| #ifndef NOFLOAT
 | |
| 	case FLOAT:
 | |
| 	case DOUBLE:
 | |
| #endif /* NOFLOAT */
 | |
| 		return 1;
 | |
| #ifndef NOBITFIELD
 | |
| 	case FIELD:
 | |
| 		return is_arith_type(tp->tp_up);
 | |
| #endif /* NOBITFIELD */
 | |
| 	default:
 | |
| 		return 0;
 | |
| 	}
 | |
| }
 |