📄 op.c
字号:
{
if( !IS_INT(offset->type) && !IS_CHAR(offset->type) )
yyerror( "Array index must be an integral type\n" );
objsize = get_sizeof( ptr->type->next ); /* Size of dereferenced */
/* object. */
if( !ptr->is_tmp ) /* Generate a physical */
ptr = tmp_gen( ptr->type, ptr ); /* lvalue. */
if( IS_CONSTANT( offset->type ) ) /* Offset is a constant.*/
{
gen("+=%s%d", ptr->name, offset->type->V_INT * objsize );
}
else /* Offset is not a con- */
{ /* stant. Do the arith- */
/* metic at run time. */
if( objsize != 1 ) /* Multiply offset by */
{ /* size of one object. */
if( !offset->is_tmp )
offset = tmp_gen( offset->type, offset );
gen( "*=%s%d", offset->name, objsize );
}
gen( "+=", ptr->name, offset->name ); /* Add offset to base. */
}
release_value( offset );
}
/* The temporary just generated (or the input variable if no temporary
* was generated) now holds the address of the desired cell. This command
* must generate an lvalue unless the object pointed to is an aggregate,
* whereupon it's n rvalue. In any event, you can just label the current
* cell as an lvalue or rvalue as appropriate and continue. The type must
* be advanced one notch to compensate for the indirection, however.
*/
synth = ptr;
tmp = ptr->type; /* Advance type one notch. */
ptr->type = ptr->type->next;
discard_link(tmp);
if( !IS_AGGREGATE(ptr->type->next) )
synth->lvalue = 1; /* Convert to lvalue. */
return synth;
}
value *do_struct( val, op, field_name )
value *val;
int op; /* . or - (the last is for ->) */
char *field_name;
{
symbol *field;
link *lp;
/* Structure names generate rvalues of type structure. The associated */
/* name evaluates to the structure's address, however. Pointers generate */
/* lvalues, but are otherwise the same. */
if( IS_POINTER(val->type) )
{
if( op != '-' )
{
yyerror("Object to left of -> must be a pointer\n");
return val;
}
lp = val->type; /* Remove POINTER declarator from */
val->type = val->type->next; /* the type chain and discard it. */
discard_link( lp );
}
if( !IS_STRUCT(val->type) )
{
yyerror("Not a structure.\n");
return val;
} /* Look up the field in the structure table: */
if( !(field = find_field(val->type->V_STRUCT, field_name)) )
{
yyerror("%s not a field\n", field_name );
return val;
}
if( val->lvalue || !val->is_tmp ) /* Generate temporary for */
val = tmp_gen( val->type, val ); /* base address if necessary; */
/* then add the offset to the */
if( field->level > 0 ) /* desired field. */
gen( "+=%s%d", val->name, field->level );
if( !IS_AGGREGATE(field->type) ) /* If referenced object isn't */
val->lvalue = 1; /* an aggregate, use lvalue. */
/* Replace value's type chain */
/* with type chain for the */
/* referenced object: */
lp = val->type;
if( !(val->type = clone_type( field->type, &val->etype)) )
{
yyerror("INTERNAL do_struct: Bad type chain\n" );
exit(1);
}
discard_link_chain( lp );
access_with( val ); /* Change the value's name */
/* field to access an object */
return val; /* of the new type. */
}
/*----------------------------------------------------------------------*/
PRIVATE symbol *find_field( s, field_name )
structdef *s;
char *field_name;
{
/* Search for "field_name" in the linked list of fields for the input
* structdef. Return a pointer to the associated "symbol" if the field
* is there, otherwise return NULL.
*/
symbol *sym;
for( sym = s->fields; sym; sym = sym->next )
{
if( !strcmp(field_name, sym->name) )
return sym;
}
return NULL;
}
/*----------------------------------------------------------------------*/
PRIVATE char *access_with( val )
value *val;
{
/* Modifies the name string in val so that it references the current type.
* Returns a pointer to the modified string. Only the type part of the
* name is changed. For example, if the input name is "WP(fp+4)", and the
* type chain is for an int, the name is be changed to "W(fp+4). If val is
* an lvalue, prefix an ampersand to the name as well.
*/
char *p, buf[ VALNAME_MAX ] ;
strcpy( buf, val->name );
for( p = buf; *p && *p != '(' /*)*/ ; ++p ) /* find name */
;
if( !*p )
yyerror( "INTERNAL, access_with: missing parenthesis\n" );
else
sprintf( val->name, "%s%s%s", val->lvalue ? "&" : "",
get_prefix(val->type), p);
return val->name;
}
PUBLIC value *call( val, nargs )
value *val;
int nargs;
{
link *lp;
value *synth; /* synthesized attribute */
/* The incoming attribute is an lvalue for a function if
* funct()
* or
* int (*p)() = funct;
* (*p)();
*
* is processed. It's a pointer to a function if p() is used directly.
* In the case of a logical lvalue (with a leading &), the name will be a
* function name, and the rvalue can be generated in the normal way by
* removing the &. In the case of a physical lvalue the name of a variable
* that holds the function's address is given. No star may be added.
* If val is an rvalue, then it will never have a leading &.
*/
if( val->sym && val->sym->implicit && !IS_FUNCT(val->type) )
{
/* Implicit symbols are not declared. This must be an implicit function
* declaration, so pretend that it's explicit. You have to modify both
* the value structure and the original symbol because the type in the
* value structure is a copy of the original. Once the modification is
* made, the implicit bit can be turned off.
*/
lp = new_link();
lp->DCL_TYPE = FUNCTION;
lp->next = val->type;
val->type = lp;
lp = new_link();
lp->DCL_TYPE = FUNCTION;
lp->next = val->sym->type;
val->sym->type = lp;
val->sym->implicit = 0;
val->sym->level = 0;
yydata( "extern\t%s();\n", val->sym->rname );
}
if( !IS_FUNCT(val->type) )
{
yyerror( "%s not a function\n", val->name );
synth = val;
}
else
{
lp = val->type->next; /* return-value type */
synth = tmp_create( lp, 0);
gen( "call", *val->name == '&' ? &val->name[1] : val->name );
gen( "=", synth->name, ret_reg(lp) );
if( nargs )
gen( "+=%s%d" , "sp", nargs * SWIDTH ); /* sp is a byte pointer, */
/* so must translate to */
release_value( val ); /* words with "* SWIDTH" */
}
return synth;
}
/*----------------------------------------------------------------------*/
char *ret_reg( p )
link *p;
{
/* Return a string representing the register used for a return value of
* the given type.
*/
if( IS_DECLARATOR( p ) )
return "rF.pp";
else
switch( p->NOUN )
{
case INT: return (p->LONG) ? "rF.l" : "rF.w.low" ;
case CHAR: return "rF.w.low" ;
default: yyerror("INTERNAL ERROR: ret_reg, bad noun\n");
return "AAAAAAAAAAAAAAAGH!";
}
}
value *assignment( op, dst, src )
int op;
value *dst, *src;
{
char *src_name;
char op_str[8], *p = op_str ;
if( !dst->lvalue ) yyerror ( "(=) lvalue required\n" );
if( !dst->is_tmp && dst->sym ) gen_comment( "%s", dst->sym->name );
/* Assemble the operator string for gen(). A leading @ is translated by
* gen() to a * at the far left of the output string. For example,
* ("@=",x,y) is output as "*x = y".
*/
if( *dst->name != '&' ) *p++ = '@' ;
if( op ) *p++ = op ;
if( op == '<' || op == '>' ) *p++ = op ; /* <<= or >>= */
/* do always */ *p++ = '=' ;
*p++ = '\0' ;
src_name = rvalue( src );
if( IS_POINTER(dst->type) && IS_PTR_TYPE(src->type) )
{
if( op )
yyerror("Illegal operation (%c= on two pointers);\n", op);
else if( !the_same_type( dst->type->next, src->type->next, 0) )
yyerror("Illegal pointer assignment (type mismatch)\n");
else
gen( "=", dst->name + (*dst->name=='&' ? 1 : 0), src_name );
}
else
{
/* If the destination type is larger than the source type, perform an
* implicit cast (create a temporary of the correct type, otherwise
* just copy into the destination. convert_type() releases the source
* value.
*/
if( !the_same_type( dst->type, src->type, 1) )
{
gen( op_str, dst->name + (*dst->name == '&' ? 1 : 0),
convert_type( dst->type, src ) );
}
else
{
gen( op_str, dst->name + (*dst->name == '&' ? 1 : 0), src_name );
release_value( src );
}
}
return dst;
}
void or( val, label )
value *val;
int label;
{
val = gen_rvalue( val );
gen ( "NE", val->name, "0" );
gen ( "goto%s%d", L_TRUE, label );
release_value( val );
}
/*----------------------------------------------------------------------*/
value *gen_rvalue( val )
value *val;
{
/* This function is like rvalue(), except that emits code to generate a
* physical rvalue from a physical lvalue (instead of just messing with the
* name). It returns the 'value' structure for the new rvalue rather than a
* string.
*/
if( !val->lvalue || *(val->name) == '&' ) /* rvalue or logical lvalue */
rvalue( val ); /* just change the name */
else
val = tmp_gen( val->type, val ); /* actually do indirection */
return val;
}
void and( val, label )
value *val;
int label;
{
val = gen_rvalue( val );
gen ( "EQ", val->name, "0" );
gen ( "goto%s%d", L_FALSE, label );
release_value( val );
}
value *relop( v1, op, v2 )
value *v1;
int op;
value *v2;
{
char *str_op ;
value *tmp;
int label;
v1 = gen_rvalue( v1 );
v2 = gen_rvalue( v2 );
if( !make_types_match( &v1, &v2 ) )
yyerror( "Illegal comparison of dissimilar types\n" );
else
{
switch( op )
{
case '>': /* > */ str_op = "GT"; break;
case '<': /* < */ str_op = "LT"; break;
case 'G': /* >= */ str_op = "GE"; break;
case 'L': /* <= */ str_op = "LE"; break;
case '!': /* != */ str_op = "NE"; break;
case '=': /* == */ str_op = "EQ"; break;
default:
yyerror("INTERNAL, relop(): Bad request: %c\n", op );
goto abort;
}
gen ( str_op, v1->name, v2->name );
gen ( "goto%s%d", L_TRUE, label = tf_label() );
if( !(v1->is_tmp && IS_INT( v1->type )) )
{
tmp = v1; /* try to make v1 an int temporary */
v1 = v2;
v2 = tmp;
}
v1 = gen_false_true( label, v1 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -