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

📄 codegen.cpp

📁 学习编译原理
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/****************************************************/
/* 文件 codegen.cpp				  					*/
/* 说明 类PASCAL语言编译器代码生成程序  			*/
/* 主题 编译器结构:原理和实例						*/	
/****************************************************/

#include "globals.h"		/*定义全局类型和变量 */

#include "util.h"			/*定义了一些实用函数*/

#include "string.h"

#include "codegen.h"		/*定义了目标代码生成文件的界面*/		

#include "code.h"           /*目标代码生成用到的一些实用函数*/

/*标号地址表*/
LabelAddr  *labelAddrT = NULL;

/*********函数声明***********/
void    codeGen(CodeFile  *midcode, char * destcode);

void	arithGen(CodeFile  *midcode);

void    operandGen(ArgRecord  *arg);

void	compaGen(CodeFile  *midcode);

void	aaddGen(CodeFile  *midcode);

void	readGen(CodeFile  *midcode);

void	writeGen(CodeFile  *midcode);

void	returnGen(CodeFile  *midcode);

void	assigGen(CodeFile  *midcode);

void	labelGen(CodeFile  *midcode);

void	jumpGen(CodeFile  *midcode , int i);

void	jump0Gen(CodeFile  *midcode);

void	valactGen(CodeFile  *midcode);

void	varactGen(CodeFile  *midcode);

void	callGen(CodeFile  *midcode);

void	pentryGen(CodeFile  *midcode);

void	endprocGen(CodeFile  *midcode);

void    FindAddr(ArgRecord  *arg );

void	FindSp(int varlevel);

void    mentryGen(CodeFile  *midcode,int savedLoc);

/************************************************/
/* 函数名 codeGen								*/ 
/* 功  能 目标代码生成主函数					*/		
/* 说  明 该函数通过扫描中间代码序列产生目标代码*/
/*        文件第二个参数codefile为目标代码文件名*/
/************************************************/
void codeGen(CodeFile  *midcode, char * destcode)
{ 
   /* 在内存中动态分配字串单元,返回单元指针s,	*
	* codefile为存储目标代码的代码文件名		*/
   char * s = (char *)malloc(strlen(destcode)+7);

   /* 将给定字串拷贝到s */
   strcpy(s,"File: ");

   /* 将目标代码文件名的字串拼接到s */
   strcat(s,destcode);
   fprintf(listing,"\n\n");

   getchar();

   /* 生成代码文件说明注释,写入代码文件 */
   emitComment("TINY Compilation to TM Code");
   emitComment(s);
 
   /* 生成标准先驱指令 */
   emitComment("Standard prelude:");
   
   /* 写入单元设置指令,清空0地址单元中内容 */
   emitRM("ST",ac,0,ac,"clear location 0");
   
   /* 写入注释,先驱指令写完 */
   emitComment("End of standard prelude.");
   
   /*为主程序入口留一个跳转语句*/
   int  savedLoc = emitSkip(1);

   /*循环处理各条中间代码,调用相应得函数产生相应得目标代码*/
   while  (midcode!=NULL)
   {
	 switch(midcode->codeR.codekind)
	 {	/*运算处理,包括算术运算和关系运算*/
		case	ADD:
		case	SUB:
		case	MULT:
		case	DIV:	
		case	LTC:
		case	EQC:
					arithGen(midcode);		break;
		/*地址加运算*/
		case   AADD:
					aaddGen(midcode);		break;
		/*输入语句*/
		case   READC:
					readGen(midcode);		break;
		/*输出语句*/
		case   WRITEC:
					writeGen(midcode);		break;
		/*返回语句*/
		case   RETURNC:
					returnGen(midcode);		break;
		/*赋值语句*/
		case   ASSIG:
					assigGen(midcode);		break;
		/*标号声明语句*/
		case   LABEL:
		case   WHILESTART:
		case   ENDWHILE:
					labelGen(midcode);		break;
		/*跳转语句*/
		case   JUMP:
					jumpGen(midcode,1);		break;
		/*条件跳转语句*/
		case   JUMP0:
					jump0Gen(midcode);		break;
		/*形实参结合语句:形参是值参*/
		case   VALACT:
					valactGen(midcode);		break;
		/*形实参结合语句:形参是变参*/
		case   VARACT:
					varactGen(midcode);		break;
		/*过程调用语句*/
		case   CALL:
					callGen(midcode);		break;
		/*过程入口声明*/
		case   PENTRY:
					pentryGen(midcode);		break;
		/*过程出口声明*/
		case   ENDPROC:
					endprocGen(midcode);	break;
		/*主程序入口处理*/
		case   MENTRY:
				    mentryGen(midcode,savedLoc); break;

		default :  fprintf(listing , " midcode  bug.\n");
	 }
   midcode = midcode->next;
   }

   /*处理完主程序,退出AR*/
   emitComment("<- end of main ");
   /* 写入注释,标志文件执行的结束 */
   emitComment("End of execution.");
   /* 写入停止指令,结束程序执行 */
   emitRO("HALT",0,0,0,"");
}

/************************************************/
/* 函数名 	arithGen							*/ 
/* 功  能 	生成算术运算的目标代码				*/		
/* 说  明										*/
/************************************************/
void	arithGen(CodeFile  *midcode)
{
   /* 如果代码生成追踪标志TraceCode为TRUE,写入注释,标注操作开始 */
  if (TraceCode) 	  emitComment("-> Op");

  /*生成左操作数的目标代码,值存在ac中*/
  operandGen(midcode->codeR.arg1);

  /* 暂存左操作数 */
  emitRM("LDA",ac2,0,ac,"op: store  left ");  
  
  /*生成右操作数的目标代码,值存在ac中*/
  operandGen(midcode->codeR.arg2);

  /* 取出左操作数ac1*/
  emitRM("LDA",ac1,0,ac2,"op: load left");

  /*根据操作符,生成运算的目标代码,ac中为计算结果*/
  switch(midcode->codeR.codekind)
  {		/*相加*/
		case	ADD:    emitRO("ADD",ac,ac1,ac,"op +");	break;
		/*相减*/
		case	SUB:    emitRO("SUB",ac,ac1,ac,"op -");	break;
		/*相乘*/
		case	MULT:   emitRO("MUL",ac,ac1,ac,"op *");	break;
		/*相除*/
		case	DIV:    emitRO("DIV",ac,ac1,ac,"op /");  break;
		/*小于*/
		case	LTC:  
						/* 写入减指令,将(左-右)操作数相减,结果送累加器ac */
					    emitRO("SUB",ac,ac1,ac,"op <") ;  

					    /* 写入判断跳转指令,如果累加器ac的值小于0,	*
					  	 * 则代码指令指示器跳过两条指令				*/
					    emitRM("JLT",ac,2,pc,"br if true") ;

					    /* 写入载入常量指令,将累加器ac赋值为0 */
					    emitRM("LDC",ac,0,0,"false case") ; 

					    /* 写入数值载入指令,代码指令指示器pc跳过下一条指令 */
					    emitRM("LDA",pc,1,pc,"unconditional jmp") ;

					    /* 写入载入常量指令,将累加器ac赋值为1 */
					    emitRM("LDC",ac,1,0,"true case") ;
					    break;

		/*等于*/
		case	EQC:
						/* 写入减法指令,将左,右操作数相减,结果送累加器ac */
						emitRO("SUB",ac,ac1,ac,"op ==") ;

						/* 写入判断跳转指令,如果累加器ac等于0,	*
						 * 代码指令指示器pc跳过两条指令			*/
						emitRM("JEQ",ac,2,pc,"br if true");

						/* 写入载入常量指令,将累加器ac赋值为0 */
						emitRM("LDC",ac,0,0,"false case") ;

						/* 写入数值载入指令,代码指令指示器pc跳过一条指令 */
						emitRM("LDA",pc,1,pc,"unconditional jmp") ;

						/* 写入载入常量指令,将累加器ac赋值为1 */
						emitRM("LDC",ac,1,0,"true case") ;
						break;
		default :       break;
  }

  /*后面要用ac,故保存ac*/
  emitRM("LDA",ac2,0,ac,"op: store  result ");  

  /*计算目的操作数的地址,存在ac中*/
  FindAddr(midcode->codeR.arg3);

  /*取出暂存的计算结果,存入ac1*/
  emitRM("LDA",ac1,0,ac2,"op: load result");

  /*计算结果存入目的操作数*/
  emitRM("ST",ac1,0,ac, "");

  /* 如果代码生成追踪标志TraceCode为TRUE,写入注释信息,标注操作结束 */
  if (TraceCode)  emitComment("<- Op") ;
 
}

/************************************************/
/* 函数名 	operandGen							*/ 
/* 功  能 	生成操作数的目标代码				*/		
/* 说  明	分操作数为常数或者变量两种情况处理	*/
/*			注意不能用ac2						*/
/************************************************/
void  operandGen(ArgRecord  *arg)
{
	switch(arg->form)
	{ /*操作数为常数*/
	  case  ValueForm :	   
			/* 如果代码生成追踪标志TraceCode为TRUE,写入注释,常数部分开始 */
			if (TraceCode) emitComment("-> Const") ;

			/* 生成载入常量指令,载入常量到累加器ac */
			emitRM("LDC",ac,arg->Attr.value,0,"load const");
	  
			/* 如果代码生成追踪标志TraceCode为TRUE,写入注释,常数部分结束 */
			if (TraceCode)  emitComment("<- Const") ;
			break; 

      /*分量为标号*/
	  case  LabelForm:
		  /* 如果代码生成追踪标志TraceCode为TRUE,写入注释,标号部分开始 */
			if (TraceCode) emitComment("-> Label") ;

			/* 生成载入标号指令,载入标号值到累加器ac */
			emitRM("LDC",ac,arg->Attr.label,0,"load label");
	  
			/* 如果代码生成追踪标志TraceCode为TRUE,写入注释,标号部分结束 */
			if (TraceCode)  emitComment("<- Label") ;
			break; 

	  /*操作数为变量,有可能是临时变量*/
	  case  AddrForm:
			 /* 如果代码生成追踪标志TraceCode为TRUE,写入注释,标注标识符开始 */
			if (TraceCode) emitComment("-> var") ;
	  
			FindAddr(arg);
			/*其中ac返回的是源变量或临时变量的绝对偏移*/
	  
			if(arg->Attr.addr.access==indir)
			{   
				
				/*取内容作为地址,再取内容*/
				emitRM("LD",ac1,0,ac,"indir load id value");
				emitRM("LD",ac,0,ac1,"");
			}
			else
			{   /*存的是值*/
				/* 写入数值载入指令,载入变量标识符的值*/
				emitRM("LD",ac,0,ac,"load id value");
			}

			/* 如果代码生成追踪标志TraceCode为TRUE,写入注释,标注标识符结束 */
	  		if (TraceCode)  emitComment("<- var") ;
			break;
	 
	  default:  break;
	}
}

/************************************************/
/* 函数名 	aaddGen								*/ 
/* 功  能 	生成地址加操作的目标代码			*/		
/* 说  明										*/
/************************************************/
void	aaddGen(CodeFile  *midcode)
{	/* 如果代码生成追踪标志TraceCode为TRUE,写入注释,aadd语句开始 */
	if(TraceCode)  emitComment("->address  add");
  
	if(midcode->codeR.arg1->Attr.addr.access == dir)
	{   /*ac中的地址即为基地址*/
		/*计算变量的绝对偏移,ac中存为变量的绝对偏移*/
        FindAddr(midcode->codeR.arg1);
	}
	else
	{   /*ac中的地址存放的内容为基地址*/
		/*计算变量的绝对偏移,ac中存为变量的绝对偏移*/
        FindAddr(midcode->codeR.arg1);
		emitRM("LD",ac,0,ac,"");
	}
    /*基地址转存到ac2*/
    emitRM("LDA",ac2,0,ac,"op: store  baseaddr ");  

	/*求地址相加运算的偏移量,存在ac中*/
	operandGen(midcode->codeR.arg2);

	/*地址相加,结果在ac中*/
	emitRO("ADD",ac2,ac2,ac,"op +");
    
    /*求目的变量的地址,存入ac*/
    FindAddr(midcode->codeR.arg3);

    /*地址相加结果写入目的变量*/
    emitRM("ST",ac2,0, ac,"");

}

/************************************************/
/* 函数名 	readGen								*/ 
/* 功  能 	生成读操作的目标代码				*/		
/* 说  明	根据变量是直接变量还是间接变量进行	*/
/*			不同的处理							*/
/************************************************/
void	readGen(CodeFile  *midcode)
{
	/*生成读指令,该指令完成读入外部数值到累加器ac2的动作*/
	emitRO("IN",ac2,0,0,"read integer value");

	/*计算变量的绝对偏移,ac中存为变量的绝对偏移*/
	FindAddr(midcode->codeR.arg1);
    
	if(midcode->codeR.arg1->Attr.addr.access == dir)
	{	/*直接存*/
		/*最后生成存储指令*/
		emitRM("ST",ac2,0,ac," var read : store value");
	}
	else
	{
		/*以ac内容作为地址找变量单元,再存*/
		emitRM("LD",ac1,0,ac,"");
		emitRM("ST",ac2,0,ac1," indir var read : store value");
	}
}

/************************************************/
/* 函数名 	writeGen							*/ 
/* 功  能 	生成写操作的目标代码				*/		
/* 说  明	调用函数得到值,并产生输出代码		*/
/************************************************/
void	writeGen(CodeFile  *midcode)
{
	/*调用函数,得到输出的值,存在ac中*/
	operandGen(midcode->codeR.arg1);
	
	/*生成写指令,该指令完成将累加器ac中的值输出的动作*/
	emitRO("OUT",ac,0,0,"write ac");

}

/************************************************/
/* 函数名 	returnGen							*/ 
/* 功  能 	生成返回语句的目标代码				*/		
/* 说  明	返回过程调用的下一条语句,注意return*/
/*			语句只在过程中出现					*/
/************************************************/
void	returnGen(CodeFile  *midcode)
{
	/*从过程里跳出,所做的工作与过程结束相同*/
	endprocGen(midcode);

}

/************************************************/
/* 函数名 	assigGen							*/ 
/* 功  能 										*/		
/* 说  明										*/
/************************************************/

⌨️ 快捷键说明

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