实验三 算符优先分析算法的设计与实现
一、 实验目的
根据算符优先分析法,对表达式进行语法分析,使其能够判断一个表达式是否正确。通过算符优先分析方法的实现,加深对自下而上语法分析方法的理解。
二、 实验要求
1、输入文法。可以是如下算术表达式的文法(你可以根据需要适当改变):
E→E+T|E-T|T
T→T*F|T/F|F
F→(E)|i
2、对给定表达式进行分析,输出表达式正确与否的判断。
程序输入/输出示例:
输入:1+2;
输出:正确
输入:(1+2)/3+4-(5+6/7);
输出:正确
输入:((1-2)/3+4
输出:错误
输入:1+2-3+(*4/5)
输出:错误
三、实验步骤
1、参考数据结构
char *VN=0,*VT=0;//非终结符和终结符数组
char firstvt[N][N],lastvt[N][N],table[N][N];
typedef struct //符号对(P,a)
{
char Vn;
char Vt;
} VN_VT;
typedef struct //栈
{
VN_VT *top;
VN_VT *bottom;
int size;
}stack;
2、根据文法求FIRSTVT集和LASTVT集
给定一个上下文无关文法,根据算法设计一个程序,求文法中每个非终结符的FirstVT 集和LastVT 集。
算符描述如下:
/*求 FirstVT 集的算法*/
PROCEDURE insert(P,a);
IF not F[P,a] then
begin
F[P,a] = true; //(P,a)进栈
end;
Procedure FirstVT;
Begin
for 对每个非终结符 P和终结符 a do
F[P,a] = false
for 对每个形如 P a…或 P→Qa…的产生式 do
Insert(P,a)
while stack 非空
begin
栈顶项出栈,记为(Q,a)
for 对每条形如 P→Q…的产生式 do
insert(P,a)
end;
end.
同理,可构造计算LASTVT的算法。
3、构造算符优先分析表
依据文法和求出的相应FirstVT和 LastVT 集生成算符优先分析表。
算法描述如下:
for 每个形如 P->X1X2…Xn的产生式 do
for i =1 to n-1 do
begin
if Xi和Xi+1都是终结符 then
Xi = Xi+1
if i<= n-2, Xi和Xi+2 是终结符, 但Xi+1 为非终结符 then
Xi = Xi+2
if Xi为终结符, Xi+1为非终结符 then
for FirstVT 中的每个元素 a do
Xi < a ;
if Xi为非终结符, Xi+1为终结符 then
for LastVT 中的每个元素 a do
a > Xi+1 ;
end
4、构造总控程序
算法描述如下:
stack S;
k = 1; //符号栈S的使用深度
S[k] = ‘#’
REPEAT
把下一个输入符号读进a中;
If S[k] VT then j = k else j = k-1;
While S[j] > a do
Begin
Repeat
Q = S[j];
if S[j-1] VT then j = j-1 else j = j-2
until S[j] < Q;
把S[j+1]…S[k]归约为某个N,并输出归约为哪个符号;
K = j+1;
S[k] = N;
end of while
if S[j] < a or S[j] = a then
begin k = k+1; S[k] = a end
else error //调用出错诊察程序
until a = ‘#’
5、对给定的表达式,给出准确与否的分析过程
6、给出表达式的计算结果。(本步骤可选作)
代码
#include <bits/stdc++.h>
using namespace std;
//定义一个非终结符的结构体
typedef struct{
char left;//非终结符
int rcount;//右边式子数量
char right[200][200];//右边
int fvtcount;
int lvtcount;
char firstvt[200];//firstvt集合
char lastvt[200];//lastvt集合
}grammar;
grammar gramSet[200];//产生式集
//变量的定义
int gramcount=0;//产生式数量初始化
int tersymcount=0;//终结符数量初始化
int nontercount=0;//非终结符数量初始化
char terSymbol[200];//终结符号
char nonter[200];//非终结符号
char table[200][200];//分析表
char test[500];//要处理的字符串
map<char, bool> isfvted;//该非终结符是否已经求过其firstvt集
map<char, bool> islvted;//是否求过lastvt集
//函数的定义
void read();//读入数据
bool judgesymbol(char ch);//判断终结符和非终结符
void symbolsort(char ch);//字符归类
void Firstvt(char sym);//求sym的first集
void Addfvt(char sym, char ch);//firstvt(ch)并入firstvt(sym)
void Lastvt(char sym);//求sym的lastvt集
void Addlvt(char sym, char ch);//lastvt(ch)并入lastvt(sym)
void Table();//创建算符优先分析表
void Show();//打印分析表
void MainControl();//总控程序
int main(int argc, char** argv) {
cout<<"输入文法: 以'#'结束"<<endl;
read();
cout<<"输入串(以'#'结束)为:"<<endl;
cin>>test;
for(int i=0;i<strlen(test);i++)//将输入的数字替换成i,便于分析
{
if(test[i]>='0'&&test[i]<='9')
test[i]='i';
}
for(int i=0;i<gramcount;i++)
{
Firstvt(gramSet[i].left);
}
for(int i=0;i<gramcount;i++)
{
Lastvt(gramSet[i].left);
}
cout<<endl;
cout<<"FirstVT集如下:"<<endl;
for(int i=0;i<gramcount;i++)
{
cout<<"FirstVT("<<gramSet[i].left<<")"<<": ";
for(int j=0;j<gramSet[i].fvtcount;j++)
cout<<gramSet[i].firstvt[j]<<" ";
cout<<endl;
}
cout<<endl;
cout<<"LastVT集如下:"<<endl;
for(int i=0;i<gramcount;i++)
{
cout<<"LastVT("<<gramSet[i].left<<")"<<": ";
for(int j=0;j<gramSet[i].lvtcount;j++)
cout<<gramSet[i].lastvt[j]<<" ";
cout<<endl;
}
cout<<endl;
cout<<"算符优先分析表如下:"<<endl;
Table();
Show();
cout<<endl;
cout<<"分析步骤如下:"<<endl;
MainControl();
return 0;
}
//读入数据
void read()
{
char str[100];
while(1)
{
cin>>str;
if(str[0]=='#')
break;
gramSet[gramcount].left=str[0];
symbolsort(str[0]);//处理左边
for(int i=3;i<strlen(str);i++)//右边从str[3]处开始;str的0-2位=‘E->’
{
int j=0;
char ter[100];
while(str[i]!='|'&&str[i]!='\0')
{
symbolsort(str[i]);//处理右边
ter[j++]=str[i++];
}
ter[j]='\0';
strcpy(gramSet[gramcount].right[gramSet[gramcount].rcount],ter);
gramSet[gramcount].rcount++;
}
gramcount++;
}
}
//判断终结符和非终结符
bool judgesymbol(char ch)
{
if(ch>='A'&&ch<='Z')
return false;
return true;
}
//字符归类
void symbolsort(char ch)
{
if(!judgesymbol(ch))
{
int flag=0;
for (int i= 0;i<nontercount; i++)
{
if (ch==nonter[i])
{
flag=1;
break;//已在非终结符集中
}
}
if(flag==0)
{
nonter[nontercount++]=ch;
isfvted.insert(pair<char, bool>(ch, false));
islvted.insert(pair<char,bool>(ch, false));
}
}
else
{
int flag=0;
for (int i=0;i<tersymcount; i++)
{
if (ch==terSymbol[i])
{
flag = 1;
break;//已在终结符集中
}
}
if (flag==0)
{
terSymbol[tersymcount++]=ch;
}
}
}
//求FirstVT集
void Firstvt(char sym)
{
int i;
for(i=0;i<gramcount;i++)
{
if(gramSet[i].left==sym)
break;//找到了该非终结符的位置
}
//处理每个产生式
for(int j=0;j<gramSet[i].rcount;j++)
{
char ch=gramSet[i].right[j][0];//获取右部第一个字符
//字符为终结符
if(judgesymbol(ch))
{
int flag=0;
for (int n=0; n<gramSet[i].fvtcount;n++)
{
if (gramSet[i].firstvt[n] == ch)
{
flag = 1;//已在firstvt集中
break;
}
}
if(flag==0){
gramSet[i].firstvt[gramSet[i].fvtcount++]=ch;//把终结符加进FIRSTVT集
}
}
//字符ch为非终结符
else
{
if(ch!=sym)
{
//还没有求过ch的firstvt集
if(!isfvted[ch])
Firstvt(ch);
//firstvt(ch)并入firstvt(sym)
Addfvt(sym,ch);
}
//P->Qa的情况
char ch1=gramSet[i].right[j][1];
if(judgesymbol(ch1))
{
int flag=0;
for (int n=0; n<gramSet[i].fvtcount;n++)
{
if (gramSet[i].firstvt[n] == ch1)
{
flag = 1;//已在firstvt集中
break;
}
}
if(flag==0)
gramSet[i].firstvt[gramSet[i].fvtcount++]=ch1;//把终结符加进FIRSTVT集
}
}
}
isfvted[sym]=true;
}
//firstvt(ch)并入firstvt(sym)
void Addfvt(char sym,char ch)
{
int s1,s2;
int c1,c2;
//找到sym的位置
for(s1=0;s1<gramcount;s1++)
{
if(gramSet[s1].left==sym)
break;
}
//找到ch的位置
for(c1=0;c1<gramcount;c1++)
{
if(gramSet[c1].left==ch)
break;
}
for(c2=0;c2<gramSet[c1].fvtcount;c2++)
{
int flag=0;
for(s2=0;s2<gramSet[s1].fvtcount;s2++)
{
if(gramSet[s1].firstvt[s2]==gramSet[c1].firstvt[c2])
{
flag=1;
break;//已存在
}
}
//firstvt(ch)并入firstvt(sym)
if(flag==0)
{
gramSet[s1].firstvt[gramSet[s1].fvtcount++]=gramSet[c1].firstvt[c2];
}
}
}
//求sym的lastvt集
void Lastvt(char sym)
{
int i;
for(i=0;i<gramcount;i++)
{
if(gramSet[i].left==sym)
break;
}
//处理每个产生式
for(int j=0;j<gramSet[i].rcount;j++)
{
int length=strlen(gramSet[i].right[j]);
int last=length-1;
char ch=gramSet[i].right[j][last];//获取右部最后一个字符
//字符为终结符
if(judgesymbol(ch))
{
int flag=0;
for (int n=0; n<gramSet[i].lvtcount;n++)
{
if (gramSet[i].lastvt[n] == ch)
{
flag = 1;//已在lastvt集中
break;
}
}
if(flag==0){
gramSet[i].lastvt[gramSet[i].lvtcount++]=ch;//把终结符加进FIRSTVT集
}
}
//字符ch为非终结符
else
{
if(ch!=sym)
{
//还没有求过ch的lastvt集
if(!islvted[ch])
Lastvt(ch);
//lastvt(ch)并入lastvt(sym)
Addlvt(sym, ch);
}
//P->aQ的情况
if(last!=0)
{
char ch1=gramSet[i].right[j][last-1];//倒数第二位
if(judgesymbol(ch1))
{
int flag=0;
for (int n=0; n<gramSet[i].lvtcount;n++)
{
if (gramSet[i].lastvt[n] == ch1)
{
flag = 1;//已在lastvt集中
break;
}
}
if(flag==0)
gramSet[i].lastvt[gramSet[i].lvtcount++]=ch1;//把终结符加进LASTVT集
}
}
}
}
islvted[sym]=true;
}
//lastvt(ch)并入lastvt(sym)
void Addlvt(char sym, char ch)
{
int s1,s2;
int c1,c2;
for(s1=0;s1<gramcount;s1++)//找到sym的位置
{
if(gramSet[s1].left==sym)
break;
}
for(c1=0;c1<gramcount;c1++)//找到ch的位置
{
if(gramSet[c1].left==ch)
break;
}
for(c2=0;c2<gramSet[c1].lvtcount;c2++)
{
int flag=0;
for(s2=0;s2<gramSet[s1].lvtcount;s2++)
{
if(gramSet[s1].lastvt[s2]==gramSet[c1].lastvt[c2])
{
flag=1;
break;
}
}
if(flag==0)
gramSet[s1].lastvt[gramSet[s1].lvtcount++]=gramSet[c1].lastvt[c2];
}
}
//创建分析表
void Table()
{
int row=tersymcount+2;//优先表的行数和列数
//分析表初始化
table[0][0]=' ';
table[0][row-1]='#';
table[row-1][0]='#';
table[row-1][row-1]='=';
//第0行
int j=1;
for(int i=0;i<tersymcount;i++)
table[0][j++]=terSymbol[i];
//第0列
int k=1;
for(int i=0;i<tersymcount;i++)
table[k++][0]=terSymbol[i];
int p;
//开始分析,填充表的内容
//对#特殊处理
for(int i=1;i<row;i++) //分析#所在的一行
{
for(int j=0;j<gramSet[0].fvtcount;j++)
{
if(table[0][i]==gramSet[0].firstvt[j])
{
table[row-1][i]='<';
break;
}
}
}
for(int i=1;i<row;i++) //分析#所在的一列
{
for(int j=0;j<gramSet[0].lvtcount;j++)
{
if(table[i][0]==gramSet[0].lastvt[j])
{
table[i][row-1]='>';
break;
}
}
}
//遍历所有产生式
for(int g=0;g<gramcount;g++)
{
//遍历一个非终结符的所有产生式
for(int i=0;i<gramSet[g].rcount;i++)
{
int n=strlen(gramSet[g].right[i]);
for(int j=0;j<n-1;j++)
{
char xi=gramSet[g].right[i][j];
char xi1=gramSet[g].right[i][j+1];
//Xi和Xi+1都是终结符
if(judgesymbol(xi)&&judgesymbol(xi1))
{
for(int r=1;r<row;r++)
{
if(table[r][0]==xi)
{
p=r;//找到xi的位置
break;
}
}
for(int l=1;l<row;l++)
{
if(table[0][l]==xi1)//找到Xi+1的位置
{
table[p][l]='=';
break;
}
}
}
if(j<n-2)
{
char xi2=gramSet[g].right[i][j+2];
if(!judgesymbol(xi1)&&judgesymbol(xi)&&judgesymbol(xi2))
{
for(int r=1;r<row;r++)
{
if(table[r][0]==xi)
{
p=r;//找到xi的位置
break;
}
}
for(int l=1;l<row;l++)
{
if(table[0][l]==xi2)//找到Xi+1的位置
{
table[p][l]='=';
break;
}
}
}
}
//Xi为终结符, Xi+1为非终结符
if(!judgesymbol(xi1)&&judgesymbol(xi))
{
int pos;
for(pos=0;pos<gramcount;pos++)
{
if(gramSet[pos].left==xi1)
break;
}
for(int r=1;r<row;r++)
{
if(table[r][0]==xi)
{
p=r;//找到xi的位置 (第p行第0列)
break;
}
}
for(int x=0;x<gramSet[pos].fvtcount;x++)//对于firstvt中的每一个元素
{
char a=gramSet[pos].firstvt[x];
for(int l=1;l<row;l++)
{
if(table[0][l]==a)//找到a的位置(第0行第l列)
{
table[p][l]='<';
break;
}
}
}
}
//if Xi为非终结符, Xi+1为终结符
if(!judgesymbol(xi)&&judgesymbol(xi1))
{
int pos;
for(pos=0;pos<gramcount;pos++)
{
if(gramSet[pos].left==xi)
break;
}
for(int r=1;r<row;r++)
{
if(table[0][r]==xi1)
{
p=r;//找到xi1的位置(第0行,p列)
break;
}
}
for(int x=0;x<gramSet[pos].lvtcount;x++)//对于lastvt中的每一个元素
{
char a=gramSet[pos].lastvt[x];
for(int l=1;l<row;l++)
{
if(table[l][0]==a)//找到a的位置(第l行,第0列)
{
table[l][p]='>';
break;
}
}
}
}
}
}
}
}
//展示分析表
void Show()
{
int row=tersymcount+2;//优先表的行数和列数
//打印表的内容
for(int k=0;k<row*11;k++)
cout<<"-";
cout<<endl;
for(int i=0;i<row;i++)
{
for(int j=0;j<row;j++)
{
cout<<table[i][j];
for(int k=0;k<9;k++)
cout<<" ";
cout<<"|";
}
cout<<endl;
for(int k=0;k<row*11;k++)
cout<<"-";
cout<<endl;
}
}
//比较s和a优先级的函数
char prio(char s,char a)
{
int row=tersymcount+2;
int i;
int j;
for(i=1;i<row;i++)
{
if(table[i][0]==s)
break;
}
for(j=1;j<row;j++)
{
if(table[0][j]==a)
break;
}
if(table[i][j]=='>')
return '>';
else if(table [i][j]=='<')
return '<';
else if(table[i][j]=='=')
return '=';
else
return 'e';
}
//总控程序
void MainControl()
{
int flag=1;
int row=tersymcount+2;
int j;
string str[100];//存储动作
str[0]="预备";
char s[100];//符号栈
for(int i=0;i<100;i++)
s[i]='\0';
int k;//符号栈的使用深度
k=0;
s[k] = '#';
char a;//存放输入串当前分析符号
int pos=0;//定位a的位置
int step=0;//步骤序号
cout << endl;
cout<<"步骤\t符号栈\t\t\t输入串\t\t\t\t动作"<<endl;
while(flag==1)
{
cout<<step++<<"\t";//打印步骤序号
cout<<s<<"\t\t\t";//打印当前符号栈
for(int i=pos;i<strlen(test);i++)//打印当前输入串
cout<<test[i];
cout<<"\t\t\t\t";
cout<<str[step-1]<<endl;
a=test[pos];
if(judgesymbol(s[k]))
j=k;
else
j=k-1;
if(prio(s[j],a)=='>')
{
string strkj;//要归约的式子
while(1)
{
char q=s[j];
if(judgesymbol(s[j-1]))
j=j-1;
else
j=j-2;
if(prio(s[j],q)=='<')
break;
}
//把S[j+1]…S[k]归约为某个N,并输出归约为哪个符号;
char N;
int flag1=1;
int flag2=1;
int flag3;
for(int K=j+1;K<=k;K++)
strkj+=s[K];
int max=strkj.length();//要归约式子的长度
for(int g=gramcount-1;g>=0;g--)
{
for(int g1=0;g1<gramSet[g].rcount;g1++)//遍历某非终结符每个产生式
{
string gram1=gramSet[g].right[g1];
int m=gram1.length();//右部产生式的长度
//右部产生式gram1与strkj需要非终结符对非终结符,终结符对终结符且终结符相等才能归约
if(max==m)//首先判断长度是否相等
{
//判断一一对应关系
int p;
for(p=0;p<max;p++)
{
if(judgesymbol(strkj[p]))//如果p位置是终结符,则需要相等
{
if(strkj[p]==gram1[p])
flag3=1;
else
flag3=0;
}
else//p位置是非终结符,则需要对应
{
if(!judgesymbol(gram1[p]))
flag3=1;
else
flag3=0;
}
if(flag3==0)
break;
}
if(flag3==1) //一一对应,则可以跳出循环
{
N=gramSet[g].left;
flag1=0;
flag2=0;
}
}
if(flag2==0)
break;
}
if(flag1==0)
break;
}
if(flag1==0)//说明可归约
{
for(int K=j+1;K<=k;K++)//将s[j+1]...s[k]移除
s[K]='\0';
k=j+1;
s[k]=N;
str[step]="归约";
}
else
flag=-1;//说明不可归约,语法错误
}
else if(prio(s[j],a)=='<'||prio(s[j],a)=='=')
{
k++;
s[k]=a;
str[step]="移进";
pos++;
}
else
flag=-1;
char start=gramSet[0].left;
if(a=='#'&&!judgesymbol(s[k])&&k==1)
{
cout<<step++<<"\t";//打印最后步骤
cout<<s<<"\t\t\t";//打印当前符号栈
for(int i=pos;i<strlen(test);i++)//打印当前输入串
cout<<test[i];
cout<<"\t\t\t\t";
cout<<str[step-1]<<endl;
flag=0;
}
}
if(flag==0)
cout<<"success!表达式正确!"<<endl;
else if(flag==-1)
cout<<"error!表达式不正确!"<<endl;
}
结果
测试数据:
文法:
E->E+T|E-T|T
T->T*F|T/F|F
F->(E)|i
#
测试输入1:
i*i+i#