improved error reporting for initialization expressions

miscellaneous changes
This commit is contained in:
dick 1986-03-14 16:15:16 +00:00
parent 6e53274b6a
commit c80f2c0817
15 changed files with 197 additions and 136 deletions

View file

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

View file

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

View file

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

View file

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

View file

@ -18,7 +18,7 @@
#include "em.h" #include "em.h"
#include "level.h" #include "level.h"
#include "decspecs.h" #include "decspecs.h"
#include "declar.h" #include "declarator.h"
#include "Lpars.h" #include "Lpars.h"
#include "mes.h" #include "mes.h"
#include "LLlex.h" #include "LLlex.h"
@ -227,6 +227,13 @@ end_proc(fbytes, nbytes)
C_end(ATW(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) do_return_expr(expr)
struct expr *expr; struct expr *expr;
{ {
@ -303,10 +310,11 @@ code_declaration(idf, expr, lvl, sc)
do_ival(&(def->df_type), expr); do_ival(&(def->df_type), expr);
else { /* produce blank space */ else { /* produce blank space */
if (size <= 0) { if (size <= 0) {
error("size of \"%s\" unknown", text); error("size of %s unknown", text);
size = (arith)0; size = (arith)0;
} }
C_bss_cst(align(size, word_align), (arith)0, 1); C_bss_cst(align(size, word_align),
(arith)0, 1);
} }
break; break;
case EXTERN: case EXTERN:

View file

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

View file

@ -180,7 +180,7 @@ EVAL(expr, val, code, true_label, false_label)
C_sbi(tp->tp_size); C_sbi(tp->tp_size);
break; break;
case POINTER: case POINTER:
if (EXPRTYPE(rightop) == POINTER) if (rightop->ex_type->tp_fund == POINTER)
C_sbs(pointer_size); C_sbs(pointer_size);
else { else {
C_ngi(rightop->ex_type->tp_size); 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); conversion(rightop->ex_type, leftop->ex_type);
break; break;
default: 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 /* If the rvalue of the expression is required but

View file

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

View file

@ -63,19 +63,6 @@ struct expr {
#define OP_OPER ex_object.ex_oper.op_oper #define OP_OPER ex_object.ex_oper.op_oper
#define OP_RIGHT ex_object.ex_oper.op_right #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 /* some bits for the ex_flag field, to keep track of various
interesting properties of an expression. interesting properties of an expression.
*/ */

View file

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

View file

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

View file

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

View file

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

View file

@ -396,7 +396,7 @@ add_field(szp, fd, pfd_type, idf, stp)
case LONG: case LONG:
/* right type; size OK? */ /* right type; size OK? */
if ((*pfd_type)->tp_size > word_size) { 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)); symbol2str((*pfd_type)->tp_fund));
*pfd_type = error_type; *pfd_type = error_type;
return field_offset; return field_offset;

View file

@ -5,6 +5,7 @@
#include "botch_free.h" #include "botch_free.h"
#include "density.h" #include "density.h"
#include "Lpars.h"
#include "idf.h" #include "idf.h"
#include "label.h" #include "label.h"
#include "arith.h" #include "arith.h"
@ -16,6 +17,8 @@
#include "type.h" #include "type.h"
#include "em.h" #include "em.h"
extern char options[];
#define compact(nr, low, up) (nr != 0 && (up - low) / nr <= (DENSITY - 1)) #define compact(nr, low, up) (nr != 0 && (up - low) / nr <= (DENSITY - 1))
static struct switch_hdr *switch_stack = 0; static struct switch_hdr *switch_stack = 0;
@ -23,19 +26,32 @@ static struct switch_hdr *switch_stack = 0;
code_startswitch(expr) code_startswitch(expr)
struct expr *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_table = text_label();
register label l_break = text_label(); register label l_break = text_label();
register struct switch_hdr *sh = new_switch_hdr(); 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); stat_stack(l_break, NO_LABEL);
sh->sh_break = l_break; sh->sh_break = l_break;
sh->sh_default = 0; sh->sh_default = 0;
sh->sh_table = l_table; sh->sh_table = l_table;
sh->sh_nrofentries = 0; sh->sh_nrofentries = 0;
sh->sh_type = expr->ex_type; /* the expression switched */ 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->sh_entries = (struct case_entry *) 0; /* case-entry list */
sh->next = switch_stack; /* push onto switch-stack */ sh->next = switch_stack; /* push onto switch-stack */
switch_stack = sh; switch_stack = sh;
@ -48,7 +64,7 @@ code_endswitch()
{ {
register struct switch_hdr *sh = switch_stack; register struct switch_hdr *sh = switch_stack;
register label tablabel; register label tablabel;
register struct case_entry *ce, *tmp; register struct case_entry *ce;
if (sh->sh_default == 0) /* no default occurred yet */ if (sh->sh_default == 0) /* no default occurred yet */
sh->sh_default = sh->sh_break; sh->sh_default = sh->sh_break;
@ -88,33 +104,42 @@ code_endswitch()
} }
C_df_ilb(sh->sh_break); C_df_ilb(sh->sh_break);
switch_stack = sh->next; /* unstack the switch descriptor */ switch_stack = sh->next; /* unstack the switch descriptor */
/* free the allocated switch structure */ /* free the allocated switch structure */
for (ce = sh->sh_entries; ce; ce = tmp) { ce = sh->sh_entries;
tmp = ce->next; while (ce) {
register struct case_entry *tmp = ce->next;
free_case_entry(ce); free_case_entry(ce);
ce = tmp;
} }
free_switch_hdr(sh); free_switch_hdr(sh);
stat_unstack(); stat_unstack();
} }
code_case(val) code_case(expr)
arith val; struct expr *expr;
{ {
register arith val;
register struct case_entry *ce; register struct case_entry *ce;
register struct switch_hdr *sh = switch_stack; register struct switch_hdr *sh = switch_stack;
if (sh == 0) { if (sh == 0) {
error("case statement not in switch"); error("case statement not in switch");
return; return;
} }
expr->ex_type = sh->sh_type;
cut_size(expr);
ce = new_case_entry(); ce = new_case_entry();
C_df_ilb(ce->ce_label = text_label()); C_df_ilb(ce->ce_label = text_label());
ce->ce_value = val; ce->ce_value = val = expr->VL_VALUE;
if (sh->sh_entries == 0) { if (sh->sh_entries == 0) {
/* first case entry */ /* first case entry */
ce->next = (struct case_entry *) 0; ce->next = (struct case_entry *) 0;
sh->sh_entries = ce; sh->sh_entries = ce;
sh->sh_lowerbd = sh->sh_upperbd = ce->ce_value; sh->sh_lowerbd = sh->sh_upperbd = val;
sh->sh_nrofentries = 1; sh->sh_nrofentries = 1;
} }
else { else {
@ -138,7 +163,8 @@ code_case(val)
insert ce right after the head insert ce right after the head
3: c1 == 0 && c2 != 0: 3: c1 == 0 && c2 != 0:
append ce to last element 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) {
if (c1->ce_value == ce->ce_value) { if (c1->ce_value == ce->ce_value) {