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

📄 codegen.cpp

📁 学习编译原理
💻 CPP
📖 第 1 页 / 共 2 页
字号:
void	assigGen(CodeFile  *midcode)
{
	/* 如果代码生成追踪标志TraceCode为TRUE,写入注释,assign语句开始 */
	if(TraceCode)  emitComment("->assign");
    
	/*赋值左部变量的地址,存在ac中*/
	FindAddr(midcode->codeR.arg2);
	/*转放在ac2中*/
    emitRM("LDA",ac2,0,ac,"op: store  addr ");  

	/*生成赋值右部的目标代码,值存在ac中*/
    operandGen(midcode->codeR.arg1);

	if(midcode->codeR.arg2->Attr.addr.access==dir)
		/*赋值,ac2中为地址*/
		emitRM("ST",ac,0,ac2,"var assign : store value");
	else
	{
		/*从ac2中取出内容,作为地址*/
		emitRM("LD",ac1,0,ac2," indir var assign");
		emitRM("ST",ac,0,ac1," store value");
	}
		
	/* 如果代码生成追踪标志TraceCode为TRUE,写入注释,assign语句结束 */
    if (TraceCode)  emitComment("<- assign") ;

}

/************************************************/
/* 函数名 	labelGen							*/ 
/* 功  能 										*/		
/* 说  明										*/
/************************************************/
void	labelGen(CodeFile  *midcode)
{
  /*取得标号值*/
  int label = midcode->codeR.arg1->Attr.label;

  /*取得当前目标代码编号*/
  int currentLoc = emitSkip(0) ;
  
  /*查找标号地址表*/
  LabelAddr  *item = labelAddrT;
  LabelAddr  *last = item;
  while (item!=NULL)
  {	if (item->label == label)
		break;
    last = item;
    item = item->next;
  }

  if (item==NULL)  /*表中没有此标号对应得项,填表 */
  { /*新建一项*/
	LabelAddr  *newItem = (LabelAddr *)malloc(sizeof(LabelAddr));
    newItem->label = label;
	newItem->destNum = currentLoc;
	newItem->next = NULL;
    /*加入标号地址表中*/
    if (labelAddrT == NULL)
		labelAddrT = newItem;
	else last->next = newItem;
 }
 else /*表中有此标号对应项,则回填目标代码*/ 
 {  
	/*退回到指令回填地址*/
	emitBackup(item->destNum);
	/*写入跳转到此标号所在目标代码位置的代码*/
	emitRM("LDC",pc,currentLoc,0,"jump to label");
	/*恢复当前目标代码*/
	emitRestore();

 }
}

/************************************************/
/* 函数名 	jumpGen								*/ 
/* 功  能	生成跳转的目标代码					*/		
/* 说  明   参数i是为了复用此函数而设,根据i	*/
/*			决定从中间代码中哪个分量取标号值	*/
/************************************************/
void	jumpGen(CodeFile  *midcode, int i)
{
  int  label ;
  /*取得标号值*/
  if (i == 1)
	    label = midcode->codeR.arg1->Attr.label;
  else  label = midcode->codeR.arg2->Attr.label; 
  
	/*查找标号地址表*/
    LabelAddr  *item = labelAddrT;
	LabelAddr  *last = item;
	while (item!=NULL)
	{	if (item->label == label)
			break;
		last = item;
		item = item->next;
	}

	if (item==NULL)  /*表中没有此标号对应得项,填表 */
	{	
		/*预留回填地址*/
		int currentLoc = emitSkip(1);

		/*新建一项*/
		LabelAddr  *newItem = (LabelAddr *)malloc(sizeof(LabelAddr));
		newItem->label = label;
		newItem->destNum = currentLoc;
		newItem->next = NULL;
		/*加入标号地址表中*/
		if (last == NULL)
			labelAddrT = newItem;
		else last->next = newItem;
	 }
	else 
		/*表中有此标号对应项,则可以生成目标代码*/ 
		emitRM("LDC",pc,item->destNum,0,"jump to label");
}

/************************************************/
/* 函数名 	jump0Gen							*/ 
/* 功  能 										*/		
/* 说  明										*/
/************************************************/
void	jump0Gen(CodeFile  *midcode)
{   
	/*取得决定是否跳转的值,存在ac中*/
	operandGen(midcode->codeR.arg1);
    /*转存到ac2中*/
    emitRM("LDA",ac2,0,ac,"op: store  addr ");  

	/* 此处为地址回填预留一个指令空间,生成不跳转时的代码*/
	int savedLoc = emitSkip(1);

	/*生成跳转代码,通过调用*/
    jumpGen(midcode,2);

	/*指令回填*/
	int  currentLoc = emitSkip(0);
	emitBackup(savedLoc);
	emitRM_Abs("JNE",ac2,currentLoc,"not jump");
	emitRestore();
    
}


/************************************************/
/* 函数名 	valactGen							*/ 
/* 功  能 	形参为值参时的形实参结合代码生成	*/		
/* 说  明										*/
/************************************************/
void	valactGen(CodeFile  *midcode)
{
	/* 如果代码生成追踪标志TraceCode为TRUE,写入注释,形实参结合开始*/
	if(TraceCode)  emitComment("->param  combine ");

	/*取得形参的偏移*/
	int  paramoff = midcode->codeR.arg2->Attr.value;

	/*调用函数,得到实参的值,存在ac中*/
	operandGen(midcode->codeR.arg1);
	
    /*进行形实参结合,在新的AR的对应形参位置写入实参值*/
    emitRM("ST",ac, paramoff, top,"store  param value");

    /* 如果代码生成追踪标志TraceCode为TRUE,写入注释,形实参结合结束*/
	if(TraceCode)  emitComment("<-param  combine ");

}

/************************************************/
/* 函数名 	varactGen							*/ 
/* 功  能 	形参为变参时的代码生成				*/		
/* 说  明										*/
/************************************************/
void	varactGen(CodeFile  *midcode)
{
	/* 如果代码生成追踪标志TraceCode为TRUE,写入注释,形实参结合开始*/
	if(TraceCode)  emitComment("->param  combine ");
	
	/*记录参数的偏移*/
    int paramoff = midcode->codeR.arg2->Attr.value;
   
	/*形参是变参*/
	/*1.实参是直接变量*/
	if(midcode->codeR.arg1->Attr.addr.access == dir)
	{   /*ac中的地址即为实参地址*/
		/*计算变量的绝对偏移,ac中存为变量的绝对偏移*/
        FindAddr(midcode->codeR.arg1);
	}
	/*2.实参是间接变量*/
	else
	{   /*ac中的地址存放的内容为实参地址*/
		/*计算变量的绝对偏移,ac中存为变量的绝对偏移*/
        FindAddr(midcode->codeR.arg1);
		emitRM("LD",ac,0,ac,"");
	}
    
	/*进行形实参结合,在新的AR的对应形参位置写入实参变量的地址*/
    emitRM("ST",ac, paramoff, top,"store  param  var");

	/* 如果代码生成追踪标志TraceCode为TRUE,写入注释,形实参结合结束*/
	if(TraceCode)  emitComment("<-param  combine ");
	
}
					
/************************************************/
/* 函数名 	callGen								*/ 
/* 功  能   过程调用处的处理工作				*/		
/* 说  明	为了节约目标代码,将过程调用中的整体*/
/*			工作分配到三部分,过程调用处,过程入*/
/*			口处,过程出口处					*/
/************************************************/
void	callGen(CodeFile  *midcode)
{
   /*保存旧的display表的偏移*/
   emitRM("ST",displayOff,6,top," save nOff");
	
   /*新的displayOff的值*/ 
   int Noff = midcode->codeR.arg3->Attr.value;
   emitRM("LDC",displayOff,Noff,0," new displayOff");

  /*记录下返回地址,注:返回地址只能在这里求得,而且是跳过保存返回
	地址得两条指令,和跳转得一条指令的下一条指令,故加3*/
  int currentLoc = emitSkip(0)+3;
  
  /*保存返回地址*/
  emitRM("LDC",ac,currentLoc,0,"save return address");
  emitRM("ST",ac,1,top,"");

  /*与跳转指令处理相同,注意:跳转写在最后*/
  jumpGen(midcode,1);
}


/************************************************/
/* 函数名 	pentryGen							*/ 
/* 功  能   过程体入口处的处理					*/		
/* 说  明	过程入口中间代码中,ARG1是过程入口	*/
/*			标号,ARG2是diplay表的偏移量,ARG3	*/
/*			是过程的层数						*/
/************************************************/
void	pentryGen(CodeFile  *midcode)
{
    
	/*首先处理标号,调用标号处理函数*/
    labelGen(midcode);
    
	/*取出AR大小信息*/
	int  ARsize = midcode->codeR.arg2->Attr.value;

    /*取出过程层数信息*/
	int  procLevel = midcode->codeR.arg3->Attr.value;

	/*保存当前sp*/
	emitRM("ST",sp,0,top,"save old sp");

	/*保存寄存器0,1,2,4*/
	emitRM("ST",ac,3,top,"save ac");
	emitRM("ST",ac1,4,top,"save ac1");
	emitRM("ST",ac2,5,top," save ac2");
	
	/*保存过程层数*/
	emitRM("LDC",ac,procLevel,0,"save procedure level");
	emitRM("ST",ac,2,top,"");

	/*移display表*/
	for(int ss = 0;ss<procLevel;ss++)
	{
		/*取原displayOff,存入ac1中*/
		emitRM("LD",ac1,6,top," fetch old display Off");
		/*ss要加上当前nOff才是对于sp的偏移*/
		emitRM("LDA",ac1,ss,ac1," old display item");
		/*ac1中为绝对地址*/
		emitRO("ADD",ac1,ac1,sp,"");
		/*取当前AR中display表的第ss项,存入ac中*/
		emitRM("LD",ac,0,ac1," fetch display table item");
				
		/*当前AR的displayOff*/
		emitRM("LDA",ac1,ss,displayOff," current display item");
		/*ac1中为绝对地址*/
		emitRO("ADD",ac1,ac1,top,"");
		/*将ac中的内容送入ac1所指地址中*/
		emitRM("ST",ac,0,ac1," send display table item");
	}

	/*在display表中的最上层填写本层的sp*/
	/*ac中存储的为display表最上层的相对off*/
	emitRM("LDA",ac,procLevel,displayOff," current sp in display");
	emitRO("ADD",ac,top,ac," absolute off");
	emitRM("ST",top,0,ac," store address" );

	/*修改sp和top*/
	emitRM("LDA",sp,0,top," new sp value");
	emitRM("LDA",top,ARsize,top,"new top value");

}

/************************************************/
/* 函数名 	endprocGen							*/ 
/* 功  能 	过程出口处的处理					*/		
/* 说  明										*/
/************************************************/
void	endprocGen(CodeFile  *midcode)
{
	/*恢复寄存器值*/
	emitRM("LD",ac,3,sp,"resume ac");
	emitRM("LD",ac1,4,sp,"resume ac1");
	emitRM("LD",ac2,5,sp,"resume ac2");
	emitRM("LD",displayOff,6,sp,"resume nOff");

	/*恢复sp和top值*/
	emitRM("LDA",top,0,sp,"resume top");
	emitRM("LD",sp,0,sp,"resume sp");

    /*取出返回地址,返回*/		
	emitRM("LD",pc,1,top," load return address");
}

/***********************************************************/
/* 函数名  mentryGen                                       */
/* 功  能  主程序入口的处理部分			                   */
/* 说  明  主程序入口中间代码的ARG2记录了主程序AR的display */
/*		   表的偏移;参数savedLoc记录跳转改变pc的指令应在的*/
/*		   位置											   */
/***********************************************************/
void mentryGen(CodeFile  *midcode ,int savedLoc)
{
	/*主程序入口*/
	int  currentLoc = emitSkip(0); 
	
	/*回退到目标代码第一条空语句处*/
	emitBackup(savedLoc);
	/*添加指令,将主程序入口地址传至指令寄存器pc*/
	emitRM("LDC",pc,currentLoc,0,"main entry");
	/*恢复当前地址*/
	emitRestore();

	emitComment("-> main procedure");
	/*处理主程序的过程活动记录,需要填写的内容有:
	  全局变量、display表*/   
	/*初始化寄存器*/
	emitRM("LDC",ac,0,0,"initialize ac");
	emitRM("LDC",ac1,0,0,"initialize ac1");
    emitRM("LDC",ac2,0,0,"initialize ac2");

	/*确定sp*/
	emitRM("ST",ac,0,sp," main sp");

	/*确定displayOff*/	
	int Noff = midcode->codeR.arg3->Attr.value;
	emitRM("LDC",displayOff,Noff,0," new displayOff");

	/*填写display表,只有主程序本层的sp(0)*/
	emitRM("ST",ac,0,displayOff," main display ");

	/*填写top,根据AR的大小*/
	int size = midcode->codeR.arg2->Attr.value;
	emitRM("LDA",top, size, sp," main top");					
}


/***********************************************************/
/* 函数名  FindAddr                                        */
/* 功  能  计算变量的绝对地址							   */
/* 说  明  将绝对地址存入ac中,注意要保证不用到ac2		   */
/***********************************************************/
void FindAddr( ArgRecord  *arg )
{
	/*源变量和临时变量处理方式不同*/
		
	/*记录该变量所在层*/
	int varLevel = arg->Attr.addr.dataLevel;
	/*记录该变量的相对偏移*/
	int varOff = arg->Attr.addr.dataOff;
	/*源变量*/
	if (varLevel != -1)
	{			
	    /*计算该变量的sp,存入ac中*/
		FindSp(varLevel);
		/*该变量相对于sp的偏移,存入ac1中*/
		emitRM("LDC",ac1,varOff,0," ");
		/* 计算绝对偏移 */
		emitRO("ADD",ac,ac,ac1," var absolute off");
	}
	/*临时变量*/
    else
	{  /*临时变量是局部的,只在本AR中有效*/
       
		/*该变量相对于sp的偏移,存入ac1中*/
		emitRM("LDC",ac1,varOff,0," ");
		/* 计算绝对偏移 */
		emitRO("ADD",ac,sp,ac1," temp absolute off"); 
	}

}

/***********************************************************/
/* 函数名  FindSp                                          */
/* 功  能  找到该变量所在AR的sp,存入ac中                   */
/* 说  明												   */
/***********************************************************/
void FindSp(int varlevel)
{
	/*先求该变量层数在AR中的位置,其中varLevel表示变量所在层*/
	emitRM("LDA",ac,varlevel,displayOff," var process");
	
	/*绝对地址*/
	emitRO("ADD",ac,ac,sp," var sp relative address");
    
	/*该变量所在AR的sp地址存在ac1中*/
	emitRM("LD",ac,0,ac," var sp");
}

⌨️ 快捷键说明

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