LL(1)算法
编译原理的语法分析中一个入门的算法就是LL(1)算法了,这里做一个总结。首先比较重要的是FIRST集和FOLLOW集合的生成。
先上个例子吧:
首先说一下FIRST集的生成,这个就要看产生式右部对应的首字母的“终结符”的个数的表现了,例如:A-> +TA|-TA|k 所以 A的FIRST集为+-k ; 同理B->*FB|/FB|k,所以B的FIRST集是*/k; D的FIRST集是xyz; 接着我们再分析F,对F分析可以得FIRST集是 ( 和 D的FIRST的并集,即(xyz,同理可以得到T和E的FIRST都是(xyz。
我们接着分析FOLLOW集。首先要说一点,可以观察按照FOLLOW集按照“非终结符顺序”从上到下是递增的(这是什么规律,但是几乎所有的LL1(1)分析表都有这个现象),从上至下依次分析,对于E,观察所有的产生式的右部:有F-> (E)|D 这个式,则我们可以得知E的FOLLOW集为#). 接下来我们分析A的FOLLOW集,观察所有的产生式的右部,发现没有跟着A的终结符,哎,没办法,照抄上面的吧:即A得FOLLOW集和E的一样,都是#)。 然后我们分析T,发现T后面总是跟着A,则A的FIRST集应该包含于T的FOLLOW集中(当然,有空k的要去掉k), 再加上上面“遗传”下来的,所以T的FOLLOW集是+-#). 同理分析下去就会得到全部的非终结符的FOLLOW集。
接着是如何运用FIRST和FOLLOW集生成LL(1)分析表。首先对所有的非终结符的FIRST进行填充,并留下这些FIRST的空k符号。这一遍刷完之后,再特别处理空k,对有空k的非终结符,将它的FOLLOW集中的所有的元素,都写成空k的式输入到LL(1)分析表中去。这样就大功告成了。
不妨再贴一个例子:
题目1:
输入开始符号,非终结符,终结符,产生式,LL(1)分析表
输出LL(1)分析表
G[E]:E →E+T | E-T | T
T →T*F | T/F | F
F →(E) | D
D →x | y | z
消除左递归G1[E]:
E →TA
A →+TA | -TA | e
T →FB
B →*FB | /FB | e
F →(E) | D
D →x | y | z
输入开始符号;
非终结符个数,非终结符,空格符分隔;
终结符个数,终结符,空格符分隔;
产生式的个数,各产生式的序号,产生式的左边和右边符号,空格符分隔;
LL(1)分析表中的产生式个数,序号,行符号,列符号,产生式编号,空格符分隔;
第一行:空,安终结符循序输出终结符,结束符‘#’,每个符号占5格;
其余行:非终结符符号,各对应终结符的产生式的右边,每个符号占5格;
- E
- 6 E A T B F D
- 9 + - * / ( ) x y z
- 13
- 1 E TA
- 2 A +TA
- 3 A -TA
- 4 A k
- 5 T FB
- 6 B *FB
- 7 B /FB
- 8 B k
- 9 F (E)
- 10 F D
- 11 D x
- 12 D y
- 13 D z
- 25
- 1 E ( 1
- 2 E x 1
- 3 E y 1
- 4 E z 1
- 5 A + 2
- 6 A - 3
- 7 A ) 4
- 8 A # 4
- 9 T ( 5
- 10 T x 5
- 11 T y 5
- 12 T z 5
- 13 B + 8
- 14 B - 8
- 15 B * 6
- 16 B / 7
- 17 B ) 8
- 18 B # 8
- 19 F ( 9
- 20 F x 10
- 21 F y 10
- 22 F z 10
- 23 D x 11
- 24 D y 12
- 25 D z 13
- + - * / ( ) x y z #
- E TA TA TA TA
- A +TA -TA k k
- T FB FB FB FB
- B k k *FB /FB k k
- F (E) D D D
- D x y z
- AC代码:
- #include <iostream>
- using namespace std;
- string S=""; //开始符号
- struct { int number;string sign[]; string res_LL[][]; } not_endsign={}; //非终结符
- struct { int number;string sign[]; } end_sign={}; //终结符
- struct { int number;int order[]; string left[],right[]; } production={}; //产生式
- struct { int number;int order[]; string rank[],col[];int production_num[]; } LL={}; //LL(1)分析表
- void input();
- void print(string a);
- int main(){
- input();
- end_sign.sign[end_sign.number] = "#";
- end_sign.number++;
- //刷整个的分析表,将分析表中的数据填入到not_endsign中去
- for(int i=;i<LL.number;i++){
- //得到LL一条数据的“行”对应的“非终结符”
- int j;
- for(j=;j<not_endsign.number&& not_endsign.sign[j]!=LL.rank[i];j++ );
- //得到LL一条数据的“列”对应的“终结符”
- int z;
- for(z=;z<end_sign.number&&end_sign.sign[z]!=LL.col[i];z++ );
- //得到LL一条数据的要赋予的值
- not_endsign.res_LL[j][z] = production.right[LL.production_num[i]- ];
- }
- //单独处理“#”
- cout<<" ";
- for(int i=;i<end_sign.number;i++){
- cout<<" "<<end_sign.sign[i];
- }
- cout<<endl;
- for(int i=;i<not_endsign.number;i++){
- print(not_endsign.sign[i]);
- cout<<not_endsign.sign[i];
- for(int j=;j<end_sign.number ;j++){
- print(not_endsign.res_LL[i][j] );
- cout<<not_endsign.res_LL[i][j];
- }
- cout<<endl;
- }
- return ;
- }
- void print(string a){
- for(int i=;i<-a.length();i++){
- cout<<" ";
- }
- return ;
- }
- void input(){
- cin>>S;
- cin>>not_endsign.number;
- for(int i=;i<not_endsign.number;i++){
- cin>>not_endsign.sign[i];
- }
- cin>>end_sign.number;
- for(int i=;i<end_sign.number;i++){
- cin>>end_sign.sign[i];
- }
- cin>>production.number;
- for(int i=;i<production.number;i++){
- cin>>production.order[i]>>production.left[i]>>production.right[i];
- }
- cin>>LL.number;
- for(int i=;i<LL.number;i++){
- cin>>LL.order[i]>>LL.rank[i]>>LL.col[i]>>LL.production_num[i];
- }
- return ;
- }
题目2:
输入开始符号,非终结符,终结符,产生式,LL(1)分析表
输出LL(1)分析表
输入开始符号;
非终结符个数,非终结符,空格符分隔;
终结符个数,终结符,空格符分隔;
产生式的个数,各产生式的序号,产生式的左边和右边符号,空格符分隔;
LL(1)分析表中的产生式个数,序号,行符号,列符号,产生式编号,空格符分隔;
输入一个算术式符号串,用#结束
输出推导过程,每一步一行,中间“ & ”前是已经识别的子串,后是栈中信息。
- E
- 6 E A T B F D
- 9 + - * / ( ) x y z
- 13
- 1 E TA
- 2 A +TA
- 3 A -TA
- 4 A k
- 5 T FB
- 6 B *FB
- 7 B /FB
- 8 B k
- 9 F (E)
- 10 F D
- 11 D x
- 12 D y
- 13 D z
- 25
- 1 E ( 1
- 2 E x 1
- 3 E y 1
- 4 E z 1
- 5 A + 2
- 6 A - 3
- 7 A ) 4
- 8 A # 4
- 9 T ( 5
- 10 T x 5
- 11 T y 5
- 12 T z 5
- 13 B + 8
- 14 B - 8
- 15 B * 6
- 16 B / 7
- 17 B ) 8
- 18 B # 8
- 19 F ( 9
- 20 F x 10
- 21 F y 10
- 22 F z 10
- 23 D x 11
- 24 D y 12
- 25 D z 13
- (x+(y-x*z)*(y+x*z))+x/z#
- # & E#
- # & TA#
- # & FBA#
- # & (E)BA#
- #( & E)BA#
- #( & TA)BA#
- #( & FBA)BA#
- #( & DBA)BA#
- #( & xBA)BA#
- #(x & BA)BA#
- #(x & A)BA#
- #(x & +TA)BA#
- #(x+ & TA)BA#
- #(x+ & FBA)BA#
- #(x+ & (E)BA)BA#
- #(x+( & E)BA)BA#
- #(x+( & TA)BA)BA#
- #(x+( & FBA)BA)BA#
- #(x+( & DBA)BA)BA#
- #(x+( & yBA)BA)BA#
- #(x+(y & BA)BA)BA#
- #(x+(y & A)BA)BA#
- #(x+(y & -TA)BA)BA#
- #(x+(y- & TA)BA)BA#
- #(x+(y- & FBA)BA)BA#
- #(x+(y- & DBA)BA)BA#
- #(x+(y- & xBA)BA)BA#
- #(x+(y-x & BA)BA)BA#
- #(x+(y-x & *FBA)BA)BA#
- #(x+(y-x* & FBA)BA)BA#
- #(x+(y-x* & DBA)BA)BA#
- #(x+(y-x* & zBA)BA)BA#
- #(x+(y-x*z & BA)BA)BA#
- #(x+(y-x*z & A)BA)BA#
- #(x+(y-x*z & )BA)BA#
- #(x+(y-x*z) & BA)BA#
- #(x+(y-x*z) & *FBA)BA#
- #(x+(y-x*z)* & FBA)BA#
- #(x+(y-x*z)* & (E)BA)BA#
- #(x+(y-x*z)*( & E)BA)BA#
- #(x+(y-x*z)*( & TA)BA)BA#
- #(x+(y-x*z)*( & FBA)BA)BA#
- #(x+(y-x*z)*( & DBA)BA)BA#
- #(x+(y-x*z)*( & yBA)BA)BA#
- #(x+(y-x*z)*(y & BA)BA)BA#
- #(x+(y-x*z)*(y & A)BA)BA#
- #(x+(y-x*z)*(y & +TA)BA)BA#
- #(x+(y-x*z)*(y+ & TA)BA)BA#
- #(x+(y-x*z)*(y+ & FBA)BA)BA#
- #(x+(y-x*z)*(y+ & DBA)BA)BA#
- #(x+(y-x*z)*(y+ & xBA)BA)BA#
- #(x+(y-x*z)*(y+x & BA)BA)BA#
- #(x+(y-x*z)*(y+x & *FBA)BA)BA#
- #(x+(y-x*z)*(y+x* & FBA)BA)BA#
- #(x+(y-x*z)*(y+x* & DBA)BA)BA#
- #(x+(y-x*z)*(y+x* & zBA)BA)BA#
- #(x+(y-x*z)*(y+x*z & BA)BA)BA#
- #(x+(y-x*z)*(y+x*z & A)BA)BA#
- #(x+(y-x*z)*(y+x*z & )BA)BA#
- #(x+(y-x*z)*(y+x*z) & BA)BA#
- #(x+(y-x*z)*(y+x*z) & A)BA#
- #(x+(y-x*z)*(y+x*z) & )BA#
- #(x+(y-x*z)*(y+x*z)) & BA#
- #(x+(y-x*z)*(y+x*z)) & A#
- #(x+(y-x*z)*(y+x*z)) & +TA#
- #(x+(y-x*z)*(y+x*z))+ & TA#
- #(x+(y-x*z)*(y+x*z))+ & FBA#
- #(x+(y-x*z)*(y+x*z))+ & DBA#
- #(x+(y-x*z)*(y+x*z))+ & xBA#
- #(x+(y-x*z)*(y+x*z))+x & BA#
- #(x+(y-x*z)*(y+x*z))+x & /FBA#
- #(x+(y-x*z)*(y+x*z))+x/ & FBA#
- #(x+(y-x*z)*(y+x*z))+x/ & DBA#
- #(x+(y-x*z)*(y+x*z))+x/ & zBA#
- #(x+(y-x*z)*(y+x*z))+x/z & BA#
- #(x+(y-x*z)*(y+x*z))+x/z & A#
- #(x+(y-x*z)*(y+x*z))+x/z & #
- AC代码:
- #include <iostream>
- #include <stack>
- using namespace std;
- string S=""; //开始符号
- struct { int number;string sign[]; string res_LL[][]; } not_endsign={}; //非终结符
- struct { int number;string sign[]; } end_sign={}; //终结符
- struct { int number;int order[]; string left[],right[]; } production={}; //产生式
- struct { int number;int order[]; string rank[],col[];int production_num[]; } LL={}; //LL(1)分析表
- string test;
- void input();
- void print(string left,stack<string > right);
- int main(){
- input();
- //定义输出结果
- string left;
- stack<string > right;
- right.push(S) ;
- print(left,right);
- while(!right.empty()){
- string top = right.top();
- string firstletter = test.substr(,);
- if(top==firstletter){
- left += top;
- test = test.substr(,test.length()- );
- right.pop();
- print(left,right);
- continue;
- }
- else {
- //替换掉 top
- for(int i=;i<LL.number;i++){
- if(LL.rank[i]==top &&LL.col[i]==firstletter ){
- right.pop();
- string temp = production.right[LL.production_num[i]- ];
- if(temp=="k") continue;
- while(temp.length()!=){
- string temp0 = temp.substr( temp.length()-,);
- right.push(temp0);
- temp = temp.substr(,temp.length()-);
- }
- }
- }
- }
- print(left,right);
- }
- return ;
- }
- void print(string left,stack<string > right){
- cout<<"#"<<left<<" & ";
- string temp="";
- while(!right.empty()){
- cout<<right.top();
- temp+=right.top();
- right.pop();
- }
- cout<<"#"<<endl;
- while(temp.length()!=){
- string temp0 = temp.substr( temp.length()-,);
- right.push(temp0);
- temp = temp.substr(,temp.length()-);
- }
- return ;
- }
- void input(){
- cin>>S;
- cin>>not_endsign.number;
- for(int i=;i<not_endsign.number;i++){
- cin>>not_endsign.sign[i];
- }
- cin>>end_sign.number;
- for(int i=;i<end_sign.number;i++){
- cin>>end_sign.sign[i];
- }
- cin>>production.number;
- for(int i=;i<production.number;i++){
- cin>>production.order[i]>>production.left[i]>>production.right[i];
- }
- cin>>LL.number;
- for(int i=;i<LL.number;i++){
- cin>>LL.order[i]>>LL.rank[i]>>LL.col[i]>>LL.production_num[i];
- }
- cin>>test;
- return ;
- }
LL(1)算法的更多相关文章
- B树——算法导论(25)
B树 1. 简介 在之前我们学习了红黑树,今天再学习一种树--B树.它与红黑树有许多类似的地方,比如都是平衡搜索树,但它们在功能和结构上却有较大的差别. 从功能上看,B树是为磁盘或其他存储设备设计的, ...
- 分布式系列文章——Paxos算法原理与推导
Paxos算法在分布式领域具有非常重要的地位.但是Paxos算法有两个比较明显的缺点:1.难以理解 2.工程实现更难. 网上有很多讲解Paxos算法的文章,但是质量参差不齐.看了很多关于Paxos的资 ...
- 【Machine Learning】KNN算法虹膜图片识别
K-近邻算法虹膜图片识别实战 作者:白宁超 2017年1月3日18:26:33 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现的深入理解.本系列文章是作者结 ...
- 红黑树——算法导论(15)
1. 什么是红黑树 (1) 简介 上一篇我们介绍了基本动态集合操作时间复杂度均为O(h)的二叉搜索树.但遗憾的是,只有当二叉搜索树高度较低时,这些集合操作才会较快:即当树的高度较高(甚至一种极 ...
- 散列表(hash table)——算法导论(13)
1. 引言 许多应用都需要动态集合结构,它至少需要支持Insert,search和delete字典操作.散列表(hash table)是实现字典操作的一种有效的数据结构. 2. 直接寻址表 在介绍散列 ...
- 虚拟dom与diff算法 分析
好文集合: 深入浅出React(四):虚拟DOM Diff算法解析 全面理解虚拟DOM,实现虚拟DOM
- 简单有效的kmp算法
以前看过kmp算法,当时接触后总感觉好深奥啊,抱着数据结构的数啃了一中午,最终才大致看懂,后来提起kmp也只剩下“奥,它是做模式匹配的”这点干货.最近有空,翻出来算法导论看看,原来就是这么简单(先不说 ...
- 神经网络、logistic回归等分类算法简单实现
最近在github上看到一个很有趣的项目,通过文本训练可以让计算机写出特定风格的文章,有人就专门写了一个小项目生成汪峰风格的歌词.看完后有一些自己的小想法,也想做一个玩儿一玩儿.用到的原理是深度学习里 ...
- 46张PPT讲述JVM体系结构、GC算法和调优
本PPT从JVM体系结构概述.GC算法.Hotspot内存管理.Hotspot垃圾回收器.调优和监控工具六大方面进行讲述.(内嵌iframe,建议使用电脑浏览) 好东西当然要分享,PPT已上传可供下载 ...
- 【C#代码实战】群蚁算法理论与实践全攻略——旅行商等路径优化问题的新方法
若干年前读研的时候,学院有一个教授,专门做群蚁算法的,很厉害,偶尔了解了一点点.感觉也是生物智能的一个体现,和遗传算法.神经网络有异曲同工之妙.只不过当时没有实际需求学习,所以没去研究.最近有一个这样 ...
随机推荐
- 服务器判断http是否中断
一般来说,只需要send或者recv一下,如果结果为零,则为掉线. 1.当recv返回值为0是表示对方已经正常(MSDN说是完美的)的断开连接.2.当recv返回SOCKET_ERROR时,说明对方已 ...
- LoadRunner 实现监控Tomcat
LoadRunenr没有监控Tomcat的专用监控器,为了用lr达到监控tomcat的目的可以通过打开Tomcat自带的Status页面之后,利用lr的关联技术得到相关的数据,把数据输出到lr自定义的 ...
- S1的小成果:MyKTV系统
转眼之间,已经到了2016年,即新的一年了!S1也结束了,收获的也不多 ,想想最后留给大家的就一个KTV项目了. 希望大家看时有所收获 现在我们一起来看KTV前台管理 主界面的运行 ...
- BUTTONS V. 2.0.0——CSS按钮库
BUTTONS-V2-CSS库样式职责 CSS库样式职责分离优点 模块样式命名更清晰化 易于维护.扩展性强 动画效果——修改样式后有过度效果,默认样式 源码如下 <!DOCTYPE html&g ...
- 这个jQuery导航菜单怎么样
效果体验:http://keleyi.com/keleyi/phtml/jqtexiao/39.htm HTML文件代码: <!DOCTYPE html> <html xmlns=& ...
- 关于在线编辑器的选择:tinymce - nilcms
一开始使用的是百度开发的编辑器:ueditor.使用方便,很容易就部署了.现在发现此编辑器也就做一些安全性的更新,而且对于这个编辑器也越来越不喜欢了. 1.臃肿.[1.4.3.3 PHP 版本].下载 ...
- c/C++二进制运算符
c/c++中常用的二进制运算符有六个.这里对这六个做简单的介绍和应用举例. 1. & : 与操作.作用于两个二进制数,当然也可以对整型数据进行操作(当两边为整型数据会自动转化为二进制数) ...
- CSS3中的弹性布局——"em"的用法
使用CSS也好久了,但一直都是在使用“px”来设置Web元素的相关属性,未敢使用“em”.主要原因是,对其并不什么了解,只知道一点概念性的东西,前段时间在项目中要求使用“em”作为单位设置元素,所以从 ...
- 『SharePoint』Content Editor Webpart不能添加引用_layouts下面的文件
好久没写了,最近没怎么学到新东西,倒是犯了一个很常见的错误,那就是试图在content editor webpart中添加位于_layouts下面的一个txt文件,虽然这个txt中只是几行简单的htm ...
- Imperva WAF使用笔记
添加IP白名单 在对自己公司网站进行安全测试时会被WAF拦截,如果把WAF彻底停掉就无法拦截到外部的攻击了. 此时可以添加IP地址白名单,白名单内的IP对网站发起扫描时不会做拦截.