近日学习过编译原理的词法分析之后,需要编写一个词法分析器来识别相应的Token。
以下是具体的实验要求:
并且给出了样例输入与样例输出
样例输入:
样例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;
}