Kaynağa Gözat

improved error reporting for initialization expressions
miscellaneous changes

dick 38 yıl önce
ebeveyn
işleme
c80f2c0817

+ 14 - 5
lang/cem/cemcom/arith.c

@@ -164,14 +164,23 @@ any2arith(expp, oper)
 		error("operator %s on non-numerical operand (%s)",
 			symbol2str(oper), symbol2str(fund));
 	case ERRONEOUS:
-		free_expression(*expp);
-		*expp = intexpr((arith)1, INT);
+		erroneous2int(expp);
 		break;
 	}
 
 	return (*expp)->ex_type->tp_fund;
 }
 
+erroneous2int(expp)
+	struct expr **expp;
+{
+	/*	the (erroneous) expression *expp is replaced by an
+		int expression
+	*/
+	free_expression(*expp);
+	*expp = intexpr((arith)0, INT);
+}
+
 struct expr *
 arith2arith(tp, oper, expr)
 	struct type *tp;
@@ -247,7 +256,7 @@ float2float(expp, tp)
 	*/
 	
 	fp_used = 1;
-	if ((*expp)->ex_class == Float)	{
+	if (is_fp_cst(*expp))	{
 		(*expp)->ex_type = tp;
 	}
 	else	{
@@ -285,7 +294,7 @@ opnd2integral(expp, oper)
 		if (fund != ERRONEOUS)
 			error("%s operand to %s",
 				symbol2str(fund), symbol2str(oper));
-		*expp = intexpr((arith)1, INT);
+		erroneous2int(expp);
 		/* fund = INT; */
 	}
 }
@@ -321,7 +330,7 @@ opnd2logical(expp, oper)
 		error("%s operand to %s",
 			symbol2str(fund), symbol2str(oper));
 	case ERRONEOUS:
-		*expp = intexpr((arith)1, INT);
+		erroneous2int(expp);
 		break;
 	}
 }

+ 1 - 5
lang/cem/cemcom/ch7.c

@@ -13,10 +13,6 @@
 #include	"Lpars.h"
 #include	"assert.h"
 
-#define	is_zero(ex)	\
-	((ex)->ex_class == Value && (ex)->VL_VALUE == (arith)0 && \
-			(ex)->VL_IDF == 0)
-
 extern char options[];
 extern char *symbol2str();
 
@@ -262,7 +258,7 @@ ch7cast(expp, oper, tp)
 		case NOTEQUAL:
 		case '=':
 		case RETURN:
-			if (is_zero(*expp))
+			if (is_cp_cst(*expp) && (*expp)->VL_VALUE == (arith)0)
 				break;
 		default:
 			warning("illegal conversion of %s to pointer",

+ 3 - 5
lang/cem/cemcom/ch7bin.c

@@ -82,7 +82,7 @@ ch7bin(expp, oper, expr)
 		fund = arithbalance(expp, oper, &expr);
 		if (fund == DOUBLE)	{
 			error("floating operand to %%");
-			*expp = intexpr((arith)1, INT);
+			erroneous2int(expp);
 		}
 		else
 			non_commutative_binop(expp, oper, expr);
@@ -235,8 +235,7 @@ pntminuspnt(expp, oper, expr)
 	if (up_type != expr->ex_type->tp_up)	{
 		error("subtracting incompatible pointers");
 		free_expression(expr);
-		free_expression(*expp);
-		*expp = intexpr((arith)0, INT);
+		erroneous2int(expp);
 		return;
 	}
 	/*	we hope the optimizer will eliminate the load-time
@@ -285,8 +284,7 @@ pointer_arithmetic(expp1, oper, expp2)
 	if (any2arith(expp2, oper) == DOUBLE)	{
 		expr_error(*expp2,
 			"illegal combination of float and pointer");
-		free_expression(*expp2);
-		*expp2 = intexpr((arith)0, INT);
+		erroneous2int(expp2);
 	}
 	ch7bin( expp2, '*',
 		intexpr(size_of_type((*expp1)->ex_type->tp_up, "object"),

+ 4 - 3
lang/cem/cemcom/ch7mon.c

@@ -76,7 +76,7 @@ ch7mon(oper, expp)
 					be used as register anymore
 				*/
 				if (def->df_sc == REGISTER) {
-					error("'&' on register variable not allowed");
+					error("& on register variable not allowed");
 					(*expp)->ex_type = error_type;
 					break;	/* break case '&' */
 				}
@@ -91,8 +91,9 @@ ch7mon(oper, expp)
 		int fund = (*expp)->ex_type->tp_fund;
 
 		if (fund == FLOAT || fund == DOUBLE)	{
-			error("~ not allowed on %s operands", symbol2str(fund));
-			*expp = intexpr((arith)1, INT);
+			error("~ not allowed on %s operands",
+						symbol2str(fund));
+			erroneous2int(expp);
 			break;
 		}
 	}

+ 11 - 3
lang/cem/cemcom/code.c

@@ -18,7 +18,7 @@
 #include	"em.h"
 #include	"level.h"
 #include	"decspecs.h"
-#include	"declar.h"
+#include	"declarator.h"
 #include	"Lpars.h"
 #include	"mes.h"
 #include	"LLlex.h"
@@ -227,6 +227,13 @@ end_proc(fbytes, nbytes)
 	C_end(ATW(nbytes));
 }
 
+do_return()
+{
+	/*	do_return generates a direct return */
+	/*	isn't a jump to the return label smarter ??? */
+	C_ret((arith)0);
+}
+
 do_return_expr(expr)
 	struct expr *expr;
 {
@@ -303,10 +310,11 @@ code_declaration(idf, expr, lvl, sc)
 				do_ival(&(def->df_type), expr);
 			else {	/* produce blank space */
 				if (size <= 0) {
-					error("size of \"%s\" unknown", text);
+					error("size of %s unknown", text);
 					size = (arith)0;
 				}
-				C_bss_cst(align(size, word_align), (arith)0, 1);
+				C_bss_cst(align(size, word_align),
+							(arith)0, 1);
 			}
 			break;
 		case EXTERN:

+ 2 - 2
lang/cem/cemcom/cstoper.c

@@ -34,7 +34,7 @@ cstbin(expp, oper, expr)
 		break;
 	case '/':
 		if (o2 == 0)	{
-			error("division by 0");
+			expr_error(expr, "division by 0");
 			break;
 		}
 		if (uns)	{
@@ -71,7 +71,7 @@ cstbin(expp, oper, expr)
 		break;
 	case '%':
 		if (o2 == 0)	{
-			error("modulo by 0");
+			expr_error(expr, "modulo by 0");
 			break;
 		}
 		if (uns)	{

+ 2 - 2
lang/cem/cemcom/eval.c

@@ -180,7 +180,7 @@ EVAL(expr, val, code, true_label, false_label)
 					C_sbi(tp->tp_size);
 				break;
 			case POINTER:
-				if (EXPRTYPE(rightop) == POINTER)
+				if (rightop->ex_type->tp_fund == POINTER)
 					C_sbs(pointer_size);
 				else	{
 					C_ngi(rightop->ex_type->tp_size);
@@ -645,7 +645,7 @@ EVAL(expr, val, code, true_label, false_label)
 				conversion(rightop->ex_type, leftop->ex_type);
 			break;
 		default:
-			crash("(EVAL) Bad operator %s\n", symbol2str(oper));
+			crash("(EVAL) bad operator %s\n", symbol2str(oper));
 		}
 
 		/*	If the rvalue of the expression is required but

+ 54 - 16
lang/cem/cemcom/expr.c

@@ -12,7 +12,7 @@
 #include	"LLlex.h"
 #include	"Lpars.h"
 #include	"decspecs.h"
-#include	"declar.h"
+#include	"declarator.h"
 #include	"storage.h"
 #include	"sizes.h"
 
@@ -212,21 +212,18 @@ intexpr(ivalue, fund)
 		the size indicated by fund.
 	*/
 	struct expr *expr = new_expr();
-
+	
 	clear((char *)expr, sizeof(struct expr));
 	expr->ex_file = dot.tk_file;
 	expr->ex_line = dot.tk_line;
-
+	
 	switch (fund) {
-
 	case INT:
 		expr->ex_type = int_type;
 		break;
-
 	case LONG:
 		expr->ex_type = long_type;
 		break;
-
 	case UNSIGNED:
 		/*	We cannot make a test like "ivalue <= max_unsigned"
 			because, if sizeof(long) == int_size holds, max_unsigned
@@ -237,17 +234,15 @@ intexpr(ivalue, fund)
 		expr->ex_type = 
 			(ivalue & ~max_unsigned) ? long_type : uint_type;
 		break;
-
 	case INTEGER:
 		expr->ex_type = (ivalue <= max_int) ? int_type : long_type;
 		break;
-
 	default:
 		crash("(intexpr) bad fund %s\n", symbol2str(fund));
 	}
 	expr->ex_class = Value;
 	expr->VL_VALUE = ivalue;
-
+	
 	cut_size(expr);
 	return expr;
 }
@@ -279,13 +274,26 @@ new_oper(tp, e1, oper, e2)
 	struct oper *op;
 
 	clear((char *)expr, sizeof(struct expr));
-	if (!e1 || !e2)	{
-		expr->ex_file = dot.tk_file;
-		expr->ex_line = dot.tk_line;
+	if (e2)	{
+		struct expr *e = e2;
+		
+		while (e->ex_class == Oper && e->OP_LEFT)
+			e = e->OP_LEFT;
+		expr->ex_file = e->ex_file;
+		expr->ex_line = e->ex_line;
+	}
+	else
+	if (e1)	{
+		struct expr *e = e1;
+		
+		while (e->ex_class == Oper && e->OP_RIGHT)
+			e = e->OP_RIGHT;
+		expr->ex_file = e->ex_file;
+		expr->ex_line = e->ex_line;
 	}
 	else	{
-		expr->ex_file = e2->ex_file;
-		expr->ex_line = e2->ex_line;
+		expr->ex_file = dot.tk_file;
+		expr->ex_line = dot.tk_line;
 	}
 	expr->ex_type = tp;
 	expr->ex_class = Oper;
@@ -333,7 +341,7 @@ chk_cst_expr(expp)
 		are cast, logical operators and the expression comma.
 		Special problems (of which there is only one, sizeof in
 		Preprocessor #if) have to be dealt with locally
-
+		
 		Note that according to K&R the negation ! is illegal in
 		constant expressions and is indeed rejected by the
 		Ritchie compiler.
@@ -369,7 +377,7 @@ chk_cst_expr(expp)
 	
 	if (err) {
 		free_expression(expr);
-		*expp = intexpr((arith)1, INT);
+		erroneous2int(expp);
 		(*expp)->ex_type = error_type;
 	}
 }
@@ -393,6 +401,36 @@ init_expression(eppp, expr)
 	*eppp = &(**eppp)->OP_RIGHT;
 }
 
+int
+is_ld_cst(expr)
+	register struct expr *expr;
+{
+	/*	An expression is a `load-time constant' if it is of the form
+		<idf> +/- <integral> or <integral>.
+	*/
+	return expr->ex_lvalue == 0 && expr->ex_class == Value;
+}
+
+int
+is_cp_cst(expr)
+	register struct expr *expr;
+{
+	/*	An expression is a `compile-time constant' if it is a
+		load-time constant, and the idf is not there.
+	*/
+	return is_ld_cst(expr) && expr->VL_IDF == 0;
+}
+
+int
+is_fp_cst(expr)
+	register struct expr *expr;
+{
+	/*	An expression is a `floating-point constant' if it consists
+		of the float only.
+	*/
+	return expr->ex_class == Float;
+}
+
 free_expression(expr)
 	struct expr *expr;
 {

+ 0 - 13
lang/cem/cemcom/expr.str

@@ -63,19 +63,6 @@ struct expr	{
 #define	OP_OPER		ex_object.ex_oper.op_oper
 #define	OP_RIGHT	ex_object.ex_oper.op_right
 
-#define	EXPRTYPE(e)	((e)->ex_type->tp_fund)
-
-/*	An expression is a `load-time constant' if it is of the form
-	<idf> +/- <integral> or <integral>;
-	it is a `compile-time constant' if it is an <integral>.
-*/
-#define	is_ld_cst(e)	((e)->ex_lvalue == 0 && (e)->ex_class == Value)
-#define	is_cp_cst(e)	(is_ld_cst(e) && (e)->VL_IDF == 0)
-
-/*	a floating constant expression ?
-*/
-#define	is_fp_cst(e)	((e)->ex_class == Float)
-
 /*	some bits for the ex_flag field, to keep track of various
 	interesting properties of an expression.
 */

+ 1 - 1
lang/cem/cemcom/expression.g

@@ -231,7 +231,7 @@ conditional_expression(struct expr **expp;)
 		{check_conditional(e2, '=', "after :");}
 		{
 			ch7bin(&e1, ':', e2);
-			opnd2test(expp, NOTEQUAL);
+			opnd2test(expp, '?');
 			ch7bin(expp, '?', e1);
 		}
 	]?

+ 2 - 2
lang/cem/cemcom/idf.c

@@ -16,7 +16,7 @@
 #include	"def.h"
 #include	"type.h"
 #include	"struct.h"
-#include	"declar.h"
+#include	"declarator.h"
 #include	"decspecs.h"
 #include	"sizes.h"
 #include	"Lpars.h"
@@ -333,7 +333,7 @@ declare_idf(ds, dc, lvl)
 			case REGISTER:
 			case AUTO:
 				if (type->tp_size == (arith)-1) {
-					error("size of local \"%s\" unknown",
+					error("size of local %s unknown",
 						idf->id_text);
 					type = idf->id_def->df_type = int_type;
 				}

+ 35 - 35
lang/cem/cemcom/ival.c

@@ -84,7 +84,8 @@ IVAL(tpp, expr)
 	register struct type *tp = *tpp;
 	
 	switch (tp->tp_fund) {
-	case ARRAY:	/* array initialisation	*/
+	case ARRAY:
+		/* array initialisation	*/
 		if (valid_type(tp->tp_up, "array element") == 0)
 			return 0;
 		if (ISCOMMA(expr))	{
@@ -96,10 +97,13 @@ IVAL(tpp, expr)
 		*/
 		if (tp->tp_up->tp_fund == CHAR && expr->ex_class == String)
 			init_string(tpp, expr);
-		else		/* " int i[24] = 12;"	*/
+		else	{
+			/* " int i[24] = 12;"	*/
 			check_and_pad(expr, tpp);
+		}
 		return 0;	/* nothing left	*/
-	case STRUCT:	/* struct initialisation */
+	case STRUCT:
+		/* struct initialisation */
 		if (valid_type(tp, "struct") == 0)
 			return 0;
 		if (ISCOMMA(expr))	{
@@ -109,13 +113,16 @@ IVAL(tpp, expr)
 		/* "struct foo f = 12;"	*/
 		check_and_pad(expr, tpp);
 		return 0;
-	case UNION:	/* sorry, but ....	*/
+	case UNION:
+		/* sorry, but ....	*/
 		error("union initialisation not allowed");
 		return 0;
 	case ERRONEOUS:
 		return 0;
-	default:	/* fundamental type	*/
-		if (ISCOMMA(expr)) {	/* " int i = {12};"	*/
+	default:
+		/* fundamental type	*/
+		if (ISCOMMA(expr))	{
+			/* " int i = {12};"	*/
 			if (IVAL(tpp, expr->OP_LEFT) != 0)
 				too_many_initialisers(expr);
 			/*	return remainings of the list for the
@@ -124,10 +131,9 @@ IVAL(tpp, expr)
 			*/
 			return expr->OP_RIGHT;
 		}
-		else {			/* "int i = 12;"	*/
-			check_ival(expr, tp);
-			return 0;
-		}
+		/* "int i = 12;"	*/
+		check_ival(expr, tp);
+		return 0;
 	}
 	/* NOTREACHED */
 }
@@ -149,15 +155,14 @@ do_array(expr, tpp)
 	struct expr *expr;
 	struct type **tpp;
 {
-	/* it is certain that ISCOMMA(expr) and tp->tp_fund == ARRAY	*/
 	register struct type *tp = *tpp;
 	register arith elem_count;
 	
-	ASSERT(tp->tp_fund == ARRAY);
+	ASSERT(tp->tp_fund == ARRAY && ISCOMMA(expr));
 	/*	the following test catches initialisations like
 		char c[] = {"just a string"};
 		or
-		char d[] = {{"just another string"}}
+		char d[] = {{"just another string"}};
 		The use of the brackets causes this problem.
 		Note: although the implementation of such initialisations
 		is completely foolish, we did it!! (no applause, thank you)
@@ -249,12 +254,11 @@ do_struct(expr, tp)
 	struct expr *expr;
 	struct type *tp;
 {
-	/* tp is a STRUCT and expr->OP_OPER == INITCOMMA	*/
-
 	struct sdef *sd = tp->tp_sdef;
 	arith bytes_upto_here = (arith)0;
 	arith last_offset = (arith)-1;
-
+	
+	ASSERT(tp->tp_fund == STRUCT && ISCOMMA(expr));
 	/* as long as there are selectors and there is an initialiser..	*/
 	while (sd && expr) {
 		if (ISCOMMA(expr->OP_LEFT)) {	/* embraced expression	*/
@@ -292,7 +296,8 @@ do_struct(expr, tp)
 			bytes_upto_here += zero_bytes(sd);
 		if (last_offset != sd->sd_offset) {
 			/* don't take the field-width more than once	*/
-			bytes_upto_here += size_of_type(sd->sd_type, "selector");
+			bytes_upto_here +=
+				size_of_type(sd->sd_type, "selector");
 			last_offset = sd->sd_offset;
 		}
 		sd = sd->sd_sdef;
@@ -308,7 +313,8 @@ do_struct(expr, tp)
 			if (sd->sd_sdef)
 				bytes_upto_here += zero_bytes(sd);
 			/* no field thrown-outs here	*/
-			bytes_upto_here += size_of_type(sd->sd_type, "selector");
+			bytes_upto_here +=
+				size_of_type(sd->sd_type, "selector");
 		} while (sd = sd->sd_sdef);
 	}
 	/* keep on aligning...	*/
@@ -440,8 +446,8 @@ check_ival(expr, type)
 {
 	/*	The philosophy here is that ch7cast puts an explicit
 		conversion node in front of the expression if the types
-		are not compatible.  In this case, the initialisation is
-		not legal. ???
+		are not compatible.  In this case, the initialisation
+		expression is no longer a constant.
 	*/
 	
 	switch (type->tp_fund) {
@@ -449,31 +455,24 @@ check_ival(expr, type)
 	case SHORT:
 	case INT:
 	case LONG:
-		if (expr->ex_class == Oper || expr->VL_IDF != 0)	{
+	case ENUM:
+		ch7cast(&expr, '=', type);
+		if (expr->ex_class != Value || expr->VL_IDF != 0)	{
 			illegal_init_cst(expr);
 			break;
 		}
-		ch7cast(&expr, '=', type);
 		con_int(expr);
 		break;
 #ifndef NOBITFIELD
 	case FIELD:
-		if (expr->ex_class == Oper || expr->VL_IDF != 0)	{
+		ch7cast(&expr, '=', type->tp_up);
+		if (expr->ex_class != Value || expr->VL_IDF != 0)	{
 			illegal_init_cst(expr);
 			break;
 		}
-		ch7cast(&expr, '=', type->tp_up);
 		put_bf(type, expr->VL_VALUE);
 		break;
 #endif NOBITFIELD
-	case ENUM:
-		if (expr->ex_class == Oper)	{
-			illegal_init_cst(expr);
-			break;
-		}
-		ch7cast(&expr, '=', type);
-		con_int(expr);
-		break;
 	case FLOAT:
 	case DOUBLE:
 		ch7cast(&expr, '=', type);
@@ -482,10 +481,11 @@ check_ival(expr, type)
 		else
 		if (expr->ex_class == Oper && expr->OP_OPER == INT2FLOAT) {
 			expr = expr->OP_RIGHT;
-			if (expr->ex_class == Value && expr->VL_IDF == 0)
-				C_con_fcon(itos(expr->VL_VALUE), type->tp_size);
-			else 
+			if (expr->ex_class != Value || expr->VL_IDF != 0)	{
 				illegal_init_cst(expr);
+				break;
+			}
+			C_con_fcon(itos(expr->VL_VALUE), type->tp_size);
 		}
 		else
 			illegal_init_cst(expr);

+ 29 - 31
lang/cem/cemcom/statement.g

@@ -108,20 +108,19 @@ if_statement
 	'('
 	expression(&expr)
 		{
-			opnd2test(&expr, NOTEQUAL);
-			if (expr->ex_class != Value)	{
-				/*	What's happening here? If the
-					expression consisted of a constant
-					expression, the comparison has
-					been optimized to a 0 or 1.
+			opnd2test(&expr, IF);
+			if (is_cp_cst(expr))	{
+				/*	The comparison has been optimized
+					to a 0 or 1.
 				*/
-				code_expr(expr, RVAL, TRUE, l_true, l_false);
-				C_df_ilb(l_true);
-			}
-			else	{
 				if (expr->VL_VALUE == (arith)0)	{
 					C_bra(l_false);
 				}
+				/* else fall through */
+			}
+			else	{
+				code_expr(expr, RVAL, TRUE, l_true, l_false);
+				C_df_ilb(l_true);
 			}
 			free_expression(expr);
 		}
@@ -159,16 +158,16 @@ while_statement
 	'('
 	expression(&expr)
 		{
-			opnd2test(&expr, NOTEQUAL);
-			if (expr->ex_class != Value)	{
-				code_expr(expr, RVAL, TRUE, l_body, l_break);
-				C_df_ilb(l_body);
-			}
-			else	{
+			opnd2test(&expr, WHILE);
+			if (is_cp_cst(expr))	{
 				if (expr->VL_VALUE == (arith)0)	{
 					C_bra(l_break);
 				}
 			}
+			else	{
+				code_expr(expr, RVAL, TRUE, l_body, l_break);
+				C_df_ilb(l_body);
+			}
 		}
 	')'
 	statement
@@ -198,15 +197,15 @@ do_statement
 		}
 	expression(&expr)
 		{
-			opnd2test(&expr, NOTEQUAL);
-			if (expr->ex_class != Value)	{
-				code_expr(expr, RVAL, TRUE, l_body, l_break);
-			}
-			else	{
+			opnd2test(&expr, WHILE);
+			if (is_cp_cst(expr))	{
 				if (expr->VL_VALUE == (arith)1)	{
 					C_bra(l_body);
 				}
 			}
+			else	{
+				code_expr(expr, RVAL, TRUE, l_body, l_break);
+			}
 			C_df_ilb(l_break);
 		}
 	')'
@@ -240,16 +239,16 @@ for_statement
 	[
 		expression(&e_test)
 		{
-			opnd2test(&e_test, NOTEQUAL);
-			if (e_test->ex_class != Value)	{
-				code_expr(e_test, RVAL, TRUE, l_body, l_break);
-				C_df_ilb(l_body);
-			}
-			else	{
+			opnd2test(&e_test, FOR);
+			if (is_cp_cst(e_test))	{
 				if (e_test->VL_VALUE == (arith)0)	{
 					C_bra(l_break);
 				}
 			}
+			else	{
+				code_expr(e_test, RVAL, TRUE, l_body, l_break);
+				C_df_ilb(l_body);
+			}
 		}
 	]?
 	';'
@@ -276,9 +275,8 @@ switch_statement
 :
 	SWITCH
 	'('
-	expression(&expr)	/* this must be an integer expression!	*/
+	expression(&expr)
 		{
-			ch7cast(&expr, CAST, int_type);
 			code_startswitch(expr);
 		}
 	')'
@@ -297,7 +295,7 @@ case_statement
 	CASE
 	constant_expression(&expr)
 		{
-			code_case(expr->VL_VALUE);
+			code_case(expr);
 			free_expression(expr);
 		}
 	':'
@@ -348,7 +346,7 @@ return_statement
 	|
 		empty
 		{
-			C_ret((arith)0);
+			do_return();
 		}
 	]
 	';'

+ 1 - 1
lang/cem/cemcom/struct.c

@@ -396,7 +396,7 @@ add_field(szp, fd, pfd_type, idf, stp)
 	case LONG:
 		/* right type; size OK? */
 		if ((*pfd_type)->tp_size > word_size) {
-			error("bit field type %s doesn't fit in word",
+			error("bit field type %s does not fit in a word",
 				symbol2str((*pfd_type)->tp_fund));
 			*pfd_type = error_type;
 			return field_offset;

+ 38 - 12
lang/cem/cemcom/switch.c

@@ -5,6 +5,7 @@
 #include	"botch_free.h"
 #include	"density.h"
 
+#include	"Lpars.h"
 #include	"idf.h"
 #include	"label.h"
 #include	"arith.h"
@@ -16,6 +17,8 @@
 #include	"type.h"
 #include	"em.h"
 
+extern char options[];
+
 #define	compact(nr, low, up)	(nr != 0 && (up - low) / nr <= (DENSITY - 1))
 
 static struct switch_hdr *switch_stack = 0;
@@ -23,19 +26,32 @@ static struct switch_hdr *switch_stack = 0;
 code_startswitch(expr)
 	struct expr *expr;
 {
-	/*	stack a new case header and fill in the necessary fields.
+	/*	Check the expression, stack a new case header and
+		fill in the necessary fields.
 	*/
 	register label l_table = text_label();
 	register label l_break = text_label();
 	register struct switch_hdr *sh = new_switch_hdr();
-
+	int fund = any2arith(&expr, SWITCH);	/* INT, LONG or DOUBLE */
+	
+	switch (fund)	{
+	case LONG:
+		if (options['R'])
+			warning("long in switch");
+		break;
+	case DOUBLE:
+		error("float/double in switch");
+		erroneous2int(&expr);
+		break;
+	}
+	
 	stat_stack(l_break, NO_LABEL);
 	sh->sh_break = l_break;
 	sh->sh_default = 0;
 	sh->sh_table = l_table;
 	sh->sh_nrofentries = 0;
 	sh->sh_type = expr->ex_type;	/* the expression switched	*/
-	sh->sh_lowerbd = sh->sh_upperbd = (arith)0;	/* ??? */
+	sh->sh_lowerbd = sh->sh_upperbd = (arith)0;	/* immaterial ??? */
 	sh->sh_entries = (struct case_entry *) 0; /* case-entry list	*/
 	sh->next = switch_stack;	/* push onto switch-stack	*/
 	switch_stack = sh;
@@ -48,7 +64,7 @@ code_endswitch()
 {
 	register struct switch_hdr *sh = switch_stack;
 	register label tablabel;
-	register struct case_entry *ce, *tmp;
+	register struct case_entry *ce;
 
 	if (sh->sh_default == 0)	/* no default occurred yet */
 		sh->sh_default = sh->sh_break;
@@ -88,33 +104,42 @@ code_endswitch()
 	}
 	C_df_ilb(sh->sh_break);
 	switch_stack = sh->next;	/* unstack the switch descriptor */
+	
 	/* free the allocated switch structure	*/
-	for (ce = sh->sh_entries; ce; ce = tmp)	{
-		tmp = ce->next;
+	ce = sh->sh_entries;
+	while (ce)	{
+		register struct case_entry *tmp = ce->next;
 		free_case_entry(ce);
+		ce = tmp;
 	}
 	free_switch_hdr(sh);
 	stat_unstack();
 }
 
-code_case(val)
-	arith val;
+code_case(expr)
+	struct expr *expr;
 {
+	register arith val;
 	register struct case_entry *ce;
 	register struct switch_hdr *sh = switch_stack;
-
+	
 	if (sh == 0)	{
 		error("case statement not in switch");
 		return;
 	}
+	
+	expr->ex_type = sh->sh_type;
+	cut_size(expr);
+	
 	ce = new_case_entry();
 	C_df_ilb(ce->ce_label = text_label());
-	ce->ce_value = val;
+	ce->ce_value = val = expr->VL_VALUE;
+	
 	if (sh->sh_entries == 0)	{
 		/* first case entry	*/
 		ce->next = (struct case_entry *) 0;
 		sh->sh_entries = ce;
-		sh->sh_lowerbd = sh->sh_upperbd = ce->ce_value;
+		sh->sh_lowerbd = sh->sh_upperbd = val;
 		sh->sh_nrofentries = 1;
 	}
 	else	{
@@ -138,7 +163,8 @@ code_case(val)
 				insert ce right after the head
 			3: c1 == 0 && c2 != 0:
 				append ce to last element
-			The case c1 == 0 && c2 == 0 cannot occur!
+			The case c1 == 0 && c2 == 0 cannot occur, since
+			the list is guaranteed not to be empty.
 		*/
 		if (c1)	{
 			if (c1->ce_value == ce->ce_value)	{