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;
*/
fp_used = 1;
- if ((*expp)->ex_class == Float) {
+ if (is_fp_cst(*expp)) {
(*expp)->ex_type = tp;
}
else {
if (fund != ERRONEOUS)
error("%s operand to %s",
symbol2str(fund), symbol2str(oper));
- *expp = intexpr((arith)1, INT);
+ erroneous2int(expp);
/* fund = INT; */
}
}
error("%s operand to %s",
symbol2str(fund), symbol2str(oper));
case ERRONEOUS:
- *expp = intexpr((arith)1, INT);
+ erroneous2int(expp);
break;
}
}
#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();
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",
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);
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
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"),
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 '&' */
}
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;
}
}
#include "em.h"
#include "level.h"
#include "decspecs.h"
-#include "declar.h"
+#include "declarator.h"
#include "Lpars.h"
#include "mes.h"
#include "LLlex.h"
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;
{
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:
break;
case '/':
if (o2 == 0) {
- error("division by 0");
+ expr_error(expr, "division by 0");
break;
}
if (uns) {
break;
case '%':
if (o2 == 0) {
- error("modulo by 0");
+ expr_error(expr, "modulo by 0");
break;
}
if (uns) {
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);
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
#include "LLlex.h"
#include "Lpars.h"
#include "decspecs.h"
-#include "declar.h"
+#include "declarator.h"
#include "storage.h"
#include "sizes.h"
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
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;
}
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;
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.
if (err) {
free_expression(expr);
- *expp = intexpr((arith)1, INT);
+ erroneous2int(expp);
(*expp)->ex_type = error_type;
}
}
*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;
{
#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.
*/
{check_conditional(e2, '=', "after :");}
{
ch7bin(&e1, ':', e2);
- opnd2test(expp, NOTEQUAL);
+ opnd2test(expp, '?');
ch7bin(expp, '?', e1);
}
]?
#include "def.h"
#include "type.h"
#include "struct.h"
-#include "declar.h"
+#include "declarator.h"
#include "decspecs.h"
#include "sizes.h"
#include "Lpars.h"
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;
}
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)) {
*/
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)) {
/* "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
*/
return expr->OP_RIGHT;
}
- else { /* "int i = 12;" */
- check_ival(expr, tp);
- return 0;
- }
+ /* "int i = 12;" */
+ check_ival(expr, tp);
+ return 0;
}
/* NOTREACHED */
}
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)
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 */
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;
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... */
{
/* 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) {
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);
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);
'('
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);
}
'('
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
}
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);
}
')'
[
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);
+ }
}
]?
';'
:
SWITCH
'('
- expression(&expr) /* this must be an integer expression! */
+ expression(&expr)
{
- ch7cast(&expr, CAST, int_type);
code_startswitch(expr);
}
')'
CASE
constant_expression(&expr)
{
- code_case(expr->VL_VALUE);
+ code_case(expr);
free_expression(expr);
}
':'
|
empty
{
- C_ret((arith)0);
+ do_return();
}
]
';'
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;
#include "botch_free.h"
#include "density.h"
+#include "Lpars.h"
#include "idf.h"
#include "label.h"
#include "arith.h"
#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;
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;
{
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;
}
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 {
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) {