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

📄 midtodemi.cpp

📁 上课时老师用过的SNL编译器
💻 CPP
📖 第 1 页 / 共 3 页
字号:
  /*取得标号值*/
  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							*/ 
/* 功  能 	生成条件跳转语句的目标代码 			*/		
/* 说  明	根据arg1的值判断是否跳转,arg2给出要*/
/*			跳转到的标号值,调用函数jumpGen处理 */
/*			跳转部分							*/
/************************************************/
void	Cmidtodemi::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	Cmidtodemi::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	Cmidtodemi::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	Cmidtodemi::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	Cmidtodemi::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	Cmidtodemi::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 Cmidtodemi::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 Cmidtodemi::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 Cmidtodemi::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 + -