【编译原理】实验二 语法分析器设计与实现

本次实验要求设计并实现一个递归下降分析器,用于对简单语言的词法序列进行语法检查和结构分析。实验内容包括利用C语言编写程序,处理以“#”结束的输入单词串,正确则输出“success”,错误则输出“error”。实验还包括理解并应用语法分析程序的算法思想,以及编写相关程序流程。实验报告需包含操作步骤、程序代码和问题思考。

实验类型: 设计性   实验学时:4   实验要求:必修

一、实验目的

编制一个递归下降分析程序,实现对词法分析程序所提供的单词序列的语法检查和结构分析。

二、实验内容

利用C语言编制递归下降分析程序,并对简单语言进行语法分析。

2.1 待分析的简单语言的语法

用扩充的BNF范式表示如下:

 

2.2 实验要求说明

输入单词串,以“#”结束,如果是文法正确的句子,则输出成功信息,打印“success”,否则输出“error”。

例如:

    输入  begin a:=9; x:=2*3; b:=a+x end #

    输出  success!

    输入  x:=a+b*c end #

    输出  error

三、仪器设备

计算机,C++6.0软件环境。

四、所需耗材

五、实验原理、方法和手段

语法分析程序的算法思想

(1)主程序示意图如图5-1所示。

(2)递归下降分析程序示意图如图5-2所示。

(3)语句串分析过程示意图如图5-3所示。

(4)statement语句分析程序流程如图5-4、5-5、5-6、5-7所示。

六、实验步骤

阅读实验说明,做好实验准备,然后进行编辑调试。

七、实验结果处理

演示结果并保存相关文件。

八、实验注意事项

注意数据输入格式,单词的匹配规则。

九、预习与思考题

预习:阅读课本相关内容,分析相关算法设计思想,熟悉VC++6.0使用方式。

思考题:类C语言程序的语法分析。

十、实验报告要求

1、实验报告中应包括相关操作步骤和程序代码。

2.书写实验报告时要结构合理,层次分明,在分析描述的时候,需要注意语言的流畅。

准备工作

代码

#include<iostream>
#include<string>
#include<fstream>
#include<windows.h> 
using namespace std;
//自定义定义两个改变字体颜色函数
void SetFontRed(){
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED);
} 
void SetFontWhite(){
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
}
/*词法分析器*/
#define MAXROW 100//源代码的最大行数
#define MAXTABLE 1000//符号表和常数表最大存储范围 
string ReservedWordList[6]={"begin","if","then","while","do","end"};//关键字表 
//声明全局变量 
string ScanBuffer[MAXROW];//扫描缓冲区,定义为字符串数组
struct SymbolTable{
	int code;
	string symbol;
}ST[MAXTABLE];//符号表 
struct ConstantTable{
	int code;
	int constant;
}CT[MAXTABLE];//常数表
int STi=0,CTi=0;//符号表和常数表指示器
struct Word{
	int code;
	string symbol;
	int constant;
}word;
int row=0,col=0;//搜索指示器,row指行,col指列 
int endrow;
char ch;//搜索指示器指示的当前字符 
string strToken;//当前字符串 
//声明全局函数 
void Input();//子程序过程,将源代码输入进扫描缓冲区 
void GetChar();//子过程程序,将下一输入字符读到ch中,搜索指示器前移一字符位置 
void GetDel();//子程序过程,检查ch中的字符是否为分隔符。若是,则调用GetChar直至ch中进入一个非分隔符(delimiters->分隔符) 
void Concat();//子程序过程,,将ch中的字符连接到strToken之后 
bool IsLetter();//布尔函数过程,判断ch中的字符是否为字母 
bool IsDigit();//布尔函数构成,判断ch中的字符是否为数字 
int Reserve();//整型函数过程,对strToken中的字符串查找保留字表,若它是一个保留字则返回它的编码,否则返回0值(假定0不是保留字的编码)
void Retract();//子程序过程,将搜索指示器回调一个字符位置,将ch置为空白字符 
int InsertID();//整型函数过程,将strToken中的标识符插入符号表,返回符号表指针 
int InsertConst();//整型函数过程,将strToken中的常数插入常数表,返回常数表指针
void LexicalAnalyzerProcError();//子程序过程,词法分析出错,提示错误信息 
//定义函数
void Input(){
	int op;
	cout<<"请输入数字选择输入格式"<<endl;
	cout<<"1,键盘输入"<<endl<<"2,文件输入"<<endl;
	cin>>op;
	int i=0;
	char c;//输入流中的当前字符 
	if(op==1){
		while((c=cin.get())!=EOF){
			ScanBuffer[i].push_back(c);
			if(c=='\n') i++;
		}
		endrow=--i;
	}
	else{
		fstream in;
		in.open("test.txt",ios::in);
		while(in.peek()!=EOF){
			c=in.get();
			ScanBuffer[i].push_back(c);
			if(c=='\n') i++;
		}
		endrow=--i;
	}
} 
void GetChar(){
	ch=ScanBuffer[row][col];
	col++;
} 
void GetDel(){
	while(ch=='\n'){
		row++;
		col=0;
		GetChar();
	} 
	while(ch==' '||ch=='\t') GetChar();
}
void Concat(){
	strToken.push_back(ch);
}
bool IsLetter(){
	return isalpha(ch);
}
bool IsDigit(){
	return isdigit(ch);
}
int Reserve(){
	int i;
	for(i=0;i<6;i++)
		if(ReservedWordList[i]==strToken) return i+1;
	return 10; 
}
void Retract(){
	col--;
	ch='\0'; 
}
void LexicalAnalyzerProcError(){
	SetFontRed();
	cout<<"[Error]"<<row<<" row"<<','<<col<<" col"<<endl;
	SetFontWhite();
} 
struct Word LexicalAnalyzer(){//结构体函数,向语法分析器返回一个单词的种别码和值 
	if(row!=endrow||ScanBuffer[row][col]!='\n'){
		int code,value;
		strToken="";
		GetChar();
		GetDel();
		if(IsLetter()){
			while(IsLetter()||IsDigit()){
				Concat();
				GetChar();
			}
			Retract();
			code=Reserve();
			if(code!=10){
				//value=InsertID(strToken);
				ST[STi].code=word.code=code;
				ST[STi].symbol=word.symbol=strToken;
				STi++;
				return word; 
				//cout<<'('<<code<<','<<strToken<<')'<<endl;
				//return (code,value);
			}
			else{
				ST[STi].code=word.code=code;
				ST[STi].symbol=word.symbol=strToken;
				STi++;
				return word;
				//cout<<'('<<code<<','<<strToken<<')'<<endl;
				//return (code,-);
			}
		}
		else if(IsDigit()){
			while(IsDigit()){
				Concat();
				GetChar();
			}
			Retract();
			//value=InsertConst();
			CT[CTi].code=word.code=11;
			CT[CTi].constant=word.constant=stoi(strToken);
			CTi++;
			return word;
			//cout<<'('<<11<<','<<strToken<<')'<<endl;
			//return ($INT,value);
		}
		else if(ch=='+'){
			word.code=13;
			word.symbol="+";
			return word;
			//return (13,-);
			//cout<<"(13,+)"<<endl;
		}
		else if(ch=='-'){
			word.code=14;
			word.symbol="-";
			return word;
			//return (14,-);
			//cout<<"(14,-)"<<endl;
		} 
		else if(ch=='*'){
			word.code=15;
			word.symbol="*";
			return word;
			//return (15,-);
			//cout<<"(15,*)"<<endl;
		} 
		else if(ch=='/'){
			word.code=16;
			word.symbol="/";
			return word;
			//return (16,-);
			//cout<<"(16,/)"<<endl;
		} 
		else if(ch==':'){
			GetChar();
			if(ch=='='){
				word.code=18;
				word.symbol=":=";
				return word;
				//return (18,-);
				//cout<<"(18,:=)"<<endl;
			}
			else{
				Retract();
				word.code=17;
				word.symbol=":";
				return word;
				//return (17,-);
				//cout<<"(17,:)"<<endl;
			}
		}
		else if(ch=='<'){
			GetChar();
			if(ch=='>'){
				word.code=21;
				word.symbol="<>";
				return word;
				//return (21,-);
				//cout<<"(21,<>)"<<endl;
			} 
			else if(ch=='='){
				word.code=22;
				word.symbol="<=";
				return word;
				//return (22,-);
				//cout<<"(22,<=)"<<endl;
			} 
			else{
				Retract();
				word.code=20;
				word.symbol="<";
				return word;
				//return (20,-);
				//cout<<"(20,<)"<<endl;
			}
		}
		else if(ch=='>'){
			GetChar();
			if(ch=='='){
				word.code=24;
				word.symbol=">=";
				return word;
				//return (24,-);
				//cout<<"(24,>=)"<<endl;
			} 
			else{
				Retract();
				word.code=23;
				word.symbol=">";
				return word;
				//return (23,-);
				//cout<<"(23,>)"<<endl;
			}
		}
		else if(ch=='='){
			word.code=25;
			word.symbol="=";
			return word;
			//return (25,-);
			//cout<<"(25,=)"<<endl;
		} 
		else if(ch==';'){
			word.code=26;
			word.symbol=";";
			return word;
			//return (26,-);
			//cout<<"(26,;)"<<endl;
		} 
		else if(ch=='('){
			word.code=27;
			word.symbol="(";
			return word;
			//return (27,-);
			//cout<<"(27,()"<<endl;
		} 
		else if(ch==')'){
			word.code=28;
			word.symbol=")";
			return word;
			//return (28,-);
			//cout<<"(28,))"<<endl;
		} 
		else if(ch=='#'){
			word.code=0;
			word.symbol="#";
			return word;
			//return (0,-);
			//cout<<"(0,#)"<<endl;
		}
		else LexicalAnalyzerProcError();
	}
}
/*词法分析器*/
//////////////////////////////////////////////////////////////////////////////////////////////////
/*语法分析器*/
//声明递归下降分析程序的子程序
void Parser();//语法分析器总控程序 
void ADVANCE();//把输入串指示器IP指向下一个输入符号
void ParserProcError();//语法分析器的出错处理子程序 
void P();//非终结符P的分析子程序 
void S();//非终结符S的分析子程序
void S1();//非终结符S'的分析子程序
void S2();//非终结符S"的分析子程序
void A();//非终结符A的分析子程序 
void E();//非终结符E的分析子程序 
void E1();//非终结符E'的分析子程序 
void T();//非终结符T的分析子程序 
void T1();//非终结符T'的分析子程序 
void F();//非终结符F的分析子程序 
//声明递归下降分析程序的全局变量 
struct Word IP;//输入串指示器,指示当前扫描器扫描出的单词在表中的地址
struct Word SYM;//IP当前所指的那个输入符号 
//定义函数
void ADVANCE(){
	IP=SYM=LexicalAnalyzer();
}
void ParserProcError(int op){
	SetFontRed();
	cout<<"[Error]"<<row<<" row"<<'\t';
	switch(op){
		case 1:if(SYM.code==11) cout<<"expect \'begin\' before "<<'\''<<SYM.constant<<'\''<<endl;
			   else cout<<"expect \'begin\' before "<<'\''<<SYM.symbol<<'\''<<endl;
			   break;
		case 2:if(SYM.code==11) cout<<"expect \'end\' before "<<'\''<<SYM.constant<<'\''<<endl;
			   else cout<<"expect \'end\' before "<<'\''<<SYM.symbol<<'\''<<endl;
			   break;
		case 3:if(SYM.code==11) cout<<"expect \'id\' before "<<'\''<<SYM.constant<<'\''<<endl;
			   else cout<<"expect \'id\' before "<<'\''<<SYM.symbol<<'\''<<endl;
			   break;
		case 4:if(SYM.code==11) cout<<"expect \':=\' before "<<'\''<<SYM.constant<<'\''<<endl;
			   else cout<<"expect \':=\' before "<<'\''<<SYM.symbol<<'\''<<endl;
			   break;
		case 5:if(SYM.code==11) cout<<"expect \'id|num|(\' before "<<'\''<<SYM.constant<<'\''<<endl;
			   else cout<<"expect \'id|num|(\' before "<<'\''<<SYM.symbol<<'\''<<endl;
			   break;
		case 6:if(SYM.code==11) cout<<"expect \')\' before "<<'\''<<SYM.constant<<'\''<<endl;
			   else cout<<"expect \')\' before "<<'\''<<SYM.symbol<<'\''<<endl;
			   break;
	}
	SetFontWhite();
}
/* 
单词符号 种别码 单词符号 种别码
begin	    1	   :	   17
if	        2	   :=	   18
then	    3	   <	   20
while	    4	   <>	   21
do	        5	   <=	   22
end	        6	   >	   23
id	        10	   >=	   24
num	        11	   =	   25
+	        13	   ;	   26
-	        14	   (	   27
*	        15	   )	   28
/	        16	   #	   0
*/ 
void P(){
	if(SYM.code==1){
		ADVANCE();
		S();
		if(SYM.code==6){
			ADVANCE();
			if(SYM.code==0){
				cout<<"语法正确"<<endl;
				return ;
			} 
		}
		else ParserProcError(2);//没有end 
	}
	else ParserProcError(1);//没有begin 
} 
void S(){
	S1();
	S2();
}
void S1(){
	A();
}
void S2(){
	if(SYM.code==26){
		ADVANCE();
		S1();
		S2();
	}
}
void A(){
	if(SYM.code==10){
		ADVANCE();
		if(SYM.code==18){
			ADVANCE();
			E();
		}
		else ParserProcError(4);//当前单词不是:= 
	}
	else ParserProcError(3);//当前单词不是id 
}
void E(){
	T();
	E1();
}
void E1(){
	if(SYM.code==13||SYM.code==14){
		ADVANCE();
		T();
		E1();
	}
}
void T(){
	F();
	T1();
}
void T1(){
	if(SYM.code==15||SYM.code==16){
		ADVANCE();
		F();
		T1();
	}
}
void F(){
	if(SYM.code==10) ADVANCE();
	else if(SYM.code==11) ADVANCE();
	else if(SYM.code==27){
		ADVANCE();
		E();
		if(SYM.code==28) ADVANCE();
		else ParserProcError(6);//')'不匹配 
	}
	else ParserProcError(5);//既不是id,也不是num,更不是'(' 
}
void Parser(){
	SetFontWhite();
	Input();
	ADVANCE();
	P();
}
int main(){
	Parser();
	return 0; 
}

 

实验一名称 词法分析程序(2学时) 实验目的 理解词法分析在编译程序中的作用;加深对有穷自动机模型的理解; 掌握词法分析程序的实现方法和技术。 实验内容 选择部分C语言的语法成分,设计其词法分析程序,要求能够识别关键字、运算符、分界符、标识符、常量(至少是整型常量,可以自己扩充识别其他常量)等,并能处理注释、部分复合运算符(如>=等)。单词以元式形式输出输出有词法错误的单词及所在行号。 实验要求 (1)待分析的简单的语法 关键字:begin if then while do end … 运算符和界符::= + - * / < <= > >= <> = == ; ( ) # , … 其他单词是标识符id和整型常数num,通过以下正规式定义: id=l(l|d)* (l:letter d:digit) num=dd* 空格、注释:在词法分析中要去掉。 (2)各种单词符号对应的种别编码(参考这张表,可以不同) (3)待分析的源程序: (a)int main() { int a=1,b=2; b/a; /* 注释部分*/ b>a; c=a+b; cout<<c; return 0; } (b)这个待分析程序有词法错误(选做) while ((a+15)>0) { if (2x = = 7) i3=z; } 实验名称 预测分析程序(2学时) 实验目的 掌握LL(1)文法分析思想;掌握预测分析程序的构造方法。 实验内容 设计实现能够识别表达式的预测分析程序。 实验要求 (1)总体要求: 1) 根据文法手工或程序方式构造预测分析表; 2) 采用程序方式构造预测分析表时,需计算First()和Follow()集合,有一定难度; 3) 根据预测分析表,设计实现预测分析总控程序,完成自上而下的语法分析器。 (2)文法的定义(可以选择此文法,也可以自己选择其他文法) (3)给出当输入串为:(i1+i2)*(i3+i4)的分析过程。(输出分析过程中的栈,输入串和利用的产生式等信息)
实验2 语法分析 一、 实验目的 编制一个递归下降分析程序,实现对词法分析程序所提供的单词序列的语法检查和结构分析。 实验内容 利用C语言编制递归下降分析程序,并对简单语言进行语法分析。 1、 待分析的简单语言的语法 用扩充的BNF表示如下: (1)::=beginend (2)::={;} (3)::= (4)::=ID:= (5)::={+|-} (6)::={*|/} (7)::=ID| NUM|() 2、实验要求说明 输入单词串,以“#结束,如果是文法正确句子,则输出成功信息,打印“success”,否则输出error”。 三、 结果验证 1. 输入:begin_a:=9;_x:=2*3;_b:=a+x_end# 输出success! 2. 分别验证其他错误(至少2个) 四、 语法分析程序的源程序代码 #include #include #include char prog[80],token[8]; char ch; int syn,p,m=0,n,sum=0,kk; //p是缓冲区prog的指针,m是token的指针 char *rwtab[6]={"begin","if","then","while","do","end"}; void scaner(); void factor(); void term(); void expression(); void statement(); #include #include #include char prog[80],token[8]; char ch; int syn,p,m=0,n,sum=0; //p是缓冲区prog的指针,m是token的指针 char *rwtab[6]={"begin","if","then","while","do","end"}; void scaner() { 同实验一代码 } void factor() { …完成函数代码 } void term() { ……完成函数代码 } void expression() { ……完成函数代码 } void statement() {//cout<<"调用statement,syn="<<syn<<endl; if(判断语句) {scaner(); if(syn==18) {//cout<<"syn=18"<<endl; scaner(); expression(); } else{cout<<"缺:=错误!"<<endl;kk=1;} } else {cout<<"error!"<<endl;kk=1;} return; } void yucu() {…..完成函数代码 } //return; } void lrparser() {//cout<<"调用Irparser"<<endl; if(syn==1) {scaner(); yucu(); if(syn==6){scaner(); if(syn==0&&(kk==0)) cout<<"success!"<<endl; } else {if(kk!=1) cout<<"缺end错误!"<<endl;kk=1;} } else{cout<<"缺begin错误!"<<endl;kk=1;} //return; } void main() {p=0; cout<>ch; 执行语句3; }while(ch!=&#39;#&#39;); p=0; scaner(); lrparser(); //cout<<syn<<&#39;,&#39;<<kk<<endl; }
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值