1、实验目的:

(1)掌握自上而下语法分析的要求与特点。

(2)掌握LL(1)语法分析的基本原理和方法。

(3)掌握相应数据结构的设计方法。


2、实验内容:

编程实现给定算术表达式的分析器。

算术表达式文法如下:

E-->E+T|T

T-->T*F|F

F-->(E)|i


3、设计说明:

首先改写文法为LL(1)文法;构造LL(1)分析表,然后编写预测分析程序。


4、设计分析与步骤

(1)将原算术表达式方法改写为LL(1)文法为:

E-->TE'

E'-->+TE'|ε

T-->FT'

T'-->*FT'|ε

F-->(E)|i


(2)计算文法中每一个非终结符的FIRST集和FOLLOW集








FIRST



FOLLOW



E



{ (,i }



{ $,) }



E’



{ +,ε }



{ ),$ }



T



{ (,i }



{ ),+,$ }



T’



{ *,ε }



{ ),+,$ }



F



{ (,i }



{ * }



(3)构造预测分析表

1、对于规则E-->TE’,因为有E的FIRST(TE’)={(,i},所以可以置M[E,(]=E-->TE’,M[E,i]=E-->TE’

2、 对规则E’-->+TE’,有FIRST(+TE’)={+},所以有M[E’,+]=E’-->+TE’

3、对规则E’-->ε,有FOLLOW(E’)={), $},所以有M[E’, )]=E’-->ε,M[E’, $]=E’-->ε

4、对于规则T-->FT’,因为有FT’的FIRST(FT’)={(,i},所以可以置M[T,(]=T-->FT’,M[T,i]=T-->FT’

5、对规则T-->*FT’,有FIRST(*FT’)={*},所以有M[T,*]=T-->*FT’

6、对规则F-->(E),有FIRST((E))={(},所以有M[F,(]=F-->(E)

7、对规则F-->ε,有FOLLOW(F)={*},所以有M[F,*]=F-->ε






I



(



)



+



*



$



E



E-->TE’



E-->TE’















E









E’-->ε



E’-->+TE’






E’-->ε



T



T-->FT’



T-->FT’















T









T’-->ε



T’-->ε



T’-->*FT’



T’-->ε



F



F-->i



F-->(E)















(4)程序设计

用vector定义的S和Stc分别作为分析栈和用户输入栈,用string类型的STC获取用户输入的原始字符串。用string类型的二维数组存储预测分析表。

1,$和E进分析栈S,$和倒序用户输入串压入用户栈Stc

2,判断S和Stc栈顶不同时为$,如果是则下一步,如果不是则跳出判断

3,根据S和Stc栈顶元素查分析表查找规则

(1)如果查到一般规则,则进行相应的S的弹栈与压栈并比较两栈顶元素,如果相等则都弹栈

(2)如果查到含空串的规则,则S弹栈并比较两栈顶元素,如果相等则都弹栈

(3)如果查表越界则显示错误

4,重复3直到两栈顶都是$元素显示分析成功

5,提示用户输入0继续分析下一条,其它输入退出程序。


//源程序代码
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
string sheet[5][6]={{"TA","TA","","","",""}, //预测分析表
{"","","e","+TA","","e"}, /行:E,A(代表 E1),T,B(代表 T1),F
{"FB","FB","","","",""}, //列:i,(,),+,*,$
{"","","e","e","*FB","e"}, //e代表空串
{"i","(E)","","","",""}};
vector S;
vector Stc;
vector SOS;
string STC;
int YourChoice;
do{
cout<S=SOS; //S代表分析栈,每次执行用空的SOS初始化
S.push_back('$');
S.push_back('E');
STC=""; //STC代表用户的表达式
cout<<"请输入您要分析的字符串:";
cin>>STC;
STC.resize(STC.size()+1);
STC[STC.size()-1]='$';
Stc=SOS; //Stc是将STC+$倒序压入的用户输入栈
for(int x=STC.size()-1;x>=0;--x)
Stc.push_back(STC[x]);
string YY="EATBF";
string XX="i()+*$";
while(!(S[S.size()-1]=='$'&&Stc[Stc.size()-1]=='$'))
{
int i=0,j=0;
查表找到相应规则
for(i=0;i<5;++i)
if(YY[i]==S[S.size()-1])
break;
for(j=0;j<6;++j)
if(XX[j]==Stc[Stc.size()-1])
break;
if(i>=5||j>=6) //如果查找超出表
{
cout<<"出错啦!"<break;
}
else if(sheet[i][j]=="") //如果查到的为空规则
{
cout<<"出错啦!"<break;
}
else
{
///分析栈里的压栈与弹栈
S.pop_back();
for(int k=sheet[i][j].size()-1;k>=0;--k)
S.push_back(sheet[i][j][k]);
if(S[S.size()-1]==Stc[Stc.size()-1]) //一般规则
{
S.pop_back();
Stc.pop_back();
}
else if(S[S.size()-1]=='e') //含空串的规则
{
S.pop_back();
if(S[S.size()-1]!='$'&&Stc[Stc.size()-1]!='$'&&S[S.size()-1]==Stc[Stc.size()-1])
{
S.pop_back();
Stc.pop_back();
}
}
}
}

if(S[S.size()-1]=='$'&&Stc[Stc.size()-1]=='$')
cout<<"分析成功!"<cout<<"输入0继续,其它退出";
}while(cin>>YourChoice&&YourChoice==0);

return 0;
}


测试用例

(1)输入i,预期显示分析成功

(2)输入iii,预期显示出错

(3)输入a,预期显示出错

(4)输入(i),预期显示分析成功

(5)输入(a),预期显示出错

(6)输入(i+i),预期显示分析成功

(7)输入(i+i,预期显示出错

(8)输入((i*i)+i)*i,预期显示分析成功

(9)输入((((i+i*i)))),预期显示分析成功

(10)输入(i+ia,预期显示出错

(11)输入i+i*i+i*a,预期显示出错