词法分析器

69 阅读10分钟

近日学习过编译原理的词法分析之后,需要编写一个词法分析器来识别相应的Token。
以下是具体的实验要求:

1d8f6596ed2729fff16bd49191ff997.png

并且给出了样例输入与样例输出
样例输入:

样例1输入:
120+10.3*12.3e-1;

样例2输入:
a="xyz";

样例3输入:
int a=12.1; float b=15e2, c=0x15e2;

样例4输入:
int a='label';

样例输出:

样例1输出:
Token :(C1 1)(P 8)(C2 1)(P 9)(C2 2)(P 13)
I :
C1 :120
C2 :10.3 12.3e-1
CT :
ST :

样例2输出:
Token :(I 1)(P 11)(ST 1)(P 13)
I :a
C1 :
C2 :
CT :
ST :xyz

样例3输出:
Token :(K 1)(I 1)(P 11)(C2 1)(P 13)(K 4)(I 2)(P 11)(C2 2)(P 12)(I 3)(P 11)(C1 1)(P 13)
I :a b c 
C1 :5602 
C2 :12.1 15e2 
CT :
ST :

样例4输出:
ERROR

实验的思路:
首先,我们应该从键盘上读取一个含有空格的字符串,然后用string类型来存储他
其次,我们应该编写适当的函数,来扫描这个字符串,从而识别相应的信息,例如Token等等。既然是需要扫描这个字符串,肯定就需要用到循环了。这里我们采用do while循环,while循环应该也可以,循环结束条件就是循环控制变量i和识别的字符串的长度一致
循环里边具体需要干什么呢?当然是识别不同的单词的Token。我们这里主要有七类单词,分别是:关键字、界符、标识符、整数(包括十六进制的数),小数(包括科学计数法的小数),字符常量,字符串常量
这些单词又可以进行归类,归并成字母类、数字类、界符、字符类和字符串类。字母类包含了标识符和关键字。数字类包括了十进制整数、十六进制整数、小数、科学计数法的小数。
当string串识别到的第一个元素是字母时,他毫无疑问就是字符类,也就是这个单词可能是标识符或者关键字。因此我们需要利用循环继续识别后边的元素

最近事多,先放代码,思路有空会更新的

#include<iostream>
#include<cmath>
//a='a'+"and"+'c'
using namespace std;
//关键字表 
string key[14] = { "int","void","break","float","while","do","struct","const","case","for","return","if","default","else" };
//界符表 
string para[20] = {"-","/","(",")","==","<=","<","+","*",">","=",",",";","++","{","}",":","?","|" ,"."};//读到右边的大括号是十六个界符 
//标志符表 
string iden[8];
//常整数表 
string c1[8];//A
//常实数表 //B
string c2[10];
//字符常量表 
string ct[8];
//字符串常量表 
string st[8]; 


//要编译的串中的第i个字符 
int i=0;
//单词自身字符串
string token;

//关键字表中第key_n个关键字 
int key_n;
//界符表 
int para_n;
//标识符表中第iden_n个关键字
int iden_n; 
//常整数表中第c1_n个关键字 
int c1_n ;
//常实数表中第c2_n个关键字 
int c2_n ;
//字符常量表 中第ct_n个关键字 
int ct_n ;
//字符串常量表 中第st_n个关键字 
int st_n ;


//单词的种别
char syn;

//十六进制的和 
int sum_16=0; 
int wrong_flag=0;//wrong_flag=0则编译过程没有错误,最后可以输出字符表一类的东西
int addsub_flag=0;//有几个加减号就是几 


bool IsLetter(char ch);  //判断是否为字母
bool IsDigit(char ch);  //判断是否为数字
bool IsPara(char ch);
void scan(string str);
int caculate16(string token);
bool IsRepeatIden(string token,string iden[]);//判断是不是重复的标识符 
bool IsRepeatConst(string token,string c[],int c_n);//看看token串和c[]数组里边有没有相同的元素,有就返回1 
bool IsRepeatChar(string token,string ct[],int ct_n);//看看ct[]数组里边有没有和token重复的 
bool IsRepeatString(string token,string st[],int st_n);//看看st[]数组里边有没有和token重复的 

int main()
{
	string str;
	getline(cin, str);//用于接收含空格的字符串 
	 
	while(i!=str.size())
	{
		scan(str);
	}
	if(wrong_flag==1 )
	{
		
		cout<<"ERROR";
		return 0;
	}
	i=0;
	key_n=0;
//界符表 
	 para_n=0;
//标识符表中第iden_n个关键字
	iden_n=0; 
//常整数表中第c1_n个关键字 
	c1_n =0;
//常实数表中第c2_n个关键字 
	c2_n=0;
//字符常量表 中第ct_n个关键字 
	ct_n=0;
//字符串常量表 中第st_n个关键字 
	st_n=0;
	addsub_flag=0;//有几个加减号就是几 
	wrong_flag=0;
	//cout<<"str: "<<str<<endl;
	cout<<"Token :";
	do
	{
		scan(str);
		
		
		switch(syn)
		{
			
			cout<<"Token :";

			case 'K'://关键字表 
					cout<<'('<<"K"<<' '<<key_n <<')';
					break ;
				
				
				
			case 'P'://界符表 
				cout<<'('<<"P"<<' '<<para_n <<')';
				break ;
			case 'I'://标识符表 
				cout<<'('<<"I"<<' '<<iden_n <<')';
				break ;
			case 'A'://常整数表C1 
				cout<<'('<<"C1"<<' '<<c1_n <<')';
				break;
			
			case 'B'://常实数表C2 
				cout<<'('<<"C2"<<' '<<c2_n <<')';
				break;
			
			case 'E'://E代字符常量表CT 
				cout<<'('<<"CT"<<' '<<ct_n <<')';
				break ;
			case 'F'://字符串常量表ST 
				cout<<'('<<"ST"<<' '<<st_n <<')';
				break ;
			
			//default
			
		}
		
	}while(i!=str.size());
	
	
		cout<<endl;
		cout<<"I :";
		for(int cnt=0;cnt<iden_n;cnt++)
		{
			cout<<iden[cnt]<<" ";
		}
		cout<<endl;
		cout<<"C1 :";
		for(int cnt=0;cnt<c1_n;cnt++)
		{
			cout<<c1[cnt]<<" ";
		}
		
		cout<<endl;
		cout<<"C2 :";
		for(int cnt=0;cnt<c2_n;cnt++)
		{
			cout<<c2[cnt]<<" ";
		}
		
		cout<<endl;
		cout<<"CT :";
		for(int cnt=0;cnt<ct_n;cnt++)
		{
			cout<<ct[cnt]<<" ";
		}
		
			cout<<endl;
		cout<<"ST :";
		for(int cnt=0;cnt<st_n;cnt++)
		{
			cout<<st[cnt]<<" ";
		}
	
		
	return 0;
}
void scan(string str)
{
	
	int cnt=0;
	int flag_danyinhao=0; //为0则说明之前没见到过单引号,
	int flag_shuangyinhao=0;// 为0则说明之前没见到过双引号,
	if (str[i]==' ')
	{
		syn =' ';
		i++;
	}
	
	else
	{
		int flag=0;
		
		//12 0x12be 22.34 34.56e+23
		if(IsDigit(str[i]))//第一位是数字 
		{
			token="";
			//十六进制数 
			syn='A';
			if(str[i]=='0'&&str[i+1]=='x')
			{
			
				token="";
			
				//syn='A';
				while(IsDigit(str[i])||str[i]=='x'||(str[i]>='a'&&str[i]<='f'))
				{
					token+=str[i];
					i++; 
				}
				
				token=to_string(caculate16(token));//将原来的16进制的字符串型的数据转换成了十进制的字符串数据存到token里边 
				
				if(!IsRepeatConst(token,c1,c1_n)) //不重复的话才能新增 
				 	c1[c1_n++]=token;
			}
			
			//处理整数
			
			else if(IsDigit(str[i])||str[i]=='.') 
			{
				int flag_e=0;//flag=0说明没有遇到e ,碰到加号减号的要终止 
				syn=0;
				while(IsDigit(str[i])||str[i]=='.'||str[i]=='+'||str[i]=='-'||str[i]=='e')
			//	while(IsDigit(str[i])||str[i]=='.')
				{
					if(IsDigit(str[i]))
					{
						token+=str[i];
						i++;
						if(syn!='B')
							syn='A';
					}
					else if(str[i]=='.')
					{
						token+=str[i];
						i++;
						syn='B';
					}
					
					else if(str[i]=='e')
					{
						flag_e=1;
						token+=str[i];
						i++;
						syn='B'; 
					}
					
					else if((str[i]=='+'||str[i]=='-')&&flag_e==1)
					{
						token+=str[i];
						if(str[i]=='+'||str[i]=='-')
						{
							addsub_flag++;
						}
							
						i++;
						syn='B'; 
					}
					else
					{
						break;
					}
				}
				if(addsub_flag>1)
				{
					wrong_flag=1;
				}
//				1
			} 
			
			//cout<<token<<" "<<"syn="<<syn<<" "<<"cnt="<<cnt;
			
			if(syn=='A')
			{
				if(!IsRepeatConst(token,c1,c1_n))
				{
				 //不重复的话才能新增 
				 	c1[c1_n++]=token;
				}
			}
			
			if(syn=='B')
			{
				if(!IsRepeatConst(token,c2,c2_n))
				{
				 //不重复的话才能新增 
				 	c2[c2_n++]=token;
				}
			}

		}
		
		
		else if(IsLetter(str[i])) //遇上字母
		{
			
			key_n=0;
			
			
			token = ""; //清空当前字符串
			while (IsDigit(str[i]) || IsLetter(str[i])) 
			{
					token += str[i];   //加入token字符串
					i++;
			}
			//str[i] = '\0';  //刚刚上面最后i++了所以补充
			syn='I';
			
			//关键字 
			for (int j = 0; j < 14; j++)
			{
				
				if (token==key[j])    //如果都是string类型,可以直接=相比较,若相等则返回1,否则为0 
				{
					syn = 'K';   
					key_n=j+1;
					flag=1; 
					break;
				}
			}
			//标识符  
			if(flag==0&&syn=='I')
			{
			 	if(!IsRepeatIden(token,iden)) //不重复的话才能新增 
			 	iden[iden_n++]=token;
			}
		}
		
		else if(str[i]=='\'')//遇上单引号了,说明是字符常量 
		{
			token="";
			if(flag_danyinhao==0)
			{
				i++;
				//i=i+2;
			} 
			else
			{
				flag_danyinhao=0;
			}
			
			if(IsLetter(str[i])&&str[i+1]=='\'')
			{
				syn='E';
				token+=str[i];
				i++;
			}
			else
			{
				wrong_flag=1;
			}
//			else
//			{
//				syn='W';
//				wrong_flag=1;//表示有有错误,必须只输出error 
//				cout<<"ERROR";
//			}
			i++;
			if(!IsRepeatChar(token,ct,ct_n)) //字符常量不重复的话才能新增 
			 	ct[ct_n++]=token;
			
		}
		
		else if(str[i]=='\"')//遇上双引号,就是遇上了字符串常量 
		{	token="";
			i++;
			while((IsLetter(str[i])||IsPara(str[i])||IsDigit(str[i]))&&str[i]!='\"')//a="xyz";'\"'
			{
				token+=str[i] ;
				syn='F';
				i++;
			} 
			i++;
			st[st_n++]=token;
		//	cout<<"11111"<<str[i]<<"22222"<<endl;
//			token="";
//		
//			if(flag_shuangyinhao==0)
//			{
//				i++;
//			} 
//			else
//			{
//				flag_shuangyinhao=0;
//			}
//			
//
//			while(str[i]!='\"')//a="xyz";'\"'
//			{
//				token+=str[i] ;
//				syn='F';
//				i++;
//			} 
//			token+='\0'; 
//		
//			
//			cout<<token<<"   ";
//			st[0]=token;
//				
			
		}
		else//界符 
		{
			token = ""; //清空当前字符串
			
			switch (str[i]) 
			{
				case'=':
					syn = 'P';
					i++;
					token = "=";
					if (str[i] == '=') 
					{
						
						i++;
						token = "==";
					}
					
					for (int j = 0; j < 16; j++)
					{
						
						if (token==para[j])    //如果都是string类型,可以直接=相比较,若相等则返回1,否则为0
						{
							
							para_n=j+1; 
							break;
						}
					}
					break;
					
				case '+':
					syn = 'P';
					i++;
					token = "+";
					if (str[i] == '+') 
					{
						
						i++;
						token = "++";
					}
					
					
					for (int j = 0; j < 16; j++)
					{
						
						if (token==para[j])    //如果都是string类型,可以直接=相比较,若相等则返回1,否则为0
						{
							
							para_n=j+1; 
							break;
						}
					}
					break;
					
				case '-':
					syn = 'P';
					i++;
					token = "-";
						
						
					for (int j = 0; j < 16; j++)
					{
							
						if (token==para[j])    //如果都是string类型,可以直接=相比较,若相等则返回1,否则为0
						{
								
							para_n=j+1; 
							break;
						}
					}
					break;	
				case '/':
					syn = 'P';
					i++;
					token = "/";
		
					for (int j = 0; j < 16; j++)
					{
							
						if (token==para[j])    //如果都是string类型,可以直接=相比较,若相等则返回1,否则为0
						{
								
							para_n=j+1; 
							break;
						}
					}
					break;
				case '(':
					syn = 'P';
					i++;
					token = "(";
		
					for (int j = 0; j < 16; j++)
					{
							
						if (token==para[j])    //如果都是string类型,可以直接=相比较,若相等则返回1,否则为0
						{
								
							para_n=j+1; 
							break;
						}
					}
					break;
				case ')':
					syn = 'P';
					i++;
					token = ")";
		
					for (int j = 0; j < 16; j++)
					{
							
						if (token==para[j])    //如果都是string类型,可以直接=相比较,若相等则返回1,否则为0
						{
								
							para_n=j+1; 
							break;
						}
					}
					break;
					
				case '<':
					syn = 'P';
					i++;
					token = "<";
					if (str[i] == '=') 
					{
						
						i++;
						token = "<=";
					}
					
					
					for (int j = 0; j < 16; j++)
					{
						
						if (token==para[j])    //如果都是string类型,可以直接=相比较,若相等则返回1,否则为0
						{
							
							para_n=j+1; 
							break;
						}
					}
					break;
					
					
					
				case '*':
					syn = 'P';
					i++;
					token = "*";
					
					
					
					for (int j = 0; j < 16; j++)
					{
						
						if (token==para[j])    //如果都是string类型,可以直接=相比较,若相等则返回1,否则为0
						{
							
							para_n=j+1; 
							break;
						}
					}
					break;
			 
				case '>':
					syn = 'P';
					i++;
					token = ">";
					
					for (int j = 0; j < 16; j++)
					{
						
						if (token==para[j])    //如果都是string类型,可以直接=相比较,若相等则返回1,否则为0
						{
							
							para_n=j+1; 
							break;
						}
					}
					break;
					
					
				case ',':
					syn = 'P';
					i++;
					token = ",";
					
					
					
					for (int j = 0; j < 16; j++)
					{
						
						if (token==para[j])    //如果都是string类型,可以直接=相比较,若相等则返回1,否则为0
						{
							
							para_n=j+1; 
							break;
						}
					}
					break;
					
				case ';':
					syn = 'P';
					i++;
					token = ";";
					
					
					for (int j = 0; j < 16; j++)
					{
						
						if (token==para[j])    //如果都是string类型,可以直接=相比较,若相等则返回1,否则为0
						{
							
							para_n=j+1; 
							break;
						}
					}
					break;
					
				case '{':
					syn = 'P';
					i++;
					token = "{";
					
					
					for (int j = 0; j < 16; j++)
					{
						
						if (token==para[j])    //如果都是string类型,可以直接=相比较,若相等则返回1,否则为0
						{
							
							para_n=j+1; 
							break;
						}
					}
					break;
					
				case '}':
					syn = 'P';
					i++;
					token = "}";
					
					for (int j = 0; j < 16; j++)
					{
						
						if (token==para[j])    //如果都是string类型,可以直接=相比较,若相等则返回1,否则为0
						{
							
							para_n=j+1; 
							break;
						}
					}
					break;
			break;
			
			
			} //switch的大括号 

		}//else界符的大括号 	
	}//else的大括号 
}//scan的大括号 
	
bool IsRepeatString(string token,string st[],int st_n)//看看st[]数组里边有没有和token重复的 
{
	cout<<"hello";
	//a="xyz";
	int index,cnt;
	for(int index=0;index<st_n;index++)
	{
		if(token==st[index])
		{
			return true;
		}
		else//cnt记录的是不相等的次数 
		{
			cnt++;
		}
	}
	
	if(cnt==st_n)
		return false;	


}
bool IsRepeatChar(string token,string ct[],int ct_n)//看看ct[]数组里边有没有和c重复的 
{
	//cout<<"hello";
	int index,cnt;
	for(int index=0;index<ct_n;index++)
	{
		if(token==ct[index])
		{
			return true;
		}
		else//cnt记录的是不相等的次数 
		{
			cnt++;
		}
	}
	
	if(cnt==ct_n)
		return false;
}

bool IsRepeatIden(string token,string iden[])
{
	int index,cnt;
	for(int index=0;index<iden_n;index++)
	{
		if(token==iden[index])
		{
			return true;
		}
		else//cnt记录的是不相等的次数 
		{
			cnt++;
		}
	}
	
	if(cnt==iden_n)
		return false;
}

bool IsRepeatConst(string token,string c[],int c_n)
{
	int index,cnt;
	for(int index=0;index<c_n;index++)
	{
		if(token==c[index])
		{
			return true;
		}
		else//cnt记录的是不相等的次数 
		{
			cnt++;
		}
	}
	
	if(cnt==c_n)
		return false;
}


int caculate16(string token)
{
	int sum=0;
	int l=token.length();
	for(int index=l-1;index>1;index--)
	{
		if(token[index]>='0'&&token[index]<='9')
		{
			sum+=(token[index]-'0')*pow(16,l-index-1);
		}
		if(token[index]>='a'&&token[index]<='f')
		{
			sum+=(token[index]-'a'+10)*pow(16,l-index-1);
		}
	}
	
	return sum;
}
//string para[16] = {"-","/","(",")","==","<=","<","+","*",">","=",",",";","++","{","}" };
bool IsPara(char ch)
{
	string sss;
	sss="";
	sss+=ch;
	//cout<<"《"<<sss<<"》"; 
//	int cnt=0;
//	while(para[cnt]!=" ")
//	{
//		cnt++;
//	}
//	cout<<cnt;
	for(int cnt=0;cnt<20;cnt++)
	{
		if(sss==para[cnt])
		{
			return true;
		}
	}
	return false;
}
bool IsLetter(char ch)  //判断是否为字母
{
	if ((ch >= 'a'&&ch <= 'z') || (ch >= 'A'&&ch <= 'Z'))
		return true;
	else
		return false;

}

bool IsDigit(char ch)  //判断是否为数字
{
	if (ch >= '0'&&ch <= '9')
		return true;
	else
		return false;

}