revised the treatment of "e op= f" expression

This commit is contained in:
erikb 1986-08-13 10:05:39 +00:00
parent 8217bef1eb
commit a7e97524e4
7 changed files with 106 additions and 92 deletions

View file

@ -75,6 +75,7 @@ statement.g
stb.c stb.c
storage.c storage.c
storage.h storage.h
stmt.str
struct.c struct.c
struct.str struct.str
switch.c switch.c

View file

@ -192,9 +192,6 @@ ch7cast(expp, oper, tp)
if ((*expp)->ex_class == String) if ((*expp)->ex_class == String)
string2pointer(expp); string2pointer(expp);
oldtp = (*expp)->ex_type; oldtp = (*expp)->ex_type;
if (oldtp == tp)
{} /* life is easy */
else
#ifndef NOBITFIELD #ifndef NOBITFIELD
if (oldtp->tp_fund == FIELD) { if (oldtp->tp_fund == FIELD) {
field2arith(expp); field2arith(expp);
@ -205,6 +202,9 @@ ch7cast(expp, oper, tp)
ch7cast(expp, oper, tp->tp_up); ch7cast(expp, oper, tp->tp_up);
else else
#endif NOBITFIELD #endif NOBITFIELD
if (oldtp == tp)
{} /* life is easy */
else
if (tp->tp_fund == VOID) /* Easy again */ if (tp->tp_fund == VOID) /* Easy again */
(*expp)->ex_type = void_type; (*expp)->ex_type = void_type;
else else
@ -311,6 +311,17 @@ ch7asgn(expp, oper, expr)
struct expr *expr; struct expr *expr;
{ {
/* The assignment operators. /* The assignment operators.
"f op= e" should be interpreted as
"f = (typeof f)((typeof (f op e))f op (typeof (f op e))e)"
and not as "f = f op (typeof f)e".
Consider, for example, (i == 10) i *= 0.9; (i == 9), where
typeof i == int.
The resulting expression tree becomes:
op=
/ \
/ \
f (typeof (f op e))e
EVAL should however take care of evaluating (typeof (f op e))f
*/ */
int fund = (*expp)->ex_type->tp_fund; int fund = (*expp)->ex_type->tp_fund;
@ -320,48 +331,30 @@ ch7asgn(expp, oper, expr)
(*expp)->ex_depth = 99; /* no direct store/load at EVAL() */ (*expp)->ex_depth = 99; /* no direct store/load at EVAL() */
/* what is 99 ??? DG */ /* what is 99 ??? DG */
} }
switch (oper) { if (oper == '=') {
case '=':
ch7cast(&expr, oper, (*expp)->ex_type); ch7cast(&expr, oper, (*expp)->ex_type);
break; }
case TIMESAB: else { /* turn e into e' where typeof(e') = typeof (f op e) */
case DIVAB: struct expr *extmp = intexpr(0, INT);
case MODAB:
check_arith_type(expp, oper); /* this is really $#@&*%$# ! */
any2arith(&expr, oper); extmp->ex_lvalue = 1;
ch7cast(&expr, CAST, (*expp)->ex_type); extmp->ex_type = (*expp)->ex_type;
break; ch7bin(&extmp, oper, expr);
case PLUSAB: /* note that ch7bin creates a tree of the expression
case MINAB: ((typeof (f op e))f op (typeof (f op e))e),
any2arith(&expr, oper); where f ~ extmp and e ~ expr;
if (fund == POINTER) { we have to use (typeof (f op e))e
check_integral_type(&expr, oper); Ch7bin does not create a tree if both operands
ch7bin(&expr, '*', were illegal or constants!
intexpr( */
size_of_type( if (extmp->ex_class == Oper) {
(*expp)->ex_type->tp_up, expr = extmp->OP_RIGHT;
"object" extmp->OP_RIGHT = NILEXPR;
), free_expression(extmp);
pa_type->tp_fund
)
);
} }
else { else
check_arith_type(expp, oper); expr = extmp;
ch7cast(&expr, CAST, (*expp)->ex_type);
}
break;
case LEFTAB:
case RIGHTAB:
check_integral_type(expp, oper);
ch7cast(&expr, oper, int_type);
break;
case ANDAB:
case XORAB:
case ORAB:
check_integral_type(expp, oper);
ch7cast(&expr, oper, (*expp)->ex_type);
break;
} }
#ifndef NOBITFIELD #ifndef NOBITFIELD
if (fund == FIELD) if (fund == FIELD)
@ -369,6 +362,7 @@ ch7asgn(expp, oper, expr)
else else
#endif NOBITFIELD #endif NOBITFIELD
*expp = new_oper((*expp)->ex_type, *expp, oper, expr); *expp = new_oper((*expp)->ex_type, *expp, oper, expr);
(*expp)->OP_TYPE = expr->ex_type; /* for EVAL() */
} }
/* Some interesting (?) questions answered. /* Some interesting (?) questions answered.
@ -393,18 +387,6 @@ is_integral_type(tp)
} }
} }
check_integral_type(expp, oper)
struct expr **expp;
{
register struct expr *expr = *expp;
if (!is_integral_type(expr->ex_type)) {
expr_error(expr, "%s on non-integral type (%s)",
symbol2str(oper), symbol2str(expr->ex_type->tp_fund));
erroneous2int(expp);
}
}
int int
is_arith_type(tp) is_arith_type(tp)
struct type *tp; struct type *tp;
@ -426,15 +408,3 @@ is_arith_type(tp)
return 0; return 0;
} }
} }
check_arith_type(expp, oper)
struct expr **expp;
{
register struct expr *expr = *expp;
if (!is_arith_type(expr->ex_type)) {
expr_error(expr, "%s on non-arithmetical type (%s)",
symbol2str(oper), symbol2str(expr->ex_type->tp_fund));
erroneous2int(expp);
}
}

View file

@ -24,6 +24,7 @@ ch7bin(expp, oper, expr)
struct expr *expr; struct expr *expr;
{ {
/* apply binary operator oper between *expp and expr. /* apply binary operator oper between *expp and expr.
NB: don't swap operands if op is one of the op= operators!!!
*/ */
any2opnd(expp, oper); any2opnd(expp, oper);
any2opnd(&expr, oper); any2opnd(&expr, oper);
@ -79,15 +80,24 @@ ch7bin(expp, oper, expr)
*expp = new_oper(expr->ex_type, *expp, PARCOMMA, expr); *expp = new_oper(expr->ex_type, *expp, PARCOMMA, expr);
break; break;
case '%': case '%':
case MODAB:
/*** NB "not float" means "integral" !!!
fund = arithbalance(expp, oper, &expr); fund = arithbalance(expp, oper, &expr);
if (fund == DOUBLE) { if (fund == DOUBLE) {
expr_error(*expp, "floating operand to %%"); expr_error(*expp, "floating operand to %s",
symbol2str(oper));
erroneous2int(expp); erroneous2int(expp);
} }
else else
non_commutative_binop(expp, oper, expr); non_commutative_binop(expp, oper, expr);
***/
opnd2integral(expp, oper);
opnd2integral(&expr, oper);
fund = arithbalance(expp, oper, &expr);
non_commutative_binop(expp, oper, expr);
break; break;
case '/': case '/':
case DIVAB:
fund = arithbalance(expp, oper, &expr); fund = arithbalance(expp, oper, &expr);
non_commutative_binop(expp, oper, expr); non_commutative_binop(expp, oper, expr);
break; break;
@ -95,6 +105,10 @@ ch7bin(expp, oper, expr)
fund = arithbalance(expp, oper, &expr); fund = arithbalance(expp, oper, &expr);
commutative_binop(expp, oper, expr); commutative_binop(expp, oper, expr);
break; break;
case TIMESAB:
fund = arithbalance(expp, oper, &expr);
non_commutative_binop(expp, oper, expr);
break;
case '+': case '+':
if (expr->ex_type->tp_fund == POINTER) { if (expr->ex_type->tp_fund == POINTER) {
/* swap operands */ /* swap operands */
@ -102,6 +116,8 @@ ch7bin(expp, oper, expr)
expr = *expp; expr = *expp;
*expp = etmp; *expp = etmp;
} }
/*FALLTHROUGH*/
case PLUSAB:
if ((*expp)->ex_type->tp_fund == POINTER) { if ((*expp)->ex_type->tp_fund == POINTER) {
pointer_arithmetic(expp, oper, &expr); pointer_arithmetic(expp, oper, &expr);
if ( expr->ex_type->tp_size != if ( expr->ex_type->tp_size !=
@ -113,10 +129,14 @@ ch7bin(expp, oper, expr)
} }
else { else {
fund = arithbalance(expp, oper, &expr); fund = arithbalance(expp, oper, &expr);
commutative_binop(expp, oper, expr); if (oper == '+')
commutative_binop(expp, oper, expr);
else
non_commutative_binop(expp, oper, expr);
} }
break; break;
case '-': case '-':
case MINAB:
if ((*expp)->ex_type->tp_fund == POINTER) { if ((*expp)->ex_type->tp_fund == POINTER) {
if (expr->ex_type->tp_fund == POINTER) if (expr->ex_type->tp_fund == POINTER)
pntminuspnt(expp, oper, expr); pntminuspnt(expp, oper, expr);
@ -131,7 +151,9 @@ ch7bin(expp, oper, expr)
} }
break; break;
case LEFT: case LEFT:
case LEFTAB:
case RIGHT: case RIGHT:
case RIGHTAB:
opnd2integral(expp, oper); opnd2integral(expp, oper);
opnd2integral(&expr, oper); opnd2integral(&expr, oper);
ch7cast(&expr, oper, int_type); /* leftop should be int */ ch7cast(&expr, oper, int_type); /* leftop should be int */
@ -152,9 +174,17 @@ ch7bin(expp, oper, expr)
case '|': case '|':
opnd2integral(expp, oper); opnd2integral(expp, oper);
opnd2integral(&expr, oper); opnd2integral(&expr, oper);
fund = arithbalance(expp, oper, &expr); /* <=== */ fund = arithbalance(expp, oper, &expr);
commutative_binop(expp, oper, expr); commutative_binop(expp, oper, expr);
break; break;
case ANDAB:
case XORAB:
case ORAB:
opnd2integral(expp, oper);
opnd2integral(&expr, oper);
fund = arithbalance(expp, oper, &expr);
non_commutative_binop(expp, oper, expr);
break;
case AND: case AND:
case OR: case OR:
opnd2test(expp, oper); opnd2test(expp, oper);

View file

@ -115,6 +115,7 @@ fundamental(tp)
case CHAR: case CHAR:
case SHORT: case SHORT:
case INT: case INT:
case ERRONEOUS:
case LONG: case LONG:
case ENUM: case ENUM:
return tp->tp_unsigned ? T_UNSIGNED : T_SIGNED; return tp->tp_unsigned ? T_UNSIGNED : T_SIGNED;

View file

@ -271,9 +271,10 @@ type2str(tp)
if (tp->tp_field) { if (tp->tp_field) {
struct field *fd = tp->tp_field; struct field *fd = tp->tp_field;
sprint(buf, "%s [s=%ld,w=%ld]", buf, sprint(buf, "%s [s=%ld,w=%ld] of ", buf,
fd->fd_shift, fd->fd_width); fd->fd_shift, fd->fd_width);
} }
else
#endif NOBITFIELD #endif NOBITFIELD
ops = 0; ops = 0;
break; break;
@ -367,7 +368,10 @@ p1_expr(lvl, expr)
o = &expr->ex_object.ex_oper; o = &expr->ex_object.ex_oper;
print("\n"); print("\n");
p1_expr(lvl+1, o->op_left); p1_expr(lvl+1, o->op_left);
p1_indent(lvl); print("%s\n", symbol2str(o->op_oper)); p1_indent(lvl);
print("%s <%s>\n", symbol2str(o->op_oper),
type2str(o->op_type)
);
p1_expr(lvl+1, o->op_right); p1_expr(lvl+1, o->op_right);
break; break;
case Type: case Type:

View file

@ -389,27 +389,33 @@ EVAL(expr, val, code, true_label, false_label)
C_sti(pointer_size); C_sti(pointer_size);
C_lal(tmpvar); C_lal(tmpvar);
C_loi(pointer_size); C_loi(pointer_size);
C_loi(tp->tp_size); C_loi(leftop->ex_type->tp_size);
conversion(leftop->ex_type, tp);
EVAL(rightop, RVAL, TRUE, NO_LABEL, NO_LABEL); EVAL(rightop, RVAL, TRUE, NO_LABEL, NO_LABEL);
assop(tp, oper); assop(tp, oper);
conversion(tp, leftop->ex_type);
if (gencode) if (gencode)
C_dup(roundup(tp->tp_size)); C_dup(roundup(leftop->ex_type->tp_size));
C_lal(tmpvar); C_lal(tmpvar);
C_loi(pointer_size); C_loi(pointer_size);
C_sti(tp->tp_size); C_sti(leftop->ex_type->tp_size);
free_tmp_var(old_offset); free_tmp_var(old_offset);
} }
else { else {
load_val(leftop, RVAL); load_val(leftop, RVAL);
conversion(leftop->ex_type, tp);
EVAL(rightop, RVAL, TRUE, NO_LABEL, NO_LABEL); EVAL(rightop, RVAL, TRUE, NO_LABEL, NO_LABEL);
assop(tp, oper); assop(tp, oper);
conversion(tp, leftop->ex_type);
if (gencode) if (gencode)
C_dup(roundup(tp->tp_size)); C_dup(roundup(leftop->ex_type->tp_size));
store_val( store_val(
&(leftop->ex_object.ex_value), &(leftop->ex_object.ex_value),
leftop->ex_type leftop->ex_type
); );
} }
if (gencode)
conversion(leftop->ex_type, expr->ex_type);
break; break;
case '(': case '(':
{ {

View file

@ -40,13 +40,16 @@ eval_field(expr, code)
struct type *tp = leftop->ex_type->tp_up; struct type *tp = leftop->ex_type->tp_up;
arith old_offset, tmpvar; arith old_offset, tmpvar;
/* The type in which the bitfield arithmetic is done: /* The type in which the bitfield arithmetic is done;
AND IN WHICH BITFIELDS ARE STORED!
*/ */
struct type *atype = tp->tp_unsigned ? uword_type : word_type; struct type *atype = tp->tp_unsigned ? uword_type : word_type;
arith asize = atype->tp_size; arith asize = atype->tp_size;
ASSERT(leftop->ex_type->tp_fund == FIELD); /* First some assertions to be sure that the rest is legal */
ASSERT(asize == word_size); /* make sure that C_loc() is legal */ ASSERT(asize == word_size); /* make sure that C_loc() is legal */
ASSERT(leftop->ex_type->tp_fund == FIELD);
leftop->ex_type = atype; /* this is cheating but it works... */ leftop->ex_type = atype; /* this is cheating but it works... */
/* Note that op is either an assignment operator or an increment/ /* Note that op is either an assignment operator or an increment/
@ -55,6 +58,8 @@ eval_field(expr, code)
if (op == '=') { if (op == '=') {
/* F = E: f = ((E & mask)<<shift) | (~(mask<<shift) & f) /* F = E: f = ((E & mask)<<shift) | (~(mask<<shift) & f)
*/ */
ASSERT(tp == rightop->ex_type);
EVAL(rightop, RVAL, TRUE, NO_LABEL, NO_LABEL); EVAL(rightop, RVAL, TRUE, NO_LABEL, NO_LABEL);
conversion(tp, atype); conversion(tp, atype);
C_loc(fd->fd_mask); C_loc(fd->fd_mask);
@ -71,10 +76,7 @@ eval_field(expr, code)
load_val(leftop, RVAL); load_val(leftop, RVAL);
C_and(asize); C_and(asize);
C_ior(asize); C_ior(asize);
store_val( store_val(&(leftop->ex_object.ex_value), atype);
&(leftop->ex_object.ex_value),
leftop->ex_type
);
} }
else { /* complex case */ else { /* complex case */
tmpvar = tmp_pointer_var(&old_offset); tmpvar = tmp_pointer_var(&old_offset);
@ -114,16 +116,19 @@ eval_field(expr, code)
C_and(asize); C_and(asize);
if (code == TRUE && (op == POSTINCR || op == POSTDECR)) if (code == TRUE && (op == POSTINCR || op == POSTDECR))
C_dup(asize); C_dup(asize);
/* the 'op' operation: */
conversion(atype, rightop->ex_type);
EVAL(rightop, RVAL, TRUE, NO_LABEL, NO_LABEL); EVAL(rightop, RVAL, TRUE, NO_LABEL, NO_LABEL);
conversion(tp, atype);
/* generate code for the operator */
if (op == PLUSPLUS || op == POSTINCR) if (op == PLUSPLUS || op == POSTINCR)
assop(atype, PLUSAB); assop(rightop->ex_type, PLUSAB);
else else
if (op == MINMIN || op == POSTDECR) if (op == MINMIN || op == POSTDECR)
assop(atype, MINAB); assop(rightop->ex_type, MINAB);
else else
assop(atype, op); assop(rightop->ex_type, op);
conversion(rightop->ex_type, atype);
C_loc(fd->fd_mask); C_loc(fd->fd_mask);
C_and(asize); C_and(asize);
if (code == TRUE && op != POSTINCR && op != POSTDECR) if (code == TRUE && op != POSTINCR && op != POSTDECR)
@ -138,10 +143,7 @@ eval_field(expr, code)
load_val(leftop, RVAL); load_val(leftop, RVAL);
C_and(asize); C_and(asize);
C_ior(asize); C_ior(asize);
store_val( store_val(&(leftop->ex_object.ex_value), atype);
&(leftop->ex_object.ex_value),
leftop->ex_type
);
} }
else { else {
C_lal(tmpvar); C_lal(tmpvar);
@ -168,7 +170,7 @@ eval_field(expr, code)
C_loc(shift); C_loc(shift);
C_sri(asize); C_sri(asize);
} }
conversion(atype, tp); conversion(atype, expr->ex_type);
} }
} }
#endif NOBITFIELD #endif NOBITFIELD