实验目的和要求
①理解无回溯的自上而下分析算法的构造思想。
②掌握LL(1)文法的判定方法。
③理解预测分析程序的构造过程。
④能够使用某种高级语言实现一个预测分析程序。
实验内容
编写一个预测分析程序,能实现以下功能:
①给定文法G,消除文法G的左递归和左公因子;
②构造并输出各非终结符的FIRST集和FOLLOW集;
③判定文法G是否为LL(1)文法;
④构造并输出G的预测分析表;
⑤任意输入一个输入串,可得到成功的分析或错误的提示,输出其分析过程或打印语法分析树。
实现思路
默认规则:
起始符S,其余大写字母为非终结符;
小写字母为终结符,#为ε;
产生式: A->BC, 其中这个是关于A的产生式,A为左部(左边部分),BC为右部 (右边部分)
Vt是终结符
Vn是非终结符
判断左递归类型
通过右产生式第一个字符的不断寻找,判断是否存在如E->E,T->T这种情况,如果存在则为间接左递归,没有则为直接左递归。
上代码:
//主要思想:递归,在一定次数内寻找E->E的情况,存在返回8
int judBD(int b,int step,char f,char z)
{
int er;
if(step==0)
return 1;
for(int i=b%m1;i<4*m1;i++)
{
if(zg[i][0]==z)
{
for(int j=0;j<m2;j++)
{
if(zy[i][0]==fz[j][0]&&fz[j][0]!=z)
{
// printf("1111111111\n");
z=fz[j][0];
if(z==f)
return 8;
return judBD(++b,--step,f,z);
}
} return judBD(++b,--step,f,z);
}
}
return 0;
}
如题只有直接左递归,消除结果如下:
消除左递归
First集:
①简单推导
first,顾名思义就是该关于该符号的所有产生式右部第一个遇到终结符。
FOLLOW集
Follow集合是针对非终结符而言的,Follow(U)所表达的是句型中非终结符U所有可能的后随终结符号的集合,特别地,“#”是识别符号的后随符。注意Follow集合是从开始符号S开始推导。且follow集中不包含ε。
-
follow(S)收入“#”,S为开始符号。
-
形如"A->…Ua…”的组合,把a直接收入到Follow(U)中。因a是紧跟在U后的终结符。
-
形如“A->…UP…”(P是非终结符)的组合,把First (P ) 直接收入到Follow(U)中
特别,A->…UP,把follow(A)也收入follow(U) -
形如"A->…U",即以U结尾,follow(A)收入follow(U)
Select集
在求出first集和follow集后
select(X->Y),先求first(Y),如果first(Y)存在#∈first(Y)的情况,则再求follow(X),最后求两者的并集即可即可
LL(1)文法的判断:
左部符号相同的进行交集比较,如果全部交集为空,则符合LL(1)文法:
Select(S->a)∩Select(S->^)∩Select(S->(T)) = {a}∩{^}∩{ ( } = ∅
Select(N->,SN)∩Select(N->#) ={ ) }∩{ , } =∅
都为空集,因此符合LL(1)文法
预测分析表:
直接select集按预测分析表格式输出,注意:如在根据输入串得到预测分析过程时,希望有T’->+,但是实际没有这个结果,此时考虑T’->ε。
预测分析过程:
- 首先将 和 开 始 符 E 压 栈 ( 字 符 序 列 后 需 要 加 上 和开始符E压栈(字符序列后需要加上 和开始符E压栈(字符序列后需要加上),若输入的第一个字符为i,查看上面的表格,E和i对应的是E=>TE’,我们就把E出栈,把E’压栈,把T压栈(注意因为是左推导,左边的需要优先处理,所以左边的要最后压栈),重复上面的步骤,若匹配到终止字符,则将输入的字符序列的指针后移,直到匹配到最后的终止符号为止。
- 在每次进栈,出栈过程中打印栈中元素。
实验反思
1.在没有构思好大体结构时就下手,导致几次推翻重来
2.使用的结构太过基础,导致代码臃肿
实验代码
代码写的有点臃肿
https://blog.csdn.net/qq_41735944/article/details/106057197