📄 op.c
字号:
}
abort:
release_value( v2 ); /* discard the other value */
return v1;
}
/*----------------------------------------------------------------------*/
PRIVATE int make_types_match( v1p, v2p )
value **v1p, **v2p;
{
/* Takes care of type conversion. If the types are the same, do nothing;
* otherwise, apply the standard type-conversion rules to the smaller
* of the two operands. Return 1 on success or if the objects started out
* the same type. Return 0 (and don't do any conversions) if either operand
* is a pointer and the operands aren't the same type.
*/
value *v1 = *v1p;
value *v2 = *v2p;
link *t1 = v1->type;
link *t2 = v2->type;
if( the_same_type(t1, t2, 0) && !IS_CHAR(t1) )
return 1;
if( IS_POINTER(t1) || IS_POINTER(t2) )
return 0;
if( IS_CHAR(t1) ) { v1 = tmp_gen(t1, v1); t1 = v1->type; }
if( IS_CHAR(t2) ) { v2 = tmp_gen(t2, v2); t2 = v2->type; }
if( IS_ULONG(t1) && !IS_ULONG(t2) )
{
if( IS_LONG(t2) )
v2->type->UNSIGNED = 1;
else
v2 = tmp_gen( t1, v2 );
}
else if( !IS_ULONG(t1) && IS_ULONG(t2) )
{
if( IS_LONG(t1) )
v1->type->UNSIGNED = 1;
else
v1 = tmp_gen( v2->type, v1 );
}
else if( IS_LONG(t1) && !IS_LONG(t2) ) v2 = tmp_gen (t1, v2);
else if( !IS_LONG(t1) && IS_LONG(t2) ) v1 = tmp_gen (t2, v1);
else if( IS_UINT(t1) && !IS_UINT(t2) ) v2->type->UNSIGNED = 1;
else if( !IS_UINT(t1) && IS_UINT(t2) ) v1->type->UNSIGNED = 1;
/* else they're both normal ints, do nothing */
*v1p = v1;
*v2p = v2;
return 1;
}
value *binary_op( v1, op, v2 )
value *v1;
int op;
value *v2;
{
char *str_op ;
int commutative = 0; /* operator is commutative */
if( do_binary_const( &v1, op, &v2 ) )
{
release_value( v2 );
return v1;
}
v1 = gen_rvalue( v1 );
v2 = gen_rvalue( v2 );
if( !make_types_match( &v1, &v2 ) )
yyerror("%c%c: Illegal type conversion\n",
(op=='>' || op =='<') ? op : ' ', op);
else
{
switch( op )
{
case '*':
case '&':
case '|':
case '^': commutative = 1;
case '/':
case '%':
case '<': /* << */
case '>': /* >> */
dst_opt( &v1, &v2, commutative );
if( op == '<' )
str_op = "<<=" ;
else if( op == '>' )
str_op = IS_UNSIGNED(v1->type) ? ">L=" : ">>=" ;
else
{
str_op = "X=";
*str_op = op ;
}
gen( str_op, v1->name, v2->name );
break;
}
}
release_value( v2 );
return v1;
}
/*----------------------------------------------------------------------*/
PRIVATE int do_binary_const( v1p, op, v2p )
value **v1p;
int op;
value **v2p;
{
/* If both operands are constants, do the arithmetic. On exit, *v1p
* is modified to point at the longer of the two incoming types
* and the result will be in the last link of *v1p's type chain.
*/
long x;
link *t1 = (*v1p)->type ;
link *t2 = (*v2p)->type ;
value *tmp;
/* Note that this code assumes that all fields in the union start at the
* same address.
*/
if( IS_CONSTANT(t1) && IS_CONSTANT(t2) )
{
if( IS_INT(t1) && IS_INT(t2) )
{
switch( op )
{
case '+': t1->V_INT += t2->V_INT; break;
case '-': t1->V_INT -= t2->V_INT; break;
case '*': t1->V_INT *= t2->V_INT; break;
case '&': t1->V_INT &= t2->V_INT; break;
case '|': t1->V_INT |= t2->V_INT; break;
case '^': t1->V_INT ^= t2->V_INT; break;
case '/': t1->V_INT /= t2->V_INT; break;
case '%': t1->V_INT %= t2->V_INT; break;
case '<': t1->V_INT <<= t2->V_INT; break;
case '>': if( IS_UNSIGNED(t1) ) t1->V_UINT >>= t2->V_INT;
else t1->V_INT >>= t2->V_INT;
break;
}
return 1;
}
else if( IS_LONG(t1) && IS_LONG(t2) )
{
switch( op )
{
case '+': t1->V_LONG += t2->V_LONG; break;
case '-': t1->V_LONG -= t2->V_LONG; break;
case '*': t1->V_LONG *= t2->V_LONG; break;
case '&': t1->V_LONG &= t2->V_LONG; break;
case '|': t1->V_LONG |= t2->V_LONG; break;
case '^': t1->V_LONG ^= t2->V_LONG; break;
case '/': t1->V_LONG /= t2->V_LONG; break;
case '%': t1->V_LONG %= t2->V_LONG; break;
case '<': t1->V_LONG <<= t2->V_LONG; break;
case '>': if( IS_UNSIGNED(t1) ) t1->V_ULONG >>= t2->V_LONG;
else t1->V_LONG >>= t2->V_LONG;
break;
}
return 1;
}
else if( IS_LONG(t1) && IS_INT(t2) )
{
switch( op )
{
case '+': t1->V_LONG += t2->V_INT; break;
case '-': t1->V_LONG -= t2->V_INT; break;
case '*': t1->V_LONG *= t2->V_INT; break;
case '&': t1->V_LONG &= t2->V_INT; break;
case '|': t1->V_LONG |= t2->V_INT; break;
case '^': t1->V_LONG ^= t2->V_INT; break;
case '/': t1->V_LONG /= t2->V_INT; break;
case '%': t1->V_LONG %= t2->V_INT; break;
case '<': t1->V_LONG <<= t2->V_INT; break;
case '>': if( IS_UNSIGNED(t1) ) t1->V_ULONG >>= t2->V_INT;
else t1->V_LONG >>= t2->V_INT;
break;
}
return 1;
}
else if( IS_INT(t1) && IS_LONG(t2) )
{
/* Avoid commutativity problems by doing the arithmetic first,
* then swapping the operand values.
*/
switch( op )
{
case '+': x = t1->V_INT + t2->V_LONG;
case '-': x = t1->V_INT - t2->V_LONG;
case '*': x = t1->V_INT * t2->V_LONG;
case '&': x = t1->V_INT & t2->V_LONG;
case '|': x = t1->V_INT | t2->V_LONG;
case '^': x = t1->V_INT ^ t2->V_LONG;
case '/': x = t1->V_INT / t2->V_LONG;
case '%': x = t1->V_INT % t2->V_LONG;
case '<': x = t1->V_INT << t2->V_LONG;
case '>': if( IS_UINT(t1) ) x = t1->V_UINT >> t2->V_LONG;
else x = t1->V_INT >> t2->V_LONG;
break;
}
t2->V_LONG = x; /* Modify v1 to point at the larger */
tmp = *v1p ; /* operand by swapping *v1p and *v2p. */
*v1p = *v2p ;
*v2p = tmp ;
return 1;
}
}
return 0;
}
/*----------------------------------------------------------------------*/
PRIVATE void dst_opt( leftp, rightp, commutative )
value **leftp;
value **rightp;
int commutative;
{
/* Optimizes various sources and destination as follows:
*
* operation is not commutative:
* if *left is a temporary: do nothing
* else: create a temporary and
* initialize it to *left,
* freeing *left
* *left = new temporary
* operation is commutative:
* if *left is a temporary do nothing
* else if *right is a temporary swap *left and *right
* else precede as if commutative.
*/
value *tmp;
if( ! (*leftp)->is_tmp )
{
if( commutative && (*rightp)->is_tmp )
{
tmp = *leftp;
*leftp = *rightp;
*rightp = tmp;
}
else
*leftp = tmp_gen( (*leftp)->type, *leftp );
}
}
value *plus_minus( v1, op, v2 )
value *v1;
int op;
value *v2;
{
value *tmp;
int v1_is_ptr;
int v2_is_ptr;
char *scratch;
char *gen_op;
gen_op = (op == '+') ? "+=" : "-=";
v1 = gen_rvalue( v1 );
v2 = gen_rvalue( v2 );
v2_is_ptr = IS_POINTER(v2->type);
v1_is_ptr = IS_POINTER(v1->type);
/* First, get all the error checking out of the way and return if
* an error is detected.
*/
if( v1_is_ptr && v2_is_ptr )
{
if( op == '+' || !the_same_type(v1->type, v2->type, 1) )
{
yyerror( "Illegal types (%c)\n", op );
release_value( v2 );
return v1;
}
}
else if( !v1_is_ptr && v2_is_ptr )
{
yyerror( "%c: left operand must be pointer", op );
release_value( v1 );
return v2;
}
/* Now do the work. At this point one of the following cases exist:
*
* v1: op: v2:
* number [+-] number
* ptr [+-] number
* ptr - ptr (types must match)
*/
if( !(v1_is_ptr || v2_is_ptr) ) /* normal arithmetic */
{
if( !do_binary_const( &v1, op, &v2 ) )
{
make_types_match( &v1, &v2 );
dst_opt( &v1, &v2, op == '+' );
gen( gen_op, v1->name, v2->name );
}
release_value( v2 );
return v1;
}
else
{
if( v1_is_ptr && v2_is_ptr ) /* ptr-ptr */
{
if( !v1->is_tmp )
v1 = tmp_gen( v1->type, v1 );
gen( gen_op, v1->name, v2->name );
if( IS_AGGREGATE( v1->type->next ) )
gen( "/=%s%d", v1->name, get_sizeof(v1->type->next) );
}
else if( !IS_AGGREGATE( v1->type->next ) )
{
/* ptr_to_nonaggregate [+-] number */
if( !v1->is_tmp )
v1 = tmp_gen( v1->type, v1 );
gen( gen_op, v1->name, v2->name );
}
else /* ptr_to_aggregate [+-] number */
{ /* do pointer arithmetic */
scratch = IS_LONG(v2->type) ? "r0.l" : "r0.w.low" ;
gen( "=", "r1.pp", v1->name );
gen( "=", scratch, v2->name );
gen( "*=%s%d", scratch, get_sizeof(v1->type->next) );
gen( gen_op, "r1.pp", scratch );
if( !v1->is_tmp )
{
tmp = tmp_create( v1->type, 0 );
release_value( v1 );
v1 = tmp;
}
gen( "=", v1->name, "r1.pp" );
}
}
release_value( v2 );
return v1;
}
rlabel( incr ) /* Return the numeric component of the next */
int incr; /* return label, postincrementing it by one */
{ /* if incr is true. */
static int num;
return incr ? num++ : num;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -