编译原理 LL(1)分析法 C++实现 First集合Follow集合Select集合预测分析表分析过程 实验报告(基于头歌实验修改)

 代码下载链接:链接

LL(1)分析 实验报告 C++实现
一、实验目的
二、实验要求
三、理论依据
3.1 自顶向下分析与LL(1)分析法
3.2 开始符号集First
3.3 后跟符号集Follow
3.4 可选符号集Select
3.5 预测分析表
四、实验步骤
4.1 求解开始符号集First
4.2 求解后跟符号集Follow
4.3 求解可选符号集Select
4.4 求解预测分析表
4.5 求解分析输入串
4.6 运行结果
五、实验代码
写在前面:
只需要代码的童鞋滑到最后便是;
需要借鉴思路的童鞋看第四部分便是;
想搞清几个概念的童鞋看第三部分便是。

一、实验目的
根据某一文法编制调试LL(1)分析程序,以便对任意输入的符号串进行分析。本次实验的目的主要是加深对预测分析LL(1)分析法的理解。

二、实验要求
手动输入文法(从文件读取)
显示文法的非终结符的First集
显示文法的非终结符的Follow集
显示规则的Select集合
构造预测分析表
对任意输入的符号串进行分析
三、理论依据
3.1 自顶向下分析与LL(1)分析法
自顶向下分析:从文法的开始符号出发,根据当前的输入串,确定下一步选择什么样的产生式替换对应的非终结符以向下推导。(如何从根节点出发根据当前输入串如何构造一棵语法树)

上图就是从开始符号S开始,根据输入串W使用自顶向下分析推导的语法树

LL(1)分析法是一种自顶向下语法分析方法,它的含义是:
第一个L:从左向右扫描输入串;
第二个L:分析过程中使用最左推导;
括号中的1:只需要向右看一个字符就可以确定如何推导。

3.2 开始符号集First
定义: First(β)是β的所有可能推导的开头终结符或可能的є

First(β)={a︱β -> ay,a∈Vt,y∈V* }
1
意义:若关于同一非终结符有多条产生式,可以根据输入符号是属于哪一产生式右部的first集来唯一确定。(first集合不相交)

3.3 后跟符号集Follow
定义:Follow(U)为所有含有U的句型中紧跟在U之后的终结符号或#组成的集合。

FOLLOW(A)={ a | S… Aa …,a∈VT }
1
意义:若关于同一非终结符有多条产生式,如果右部为空,也可以根据输入符号是属于哪一产生式左部的follow集合来唯一确定。(follow集合不相交)

3.4 可选符号集Select
定义:可以选用该产生式进行推导的输入符号的集合。

Select(A→β)= 
(1)First(β),当β不为空符号串
(2)Follow(A),当β为空符号串
1
2
3
意义:比如上面式子表示,First(β)或者Follow(A)集合中的元素,可以使用A→β这条产生式进行推导。

用于判定:必须唯一确定产生式才能成功地推导下去,所以同一个非终结符开始的产生式的select集合不能有交集。

3.5 预测分析表
定义:根据分析栈栈顶元素,以及当前输入串字符,可以唯一确定一条产生式。把所有可能的情况总结成为一张表,就是预测分析表。
不能推导的格子写成ERR。分析输入串的时候就只需要查询这张表。前面求的几个非终结符集合都是构建起这个表的基础。

四、实验步骤
4.1 求解开始符号集First
总体思路:

1、如果X∈Vt,FIrst(X)=X;
2、如果X∈Vn,X→a…,FIrst(X)=a;
3、如果X∈Vn,X→ε,则ε∈FIrst(X)
4、如果X∈Vn,X→Y 1 Y_1Y 
1

 Y 2 Y_2Y 
2

 Y 3 Y_3Y 
3

 ,
如果Y 1 Y_1Y 
1

 ,Y 2 Y_2Y 
2

 →ε,则FIrst(Y 1 Y_1Y 
1

 )∪FIrst(Y 2 Y_2Y 
2

 )-{ε}∈FIrst(X)
如果Y 1 Y_1Y 
1

 ,Y 2 Y_2Y 
2

 ,Y 3 Y_3Y 
3

 →ε,则FIrst(Y 1 Y_1Y 
1

 )∪FIrst(Y 2 Y_2Y 
2

 )∪FIrst(Y 3 Y_3Y 
3

 )∪{ε}∈FIrst(X)
Y更多就以此类推
5、重复上述步骤直到First集合不再增大
求解思路:以vn为例

遍历文法的非终结符集合,逐个求解,将结果插入到FIRST集合。

结果使用一个set<char>进行存储。
FIRST集合使用一个unordered_map哈希表存储,键为非终结符,值为所求得的结果。

逐个求解:
1、获取vn的所有右部,进行分析
2、遍历右部,一个个右部分析,各自求解first集加入到results
2.1 遍历当前右部(一个个字符分析)
如果第一个字符是终结符,加入first集合并且跳出循环;(这里会添加多余的空符)
如果是非终结符,则递归处理;
如果非终结符可以推空还需要循环处理该右部的下一字符(如果有)
3、遍历结束,最后如果该字符不能推空,就要删除results中的空符;返回result
流程图:大体如下,详细实现见代码。

4.2 求解后跟符号集Follow
总体思路:

1、如果X是开始符号,#∈Follow(X);
2、如果A→αXβ,则First(β) - {ε} ∈ Follow(X);如果β可以推空,Follow(A)∈Follow(X)
3、重复上述步骤直到Follow集合不再增大
求解思路:

遍历文法的非终结符集合,逐个求解,将结果插入到FOLLOW集合。然后完善follow集合直到follow集合不再增大。

结果使用一个set进行存储。
FOLLOW集合也使用一个unordered_map哈希表存储,键为非终结符,值为所求得的结果。

逐个求解:
1、对于开始符号,把#加到results
2、遍历当前文法所有的右侧表达式,
遍历当前右部进行分析,如果发现了vn,则可进行下一步骤以获取results元素
如果当前字符vn是最后一个字符,说明位于句尾,则把#加入,否则遍历vn后的字符
如果遇到终结符,直接加入到results,并break退出循环
否则就是非终结符,那么求其first集合,去掉空后加入到results;此时还要考虑是继续循环还是跳出循环:
如果当前字符可以推空,而且不是最后一个字符,说明还要继续分析下一个字符
如果可以推空但是是最后一个字符,那么把#加入results
如果不可以推空,直接跳出循环即可(可以推空,后面字符的first集合才有可能作为vn的follow集合)
3、遍历完成,返回results;
4、完善follow集合:对于所有非终结符,若遇到后面没有字符,或者是一个可推空的字符,还要把左部的follow集合加入结果集。
5、往复第4步直到follow集不再变大。(这个地方使用递归求解时会由于文法的右递归陷入死循环,所以就先求一遍不考虑思路2中β推空的情况,求解第一遍follow,然后在完善follow集合的过程中考虑进去)
流程图

完善Follow集合流程图


4.3 求解可选符号集Select
总体思路

对一条产生式:A→β

如果β不可以推空,select(A→β) = first(β)
如果β可以推空,select(A→β) = (first(β)-{ε})∪follow(A)
求解思路

得到产生式的left和right
遍历右部产生式,首先分析右部第一个字符:right[0]
2.1 如果是终结符:(如果为空符,则把follow(left)加入results,否则直接把该符号加入到results),然后break
2.2 如果是非终结符:把first(right[0])-’~'加入到results;如果还可以推空,则要继续往后看(continue)。如果是最后一个字符,则把follow(left)加入results
流程图


4.4 求解预测分析表
总体思路

Select(A→BC)={a,b,c}表示:
栈顶元素为A的时候,如果输入串当前字符是a或b或c,就可以确定选用A→BC进行推导。
预测分析表就是遍历所有select将所有情况一一存储得到的。

求解思路

遍历select集合
获取left和->right;以及对应的终结符集合chars
遍历chars,获取单个字符ch:
把left和ch配对作为TABLE的键,而->right作为值
流程图


4.5 求解分析输入串
总体思路

首先把#和开始符S放入分析栈,设输入串的字符ch,进入分析,过程中:
对于栈顶元素X进行分析,如果是和ch一样的终结符说明匹配成功,否则要看能否推导(查预测分析表是否有东西)。如果能推导,产生式逆序进栈,否则文法不能接受该字符串,分析完成。
最后如果分析栈和输入串都只剩下#,就说明匹配成功,当前文法接受该字符串。
求解思路

构建先进后出栈,将#、S进栈
遍历句子,一个个符号送a;和栈顶送X,进入分析
2.1 如果X是终结符
如果和a相等,说明匹配成功:X出栈,并读取下一个字符;
否则是无法匹配:失败退出
2.2 如果X是末尾符
a也是末尾符,接受分析字符串:成功退出
a不是末尾符,不接受分析字符串,失败退出
2.3 否则X就是非终结符
查找预测分析表,看是否有表达式
如果没有,分析出错,失败退出
如果有,X元素出栈,表达式逆序进栈,继续循环句子且要重复分析a
遍历完成,程序结束
流程图


4.6 运行结果
文法 grammar.txt:

E->TG
G->+TG
G->~
T->FS
S->*FS
S->~
F->(E)
F->i

输入串:

i*(i+i)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值