www.pudn.com > subpas.rar > analyze.c


/****************************************************/ 
/* File: analyze.c                                  */ 
/* Semantic analyzer implementation					*/ 
/* for the SubPas compiler							*/ 
/****************************************************/ 
 
#include "globals.h" 
#include "util.h" 
#include "parse.h" 
#include "analyze.h" 
 
/* 当前检查所在的子函数或过程*/ 
static TreeNode * currentPro=NULL; 
 
TreeNode * syntaxTree; 
 
/* 返回变量的声明节点 
 * @param name 变量名 
 8 @return 该变量的声明的节点指针 
 */ 
TreeNode * lookUpVar(char * name) 
{	 
	TreeNode * t; 
	if(currentPro!=NULL){		 
		t = currentPro->child[0];  //是否在函数的参数中? 
		while (t!=NULL){ 
			if(strcmp(t->name,name)==0) return t; 
			t = t->sibling; 
		} 
		t = currentPro -> child[1];  //是否在函数的局部变量声明中? 
		while (t!=NULL){ 
			if(strcmp(t->name,name)==0) return t; 
			t = t->sibling; 
		} 
	}    
	t = syntaxTree->child[1];  //是否在全局变量声明中? 
	while (t!=NULL){ 
		if(strcmp(t->name,name)==0) return t; 
		t = t->sibling; 
	} 
	return NULL;        //找不到,返回NULL 
} 
 
 
/* 返回函数的声明节点 
 * @param name 函数名 
 * @return 函数声明的节点指针 
 */ 
TreeNode * lookUpPro(char * name) 
{ 
	TreeNode * t = syntaxTree->sibling; 
	while(t!=NULL && (currentPro != NULL && t != currentPro->sibling)){    
		if(strcmp(t->name,name)==0) return t; 
		t = t->sibling; 
	} 
	return NULL; 
} 
 
/* 检查是否有重复变量声明,方法是将参数和局部变量声明逐一比较 
 * @param proNode 函数或过程的声明节点 
 * @return 若有重复声明,返回第二个声明变量的节点,否则返回NULL 
 */ 
TreeNode * idCheck(TreeNode * proNode) 
{ 
	TreeNode * t1 = proNode->child[0];	//检查参数 
	TreeNode * t2; 
	while(t1!=NULL){		 
		int flag = TRUE; 
		t2 = t1->sibling; 
		while(t2!=NULL){		//先跟参数比较 
			if(strcmp(t1->name,t2->name)==0) return t2; 
			t2 = t2->sibling; 
			if(t2==NULL && flag==TRUE){ 
				t2 = proNode->child[1];	//再跟局部变量比较 
				flag = FALSE;	 
			} 
		} 
		t1 = t1->sibling; 
	} 
	t1 = proNode->child[1];		//检查局部变量 
	while(t1!=NULL){ 
		t2 = t1->sibling; 
		while(t2!=NULL){ 
			if(strcmp(t1->name,t2->name)==0) return t2; 
			t2 = t2->sibling; 
		} 
		t1 = t1->sibling; 
	} 
	return NULL; 
} 
/* 错误信息种类*/ 
typedef enum {type_mismatch , op_err, dec_again , undec_id , test_err , param_must_be_id, 
			  param_num_err , array_overflow , array_index_err } ErrorType; 
			   
/* 打印语法错误信息 
 * @param t 发生错误的节点 
 * @param err 错误信息种类 
 */ 
void printError(TreeNode * t,ErrorType err) 
{ 
	switch (err) { 
		case type_mismatch: 
			if (t->child[1]) 
				printf("Error:(line %d) Incompatible types:%s and %s.\n", 
							t->lineno,getType(t->child[0]),getType(t->child[1])); 
			else printf("Error:(line %d) Incompatible types.\n",t->lineno); 
			break; 
		case op_err: 
			if(t->kind.exp==SignK)	 
				printf("Error:(line %d) Type of Signed-Operation must be Integer or Real.\n",t->lineno); 
			else  
				printf("Error:(line %d) Type of NOT-Operation must be Boolean.\n",t->lineno);			 
			break; 
		case dec_again: 
			printf("Error:(line %d) Identifier redeclared:%s.\n",t->lineno,t->name); 
			break; 
		case undec_id: 
			printf( "Error:(line %d) Undeclared identifier:%s.\n",t->lineno,t->name); 
			break; 
		case test_err: 
			printf( "Error:(line %d) Type of expression must be BOOLEAN.\n",t->lineno); 
			break; 
		case param_must_be_id: 
			printf( "Error:(line %d) Wrong parameter:the parameter must be variable identifier.\n",t->lineno); 
			break;	 
		case param_num_err: 
			printf( "Error:(line %d) The number of parameters is mismatched:%s.\n",t->lineno,t->name); 
			break; 
		case array_overflow: 
			printf( "Error:(line %d) Array index overflow:%s.\n",t->lineno,t->name); 
			break; 
		case array_index_err: 
			printf( "Error:(line %d) Array index must be integer:%s.\n",t->lineno,t->name); 
			break; 
	} 
	Error = TRUE; 
} 
static TreeNode * ReadlnParam = NULL;	//readln语句的参数 
static TreeNode * WritelnParam = NULL;  //writeln语句的参数 
static TreeNode * ReadlnDec = NULL;    //readln语句的声明 
static TreeNode * WritelnDec = NULL;  //writeln的声明 
 
//是否用到Readln语句 
int ReadlnUsed = FALSE; 
 
//是否用到Writeln语句 
int WritelnUsed = FALSE; 
 
/* 进行错误检查,若有错误,打印出错误信息 
 * @param t 树节点 
 */ 
void errorCheck(TreeNode * t) 
{    
	TreeNode * tree; 
	if(t==NULL) return; 
	switch (t->nodekind) 
	{  
    case Pro: 
		if (t->kind.pro == SubP)  currentPro = t; 
		tree=idCheck(t);		//检查全局变量是否有重复声明 
		if(tree!=NULL) printError(tree,dec_again); 
		if (t->kind.pro ==MainP){	 //若是主过程,则 
			errorCheck(t->sibling);  //先对子过程和子函数进行检查 
			errorCheck(t->child[2]); //再检查主过程语句 
		}else{ 
			errorCheck(t->child[2]); //否则,先检查子过程(函数)的语句 
			errorCheck(t->sibling);  //再检查下一个子过程(函数) 
		}	 
		break; 
    case Stmt: 
		errorCheck(t->child[0]); 
		errorCheck(t->child[1]); 
		errorCheck(t->child[2]); 
		switch (t->kind.stmt) 
		{  
		case IfK: 
        case WhileK: 
			if (t->child[0]->type != Boolean) 
				printError(t->child[0],test_err); 
			break; 
		case CallK:  
			if (!strcmp(t->name,"readln")) { 
				TreeNode * realp = t->child[0]; 
				if (realp->type != Integer) 
					printError(realp,type_mismatch); 
				else if (realp->kind.exp != IdK && realp->kind.exp != ArrayK) 
					printError(realp,param_must_be_id); 
				else if (realp->sibling) 
					printError(t,param_num_err); 
				else { 
					ReadlnUsed = TRUE; 
					if (!ReadlnParam) { 
						ReadlnParam = newExpNode(IdK); 
						ReadlnParam ->type = Integer; 
						ReadlnParam ->attr.paramkind = ByRefer; 
 
						ReadlnDec = newStmtNode(CallK); 
						ReadlnDec ->child[0]=ReadlnParam; 
						ReadlnDec ->name = (char *)malloc(8); 
						strcpy(ReadlnDec->name,"_readln"); 
					} 
					t->child[2] = ReadlnDec; 
				} 
			}else if (!strcmp(t->name,"writeln")){ 
				TreeNode * realp = t->child[0]; 
				if (realp->type != Integer) 
					printError(realp,type_mismatch); 
				else if (realp->sibling) 
					printError(t,param_num_err); 
				else { 
					WritelnUsed = TRUE; 
					if(!WritelnParam) { 
						WritelnParam = newExpNode(IdK); 
						WritelnParam ->type = Integer; 
						WritelnParam ->attr.paramkind = ByVal; 
						 
						WritelnDec = newStmtNode(CallK); 
						WritelnDec ->child[0] = WritelnParam; 
						WritelnDec ->name = (char *)malloc(12); 
						strcpy(WritelnDec->name,"_writeln"); 
					} 
					t->child[2] = WritelnDec; 
				} 
			}else{ 
				tree = lookUpPro(t->name);  
				if(tree==NULL) printError(t , undec_id); 
				else{ 
					TreeNode * formp; //形参, 
					TreeNode * realp; //实参 
					t->type = tree->type; 
					for (formp = tree->child[0],realp = t->child[0];  
						formp != NULL && realp != NULL; 
						formp = formp->sibling, realp = realp->sibling){ 
						if (formp->type != realp->type && !(formp->type==Real && realp->type==Integer)) 
							printError( realp , type_mismatch); 
						else if(formp->attr.paramkind == ByRefer && realp->kind.exp!=IdK) 
							printError(realp , param_must_be_id); 
					} 
					if (formp != NULL || realp != NULL) 
						printError( t , param_num_err); 
					t->child[2] = tree;     //指向声明节点 
				}  
			} 
			break; 
		case AssignK: 
			if (t->child[0]->type != t->child[1]->type) { 
				if (t->child[0]->type == Real && t->child[1]->type == Integer) 
					t->type = t->child[1]->type = Real; 
				else  
					printError( t,type_mismatch); 
			} 
			if( t->child[0]->kind.stmt == CallK){	//由于是先Check child[0],故可能为CallK 
				if (strcmp(t->child[0]->name,currentPro->name) == 0)  //判断是否为返回语句 
					t->kind.stmt = ReturnK;			//赋值语句转为返回语句 
				else printError( t->child[0],undec_id); 
				} 
			break; 
		} 
		if(t->sibling) errorCheck(t->sibling); 
		break; 
	case Exp: 
		switch (t->kind.exp) 
		{  
		case OpK: 
			errorCheck(t->child[0]); 
			errorCheck(t->child[1]);	 
			switch(t->attr.op) { 
			case PLUS: case MINUS: case TIMES: case OVER: case MOD: case DIV: 
				if ((t->child[0]->type != Integer && t->child[0]->type != Real) || 
					(t->child[1]->type != Integer && t->child[1]->type != Real)) 
					printError(t, type_mismatch); 
				else if (t->child[0]->type == Real || t->child[1]->type == Real) 
					t->type = Real; 
				else if (t->attr.op == OVER) t->type = Real; 
				else t->type = Integer; 
				break; 
			case EQ: case NE: 
				if(t->child[0]->type == Boolean && t->child[1]->type == Boolean){ 
					t->type = Boolean; 
					break; 
				}	 
			case LT: case LE: case GT: case GE:  
				if ((t->child[0]->type != Integer && t->child[0]->type != Real) || 
					(t->child[1]->type != Integer && t->child[1]->type != Real)) 
					printError(t, type_mismatch); 
				else  
					t->type = Boolean; 
				break; 
			case AND: case OR: 
				if ((t->child[0]->type != Boolean) ||( t->child[1]->type != Boolean)) 
					printError(t, type_mismatch); 
				else 
					t->type = Boolean; 
				break; 
			case NOT: 
				if (t->child[0]->type != Boolean)  
					printError(t, op_err); 
				else 
					t->type = Boolean; 
				break; 
			} 
			break; 
		case SignK: 
			errorCheck(t->child[0]); 
			if(t->child[0]->kind.exp==NumK){ 
				t->kind.exp =NumK; 
				t->attr.intval = -(t->child[0]->attr.intval); 
				t->type = Integer; 
				t->child[0] = NULL; 
			}else if( t->child[0]->kind.exp==RealNumK ){ 
				t->kind.exp =RealNumK; 
				t->attr.realval = -(t->child[0]->attr.realval); 
				t->type = Real; 
				t->child[0] = NULL; 
			}else if(t->child[0]->type != Integer && t->child[0]->type != Real) 
				printError(t, op_err); 
			else t->type = t->child[0]->type; 
			break; 
        case IdK: 
			tree = lookUpVar(t->name); 
			if(tree!=NULL) { 
				if(tree->type==Array){ 
					if(!t->child[0]) { 
						printError(t , array_index_err); 
						break; 
					} 
					errorCheck(t->child[0]); 
					if(t->child[0]->kind.exp == NumK){  //检查数组上下界 
						int i = t->child[0]->attr.intval; 
						if(i < tree->attr.arrayattr->low || i > tree->attr.arrayattr->high) 
							printError(t,array_overflow); 
					} 
					else if(t->child[0]->type!=Integer) 
						printError(t , array_index_err); 
					t->kind.exp = ArrayK;			//转为ArrayK 
					t->type = tree->attr.arrayattr->type; 
					t->attr.arrayattr = tree->attr.arrayattr; 
				} 
				else t->type=tree->type; 
			}else{	 
				tree = lookUpPro(t->name);		//检查是否为函数调用(这时只有函数没有括号)或返回赋值 
				if(tree!=NULL && tree->type!=Void) { 
					t->nodekind = Stmt;	 
					t->kind.stmt = CallK; 
					t->type = tree->type; 
				} 
			} 
			if (tree == NULL) 
				printError(t , undec_id); 
			else t->child[2] = tree;   //指向声明节点 
			 
			break; 
		} 
		if (t->sibling) errorCheck(t->sibling); //若该节点为参数时有兄弟节点 
		break; 
	} 
}