1 输入任意文法,改写文法使其成为LL(1)文法。
1.1 由于老师给的应该是最适合我们联系的LL(1)文法,所以说我也是用以下文法进行分析。
E→E+T | T
T→T*F | F
F→( E ) | i
注意e在此表示‘’,也就是空,表示没有任何字符输入。
1.2 消除左递归
E--------TE’
E’----------+TE’|e
T ------------FT’
T’---------------*FT’|e
F------------------(E)|i
1.3 消除回溯
1.3.1 FIRST和FALLOW集合
1.3.2 判断
FIRST(E’)∩FOLLOW(E’)= 空集
FIRST(T’)∩FOLLOW(T’)=空集
所以上述文法式LL(1)文法
2 构造文法的预测分析表;
3 设计堆栈和预测分析表的机内表示
我将会使用MAP作为机内表示的数据结构
///E’,T’分别表示为e,t
//~表示空,也就是 无输入
map<pair<string,string>,string> forecast;
void fore_init()
{
forecast[pair<string,string>(“E”,“i”)]=“Te”;
forecast[pair<string,string>(“T”,“i”)]=“Ft”;
forecast[pair<string,string>(“F”,“i”)]=“i”;
forecast[pair<string,string>(“e”,"+")]="+Te";
forecast[pair<string,string>(“t”,"+")]="~";
forecast[pair<string,string>(“t”,"*")]="*Ft";
forecast[pair<string,string>(“E”,"(")]=“Te”;
forecast[pair<string,string>(“T”,"(")]=“Ft”;
forecast[pair<string,string>(“F”,"(")]="(E)";
forecast[pair<string,string>(“e”,")")]="~";
forecast[pair<string,string>(“t”,")")]="~";
forecast[pair<string,string>(“e”,"#")]="~";
forecast[pair<string,string>(“t”,"#")]="~";
}
4 设计并书写语法分析程序;
```cpp
#include<iostream>
#include<map>
#include<stack>
#include<cstring>
using namespace std;
///E',T'分别表示为e,t
//~表示空,也就是 无输入 ,
//这里是forecast集
map<pair<string,string>,string> forecast;
void fore_init()
{
forecast[pair<string,string>("E","i")]="Te";
forecast[pair<string,string>("T","i")]="Ft";
forecast[pair<string,string>("F","i")]="i";
forecast[pair<string,string>("e","+")]="+Te";
forecast[pair<string,string>("t","+")]="~";
forecast[pair<string,string>("t","*")]="*Ft";
forecast[pair<string,string>("E","(")]="Te";
forecast[pair<string,string>("T","(")]="Ft";
forecast[pair<string,string>("F","(")]="(E)";
forecast[pair<string,string>("e",")")]="~";
forecast[pair<string,string>("t",")")]="~";
forecast[pair<string,string>("e","#")]="~";
forecast[pair<string,string>("t","#")]="~";
}
void fore_insert(pair<string,string> a,string b)
{
forecast[a]=b;
}
///接下来构建分析栈
stack<char> analysis;
void analysis_init()
{
analysis.push('#');
analysis.push('E');
}
///接下来构建展示函数
void show(int step,stack<char> analyse,char remaining[],string Production)
{
stack<char> reanalyse;
cout<<step<<"\t\t";
while(!analyse.empty())
{
reanalyse.push(analyse.top());
analyse.pop();
}
while(!reanalyse.empty())
{
cout<<reanalyse.top();
reanalyse.pop();
}
cout<<"\t\t\t"<<remaining<<"\t\t\t"<<Production<<endl;
}
这里是逆序入栈函数
void reprod(string production)
{
int i=production.length();
for(--i;i>=0;--i)
{
analysis.push(production[i]);
}
}
///接下来构建判断函数
//输入数组
char in[1000];
void judge()
{
cin>>in;
cout<<"\n序号\t\t"<<"栈内字符\t\t"<<"余留字符\t\t"<<"所用产生式"<<endl;
int i;///这个是in的坐标,用于逐个检验字符
int j;//这个是产生时的坐标,用来逆序读入站
string prod;//这个用来接收产生式
pair<string,string> k;//这个是预测分析表的坐标
string term,nonterm;///终结符,非终结符
int step;//用来记录步骤
step=0;
i=0;
while(!analysis.empty())
{
term=analysis.top();
nonterm=in[i];
k.first=term;
k.second=nonterm;
if(forecast.find(k)!=forecast.end())
{
prod=forecast[k];///找到产生式
show(step,analysis,in+i,term+"->"+prod);///展示现在站内状况
analysis.pop();///z顶部元素出战
reprod(prod);//其他元素入站
if(analysis.top()==in[i])//如果栈顶元素和正在检验的字符一致
{
show(step,analysis,in+i,"匹配成功,出栈");///展示现在站内状况
i++;//坐标后移
analysis.pop();///z顶部元素出战
}
else if(analysis.top()=='~')
{
analysis.pop();
show(step,analysis,in+i,"空字符产生式匹配成功,出栈");///展示现在站内状况
}
else
{
//什么都不做
}
}
else
{
if(analysis.top()==in[i])//如果栈顶元素和正在检验的字符一致
{
show(step,analysis,in+i,"匹配成功,出栈");///展示现在站内状况
i++;//坐标后移
analysis.pop();///z顶部元素出战
continue;
}
else if(analysis.top()=='~')//貌似没什么用,保险一点加上了
{
analysis.pop();
show(step,analysis,in+i,"空字符产生式匹配成功,出栈");///展示现在站内状况
}
//show(step,analysis,in+i,term+"->"+prod);///展示现在站内状况
cout<<"error"<<endl;
return;
}
step++;
}
cout<<"acc"<<endl;
}
int main()
{
fore_init(); //预测分析表初始化
analysis_init();//分析栈初始化
memset(in,0,1000);
cout<<"E',T'分别表示为e,t,~表示空,也就是 无输入"<<endl;
judge();
}
5 调试并运行语法分析程序
5.1 测试数据:
5.1.1 正确数据i+i*i#
5.1.2 正确数据i*i+i#
5.1.3 正确数据 无限个i+ 最后添加一个i#
5.1.4 错误数据iiiiii
5.1.5 非法数据i+i8i
5.2 实验结果分析
分析程序中文法存储所采用的数据结构
pair和map数据结构
采用的数据结构是三维坐标,map<pair<string,string>,string> forecast;通过前两个string来唯一确定出第三个tring,也就是产生式的值。
将产生时存储到map里
forecast[pair<string,string>(“E”,“i”)]=“Te”;
forecast[pair<string,string>(“T”,“i”)]=“Ft”;
forecast[pair<string,string>(“F”,“i”)]=“i”;
forecast[pair<string,string>(“e”,"+")]="+Te";
forecast[pair<string,string>(“t”,"+")]="~";
forecast[pair<string,string>(“t”,"*")]="*Ft";
forecast[pair<string,string>(“E”,"(")]=“Te”;
forecast[pair<string,string>(“T”,"(")]=“Ft”;
forecast[pair<string,string>(“F”,"(")]="(E)";
forecast[pair<string,string>(“e”,")")]="~";
forecast[pair<string,string>(“t”,")")]="~";
forecast[pair<string,string>(“e”,"#")]="~";
forecast[pair<string,string>(“t”,"#")]="~";
接下来通过
pair<string,string> k;//这个是预测分析表的坐标
string term,nonterm;///终结符,非终结符
string prod;//这个用来接收产生式
term=analysis.top();
nonterm=in[i];
k.first=term;
k.second=nonterm;
prod=forecast[k];///找到产生式
到最后一步位置,便可以唯一确定一个字符串
Stack数据结构
栈主要用来当做分析栈
stack analysis;
void analysis_init()
{
analysis.push(’#’);
analysis.push(‘E’);
}
初始状态两个字符,按照ll1(1),文法进行操作,栈空表示接受字符串