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

📄 analyze.cpp

📁 内含源代码和编译实验报告
💻 CPP
字号:
/******************************************************************
** 文件名: analyze.cpp

** 描  述: 这是一个完整的语义分析器,实现C-语言的语义分析功能。基本的
**         流程是:先建立一个空符号表,再建一个语法分析器,语法分析器会
**         产生一棵对于源程序的语法树,再把语法树中的源程序中的函数名,
**         变量名及它们的作用域,所在行数等等信息存储在符号表中,建立
**         完毕后,再对语法树进行后序遍历执行语言语义检查,主要是表达式
**         类型匹配检查,变量有效性检查,函数及变量作用域检查。函数返
**         类型正确性检查,函数调用时的参数表检查。
**             C-的所有符号都是有作用域的, 但goto语句突破了这个限制,
**         所以,必须为goto语句单独执行第二遍语义分析。
******************************************************************/
#include "globals.h"
#include "ExternGla"
#include "scan.h"
#include "prase.h"
#include "symtab.h"
#include "analyze.h"

/*********************************************************
**静态成员变量的声明。
*******************************************************/
int Canalyzer::m_ilocation=1;				//记录变量或函数名出现的顺序(占的内存位置)
Csymboltab*	Canalyzer::m_Csymtab;			//符号表。
CTreeNode	*Canalyzer::m_syntaxTree;		//语法树。
CPraser		*Canalyzer::m_pPraser;			//语法分析器。
int			Canalyzer::m_ilineno;
int			Canalyzer::m_ierror=0;

/********************************************
**构造函数,完成语义分析器的所有功能。
********************************************/
Canalyzer::Canalyzer(){
	try{
		m_Csymtab = new Csymboltab;
		CPraser *m_pPraser=new CPraser;
		m_syntaxTree=m_pPraser->m_program;
		cout<<"Building Symbol Table..."<<endl;
		buildSymtab(m_syntaxTree);				//根据语法树建立完整的符号表。
		if(AllFlags.m_iTraceAnalyze){
			cout<<"\nSmybol table:\n\n";
			m_Csymtab->printSymtab();}
		cout<<"Checkint Types..."<<endl;
		typeCheck(m_syntaxTree);				//执行语义检查。
		if(m_ierror==1) exit(0);				//有错误存在,代码生成被阻止。
	}
	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);}
}

Canalyzer::~Canalyzer(){
	delete m_pPraser;
	delete m_Csymtab;
}

/*******************************************************
**先序遍历语法树完成符号表的创建(当preProc=insertNode,postProc=nullProc时)
**后序遍符号表完成语义分析。(当preProc=nullProc,postProc=checdNode时)
**********************************************************/
void Canalyzer::traverse(CTreeNode* t, void(* preProc)(CTreeNode *),
										void(* postProc)(CTreeNode *)){
	if(t!= NULL){
		preProc(t);
		for(int i=0;i<3;i++)
			traverse(t->m_pchild[i],preProc,postProc);
		postProc(t);
		traverse(t->m_pbrother,preProc,postProc);
	}
}

/**********************************************
**空函数,不执行任何功能,主要是为辅助traverse
************************************************/
void Canalyzer::nullProc(CTreeNode *t){
	return;
}

/***********************************************
**向符号表中插入一个变量或函数名。
***********************************************/
void Canalyzer::insertNode(CTreeNode *t){
	switch(t->m_Ennodekind){
		case FuncK:
			if(m_Csymtab->st_lookup(t->m_strIDname,t->m_strScope)==-1)
				m_Csymtab->st_insert(t->m_strIDname, t->m_strScope, 
								t->m_EnTypevalue,t->m_ilineno, m_ilocation++);
			else{						//函数定义不可能两次出现,否则为重定义。
				cout<<"Error in line "<<t->m_ilineno<<": function: '"
									<<t->m_strIDname<<"'"<<" : redefinition"<<endl;
				m_ierror=1;}
			break;
		case DeclK:
		case ParaK:
			if(m_Csymtab->st_lookup(t->m_strIDname,t->m_strScope)==-1)
				m_Csymtab->st_insert(t->m_strIDname, t->m_strScope, t->m_EnTypevalue,
											t->m_ilineno, m_ilocation++);
			else{	//同一变量的定义在同一作用域内也不能两次出现,否则为重定义。
				cout<<"Error in line "<<t->m_ilineno<<": '"<<t->m_strIDname
												<<"'"<<" : redefinition"<<endl;
				m_ierror=1;}
			break;
		case ExpK:
			switch(t->kind.m_EnExpKind){
				case IdK:
					if(t->m_pfather->m_Ennodekind==StmtK && t->m_pfather
														->kind.m_EnStmtKind==GotoK)
							break;			//对goto的地址符号将在第二遍进行处理。
					if(m_Csymtab->st_lookup(t->m_strIDname,t->m_strScope)==-1
							&& m_Csymtab->st_lookup(t->m_strIDname,"Global")==-1){
						//表达式中的符号不可能在表中找不到,因为事前必须声明。
						//但一个函数中的变量可能是局部的,也可能是全局的。
						cout<<"Error in line "<<t->m_ilineno<<":  '"
									<<t->m_strIDname<<"' : undeclared identifier"<<endl;
						m_ierror=1;}
					else{
						//如果是局部的,插入一个局部符号。
						if(m_Csymtab->st_lookup(t->m_strIDname,t->m_strScope)!=-1)
								m_Csymtab->st_insert(t->m_strIDname, t->m_strScope
												, t->m_EnTypevalue, t->m_ilineno, 0);
						else//否则为全局的。
								m_Csymtab->st_insert(t->m_strIDname, "Global"
										, t->m_EnTypevalue, t->m_ilineno, 0);}
					break;
				default:
					break;}
			break;
		case StmtK:
			switch(t->kind.m_EnStmtKind){
				case AddressK:		//符号地址。
					if(m_Csymtab->st_lookup(t->m_pchild[0]->m_strIDname,"Global")!=-1){
						cout<<"Error in line "<<t->m_ilineno<<":  '"
									<<t->m_pchild[0]->m_strIDname<<"': label redefined"<<endl;
						m_ierror=1;}
					else
						m_Csymtab->st_insert(t->m_pchild[0]->m_strIDname, "Global", 
									t->m_EnTypevalue,t->m_ilineno, m_ilocation++);
					break;
				default:
					break;}
			break;
		default:
			break;}
}

/************************************************
** 对符号表执行语义检查。
*************************************************/
void Canalyzer::checkNode(CTreeNode *t){
	CTreeNode *p=t;						//为break,continue的检查所专用。
	switch(t->m_Ennodekind){
		case ExpK:
			switch(t->kind.m_EnExpKind){
				case OpK://表达式中,表达式的类型由精度高的子表达式类型决定。
					if(t->m_pchild[1]==NULL){
						t->m_EnTypevalue=t->m_pchild[0]->m_EnTypevalue;
						break;}
					if(t->m_pchild[0]->m_EnTypevalue == VOID ||
											t->m_pchild[1]->m_EnTypevalue == VOID){
						cout<<"Error in line "<<t->m_ilineno<<
													": illegal use of type 'void'"<<endl;
						m_ierror=1;}
					else if(t->m_pchild[0]->m_EnTypevalue == FLOAT ||
										t->m_pchild[1]->m_EnTypevalue == FLOAT)
						t->m_EnTypevalue=FLOAT;
					else if(t->m_pchild[0]->m_EnTypevalue == INT ||
										t->m_pchild[1]->m_EnTypevalue == INT)
						t->m_EnTypevalue=INT;
					else t->m_EnTypevalue=CHAR;
					break;
				case IdK:		//变量的类型在符号表中可以找到。
					if((t->m_EnTypevalue=m_Csymtab->
								st_lookuptype(t->m_strIDname,t->m_strScope))==ERROR)
						t->m_EnTypevalue=m_Csymtab->st_lookuptype(t->m_strIDname,"Global");
					break;
				default:
					break;}
			break;
		case StmtK:
			switch(t->kind.m_EnStmtKind){
				case ReturnK:	//函数返回类型必须精确匹配。
					if(t->m_pchild[0]==NULL){ //return不带参数,则函数返回类型必为void.
						if(m_Csymtab->st_lookuptype(t->m_strScope, "Global")!=VOID){
							cout<<"Error in line "<<t->m_ilineno<<": Function '"
								<<t->m_strScope<<"' must return a value."<<endl;
							m_ierror=1;}
					}
					break;
				case BreakK:
					//break语句的基本处理思想是沿着树往双亲结点搜索,如果找不到for,或while
					//语句,则说明该break句子位置不对,continue相同处理。
					while(p->m_pfather!=NULL && (p->m_pfather->m_Ennodekind!=StmtK ||
								(p->m_pfather->kind.m_EnStmtKind!=ForK 
												&& p->m_pfather->kind.m_EnStmtKind!=WhileK)))
						p=p->m_pfather; 
					if(p->m_pfather==NULL){
						cout<<"Error in line "<<t->m_ilineno<<": illegal break"<<endl;
						m_ierror=1;}
					break;
				case ContinueK:    //同continue语句。
					while(p->m_pfather!=NULL && (p->m_pfather->m_Ennodekind!=StmtK ||
								(p->m_pfather->kind.m_EnStmtKind!=ForK 
												&& p->m_pfather->kind.m_EnStmtKind!=WhileK)))
						p=p->m_pfather; 
					if(p->m_pfather==NULL){
						cout<<"Error in line "<<t->m_ilineno<<": illegal continue."<<endl;
						m_ierror=1;}
					break;
				default:
					break;}
			break;
		default:
			break;}
}

/*************************************************
** 因为goto语句是突破作用域范围的限制的,所以必须
** 为它单独执行一遍语义检查。
*************************************************/
void Canalyzer::checkgoto(CTreeNode *t){
	switch(t->m_Ennodekind){
		case StmtK:
			switch(t->kind.m_EnStmtKind){
				case GotoK:
					if(m_Csymtab->st_lookup(t->m_pchild[0]->m_strIDname)==-1){
						cout<<"Error in line "<<t->m_ilineno<<": '"<<t->m_pchild[0]->
													m_strIDname<<"'"<<" was undefined."<<endl;
						m_ierror=1;}
					else
						m_Csymtab->st_insert(t->m_pchild[0]->m_strIDname, 
									t->m_EnTypevalue,t->m_ilineno, 0);
					break;
				default:
					break;}
			break;
		default:
			break;}
}

/********************************************************
**先序遍历语法树构造符号表,并打印出符号表。
********************************************************/
void Canalyzer::buildSymtab(CTreeNode* syntaxTree){
	traverse(syntaxTree, insertNode,nullProc);
}

/******************************************************
**后序遍历语法树,结合符号表执行语义分析。
**  在第二遍语义检查结束时,确定main函数的存在。
******************************************************/
void Canalyzer::typeCheck(CTreeNode* syntaxTree){
	traverse(syntaxTree,nullProc,checkNode);
	traverse(syntaxTree,nullProc,checkgoto);		//执行第二遍语义分析,为goto匹配符号地址。
	if(m_Csymtab->st_lookup("main","Global")==-1){	//语义分析结束,确定一下main函数是否存在。
		cout<<"unresolved external symbol main"<<endl;
		m_ierror=1;}
}


⌨️ 快捷键说明

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