⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 op.c

📁 一个c语言写做的编译器的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*@A (C) 1992 Allen I. Holub                                                */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tools/debug.h>
#include <tools/hash.h>
#include <tools/l.h>
#include <tools/compiler.h>
#include <tools/c-code.h>
#include <tools/occs.h>
#include "symtab.h"
#include "value.h"
#include "proto.h"
#include "label.h"

/* OP.C 	This file contains support subroutines for the arithmetic */
/*		operations in c.y.					  */

symbol	*Undecl = NULL; /* When an undeclared symbol is used in an expression,
			 * it is added to the symbol table to suppress subse-
			 * quent error messages. This is a pointer to the head
			 * of a linked list of such undeclared symbols. It is
			 * purged by purge_undecl() at the end of compound
			 * statements, at which time error messages are also
			 * generated.
			 */

static  int	make_types_match P((value **v1p, value **v2p		));
static  int	do_binary_const	 P((value **v1p, int op, value **v2p	));
static  symbol *find_field	 P((structdef *s, char *field_name	));
static  char   *access_with	 P((value *val				));
static  void	dst_opt		 P((value **lp, value **rp, int	commut  ));
/*----------------------------------------------------------------------*/
value	*do_name( yytext, sym )
char	*yytext;		/* Lexeme				    */
symbol	*sym;			/* Symbol-table entry for id, NULL if none. */
{
    link   *chain_end, *lp ;
    value  *synth;
    char   buf[ VALNAME_MAX ];

    /* This routine usually returns a logical lvalue for the referenced symbol.
     * The symbol's type chain is copied into the value and value->name is a
     * string, which when used as an operand, evaluates to the address of the
     * object. Exceptions are aggregate types (arrays and structures), which
     * generate pointer temporary variables, initialize the temporaries to point
     * at the first element of the aggregate, and return an rvalue that
     * references that pointer. The type chain is still just copied from the
     * source symbol, so a structure or pointer must be interpreted as a pointer
     * to the first element/field by the other code-generation subroutines.
     * It's also important that the indirection processing (* [] . ->) set up
     * the same sort of object when the referenced object is an aggregate.
     *
     * Note that !sym must be checked twice, below. The problem is the same one
     * we had earlier with typedefs. A statement like foo(){int x;x=1;} fails
     * because the second x is read when the semicolon is shifted---before
     * putting x into the symbol table. You can't use the trick used earlier
     * because def_list is used all over the place, so the symbol table entries
     * can't be made until local_defs->def_list is processed. The simplest
     * solution is just to call findsym() if NULL was returned from the scanner.
     *
     * The second if(!sym) is needed when the symbol really isn't there.
     */

    if( !sym )
	sym = (symbol *) findsym( Symbol_tab, yytext );

    if( !sym )
	sym  = make_implicit_declaration( yytext, &Undecl );

    if( IS_CONSTANT(sym->etype) )		     /* it's an enum member */
    {
	if( IS_INT(sym->type) )
	    synth = make_icon( NULL, sym->type->V_INT );
	else
	{
	    yyerror("Unexpected noninteger constant\n");
	    synth = make_icon( NULL, 0 );
	}
    }
    else
    {
	gen_comment("%s", sym->name);	/* Next instruction will have symbol */
					/* name as a comment.		     */

	if( !(lp = clone_type( sym->type, &chain_end)) )
	{
	    yyerror("INTERNAL do_name: Bad type chain\n" );
	    synth = make_icon( NULL, 0 );
	}
	else if( IS_AGGREGATE(sym->type) )
	{
	    /* Manufacture pointer to first element */

	    sprintf(buf, "&%s(%s)",
			    IS_ARRAY(sym->type) ? get_prefix(lp) : BYTE_PREFIX,
			    sym->rname );

	    synth = tmp_create(sym->type, 0);
	    gen( "=", synth->name, buf );
	}
	else
	{
	    synth	  = new_value();
	    synth->lvalue = 1	;
	    synth->type	  = lp	;
	    synth->etype  = chain_end;
	    synth->sym	  = sym	;

	    if( sym->implicit || IS_FUNCT(lp) )
		strcpy( synth->name, sym->rname );
	    else
		sprintf(synth->name,
			  (chain_end->SCLASS == FIXED) ? "&%s(&%s)" : "&%s(%s)",
						    get_prefix(lp), sym->rname);
	}
    }

    return synth;
}
/*----------------------------------------------------------------------*/
symbol	*make_implicit_declaration( name, undeclp )
char	*name;
symbol  **undeclp;
{
    /* Create a symbol for the name, put it into the symbol table, and add it
     * to the linked list pointed to by *undeclp. The symbol is an int. The
     * level field is used for the line number.
     */

    symbol	*sym;
    link   	*lp;
    extern int	yylineno;	/* created by LeX */
    extern char *yytext;

    lp		  = new_link();
    lp->class     = SPECIFIER;
    lp->NOUN      = INT;
    sym		  = new_symbol( name, 0 );
    sym->implicit = 1;
    sym->type	  = sym->etype = lp;
    sym->level    = yylineno;	   /* Use the line number for the declaration */
				   /* level so that you can get at it later   */
				   /* if an error message is printed.	      */

    sprintf( sym->rname, "_%1.*s", sizeof(sym->rname)-2, yytext );
    addsym ( Symbol_tab,	   sym		);

    sym->next  = *undeclp;			/* Link into undeclared list. */
    *undeclp   = sym;

    return sym;
}
/*----------------------------------------------------------------------*/
PUBLIC	void purge_undecl()
{
    /* Go through the undeclared list. If something is a function, leave it in
     * the symbol table as an implicit declaration, otherwise print an error
     * message and remove it from the table. This routine is called at the
     * end of every subroutine.
     */

    symbol *sym, *cur ;

    for( sym = Undecl; sym; )
    {
	cur	  = sym;		/* remove current symbol from list */
	sym	  = sym->next;
	cur->next = NULL;

	if( cur->implicit )
	{
	    yyerror("%s (used on line %d) undeclared\n", cur->name, cur->level);
	    delsym( Symbol_tab, cur );
	    discard_symbol( cur );
	}
    }
    Undecl = NULL;
}
value *do_unop( op, val )
int   op;
value *val;
{
    char   *op_buf = "=?" ;
    int	   i;

    if( op != '!' )	/* ~ or unary - */
    {
	if( !IS_CHAR(val->type) && !IS_INT(val->type) )
	    yyerror( "Unary operator requires integral argument\n" );

	else if( IS_UNSIGNED(val->type) && op == '-' )
	    yyerror( "Minus has no meaning on an unsigned operand\n" );

	else if( IS_CONSTANT( val->type ) )
	    do_unary_const( op, val );
	else
	{
	    op_buf[1] = op;
	    gen( op_buf, val->name, val->name );
	}
    }
    else		/* ! */
    {
	if( IS_AGGREGATE( val->type ) )
	    yyerror("May not apply ! operator to aggregate type\n");

	else if( IS_INT_CONSTANT( val->type ) )
	    do_unary_const( '!', val );
	else
	{
	    gen( "EQ",       rvalue(val), "0"	         ); /* EQ(x, 0)       */
	    gen( "goto%s%d", L_TRUE,      i = tf_label() ); /*   goto T000;   */
	    val = gen_false_true( i, val );		    /* fall thru to F */
	}
    }
    return val;
}
/*----------------------------------------------------------------------*/
void do_unary_const( op, val )
int	op;
value	*val;
{
    /* Handle unary constants by modifying the constant's internal value
     * according to the incomming operator. No code is generated.
     */

    link *t = val->type;

    if( IS_INT(t) )
    {
	switch( op )
	{
	case '~':	t->V_INT = ~t->V_INT;	break;
	case '-':	t->V_INT = -t->V_INT;	break;
	case '!':	t->V_INT = !t->V_INT;	break;
	}
    }
    else if( IS_LONG(t) )
    {
	switch( op )
	{
	case '~':	t->V_LONG = ~t->V_LONG;	break;
	case '-':	t->V_LONG = -t->V_LONG;	break;
	case '!':	t->V_LONG = !t->V_LONG;	break;
	}
    }
    else
	yyerror("INTERNAL do_unary_const: unexpected type\n");
}
/*----------------------------------------------------------------------*/
int	tf_label()
{		 	/* Return the numeric component of a label for use as */
    static int label;	/* a true/false target for one of the statements      */
    return ++label;	/* processed by gen_false_true().		      */
}
/*----------------------------------------------------------------------*/

value	*gen_false_true( labelnum, val )
int	labelnum;
value	*val;
{
    /* Generate code to assign true or false to the temporary represented by
     * val. Also, create a temporary to hold the result, using val if it's
     * already the correct type. Return a pointer to the target. The FALSE
     * code is at the top. If val is NULL, create a temporary. Labelnum must
     * have been returned from a previous tf_label() call.
     */

    if( !val )
	val = tmp_create( NULL, 0 );

    else if( !val->is_tmp || !IS_INT(val->type) )
    {
	release_value( val );
	val = tmp_create( NULL, 0 );
    }
    gen( ":%s%d",    L_FALSE,   labelnum );	/* F000:	 	*/
    gen( "=",        val->name, "0" );		/*	  t0 = 0	*/
    gen( "goto%s%d", L_END,	labelnum );	/*	  goto E000;	*/
    gen( ":%s%d",    L_TRUE,    labelnum );	/* T000:	 	*/
    gen( "=",	     val->name, "1" );		/*	  t0 = 1;	*/
    gen( ":%s%d",    L_END,     labelnum );	/* E000:	 	*/
    return val;
}

value	*incop( is_preincrement, op, val )		         /* ++ or -- */
int	is_preincrement;	     /* Is preincrement or predecrement.     */
int	op;			     /* '-' for decrement, '+' for increment */
value	*val;			     /* lvalue to modify.		     */
{
    char  *name;
    char  *out_op  = (op == '+') ? "+=%s%d" : "-=%s%d" ;
    int   inc_amt  ;

    /* You must use rvalue_name() in the following code because rvalue()
     * modifies the val itself--the name field might change. Here, you must use
     * the same name both to create the temporary and do the increment so you
     * can't let the name be modified.
     */

    if( !val->lvalue )
	yyerror("%c%c: lvalue required\n", op, op );
    else
    {
	inc_amt = (IS_POINTER(val->type)) ? get_sizeof(val->type->next) : 1 ;
	name    = rvalue_name( val );

	if( is_preincrement )
	{
	    gen( out_op, name, inc_amt );
	    val = tmp_gen( val->type, val );
	}
	else						 /* Postincrement. */
	{
	    val = tmp_gen( val->type, val );
	    gen( out_op, name, inc_amt );
	}
    }
    return val;
}
value *addr_of( val )
value *val;
{
    /* Process the & operator. Since the incoming value already holds the
     * desired address, all you need do is change the type (add an explicit
     * pointer at the far left) and change it into an rvalue. The first argument
     * is returned.
     */

    link  *p;

    if( val->lvalue )
    {
	p	    = new_link();
	p->DCL_TYPE = POINTER;
	p->next     = val->type;
	val->type   = p;
	val->lvalue = 0;
    }
    else if( !IS_AGGREGATE(val->type) )
	yyerror( "(&) lvalue required\n" );

    return val;
}

value *indirect( offset, ptr )
value *offset;			/* Offset factor (NULL if it's a pointer). */
value *ptr;			/* Pointer that holds base address.	   */
{
    /* Do the indirection, If no offset is given, we're doing a *, otherwise
     * we're doing ptr[offset]. Note that, strictly speaking, you should create
     * the following dumb code:
     *
     *			t0 = rvalue( ptr );	(if ptr isn't a temporary)
     *			t0 += offset		(if doing [offset])
     *			t1 = *t0;		(creates a rvalue)
     *						lvalue attribute = &t1
     *
     * but the first instruction is necessary only if ptr is not already a
     * temporary, the second only if we're processing square brackets.
     *
     * The last two operations cancel if the input is a pointer to a pointer. In
     * this case all you need to do is remove one * declarator from the type
     * chain. Otherwise, you have to create a temporary to take care of the type
     * conversion.
     */

    link  *tmp     ;
    value *synth   ;
    int	  objsize  ;	/* Size of object pointed to (in bytes)		   */

    if( !IS_PTR_TYPE(ptr->type) )
	yyerror( "Operand for * or [N] Must be pointer type\n" );

    rvalue( ptr );   	  /* Convert to rvalue internally. The "name" field   */
			  /* is modified by removing leading &'s from logical */
			  /* lvalues.					      */
    if( offset )	  /* Process an array offset.			      */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -