【编译原理】语法分析实验2021-10-24

本文介绍了一个基于LL(k)文法的递归下降分析程序,程序通过词法分析和语法分析实现对源代码的解析。程序首先进行词法分析,识别各类符号和关键字,然后通过一系列的子程序对不同结构进行解析,如表达式、语句、函数定义等。程序使用了自定义的标记系统 VoidFunction 来区分有返回值和无返回值的函数。此外,程序强调了分阶段编写和测试的重要性,以避免大量错误积累。
摘要由CSDN通过智能技术生成

【文法定义】在这里插入图片描述在这里插入图片描述在这里插入图片描述

【说明】

①代码思想是基于教材P86写的递归下降分析程序,一个产生式对应一个子程序
②本文法应该是一个LL(k)文法,当我们不确定要用哪一个产生式时,就继续往后查看一两个符号来确定用哪个产生式
③代码中第一次实验《词法分析实验》的结果单词类型保存在数组token[],类型为string,对应单词存放在val[]数组,第二次实验就直接用一个整型变量q来指向当前单词
④第一次实验偷懒用了一下map,第二次实验也偷懒直接在子程序中输出
⑤本文只提供思路,请不要复制或替换名词后交上去
2021/10/29更新:
⑥parse10()和parse234()里,有个VoidFunction[],类型为map<string,int>。它是一个标记,作用是标记一个函数是“有返回的”还是“无返回的”,如果VoidFunction[函数名]为1就是无返回函数。设置这个标记的原因是:parse17<语句>定义时,要区分是“有返回”还是“无返回”;而且这样做可以把23和24就合并为234,比较简洁。
⑦写代码一定要写一部分就要运行一下,确保这部分正确了再写下一个部分,而不是全部写完了再来debug,那样的话所有的bug就会叠加起来。找错误的时候,可以在代码中输出一些有用的信息或者符号什么的,就可以准确地找到错误发生的位置,再分析为什么会这样,改完后再把输出注释掉。

【代码】

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<map>
#include <fstream>
#define endl '\n'
using namespace std;
const int MAXN=10000;

int isdigtal(char ch)
{
	if(ch>='0'&&ch<='9')return 1;
	return 0;
}
int isletter(char ch)
{
	if(ch>='a'&&ch<='z'||ch>='A'&&ch<='Z')return 1;
	return 0;
}
map <string,string>wsym;
int len=0;
char in[MAXN];			//输入流
int token_num=0;
string token[MAXN];		//词法分析token序列
string val[MAXN];
void init()
{
	wsym["const"]="CONSTTK";
	wsym["int"]="INTTK";
	wsym["char"]="CHARTK";
	wsym["void"]="VOIDTK";
	wsym["main"]="MAINTK";
	wsym["if"]="IFTK";
	wsym["else"]="ELSETK";
	wsym["do"]="DOTK";
	wsym["while"]="WHILETK";
	wsym["for"]="FORTK";
	wsym["scanf"]="SCANFTK";
	wsym["printf"]="PRINTFTK";
	wsym["return"]="RETURNTK";
	wsym["+"]="PLUS";
	wsym["-"]="MINU";
	wsym["*"]="MULT";
	wsym["/"]="DIV";
	wsym[","]="COMMA";
	wsym[";"]="SEMICN";
	wsym["("]="LPARENT";
	wsym[")"]="RPARENT";
	wsym["["]="LBRACK";
	wsym["]"]="RBRACK";
	wsym["{"]="LBRACE";
	wsym["}"]="RBRACE";	
	
	//读取文件转存in数组
	ifstream testfile("testfile.txt",ios::in);
	if(!testfile)
	{
		cout<<"open testfile.txt error!"<<endl;
		exit(1);
	}
	testfile.unsetf(ios::skipws);
	while(!testfile.eof()){
		testfile >> in[len++];
	}
	testfile.close();
	//for(int i=0;i<len;i++)cout<<i<<" "<<in[i]<<endl;
}
void cifafenxi()
{
	int p=0;
	while(p<len)
	{
		while(in[p]==' '||in[p]=='\n')p++;
		if(isletter(in[p])||in[p]=='_')
		{
			string s="";
			while(isletter(in[p])||isdigtal(in[p])||in[p]=='_')
			{
				s+=in[p++];
			}
			if(wsym[s]!="")
			{
				token[token_num] = wsym[s];
			}
			else
			{
				token[token_num] = "IDENFR";
			}
			val[token_num]=s;
			token_num++;
		}
		else if(isdigtal(in[p]))
		{
			string s="";
			int num=0;
			while(isdigtal(in[p]))
			{
				num=num*10+(in[p]-'0');	
				s+=in[p++];
			}
			token[token_num] = "INTCON";
			val[token_num]=s;
			token_num++;
		}
		else if(in[p]=='=')
		{
			if(in[p+1]=='=')//双等号
			{
				token[token_num] = "EQL";
				val[token_num]="==";
				token_num++;
				p+=2;
			}
			else 
			{
				token[token_num] = "ASSIGN";
				val[token_num]="=";
				token_num++;
				p++;
			}
		}
		else if(in[p]=='+'||in[p]=='-'||in[p]=='*'||in[p]=='/'
				||in[p]==';'||in[p]==','||in[p]=='('||in[p]==')'
				||in[p]=='['||in[p]==']'||in[p]=='{'||in[p]=='}')
		{
			string s="";s+=in[p];
			p++;
			token[token_num] = wsym[s];
			val[token_num]=s;
			token_num++;
		}
		else if(in[p]==39)//单引号
		{
			p++;
			string s="";s+=in[p];
			p++;
			if(in[p]==39)p++;
			token[token_num] = "CHARCON";
			val[token_num]=s;
			token_num++;
		}
		else if(in[p]=='"')
		{
			string s;
			p++;
			while(in[p]!='"')
			{
				s+=in[p];
				p++;
			}
			p++;
			token[token_num] = "STRCON";
			val[token_num]=s;
			token_num++;
		}
		else if(in[p]=='<')
		{
			if(in[p+1]=='=')//小于等于号
			{
				token[token_num] = "LEQ";
				val[token_num]="<=";
				token_num++;
				p+=2;
			}
			else 
			{
				token[token_num] = "LSS";
				val[token_num]="<";
				token_num++;
				p++;
			}
		}
		else if(in[p]=='>')
		{
			if(in[p+1]=='=')//大于等于号
			{
				token[token_num] = "GEQ";
				val[token_num]=">=";
				token_num++;
				p+=2;
			}
			else 
			{
				token[token_num] = "GRE";
				val[token_num]=">";
				token_num++;
				p++;
			}
		}
		else if(in[p]=='!')
		{
			if(in[p+1]=='=')//不等于号
			{
				token[token_num] = "NEQ";
				val[token_num]="!=";
			    token_num++;
				p+=2;
			}
		}
		else p++;
	}
	
	/*输出
	ofstream output("output.txt",ios::out);
	for(int i=0;i<token_num;i++)
	{
		output<<token[i]<<" "<<val[i]<<endl;
	}
	output.close();
	*/
	return;                                                                                                                                                                                          
}
int q;//token[q]==lookahead
map <string,int>VoidFunction;
void MatchToken(string expected);
void parse0();		//<字符串>
void parse1();		//<程序>
void parse2();		//<常量说明>
void parse3();		//<常量定义>
void parse4();		//<无符号整数>	
void parse5();		//<整数>
void parse6();		//<声明头部>
void parse7();		//<变量说明>
void parse8();		//<变量定义>
void parse9();		//<有返回值函数定义>
void parse10();		//<无返回值函数定义>
void parse11();		//<复合语句>
void parse12();		//<参数表>
void parse13();		//<主函数>
void parse14();		//<表达式>
void parse15();		//<项>
void parse16();		//<因子>
void parse17();		//<语句>
void parse18();		//<赋值语句>
void parse19();		//<条件语句>
void parse20();		//<条件>
void parse21();		//<循环语句>
void parse22();		//<步长>
void parse234();	//<有无返回值函数调用语句>
void parse25();		//<值参数表> 
void parse26();     //<语句列>
void parse27();     //<读语句>
void parse28();     //<写语句>
void parse29();		//<返回语句>
ofstream output("output.txt",ios::out);
void yufafenxi()
{
	q=0;
	parse1();
	output.close();
	return;
}
int main()
{
	init();
    cifafenxi();
    yufafenxi();
	return 0;
}
void parse0()
{
	//<字符串> ::=  "{十进制编码为32,33,35-126的ASCII字符}"
	MatchToken("STRCON");
	printf("<字符串>\n");
	output<<"<字符串>\n";
}
void parse1()
{
	//<程序> ::= [<常量说明>][<变量说明>]
	//				{<有返回值函数定义>|<无返回值函数定义>}<主函数>
	if(token[q]=="CONSTTK"){
		parse2();
	}
	if((token[q]=="INTTK"||token[q]=="CHARTK")&&
					token[q+1]=="IDENFR"&&token[q+2]!="LPARENT"){
		parse7();
	}
	
	while((token[q]=="INTTK"||token[q]=="CHARTK"||token[q]=="VOIDTK")&&
						token[q+1]=="IDENFR"&&token[q+2]=="LPARENT"){
		if(token[q]=="VOIDTK"){
			parse10();
		}
		else{
			parse9();
	 	}
	}
	if(token[q]=="VOIDTK"&&token[q+1]=="MAINTK"){
		parse13();
	}
	if(q==token_num){
		printf("<程序>\n");
		output<<"<程序>\n";
		return;
	}
	else{
		printf("shitbrofuckingerror");
		exit(0);
	}
}
void parse2()
{
	//<常量说明> ::=  const<常量定义>;{ const<常量定义>;}
	do{
		MatchToken("CONSTTK");
		parse3();
		MatchToken("SEMICN");
	}while(token[q]=="CONSTTK");
	printf("<常量说明>\n");
	output<<"<常量说明>\n";
	
}
void parse3()
{
	//<常量定义>   ::=   int<标识符>=<整数>{,<标识符>=<整数>}
    //                       | char<标识符>=<字符>{,<标识符>=<字符>}
	if(token[q]=="INTTK"){
		MatchToken("INTTK");
		MatchToken("IDENFR");
		MatchToken("ASSIGN");
		parse5();
		while(token[q]=="COMMA"){
			MatchToken("COMMA");
			MatchToken("IDENFR");
			MatchToken("ASSIGN");
			parse5();
		}
	}
	if(token[q]=="CHARTK"){
		MatchToken("CHARTK");
		MatchToken("IDENFR");
		MatchToken("ASSIGN");
		MatchToken("CHARCON");	
		while(token[q]=="COMMA"){
			MatchToken("COMMA");
			MatchToken("IDENFR");
			MatchToken("ASSIGN");
			MatchToken("CHARCON");
		}		
	}
	printf("<常量定义>\n");
	output<<"<常量定义>\n";
}
void parse4()
{
	//<无符号整数> ::= <非零数字>{<数字>}| 0
	if(val[q][0]=='0'&&val[q].length()>1){
		printf("error");
		exit(0);
	}
	else MatchToken("INTCON");
	printf("<无符号整数>\n");
	output<<"<无符号整数>\n";
}
void parse5()
{
	//<整数> ::= [+|-]<无符号整数>
	if(token[q]=="PLUS")MatchToken("PLUS");
	else if(token[q]=="MINU")MatchToken("MINU");
	parse4();
	printf("<整数>\n");
	output<<"<整数>\n";
}
void parse6()
{
	//<声明头部> ::=  int<标识符> |char<标识符>
	if(token[q]=="INTTK")MatchToken("INTTK");
	else if(token[q]=="CHARTK")MatchToken("CHARTK");
	MatchToken("IDENFR");
	printf("<声明头部>\n");
	output<<"<声明头部>\n";
}
void parse7()
{
	//<变量说明> ::= <变量定义>;{<变量定义>;}
	do{
		parse8();
		MatchToken("SEMICN");
	}while((token[q]=="INTTK"||token[q]=="CHARTK")&&
					token[q+1]=="IDENFR"&&token[q+2]!="LPARENT");
	printf("<变量说明>\n");
	output<<"<变量说明>\n";
}
void parse8()
{
	//<变量定义> ::= <类型标识符>
	//							  (<标识符>|<标识符>'['<无符号整数>']')
	//							{,(<标识符>|<标识符>'['<无符号整数>']')}
	if(token[q]=="INTTK")MatchToken("INTTK");
	else if(token[q]=="CHARTK")MatchToken("CHARTK");
	
	MatchToken("IDENFR");
	if(token[q]=="LBRACK"){
		MatchToken("LBRACK");
		parse4();
		MatchToken("RBRACK");
	}
	while(token[q]=="COMMA"){
		MatchToken("COMMA");
		MatchToken("IDENFR");
		if(token[q]=="LBRACK"){
			MatchToken("LBRACK");
			parse4();
			MatchToken("RBRACK");
		}
	}
	printf("<变量定义>\n");
	output<<"<变量定义>\n";
}
void parse9()
{
	//<有返回值函数定义> ::=  <声明头部>'('<参数表>')' '{'<复合语句>'}'
	parse6();
	MatchToken("LPARENT");
	parse12();
	MatchToken("RPARENT");
	MatchToken("LBRACE");
	parse11();
	MatchToken("RBRACE");
	printf("<有返回值函数定义>\n");
	output<<"<有返回值函数定义>\n";
}
void parse10()
{
	//<无返回值函数定义> ::= void<标识符>'('<参数表>')''{'<复合语句>'}'
	MatchToken("VOIDTK");
	VoidFunction[val[q]]=1;
	MatchToken("IDENFR");
	MatchToken("LPARENT");
	parse12();
	MatchToken("RPARENT");
	MatchToken("LBRACE");
	parse11();
	MatchToken("RBRACE");
	printf("<无返回值函数定义>\n");
	output<<"<无返回值函数定义>\n";
}
void parse11()
{
	//<复合语句> ::=  [<常量说明>][<变量说明>]<语句列>
	if(token[q]=="CONSTTK"){
		parse2();
	}
	if((token[q]=="INTTK"||token[q]=="CHARTK")&&
					token[q+1]=="IDENFR"&&token[q+2]!="LPARENT"){
		parse7();
	}
	parse26();
	printf("<复合语句>\n");
	output<<"<复合语句>\n";
}
void parse12()
{
	//<参数表> ::=  <类型标识符><标识符>{,<类型标识符><标识符>}| <空>
	if(token[q]!="RPARENT")//如果下一个token为右小括号,则为空
	{
		if(token[q]=="INTTK")MatchToken("INTTK");
		else if(token[q]=="CHARTK")MatchToken("CHARTK");
		MatchToken("IDENFR");
		while(token[q]=="COMMA"){
			MatchToken("COMMA");
			if(token[q]=="INTTK")MatchToken("INTTK");
			else if(token[q]=="CHARTK")MatchToken("CHARTK");
			MatchToken("IDENFR");
		}		
	}
	printf("<参数表>\n");
	output<<"<参数表>\n";
}
void parse13()
{
	//<主函数> ::= void main‘(’‘)’ ‘{’<复合语句>‘}’
	MatchToken("VOIDTK");
	MatchToken("MAINTK");
	MatchToken("LPARENT");
	MatchToken("RPARENT");
	MatchToken("LBRACE");
	parse11();
	MatchToken("RBRACE");	
	printf("<主函数>\n");
	output<<"<主函数>\n";
}
void parse14()
{
	//14<表达式> ::= [+|-]<项>{<加法运算符><项>}
	if(token[q]=="PLUS")MatchToken("PLUS");
	else if(token[q]=="MINU")MatchToken("MINU");
	parse15();
	while(token[q]=="PLUS"||token[q]=="MINU")
	{
		if(token[q]=="PLUS")MatchToken("PLUS");
		else if(token[q]=="MINU")MatchToken("MINU");
		parse15();
	}
	printf("<表达式>\n");
	output<<"<表达式>\n";
}
void parse15()
{
	//15<项> ::= <因子>{<乘法运算符><因子>}
	parse16();
	while(token[q]=="MULT"||token[q]=="DIV")
	{
		if(token[q]=="MULT")MatchToken("MULT");
		else if(token[q]=="DIV")MatchToken("DIV");
		parse16();
	}
	printf("<项>\n");
	output<<"<项>\n";
}
void parse16()
{
	//<因子> ::= <标识符>|<标识符>'['<表达式>']'
	//			|'('<表达式>')'|<整数>|<字符>|<有返回值函数调用语句> 
	if(token[q]=="IDENFR"){
		if(token[q+1]=="LBRACK"){
		MatchToken("IDENFR");
		MatchToken("LBRACK");
		parse14();
		MatchToken("RBRACK");
		}
		else if(token[q+1]=="LPARENT")parse234();
		else MatchToken("IDENFR");
	}
	else if(token[q]=="LPARENT"){MatchToken("LPARENT");parse14();MatchToken("RPARENT");}
	else if(token[q]=="INTCON"||token[q]=="PLUS"||token[q]=="MINU")parse5();
	else if(token[q]=="CHARCON")MatchToken("CHARCON");
	printf("<因子>\n");
	output<<"<因子>\n";
}
void parse17()
{
	/*<语句> ::= <条件语句>|<循环语句>| '{'<语句列>'}'
				| <有返回值函数调用语句>; |<无返回值函数调用语句>;|<赋值语句>;
				|<读语句>;|<写语句>;|<空>;|<返回语句>;
	*/
	
	if(token[q]=="IFTK")parse19();
	else if(token[q]=="WHILETK"||token[q]=="DOTK"||token[q]=="FORTK")parse21();
	else if(token[q]=="LBRACE"){MatchToken("LBRACE");parse26();MatchToken("RBRACE");}
	else if(token[q]=="IDENFR")
	{
		if(token[q+1]=="LPARENT"){parse234();MatchToken("SEMICN");}
		else {parse18();MatchToken("SEMICN");}
	}
	else if(token[q]=="SCANFTK"){parse27();MatchToken("SEMICN");}
	else if(token[q]=="PRINTFTK"){parse28();MatchToken("SEMICN");}
	else if(token[q]=="RETURNTK"){parse29();MatchToken("SEMICN");}
	else if(token[q]=="SEMICN")MatchToken("SEMICN");
	printf("<语句>\n");
	output<<"<语句>\n";
}
void parse18()
{
	//<赋值语句> ::=  <标识符>=<表达式>
	//					|<标识符>'['<表达式>']'=<表达式>
	MatchToken("IDENFR");
	if(token[q]=="LBRACK"){MatchToken("LBRACK");parse14();MatchToken("RBRACK");}
	MatchToken("ASSIGN");
	parse14();
	printf("<赋值语句>\n");
	output<<"<赋值语句>\n";
}
void parse19()
{
	//<条件语句> ::= if '('<条件>')'<语句>[else<语句>]
	MatchToken("IFTK");
	MatchToken("LPARENT");
	parse20();
	MatchToken("RPARENT");
	parse17();
	if(token[q]=="ELSETK")
	{
		MatchToken("ELSETK");
		parse17();
	}
	printf("<条件语句>\n");
	output<<"<条件语句>\n";
}
void parse20()
{
	//<条件>    ::=  <表达式><关系运算符><表达式> //整型表达式之间才能进行关系运算
    //   |<表达式>    //表达式为整型,其值为0条件为假,值不为0时条件为真                                             
	parse14();
	if(token[q]=="LSS"||token[q]=="LEQ"||token[q]=="GRE"
	 ||token[q]=="GEQ"||token[q]=="EQL"||token[q]=="NEQ"){
		MatchToken(token[q]);
		parse14();
	}
	printf("<条件>\n");
	output<<"<条件>\n";
}
void parse21()
{
	//<循环语句> ::=  while '('<条件>')'<语句>
	//					|do<语句>while '('<条件>')' 
	//					|for'('<标识符>=<表达式>;<条件>;<标识符>=<标识符>(+|-)<步长>')'<语句>
	if(token[q]=="WHILETK"){
		MatchToken("WHILETK");
		MatchToken("LPARENT");
		parse20();
		MatchToken("RPARENT");		
		parse17();
	}
	else if(token[q]=="DOTK"){
		MatchToken("DOTK");
		parse17();
		MatchToken("WHILETK");
		MatchToken("LPARENT");
		parse20();
		MatchToken("RPARENT");	
	}
	else if(token[q]=="FORTK"){
		MatchToken("FORTK");
		MatchToken("LPARENT");
		MatchToken("IDENFR");
		MatchToken("ASSIGN");
		parse14();
		MatchToken("SEMICN");
		parse20();
		MatchToken("SEMICN");
		MatchToken("IDENFR");
		MatchToken("ASSIGN");
		MatchToken("IDENFR");
		if(token[q]=="PLUS")MatchToken("PLUS");
		else if(token[q]=="MINU")MatchToken("MINU");
		parse22();
		MatchToken("RPARENT");	
		parse17();
	}
	printf("<循环语句>\n");
	output<<"<循环语句>\n";
}
void parse22()
{
	//<步长>::= <无符号整数>
	parse4();  
	printf("<步长>\n");
	output<<"<步长>\n";
}
void parse234()
{
	//<有无返回值函数调用语句> ::= <标识符>'('<值参数表>')'
	int FunctionType = VoidFunction[val[q]];
	MatchToken("IDENFR");
	MatchToken("LPARENT");
	parse25();
	MatchToken("RPARENT");
	if(FunctionType==1)output<<"<无返回值函数调用语句>\n";
	else output<<"<有返回值函数调用语句>\n";
}
void parse25()
{
	//<值参数表> ::= <表达式>{,<表达式>}|<空>
	if(token[q]!="RPARENT")
	{
		parse14();
		while(token[q]=="COMMA")
		{
			MatchToken("COMMA");
			parse14();
		}
	}
	printf("<值参数表>\n");
	output<<"<值参数表>\n";
}
void parse26()
{
	//<语句列> ::= {<语句>}
	while(token[q]!="RBRACE")parse17();
	printf("<语句列>\n");
	output<<"<语句列>\n";
}
void parse27()
{
	//<读语句> ::=  scanf '('<标识符>{,<标识符>}')'
	MatchToken("SCANFTK");
	MatchToken("LPARENT");
	MatchToken("IDENFR");
	while(token[q]=="COMMA"){
		MatchToken("COMMA");
		MatchToken("IDENFR");
	}
	MatchToken("RPARENT");
	printf("<读语句>\n");
	output<<"<读语句>\n";
}
void parse28()
{
	//<写语句> ::= printf '(' <字符串>,<表达式> ')'
	//				| printf '('<字符串> ')'
	//				| printf '('<表达式>')'
	MatchToken("PRINTFTK");
	MatchToken("LPARENT");
	if(token[q]=="STRCON")parse0();
	else parse14();
	if(token[q]=="COMMA"){MatchToken("COMMA");parse14();}
	MatchToken("RPARENT");
	printf("<写语句>\n");
	output<<"<写语句>\n";
}
void parse29()
{
	//<返回语句> ::=  return['('<表达式>')'] 
	MatchToken("RETURNTK");
	if(token[q]=="LPARENT"){MatchToken("LPARENT");parse14();MatchToken("RPARENT");}

	printf("<返回语句>\n");
	output<<"<返回语句>\n";
}
void MatchToken(string expected)
{
	if(token[q]==expected){
		cout<<token[q]<<" "<<val[q]<<endl;
		output<<token[q]<<" "<<val[q]<<endl;
		q++;
	}
	else{
		printf("shitbrofuckingerror_tm");
		exit(0);
	}
}
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值