improved error reporting for initialization expressions
authordick <none@none>
Fri, 14 Mar 1986 16:15:16 +0000 (16:15 +0000)
committerdick <none@none>
Fri, 14 Mar 1986 16:15:16 +0000 (16:15 +0000)
miscellaneous changes

15 files changed:
lang/cem/cemcom/arith.c
lang/cem/cemcom/ch7.c
lang/cem/cemcom/ch7bin.c
lang/cem/cemcom/ch7mon.c
lang/cem/cemcom/code.c
lang/cem/cemcom/cstoper.c
lang/cem/cemcom/eval.c
lang/cem/cemcom/expr.c
lang/cem/cemcom/expr.str
lang/cem/cemcom/expression.g
lang/cem/cemcom/idf.c
lang/cem/cemcom/ival.c
lang/cem/cemcom/statement.g
lang/cem/cemcom/struct.c
lang/cem/cemcom/switch.c

index 04f843a..3b780bc 100644 (file)
@@ -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;
        }
 }
index 38fcbc2..2a6d564 100644 (file)
 #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",
index ee30b03..469a01e 100644 (file)
@@ -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"),
index 061db81..3c25f37 100644 (file)
@@ -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;
                }
        }
index 788e4db..1d0df57 100644 (file)
@@ -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:
index 414e18d..9b4e09e 100644 (file)
@@ -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)        {
index d3e38a5..094cf62 100644 (file)
@@ -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
index 72c43ef..1276068 100644 (file)
@@ -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;
 {
index 87f6114..b322e89 100644 (file)
@@ -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.
 */
index 94976c6..9d9a4fd 100644 (file)
@@ -231,7 +231,7 @@ conditional_expression(struct expr **expp;)
                {check_conditional(e2, '=', "after :");}
                {
                        ch7bin(&e1, ':', e2);
-                       opnd2test(expp, NOTEQUAL);
+                       opnd2test(expp, '?');
                        ch7bin(expp, '?', e1);
                }
        ]?
index 9739c8a..1486876 100644 (file)
@@ -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;
                                }
index baf2b5e..3a5efa3 100644 (file)
@@ -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);
index e35ac98..af12742 100644 (file)
@@ -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();
                }
        ]
        ';'
index 752bcdf..6b19458 100644 (file)
@@ -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;
index 8a695de..ba0c745 100644 (file)
@@ -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)       {