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

📄 pl.cpp

📁 这是我们的一个上机题,做词法分析和语法的,希望对大家的学习有所帮助
💻 CPP
📖 第 1 页 / 共 4 页
字号:
							else
							{//形式参数
								if(CurSymbol->type!=IDENT)
									error(14);//应该是标识符
								else
								{
									k=GETPOSITION(CurSymbol->value.lpValue);
									getASymbol();
									if(k!=0)
									{
										if(NAMETAB[k].kind!=VARIABLE)
											error(16);//应该是变量
										typeItem.typ=NAMETAB[k].type;
										typeItem.ref=NAMETAB[k].ref;
										if(NAMETAB[k].normal)
											GEN(LODA,NAMETAB[k].level,NAMETAB[k].unite.address);
										else
											GEN(LOD,NAMETAB[k].level,NAMETAB[k].unite.address);
										if(CurSymbol->type==LBRACK)
										{   
											ARRAYELEMENT(tempList,typeItem);
										}
										if(NAMETAB[cp].type!=typeItem.typ || NAMETAB[cp].ref!=typeItem.ref)
											error(29);//实参与形参类型不一致
									}
								}
							}
						}
					}
					while(CurSymbol->type==COMMA);
					delete tempList1;
					if(CurSymbol->type==RPAREN)
						getASymbol();
					else
						error(2);//应该是')'
				}
				if(cp<lastPar)
					error(30);//实在参数个数不够
				GEN(CAL,NAMETAB[i].level,NAMETAB[i].unite.address);
				if(NAMETAB[i].level<displayLevel)
					GEN(UDIS,NAMETAB[i].level,displayLevel);
			}
		}
		else
			error(18);//应该是过程名
	}
	else
		error(14);//应该是标识符
	delete tempList;
}

void STATEMENT(SYMLIST * list)  //普通语句的分析,这些语句有几种形式,分别以不同的标识符开头
{
	////////////////////////////////////////////////////
	SYMLIST * tempList=new SYMLIST;
	COPYLIST(tempList,listAddSym(&STATBEGSYS,IDENT));
	////////////////////////////////////////////////////

	if(SYMINLIST(CurSymbol->type,tempList))  //通过不同的标识符辨别是那种语句
	{
		switch(CurSymbol->type)
		{
		case IDENT: ASSIGNMENT(list);break;
		case CALLSYM: CALL(list);break;
		case IFSYM: IFSTATEMENT(list);break;
		case WHILESYM: WHILESTATEMENT(list);break;
		case BEGINSYM: COMPOUND(list);break;
		//*******************************************************
		//修改
		case FORSYM: FORSTATEMENT(list);break;//for语句
		case REPEATSYM:REPEATSTATEMENT(list);break;//repeat语句
		case CASESYM:CASESTATEMENT(list);break;//case语句
		//*******************************************************
		}
	}
	delete tempList;
}


void BLOCK(SYMLIST * list,int level)  //过程体的分析
{
	int cx,tx,programBlock;
    int dx;
	dx=DX;//记录静态上层局部数据区大小
	DX=3;//将本程序体的活动记录留出三个单元出来,用做连接数据
	tx=TX;
	NAMETAB[tx].unite.address=CX;

	if(displayLevel>MAXLEVELDEPTH)
		error(26);//程序体表溢出
	ENTERBLOCK();  //登记过程体
	programBlock=BX;
	DISPLAY[displayLevel]=BX;
	NAMETAB[tx].type=NOTYP;
	NAMETAB[tx].ref=programBlock;

	if(CurSymbol->type==LPAREN && displayLevel>1)
	{
		PARAMENTERLIST(list);  //编译过程列表
		if(CurSymbol->type==SEMICOLON)
			getASymbol();
		else
			error(1);//应该是';'
	}
	else if(displayLevel>1)
	{
		if(CurSymbol->type==SEMICOLON)
			getASymbol();
		else
			error(1);//应该是';'
	}
	BTAB[programBlock].lastPar=TX;
	BTAB[programBlock].pSize=DX;
	GEN(JMP,0,0);
	do
	{
		switch(CurSymbol->type)  //针对当前不同的不好进行不同的声明
		{			
		case CONSTSYM:
			getASymbol();
			do
			{
				CONSTDECLARATION(list);  //常量声明,一次可声明多个
			}
			while(CurSymbol->type==IDENT);
			break;
		case TYPESYM:
			getASymbol();
			do
			{
				TYPEDECLARATION(list);  //类型声明,一次可声明多个
			}
			while(CurSymbol->type==IDENT);
			break;
		case VARSYM:
			getASymbol();
			do
			{
				VARDECLARATION(list);  //变量声明,一次可声明多个
			}
			while(CurSymbol->type==IDENT);				
			break;
		}
		while(CurSymbol->type==PROCSYM)
			PROCDECLARATION(list);    //过程声明,每次只能声明一个
	}while(SYMINLIST(CurSymbol->type,&DECLBEGSYS));
	CODE[NAMETAB[tx].unite.address].address=CX;//将执行语句的开始处地址回填
	JUMADRTAB[JX]=CX;
	JX++;
	NAMETAB[tx].unite.address=CX;//代码开始地址
	cx=CX;
	GEN(ENTP,displayLevel,DX);

	////////////////////////////////////////////////////
	SYMLIST * tempList=new SYMLIST;
	COPYLIST(tempList,listAddSym(listAddSym(list,ENDSYM),SEMICOLON));
	STATEMENT(tempList);
	delete tempList;
	////////////////////////////////////////////////////
    CODE[cx].address=DX;//回填数据区大小
	if(displayLevel>1)
		GEN(RETP,0,0);//从程序体返回
	else
		GEN(ENDP,0,0);//程序结束
	QUITBLOCK();
	DX=dx;//恢复静态上层局部数据区大小
}

int Feof(FILE *fp)//判断是否到了源文件尾
{
	int getChar;
	getChar=fgetc(fp);
	if(getChar==-1)
	{
		if(feof(fp))
			return 1;//如果是,返回“真”
	}
	else
		fseek(fp,-1,SEEK_CUR);//否则,将指向文件流的指针向后移动一个字符
	return 0;
}


SYMBOL GetReserveWord(char *nameValue)//判断得到的符号是否是保留字
{
	int i;

	char reserveWord[NUMOFWORD][20]=
	{
		"and","begin","const","else","if","not","or","program","type","while",
		"array","call","do","end","mod","of","procedure","then","var",
		//添加                   @@@@@@
		"repeat","until","case","for","to"
	};
	SYMBOL reserveType[NUMOFWORD]=
	{
		ANDSYM,BEGINSYM,CONSTSYM,ELSESYM,IFSYM,NOTSYM,ORSYM,PROGRAMSYM,TYPESYM,WHILESYM,
		ARRAYSYM,CALLSYM,DOSYM,ENDSYM,MODSYM,OFSYM,PROCSYM,THENSYM,VARSYM,
		//添加                   @@@@@@
		REPEATSYM,UNTILSYM,CASESYM,FORSYM,TOSYM
	};

	for(i=0;i<NUMOFWORD;i++)  //这里采用了遍历的做法,但是效率不高,可以考虑采用二叉查找法
		if(!stricmp(reserveWord[i],nameValue))
			return reserveType[i];
	return (SYMBOL)0;
}

void AddSymbolNode(SymbolItem **current,int lineNumber,SYMBOL type,int iValue)  //在词法分析的时候向符号列表中加入一个分析出来的符号
{
		(*current)->next=new SymbolItem; 
		if(!(*current)->next)
		{
			error(27);//系统为本编译程序分配的堆不够用
			exit(4);
		}
		(*current)=(*current)->next;
		(*current)->lineNumber=lineNumber;
		(*current)->type=type;
		(*current)->value.iValue=iValue; 
		(*current)->next=NULL; 
}

void getSymbols(FILE *srcFile)  //从源文件读入字符,获得符号链表,词法分析
{
	int lineNumber=1;
	char nameValue[MAXSYMNAMESIZE];
	int nameValueint;
	char readChar;
	SymbolItem head,*current=&head;

	printf("\n进行词法分析  -->-->-->-->-->-->-->-->  ");

	while(!Feof(srcFile))
	{
		readChar=fgetc(srcFile);

		if(iscsymf(readChar))
		{
			nameValueint=0;
			do
			{
				nameValue[nameValueint++]=readChar;
				readChar=fgetc(srcFile);
				if(Feof(srcFile)) 
					break;
			}while(iscsym(readChar) || isdigit(readChar)); 
			nameValue[nameValueint]=0;
			fseek(srcFile,-1,SEEK_CUR);
			current->next=new SymbolItem;
			current=current->next;
			current->lineNumber=lineNumber;
			if(!(current->type=GetReserveWord(nameValue)))//不是保留字
			{
				current->type=IDENT;
				current->value.lpValue=new char[nameValueint]; 
				strcpy(current->value.lpValue,nameValue);
			}
			current->next=NULL; 
		}
		else if(isdigit(readChar))
		{
			nameValueint=0;
			do
			{
				nameValue[nameValueint++]=readChar;
				readChar=fgetc(srcFile);
				if(Feof(srcFile)) 
					break;
			}while(isdigit(readChar)); 
			nameValue[nameValueint]=0;
			fseek(srcFile,-1,SEEK_CUR);
			AddSymbolNode(&current,lineNumber,INTCON,atoi(nameValue));
		}
		else switch(readChar)
		{
			case '	':				//字符 'tab'
			case ' ':	
				break;
			case '\n':
				break;
			case '\r':             //换行符
				lineNumber++;     
				break;
			case ':':
				if(Feof(srcFile))
					break;
				readChar=fgetc(srcFile);
				if(readChar=='=')
					AddSymbolNode(&current,lineNumber,BECOMES,0);
				else
				{
					fseek(srcFile,-1,SEEK_CUR);
					AddSymbolNode(&current,lineNumber,COLON,0);
				}
				break;
			case '<':
				if(Feof(srcFile))
					break;
				readChar=fgetc(srcFile);
				if(readChar=='=')
					AddSymbolNode(&current,lineNumber,LEQ,0);
				else if(readChar=='>')
					AddSymbolNode(&current,lineNumber,NEQ,0);
				else
				{
					fseek(srcFile,-1,SEEK_CUR);
					AddSymbolNode(&current,lineNumber,LSS,0);
				}
				break;
			case '>':
				if(Feof(srcFile))
					break;
				readChar=fgetc(srcFile);
				if(readChar=='=')
					AddSymbolNode(&current,lineNumber,GEQ,0);
				else
				{
					fseek(srcFile,-1,SEEK_CUR);
					AddSymbolNode(&current,lineNumber,GTR,0);
				}
				break;
			case '.':
				if(Feof(srcFile))
				{
					AddSymbolNode(&current,lineNumber,PERIOD,0);
					break;
				}
				readChar=fgetc(srcFile);
				if(readChar=='.')
					AddSymbolNode(&current,lineNumber,DPOINT,0);
				else
				{
					fseek(srcFile,-1,SEEK_CUR);
					AddSymbolNode(&current,lineNumber,PERIOD,0);
				}
				break;
			case '\'':
				readChar=fgetc(srcFile);
				if(Feof(srcFile))
					break;
				if(fgetc(srcFile)=='\'')
					AddSymbolNode(&current,lineNumber,CHARCON,readChar);
				else
					error(1);//////////////////////////
				break;
			case '+':
				AddSymbolNode(&current,lineNumber,PLUS,0);
				break;
			case '-':
				AddSymbolNode(&current,lineNumber,MINUS,0);
				break;
			case '*':
				AddSymbolNode(&current,lineNumber,TIMES,0);
				break;
			case '/':
				AddSymbolNode(&current,lineNumber,DIVSYM,0);
				break;
			case '(':
				AddSymbolNode(&current,lineNumber,LPAREN,0);
				break;
			case ')':
				AddSymbolNode(&current,lineNumber,RPAREN,0);
				break;
			case '=':
				AddSymbolNode(&current,lineNumber,EQL,0);
				break;
			case '[':
				AddSymbolNode(&current,lineNumber,LBRACK,0);
				break;
			case ']':
				AddSymbolNode(&current,lineNumber,RBRACK,0);
				break;
			case ';':
				AddSymbolNode(&current,lineNumber,SEMICOLON,0);
				break;
			case ',':
				AddSymbolNode(&current,lineNumber,COMMA,0);
				break;
			default:
				error(38);
		}   //switch end
	}		//while end
	Symbols=head.next; 
	CurSymbol=Symbols;
	if(nError)
	{
		printf("\n%d errors found.",nError);
		exit(2);
	}
	else
		printf("词法分析成功!\n\n");
}

void getASymbol()  //采用递归下降的语法分析,逐个的获取一个单词符号
{
	if(CurSymbol->next)
		CurSymbol=CurSymbol->next;
	else
	{
		error(43);  //语法分析没有完毕,需要标识符
		exit(3);
	}

}

void destroySymbols()  //编译完毕,将符号链表释放
{
	SymbolItem *current,*needDel;
	current=Symbols;
	while(current)
	{
		needDel=current;
		current=current->next;
		delete needDel;
	}
}


/////////////下面这三个函数是为了模拟pascal源程序中的set类型而开发的////////////

SYMLIST * listsAdd(SYMLIST * list1,SYMLIST * list2)  //两个“集合”相加,返回一个“集合”
{
	SYMLIST * temp=new SYMLIST;
	COPYLIST(temp,list1);
	temp->AddTail(list2);
	return temp;
}
		
SYMLIST * listAddSym(SYMLIST * list,SYMBOL sym)  //一个“集合”加上一个“元素”,返回一个“集合”
{
	SYMLIST * temp=new SYMLIST;
	COPYLIST(temp,list);
	temp->AddTail(sym);
	return temp;
}

int SYMINLIST(SYMBOL sym,SYMLIST * list)  //判断一个“元素”是否在“集合”里面
{
	for(POSITION pos=list->GetHeadPosition();pos;)
	{
		SYMBOL temp;
		temp=list->GetNext(pos);
		if(temp==sym)
			return 1;  //如果在,返回非零
	}
	return 0;  //不在,则返回零
}

void COPYLIST(SYMLIST * list1,SYMLIST * list2)  //“集合”之间的拷贝
{
	for(POSITION pos=list2->GetHeadPosition();pos;)
	{
		SYMBOL temp;
		temp=list2->GetNext(pos);
		list1->AddTail(temp);
	}
}


/////////////////////  主程序  ///////////////////////
int main(int argc, char* argv[])  
{
	char srcFilename[FILENAMESIZE];
	FILE *srcFile;
	char *srcFileNamePoint;

	if(argc>1)
		strcpy(srcFilename,argv[1]);
	else
	{
		printf("Please input the source file name : ");
		scanf("%s",srcFilename);
	}
	if(!(srcFile=fopen(srcFilename,"rb")))
	{
		printf("Error : source file %s not found\n",srcFilename);
		exit(1);
	}

	printf("\n第一遍:词法分析");
	getSymbols(srcFile);//第一遍,取得所有的符号,第二遍才开始语法分析和代码生成

	printf("第二遍:语法分析和代码生成\n");
	INITIAL();  //初始化
	ENTERPREID();  //预填符号表

	printf("\n**************   下面是部分的生成代码   ***************\n\n");
	if (CurSymbol->type!=PROGRAMSYM)
		error(13);  //应该是'program'
	getASymbol();
	if(CurSymbol->type!=IDENT)
		error(14);  //应该是标识符
	getASymbol();
	if(CurSymbol->type!=SEMICOLON)
		error(1);  //应该是';'
	else 
		getASymbol();

	//////////////////////////////////////////////////////////
	SYMLIST * tempList3=new SYMLIST;
	COPYLIST(tempList3,listsAdd(listAddSym(&DECLBEGSYS,PERIOD),&STATBEGSYS));
	BLOCK(tempList3,0);
	delete tempList3;
	//////////////////////////////////////////////////////////

	if(CurSymbol->type!=PERIOD)
		error(8);  //应该是'.'
	if(nError==0)
	{
		for(srcFileNamePoint=&srcFilename[strlen(srcFilename)];*srcFileNamePoint!='.' && srcFileNamePoint!=srcFilename;srcFileNamePoint--)
		;
	    *srcFileNamePoint=0;  //删除后面的扩展名
		WriteCodeList(strcat(srcFilename,".lst"));
		for(srcFileNamePoint=&srcFilename[strlen(srcFilename)];*srcFileNamePoint!='.' && srcFileNamePoint!=srcFilename;srcFileNamePoint--)
			;
		*srcFileNamePoint=0;  //删除后面的扩展名
		WriteObjCode(strcat(srcFilename,".pld"));
		for(srcFileNamePoint=&srcFilename[strlen(srcFilename)];*srcFileNamePoint!='.' && srcFileNamePoint!=srcFilename;srcFileNamePoint--)
			;
		*srcFileNamePoint=0;  //删除后面的扩展名
		WriteLabelCode(strcat(srcFilename,".lab"));
		destroySymbols();
		fclose(srcFile);
		
		//printf("\n编译成功!请输入任何字符退出。");
		printf("\n编译成功!");
		
		int a=0;
		scanf("%d",a);       //一个简单的关卡,程序执行完毕后可以停下,您可以观看生成的代码,注意,代码是部分的,有些操作数没有填上去
		return 0;
	}
	destroySymbols();
	
	int b=0;
	scanf("%d",b);     //一个简单的关卡,程序执行完毕后可以停下,您可以观看生成的代码,注意,代码是部分的,有些操作数没有填上去
	return 0;
}

⌨️ 快捷键说明

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