ack/lang/cem/cemcom/arith.c

494 lines
9.8 KiB
C
Raw Normal View History

1986-03-10 13:07:55 +00:00
/* $Header$ */
/* A R I T H M E T I C C O N V E R S I O N S */
/* This file contains the routines for the various conversions that
may befall operands in C. It is structurally a mess, but I haven't
decided yet whether I can't find the right structure or the
semantics of C is a mess.
*/
#include "botch_free.h"
#include "nobitfield.h"
#include "alloc.h"
#include "idf.h"
#include "arith.h"
#include "type.h"
#include "label.h"
#include "expr.h"
#include "Lpars.h"
#include "storage.h"
#include "field.h"
#include "mes.h"
extern char *symbol2str();
extern char options[];
int
arithbalance(e1p, oper, e2p) /* RM 6.6 */
struct expr **e1p, **e2p;
{
/* The expressions *e1p and *e2p are balanced to be operands
of the arithmetic operator oper.
*/
register int t1, t2, u1, u2;
t1 = any2arith(e1p, oper);
t2 = any2arith(e2p, oper);
/* Now t1 and t2 are either INT or LONG or DOUBLE */
if (t1 == DOUBLE && t2 != DOUBLE)
t2 = int2float(e2p, double_type);
else
if (t2 == DOUBLE && t1 != DOUBLE)
t1 = int2float(e1p, double_type);
else
if (t1 == DOUBLE)
return DOUBLE;
/* Now they are INT or LONG */
u1 = (*e1p)->ex_type->tp_unsigned;
u2 = (*e2p)->ex_type->tp_unsigned;
/* if either is long, the other will be */
if (t1 == LONG && t2 != LONG)
t2 = int2int(e2p, u2 ? ulong_type : long_type);
else
if (t2 == LONG && t1 != LONG)
t1 = int2int(e1p, u1 ? ulong_type : long_type);
/* if either is unsigned, the other will be */
if (u1 && !u2)
t2 = int2int(e2p, (t1 == LONG) ? ulong_type : uint_type);
else
if (!u1 && u2)
t1 = int2int(e1p, (t2 == LONG) ? ulong_type : uint_type);
return t1;
}
relbalance(e1p, oper, e2p)
register struct expr **e1p, **e2p;
{
/* The expressions *e1p and *e2p are balanced to be operands
of the relational operator oper.
*/
if ((*e1p)->ex_type->tp_fund == FUNCTION)
function2pointer(e1p);
if ((*e2p)->ex_type->tp_fund == FUNCTION)
function2pointer(e2p);
if ((*e1p)->ex_type->tp_fund == POINTER)
ch76pointer(e2p, oper, (*e1p)->ex_type);
else
if ((*e2p)->ex_type->tp_fund == POINTER)
ch76pointer(e1p, oper, (*e2p)->ex_type);
else
if ( (*e1p)->ex_type == (*e2p)->ex_type &&
(*e1p)->ex_type->tp_fund == ENUM
)
{}
else
arithbalance(e1p, oper, e2p);
}
ch76pointer(expp, oper, tp)
register struct expr **expp;
register struct type *tp;
{
/* Checks whether *expp may be compared to tp using oper,
as described in chapter 7.6 and 7.7.
tp is known to be a pointer.
*/
if ((*expp)->ex_type->tp_fund == POINTER) {
if ((*expp)->ex_type != tp)
ch7cast(expp, oper, tp);
}
else
if ( is_integral_type((*expp)->ex_type) &&
( !options['R'] /* we don't care */ ||
(oper == EQUAL || oper == NOTEQUAL || oper == ':')
)
) /* ch 7.7 */
ch7cast(expp, CAST, tp);
else {
expr_error(*expp, "%s on %s and pointer",
1986-03-10 13:07:55 +00:00
symbol2str(oper),
symbol2str((*expp)->ex_type->tp_fund)
);
ch7cast(expp, oper, tp);
}
}
int
any2arith(expp, oper)
register struct expr **expp;
{
/* Turns any expression into int_type, long_type or
double_type.
*/
int fund = (*expp)->ex_type->tp_fund;
switch (fund) {
case CHAR:
case SHORT:
int2int(expp,
(*expp)->ex_type->tp_unsigned ? uint_type : int_type);
break;
case INT:
case LONG:
break;
case ENUM:
if ( is_test_op(oper) || oper == '=' || oper == PARCOMMA ||
oper == ',' || oper == ':' ||
( !options['R'] &&
(is_arith_op(oper) || is_asgn_op(oper))
)
)
{}
else
expr_warning(*expp, "%s on enum", symbol2str(oper));
1986-03-10 13:07:55 +00:00
int2int(expp, int_type);
break;
case FLOAT:
float2float(expp, double_type);
break;
case DOUBLE:
break;
#ifndef NOBITFIELD
case FIELD:
field2arith(expp);
break;
#endif NOBITFIELD
default:
expr_error(*expp, "operator %s on non-numerical operand (%s)",
1986-03-10 13:07:55 +00:00
symbol2str(oper), symbol2str(fund));
case ERRONEOUS:
erroneous2int(expp);
1986-03-10 13:07:55 +00:00
break;
}
return (*expp)->ex_type->tp_fund;
}
erroneous2int(expp)
struct expr **expp;
{
/* the (erroneous) expression *expp is replaced by an
int expression
*/
int flags = (*expp)->ex_flags;
free_expression(*expp);
*expp = intexpr((arith)0, INT);
(*expp)->ex_flags = (flags | EX_ERROR);
}
1986-03-10 13:07:55 +00:00
struct expr *
arith2arith(tp, oper, expr)
struct type *tp;
int oper;
struct expr *expr;
{
/* arith2arith constructs a new expression containing a
run-time conversion between some arithmetic types.
*/
register struct expr *new = new_expr();
clear((char *)new, sizeof(struct expr));
new->ex_file = expr->ex_file;
new->ex_line = expr->ex_line;
new->ex_type = tp;
new->ex_class = Type;
return new_oper(tp, new, oper, expr);
}
int
int2int(expp, tp)
register struct expr **expp;
struct type *tp;
{
/* The expression *expp, which is of some integral type, is
converted to the integral type tp.
*/
if (is_cp_cst(*expp)) {
(*expp)->ex_type = tp;
cut_size(*expp);
}
else {
*expp = arith2arith(tp, INT2INT, *expp);
}
return (*expp)->ex_type->tp_fund;
}
int
int2float(expp, tp)
struct expr **expp;
struct type *tp;
{
/* The expression *expp, which is of some integral type, is
converted to the floating type tp.
*/
fp_used = 1;
*expp = arith2arith(tp, INT2FLOAT, *expp);
return (*expp)->ex_type->tp_fund;
}
float2int(expp, tp)
struct expr **expp;
struct type *tp;
{
/* The expression *expp, which is of some floating type, is
converted to the integral type tp.
*/
fp_used = 1;
*expp = arith2arith(tp, FLOAT2INT, *expp);
}
float2float(expp, tp)
struct expr **expp;
struct type *tp;
{
/* The expression *expp, which is of some floating type, is
converted to the floating type tp.
There is no need for an explicit conversion operator
if the expression is a constant.
*/
fp_used = 1;
if (is_fp_cst(*expp))
1986-03-10 13:07:55 +00:00
(*expp)->ex_type = tp;
else
1986-03-10 13:07:55 +00:00
*expp = arith2arith(tp, FLOAT2FLOAT, *expp);
}
array2pointer(expp)
struct expr **expp;
{
/* The expression, which must be an array, is converted
1986-03-10 13:07:55 +00:00
to a pointer.
*/
(*expp)->ex_type =
construct_type(POINTER, (*expp)->ex_type->tp_up, (arith)0);
}
function2pointer(expp)
struct expr **expp;
{
/* The expression, which must be a function, is converted
1986-03-10 13:07:55 +00:00
to a pointer to the function.
*/
(*expp)->ex_type =
construct_type(POINTER, (*expp)->ex_type, (arith)0);
}
string2pointer(expp)
struct expr **expp;
{
/* The expression, which must be a string constant, is converted
to a pointer to the string-containing area.
*/
struct expr *ex = *expp;
label lbl = data_label();
code_string(ex->SG_VALUE, ex->SG_LEN, lbl);
ex->ex_class = Value;
ex->VL_CLASS = Label;
ex->VL_LBL = lbl;
ex->VL_VALUE = (arith)0;
}
1986-03-10 13:07:55 +00:00
opnd2integral(expp, oper)
struct expr **expp;
int oper;
{
register int fund = (*expp)->ex_type->tp_fund;
if (fund != INT && fund != LONG) {
expr_error(*expp, "%s operand to %s",
1986-03-10 13:07:55 +00:00
symbol2str(fund), symbol2str(oper));
erroneous2int(expp);
1986-03-10 13:07:55 +00:00
/* fund = INT; */
}
}
opnd2logical(expp, oper)
struct expr **expp;
int oper;
{
register int fund;
if ((*expp)->ex_type->tp_fund == FUNCTION)
function2pointer(expp);
#ifndef NOBITFIELD
else
if ((*expp)->ex_type->tp_fund == FIELD)
field2arith(expp);
#endif NOBITFIELD
fund = (*expp)->ex_type->tp_fund;
switch (fund) {
case CHAR:
case SHORT:
case INT:
case LONG:
case ENUM:
case POINTER:
case FLOAT:
case DOUBLE:
break;
default:
expr_error(*expp, "%s operand to %s",
1986-03-10 13:07:55 +00:00
symbol2str(fund), symbol2str(oper));
case ERRONEOUS:
erroneous2int(expp);
1986-03-10 13:07:55 +00:00
break;
}
}
opnd2test(expp, oper)
struct expr **expp;
{
opnd2logical(expp, oper);
if ((*expp)->ex_class == Oper && is_test_op((*expp)->OP_OPER))
{ /* It is already a test */ }
else
ch7bin(expp, NOTEQUAL, intexpr((arith)0, INT));
}
int
is_test_op(oper)
{
switch (oper) {
case '<':
case '>':
case LESSEQ:
case GREATEREQ:
case EQUAL:
case NOTEQUAL:
case '!':
case AND:
case OR: /* && and || also impose a test */
return 1;
default:
return 0;
}
/*NOTREACHED*/
}
int
is_arith_op(oper)
{
switch (oper) {
case '*':
case '/':
case '%':
case '+':
case '-':
case LEFT:
case RIGHT:
case '&':
case '^':
case '|':
return 1;
default:
return 0;
}
}
int
is_asgn_op(oper)
{
switch (oper) {
case '=':
case PLUSAB:
case MINAB:
case TIMESAB:
case DIVAB:
case MODAB:
case LEFTAB:
case RIGHTAB:
case ANDAB:
case ORAB:
case XORAB:
return 1;
default:
return 0;
}
}
any2opnd(expp, oper)
struct expr **expp;
{
if (!*expp)
return;
switch ((*expp)->ex_type->tp_fund) { /* RM 7.1 */
case CHAR:
case SHORT:
case ENUM:
case FLOAT:
any2arith(expp, oper);
break;
case ARRAY:
array2pointer(expp);
break;
case POINTER:
if ((*expp)->ex_class == String)
string2pointer(expp);
break;
1986-03-10 13:07:55 +00:00
#ifndef NOBITFIELD
case FIELD:
field2arith(expp);
break;
#endif NOBITFIELD
}
}
#ifndef NOBITFIELD
field2arith(expp)
struct expr **expp;
{
/* The expression to extract the bitfield value from the
memory word is put in the tree.
*/
register struct type *tp = (*expp)->ex_type->tp_up;
register struct field *fd = (*expp)->ex_type->tp_field;
register struct type *atype = tp->tp_unsigned ? uword_type : word_type;
(*expp)->ex_type = atype;
if (atype->tp_unsigned) { /* don't worry about the sign bit */
ch7bin(expp, RIGHT, intexpr((arith)fd->fd_shift, INT));
ch7bin(expp, '&', intexpr(fd->fd_mask, INT));
}
else { /* take care of the sign bit: sign extend if needed */
register arith bits_in_type = atype->tp_size * 8;
ch7bin(expp, LEFT,
1986-03-17 17:47:04 +00:00
intexpr(bits_in_type - fd->fd_width - fd->fd_shift,
INT)
1986-03-10 13:07:55 +00:00
);
ch7bin(expp, RIGHT, intexpr(bits_in_type - fd->fd_width, INT));
}
ch7cast(expp, CAST, tp); /* restore its original type */
}
#endif NOBITFIELD
/* switch_sign_fp() negates the given floating constant expression
The lexical analyser has reserved an extra byte of space in front
of the string containing the representation of the floating
constant. This byte contains the '-' character and we have to
take care of the first byte the fl_value pointer points to.
*/
switch_sign_fp(expr)
struct expr *expr;
{
if (*(expr->FL_VALUE) == '-')
++(expr->FL_VALUE);
else
--(expr->FL_VALUE);
}