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

📄 cgen.cpp

📁 内含源代码和编译实验报告
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/******************************************************************
** 文件名: cgen.cpp

** 描  述: 这是一个实际的8086/8088汇编代码生成器。将c-语言生成最终
**         目标代码,由于汇编代码本身的一些功能限制,及实现的复杂性,
**         在最终定型时,功能上作了一些取舍,如下:
**             c-语言是支持float型数据的,也可以生成最终的代码,但
**         带有float型数据的代码将不可运行。
**             char型与int型数据统一使用16位寄存器,
**             为避免栈操作的复杂性,所有函数的局部变量将成为静态
**         变量,这将导致递归调用虽能进行,但得不到正确的结果。
**             该语言,在条件与循环控制上做的比较完备,if{}else{}
**         while{},for(){},break,continue均作过严格的测试,使语言
**         具有较强的过程控制能力。
******************************************************************/
#include "globals.h"
#include "scan.h"
#include "prase.h"
#include "symtab.h"
#include "analyze.h"
#include "cgen.h"
#include "ExternGla"

/*****************************************************************
**静态成员变量的声明及初始化
*****************************************************************/
Canalyzer*	Cgenerator::m_panalyzer=NULL;		//一个成员语义分析器。
int  Cgenerator::m_iunique=0;					//用于辅助生成唯一的符号地址。

/*****************************************************************
**  代码生成器的构造函数,先构造一个语义分析器,语义分析器将先
** 调用文法分析器,再完成语义分析功能。
*****************************************************************/
Cgenerator::Cgenerator(){
	try{
		m_panalyzer= new Canalyzer;
		cout<<"generating code..."<<endl;
		codeGen();					//开始生成目标代码。
	}
	catch (bad_alloc){									//处理堆分配异常。
		cout<<"Can't be allocated in heap, the programme must be terminated."<<endl;
		exit(1);}
	catch (...){
		cout<<"Something error,the program was terminated.";
		exit(1);}
}

Cgenerator::~Cgenerator(){
	delete m_panalyzer;
}

/***************************************************************
**代码生成分三步进行:生成数据段,生成堆栈段,然后生成代码段。
***************************************************************/
void Cgenerator::codeGen(void){
	Data_seg();
	Stack_seg();
	Code_seg();
}

/****************************************************************
**生成数据段,首先将所有全局变量加上后缀"@Glo"后放入数据段,然后
**将各函数的参数,局部变量全部加上各自的作用域作为后缀放入数据段
**这样,致使函数的成局部变量全成了静态的,这是因为时间不足,而在
** 设计上采取的一个折衷办法。
**递归调用将不能产生正确的结果。
*****************************************************************/
void Cgenerator::Data_seg(void){
	CTreeNode *p=NULL,*t=NULL;
	AllGlobals.code.write("Data_seg		segment\n",18);
	AllGlobals.code.write("\n@@Show@@\tdw\t?",14);//这是显示例程用到的数据,每个程序都有。
	p=m_panalyzer->m_syntaxTree;
	do{
		if(p->m_Ennodekind==DeclK)
			generate_data("@Glo",p);			//生成全局变量。
		else{
			t=p->m_pchild[0];
			if(t){								//函数参数表生成。
				do{
					generate_data(t->m_pfather->m_strIDname, t);
					t=t->m_pbrother;
				}while(t!=NULL);
			}
			t=p->m_pchild[1];
			if(t){								//函数局部变量生成。
				do{
					if(t->m_Ennodekind==DeclK)
						generate_data(t->m_pfather->m_strIDname, t);
					t=t->m_pbrother;
				}while(t!=NULL);
			}
		}
		p=p->m_pbrother;
	}while(p!=NULL);
	AllGlobals.code.write("\nData_seg		ends\n\n",17);//整个数据段生成结束。
}

/**************************************************************************
**    向数据段写入一个变量。
**************************************************************************/
void Cgenerator::generate_data(const char *pa_suffix,CTreeNode* pa_Declare){
	strcat(pa_Declare->m_strIDname, pa_suffix); //为变量加上作用域后缀。
	AllGlobals.code.write("\n",1);
	AllGlobals.code.write(pa_Declare->m_strIDname,strlen(pa_Declare->m_strIDname));
	AllGlobals.code.write("\t",1);
	AllGlobals.code.write("DW\t?\n",5);//char与int统一占用16位寄存器。
	return;
}

/**********************************************************************
**  生成堆栈段。(这是一段模板,每个程序都一样)
*********************************************************************/
void Cgenerator::Stack_seg(void){
	AllGlobals.code.write("Stack_seg		segment\n",19);
	AllGlobals.code.write("dw\t100 dup(?)\n",14);
	AllGlobals.code.write("@tos\tlabel\tword\n",16);
	AllGlobals.code.write("Stack_seg		ends\n\n",17);
}

/********************************************************************
**生成代码段,代码段起始将有一段例行操作,完成后,将main函数写在开始处
**接下来依次写上各个函数,所有该编译器所编译的程序的所有代码将在一个段
**中,程序大小受到严格限制。
*********************************************************************/
void Cgenerator::Code_seg(void){
	CTreeNode *p=NULL;
	AllGlobals.code.write("Code_seg		segment\n",18);
	AllGlobals.code.write("main\tproc\tfar\n",14);
	AllGlobals.code.write("\tassume cs:Code_seg,ds:Data_seg,ss:Stack_seg\nstart:\n",52);
	AllGlobals.code.write("mov\tax,Stack_seg\nmov\tss,ax\nmov\tsp,offset @tos\n",46);
	AllGlobals.code.write("push\tds\nsub\tax,ax\npush\tax\n",26);
	AllGlobals.code.write("mov\tax,Data_seg\nmov\tds,ax\n",26);
	p=m_panalyzer->m_syntaxTree;
	do{
		if(p->m_Ennodekind==FuncK && strcmp(p->m_strIDname,"main")==0){
			generate_func(p);break;}			//先生成main函数。
		p=p->m_pbrother;
	}while(p!=NULL);
	generate_show_func();						//再插入两个用于显示的函数。供write调用。
	p=m_panalyzer->m_syntaxTree;
	do{
		if(p->m_Ennodekind==FuncK && strcmp(p->m_strIDname,"main")!=0){
			AllGlobals.code.write("\n",1);		//生成其他的函数。
			AllGlobals.code.write(p->m_strIDname,strlen(p->m_strIDname));
			AllGlobals.code.write("\tproc\tnear\n",11);
			AllGlobals.code.write("\npop\tbp",7);	// bp主要用于处理ip寄存器。
			generate_func(p);}
		p=p->m_pbrother;
	}while(p!=NULL);
	AllGlobals.code.write("\nCode_seg		ends\n",16);
	AllGlobals.code.write("\tend	start",10);
}

/***************************************************************
**显示例程,代码生成器将为每个程序自动插入这段程序,供writed调用
**用于显示数值。
****************************************************************/
void Cgenerator::generate_show_func(void){
	AllGlobals.code.write("Show@@Show\tproc\tnear",20);
	AllGlobals.code.write("\npop\tbp",7);
	AllGlobals.code.write("\npop\tbx",7);
	AllGlobals.code.write("\npush\tbp",8);
	AllGlobals.code.write("\nmov\t@@Show@@,bx",16);
	AllGlobals.code.write("\nmov\tcx,10000d",14);
	AllGlobals.code.write("\ncmp\t@@Show@@,cx",16);
	AllGlobals.code.write("\njl\t@@1000",10);
	AllGlobals.code.write("\ncall\tShow@@22",14);
	AllGlobals.code.write("\n@@1000:",8);
	AllGlobals.code.write("\nmov\tcx,1000d",13);
	AllGlobals.code.write("\ncmp\t@@Show@@,cx",16);
	AllGlobals.code.write("\njl\t@@100",9);
	AllGlobals.code.write("\ncall\tShow@@22",14);
	AllGlobals.code.write("\n@@100:",7);
	AllGlobals.code.write("\nmov\tcx,100d",12);
	AllGlobals.code.write("\ncmp\t@@Show@@,cx",16);
	AllGlobals.code.write("\njl\t@@10",8);
	AllGlobals.code.write("\ncall\tShow@@22",14);
	AllGlobals.code.write("\n@@10:",6);
	AllGlobals.code.write("\nmov\tcx,10d",11);
	AllGlobals.code.write("\ncmp\t@@Show@@,cx",16);
	AllGlobals.code.write("\njl\t@@1",7);
	AllGlobals.code.write("\ncall\tShow@@22",14);
	AllGlobals.code.write("\n@@1:",5);
	AllGlobals.code.write("\nmov\tcx,1d",10);
	AllGlobals.code.write("\ncall\tShow@@22",14);
	AllGlobals.code.write("\nret",4);
	AllGlobals.code.write("\nShow@@Show\tendp",16);
	AllGlobals.code.write("\nShow@@22\tproc\tnear",19);
	AllGlobals.code.write("\nmov\tax,bx",10);
	AllGlobals.code.write("\nmov\tdx,0",9);
	AllGlobals.code.write("\ndiv\tcx",7);
	AllGlobals.code.write("\nmov\tbx,dx",10);
	AllGlobals.code.write("\nmov\tdl,al",10);
	AllGlobals.code.write("\nadd\tdl,30h",11);
	AllGlobals.code.write("\nmov\tah,2h",10);
	AllGlobals.code.write("\nint\t21h",8);
	AllGlobals.code.write("\nret",4);
	AllGlobals.code.write("\nShow@@22\tendp",14);
}

/*********************************************************
**每个函数代码的实际生成,首先将参数出栈保存,处理完ip,
**进入函数具体语句体的处理。
*********************************************************/
void Cgenerator::generate_func(CTreeNode* pa_Func){
	CTreeNode *p=pa_Func->m_pchild[0];
	if(strcmp(pa_Func->m_strIDname,"main")!=0){
		generate_params(p);			//参数出栈保存。
		AllGlobals.code.write("\npush\tbp",8);}	//处理ip.ip应始终位于栈的最顶层。
	p=pa_Func->m_pchild[1];
	if(p){
		do{
			generate_stmt(p);				//生成具体的语句。
			p=p->m_pbrother;
		}while(p!=NULL);
	}
	if(strcmp(pa_Func->m_strIDname,"main")!=0){
		AllGlobals.code.write("\npush\tbp",9);}
	AllGlobals.code.write("\nret\n",5);
	AllGlobals.code.write(pa_Func->m_strIDname,strlen(pa_Func->m_strIDname));
	AllGlobals.code.write("\tendp\n\n",7);
}

/*****************************************************************
**  函数参数表的处理,每个函数应在起始处,将所有的参数出栈保存
******************************************************************/
void Cgenerator::generate_params(CTreeNode* pa_param){
	CTreeNode *p=pa_param;
	if(p){ 
		do{
			AllGlobals.code.write("\npop\tax\nmov\t",12);
			AllGlobals.code.write(p->m_strIDname,strlen(p->m_strIDname));
			AllGlobals.code.write(",ax\n",4);
			p=p->m_pbrother;
		}while(p!=NULL);
	}
	return;
}

/******************************************************************
**函数体内具体语句的处理,语句包括表达式和一般语句两种。
******************************************************************/
void Cgenerator::generate_stmt(CTreeNode* pa_commpound){
	switch(pa_commpound->m_Ennodekind){
		case ExpK:
			generator_exp(pa_commpound);
			break;
		case StmtK:
			generator_substmt(pa_commpound);
			break;
		default:
			break;
	}
}

/**********************************************************************
** 表达式的生成,主要借用栈,采用递归方式进行。
***********************************************************************/
void Cgenerator::generator_exp(CTreeNode* pa_exp){
	switch(pa_exp->kind.m_EnExpKind){
		case ConstK:// 表达式指令中,遇到变量或常数,则压栈。(变量名需扩展处理).
		case IdK:
			if(pa_exp->m_EnTypevalue==CCHAR && pa_exp->kind.m_EnExpKind==ConstK)
				AllGlobals.code.write("\nmov\tax,\'",9);//字符常量要加单引号。
			else
				AllGlobals.code.write("\nmov\tax,",8);
			if(pa_exp->kind.m_EnExpKind==IdK) //变量名作扩展处理。
				if((pa_exp->m_EnTypevalue=m_panalyzer->m_Csymtab->
								st_lookuptype(pa_exp->m_strIDname,pa_exp->m_strScope))!=ERROR)
					strcat(pa_exp->m_strIDname,pa_exp->m_strScope);
			else
					strcat(pa_exp->m_strIDname,"@Glo");
			AllGlobals.code.write(pa_exp->m_strIDname,strlen(pa_exp->m_strIDname));
			if(pa_exp->m_EnTypevalue==CCHAR && pa_exp->kind.m_EnExpKind==ConstK)	
				AllGlobals.code.write("\'",1);
			AllGlobals.code.write("\npush\tax",8);
			break;
		case OpK:		//碰到操作符,则对他的操作数作递归处理,再处理操作符。
			CTreeNode *p1=pa_exp->m_pchild[0];
			CTreeNode *p2;
			if(pa_exp->m_pchild[1]) p2=pa_exp->m_pchild[1];
			else p2=NULL;			//单目运算符的p2为NULL,
			generate_stmt(p1);

⌨️ 快捷键说明

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