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

📄 cg.c

📁 《编译方法》课程设计内容2.《编译方法》课程设计内容
💻 C
📖 第 1 页 / 共 2 页
字号:

}	/* void  cg_cond( char *op,
	     	          SYMB *a,
	     		  int   l ) */


void  cg_arg( SYMB *a )

/* 实参语句的翻译: 实参语句出现在函数调用语句之前, 而实参的内存地址应该在被
   函数栈的活动记录之后, 因此在此不能增加tos的方式分配内存, 我们用next_arg记
   录实参的偏移量, 即实参的相对于当前栈顶的偏移量应是: tos + VAR_OFF + 
   next_arg, 其中VAR_OFF是活记录的长度, 注意, 按照这样的假设, 实参语句之后
   只能出现函数调用语句 */

{
	int  r  = get_rreg( a ) ;

	printf( "       STI  R%d,%d(R%d)\n", r, tos + VAR_OFF + next_arg,
		R_P ) ;
	next_arg += 4 ;

}	/* void  cg_arg( SYMB *a ) */


void  cg_call( int   f,
	       SYMB *res )

/* 函数调用语句将翻译为:

      LDA  f(R0),R2
      STI  R1,tos(R1)
      LDA  tos(R1),R1
      BAL  R2,R3
    ( STI  R4,res )
   
   即: 将被调用函数指针装入R2, 将当前栈指针装入当前栈顶作为第一条活记录装
   入栈顶, 将当前栈顶指针作为被调用函数的栈指针装入R1, 转移指令到被调用函数,
   同时将函数调用之后的第一条指令装入R3, 如果函数有返回值, 则将函数的返回值
   R4装入到res的内存中. 重新对next_arg置0 */
   

{
	flush_all() ;  /* 刷新寄存器 */
	next_arg = 0 ;
	printf( "       LDA  L%d,R%d\n", f, R_CALL ) ;
	printf( "       STI  R%d,%d(R%d)\n", R_P, tos, R_P ) ;
	printf( "       LDA  %d(R%d),R%d\n", tos, R_P, R_P ) ;
	printf( "       BAL  R%d,R%d\n", R_CALL, R_RET ) ;

	if( res != NULL )		      /* 是否有返回值 */
		insert_desc( R_RES, res, MODIFIED ) ;

}	/* void  cg_call( int   f,
		          SYMB *res ) */


void  cg_return( SYMB *a )

/* 函数返回语句将翻译为下述汇编指令: 

    ( LDI  a,R4 )
      LDI  4(R1),R2    
      LDI  0(R1),R1    
      BAL  R2,R3

  即, 将返回值装入寄存器R4中, 将活记录中的指令指令装入R2, 将调用函数的
  栈指针装入R1, 将指令转移R2, 如果a是空, 则不装载返回值 */

{
	if( a != NULL )
	{
		spill_one( R_RES ) ;
		load_reg( R_RES, a ) ;
	}

	printf( "       LDI  %d(R%d),R%d\n", PC_OFF, R_P, R_CALL ) ;	
	printf( "       LDI  %d(R%d),R%d\n", P_OFF, R_P, R_P ) ;	
	printf( "       BAL  R%d,R%d\n", R_CALL, R_RET ) ;	

}	/* void  cg_return( SYMB *a ) */


void  cg_sys( char *fn )		 /* 文件名 */

/* copy库函数到标准输出 */

{
	FILE *fd = fopen( fn, "r" ) ; /* 库函数名 */
	int  c ;

	if( fd == NULL )
	{
		error( "cannot open system file" ) ;
		exit( 0 ) ;
	}

	while((c = getc( fd )) != EOF )
		putchar( c ) ;

	fclose( fd ) ;

}	/* void  cg_sys( char *fn ) */


void  cg_strings( void )

/* 字符串常量将以静态的方式保存, 在汇编代码中通过标号的方式访问这些静态数据,
   因此, 在目标汇编语言中, 通过连续的虚拟汇编指令DB保存字符串常量, 注意在字
   符串的结尾处加上字符串结束标记ASCII 0 */

{
	int  i ;

	for( i = 0 ; i < HASHSIZE ; i++)   /* 扫描整个符号表, 寻找字符串常量 */
	{
		SYMB *sl ;

		for( sl = symbtab[i] ; sl != NULL ; sl = sl->next )
			if( sl->type == T_TEXT )
				cg_str( sl ) ;
	}

	printf( "L0:\n" ) ;

}	/* void  cg_strings( void ) */


void  cg_str( SYMB *s )

/* 对每个字符串常量生成数据DB指令 */

{
	char *t = s->TEXT1 ;		 /* 字符串首字符 */
	int   i ;

	printf( "L%d:\n", s->VAL2 ) ;	 /* 首先产生标号语句 */

	for( i = 1 ; t[i + 1] != EOS ; i++ )
		if( t[i] == '\\' )
			switch( t[++i] )
			{
				case 'n':

					printf( "       DB   %d\n", '\n' ) ;
					break ;

				case '\"':

					printf( "       DB   %d\n", '\"' ) ;
					break ;
			}
		else
			printf( "       DB   %d\n", t[i] ) ;

	printf( "       DB   0\n" ) ;	 /* 字符串结束标记 */

}	/* void  cg_str( SYMB *s ) */


/* 以下的函数是在翻译时对寄存器进行管理的有关函数 */

void  flush_all( void )

/* 刷新所有的寄存器, 在函数调用时使用 */

{
	int  r ;

	spill_all() ;

	for( r = R_GEN ; r < R_MAX ; r++ )   /* 刷新寄存器标记 */
		clear_desc( r ) ;

}	/* void  flush_all( void ) */


void  spill_all( void )

/* 回填所有的寄存器到对应的内存中 */

{
	int  r ;

	for( r = R_GEN ; r < R_MAX ; r++ )
		spill_one( r ) ;

}	/* spill_all( void ) */


void  spill_one( int  r )

/* 回填指定的寄存器到对应的内存中 */

{
	if( rdesc[r].modified ) /* 是否被修改 */
	{
		printf( "       STI  R%d,%d(R%d)\n", r, rdesc[r].name->ADDR2,
			R_P ) ;
		rdesc[r].modified = UNMODIFIED ;
	}

}	/* void  spill_one( int  r ) */


void  load_reg( int   r,		 /* 寄存器编号 */
		SYMB *n )		 /* 变量名 */

/* "load_reg()" 装载一个值到指定的寄存器中, 如果该变脸已在寄存器中, 则用指令
   LDR从寄存器中直接装载; 如果要装载字符串常量和常量, 则用LDA; 而对变量则用
   LDI装载 */

{
	int  s ;

	/* 查看n是否已在寄存其中 */

	for( s = 0 ; s < R_MAX ; s++ )	
		if( rdesc[s].name == n )
		{
			printf( "       LDR  R%d,R%d\n", s, r ) ;
			insert_desc( r, n, rdesc[s].modified ) ; 
				/* 标记和原有的寄存器相同 */
			return ;
		}

	/* 不在寄存器中, 分情况讨论 */

	switch( n->type )
	{
	case T_INT: 	/* 常量 */

		printf( "       LDA  %d(R0),R%d\n", n->VAL1, r ) ;
			/* 由于R0总是0, 因此, R0的值加上n的数值为n本身 */
		break ;

	case T_VAR:	/* 变量 */

		printf( "       LDI  %d(R%d),R%d\n", n->ADDR2, R_P, r ) ;
		break ;

	case T_TEXT:	/* 字符串常量 */

		printf( "       LDA  L%d,R%d\n", n->VAL2, r ) ;
		break ;
	}

	insert_desc( r, n, UNMODIFIED ) ; /* 设置标记为未修改 */

}	/* void  load_reg( int   r,
			   SYMB *n ) */


void  clear_desc( int   r )		 /* 寄存器编号 */

/* 清除指定的寄存器 */

{
	rdesc[r].name = NULL ;

}	/* void  clear_desc( int   r ) */


void  insert_desc( int   r,
		   SYMB *n,
		   int   mod )

/* 装入一个指定的寄存器. */

{
	rdesc[r].name     = n ;
	rdesc[r].modified = mod ;

}	/* void  insert_desc( int   r,
		   	      SYMB *n,
		   	      int   mod ) */


/* These two routines implement the simple register allocation algorithm
   described in chapter 10. "get_rreg()" gets a register that will hold an
   operand and be overwritten by a result. "get_areg()" gets a register that
   will hold an operand that will no be overwritten. */


int  get_rreg( SYMB *c )

/* 获得第一个寄存器, 由于运算是在寄存器上进行, 因此, 对于运算:

      a := b op c

   首先要将c装入一个寄存器中, 我们通过申请的方式来装载c, 使寄存器达到最优
   的效率, 申请的原则是: 1. 如果c已在某一个寄存器中, 则回填该寄存器并返回
   该寄存器编码; 2. 空寄存器; 3. 修改标记为假的寄存器; 4. 修改标记为真的
   寄存器, 这时需要回填该寄存器 */

{
	int        r ;			 /* 对寄存器数组遍历的变量 */

	for( r = R_GEN ; r < R_MAX ; r++ )   /* 已在一寄存器中 */
		if( rdesc[r].name == c )
		{
			spill_one( r ) ;
			return r ;
		}

	for( r = R_GEN ; r < R_MAX ; r++ )
		if( rdesc[r].name == NULL )  /* 使用空寄存器 */
		{
			load_reg( r, c ) ;
			return r ;
		}

	for( r = R_GEN ; r < R_MAX ; r++ )
		if( !rdesc[r].modified )     /* 使用修改标记为假的寄存器 */
		{
			clear_desc( r ) ;
			load_reg( r, c ) ;
			return r ;
		}

	spill_one( R_GEN ) ;		     /* 使用修改标记为真的寄存器 */
	clear_desc( R_GEN ) ;
	load_reg( R_GEN, c ) ;
	return R_GEN ;

}	/* int  get_rreg( SYMB *c ) */


int  get_areg( SYMB *b,
	       int   cr )		 /* 已使用寄存器编号 */

/* 同上一样, 但是, 在使用非空寄存器时, 一定不能使用cr */ 


{
	int        r ;			 /* 对寄存器数组遍历的变量 */

	for( r = R_ZERO ; r < R_MAX ; r++ )
		if( rdesc[r].name == b )              /* 已在一寄存器中 */
			return r ;

	for( r = R_GEN ; r < R_MAX ; r++ )
		if( rdesc[r].name == NULL )           /* 使用空寄存器 */
		{
			load_reg( r, b ) ;
			return r ;
		}

	for( r = R_GEN ; r < R_MAX ; r++ )
		if( !rdesc[r].modified && (r != cr))  /* 使用修改标记为假的寄存器  */
		{
			clear_desc( r ) ;
			load_reg( r, b ) ;
			return r ;
		}

	for( r = R_GEN ; r < R_MAX ; r++ )
		if( r != cr )		 	       /* 使用修改标记为真的寄存器  */
		{
			spill_one( r ) ;
			clear_desc( r ) ;
			load_reg( r, b ) ;
			return r ;
		}

}	/* int  get_areg( SYMB *b,
	  	          int   cr ) */

⌨️ 快捷键说明

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