编译原理的语法分析中一个入门的算法就是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格;

样例输入
aaarticlea/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAARABIDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAAAAMFBwT/xAAlEAACAQQCAQMFAAAAAAAAAAABAgMABAURBiESIjFBMjZxdbP/xAAYAQACAwAAAAAAAAAAAAAAAAAAAwEEBf/EABsRAQEAAgMBAAAAAAAAAAAAAAEAAgMEEyFh/9oADAMBAAIRAxEAPwDQeRW+SyVnctBIkiiScOk87qm0ciP0aZWA8dkEDZA2fcGPCWPI+PXkUt3GIcQjkyQxTGdtMrAhUVQO5CraVd/UB1pa7cnHmbaW5hjxEktoZJJGulnjChWYsT4lvLoHvr3B1vommvuQYaSe/jGSxrW9yXEiCWIiTe9eWohvs/LH8n5ocDh9jlnsER+zt+9wDE9G0uKWO4hSaGRJIpFDI6MCrKewQR7ilVfFPs7B/r4P5rStB8ZJW9KUqIlKUoi//9k=" alt="" /> 将样例输入复制到剪贴板
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)分析表中的产生式个数,序号,行符号,列符号,产生式编号,空格符分隔;
输入一个算术式符号串,用#结束

输出格式

输出推导过程,每一步一行,中间“ & ”前是已经识别的子串,后是栈中信息。

样例输入
aaarticlea/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAARABIDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAAAAMFBwT/xAAlEAACAQQCAQMFAAAAAAAAAAABAgMABAURBiESIjFBMjZxdbP/xAAYAQACAwAAAAAAAAAAAAAAAAAAAwEEBf/EABsRAQEAAgMBAAAAAAAAAAAAAAEAAgMEEyFh/9oADAMBAAIRAxEAPwDQeRW+SyVnctBIkiiScOk87qm0ciP0aZWA8dkEDZA2fcGPCWPI+PXkUt3GIcQjkyQxTGdtMrAhUVQO5CraVd/UB1pa7cnHmbaW5hjxEktoZJJGulnjChWYsT4lvLoHvr3B1vommvuQYaSe/jGSxrW9yXEiCWIiTe9eWohvs/LH8n5ocDh9jlnsER+zt+9wDE9G0uKWO4hSaGRJIpFDI6MCrKewQR7ilVfFPs7B/r4P5rStB8ZJW9KUqIlKUoi//9k=" alt="" /> 将样例输入复制到剪贴板
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)算法的更多相关文章

  1. B树——算法导论(25)

    B树 1. 简介 在之前我们学习了红黑树,今天再学习一种树--B树.它与红黑树有许多类似的地方,比如都是平衡搜索树,但它们在功能和结构上却有较大的差别. 从功能上看,B树是为磁盘或其他存储设备设计的, ...

  2. 分布式系列文章——Paxos算法原理与推导

    Paxos算法在分布式领域具有非常重要的地位.但是Paxos算法有两个比较明显的缺点:1.难以理解 2.工程实现更难. 网上有很多讲解Paxos算法的文章,但是质量参差不齐.看了很多关于Paxos的资 ...

  3. 【Machine Learning】KNN算法虹膜图片识别

    K-近邻算法虹膜图片识别实战 作者:白宁超 2017年1月3日18:26:33 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现的深入理解.本系列文章是作者结 ...

  4. 红黑树——算法导论(15)

    1. 什么是红黑树 (1) 简介     上一篇我们介绍了基本动态集合操作时间复杂度均为O(h)的二叉搜索树.但遗憾的是,只有当二叉搜索树高度较低时,这些集合操作才会较快:即当树的高度较高(甚至一种极 ...

  5. 散列表(hash table)——算法导论(13)

    1. 引言 许多应用都需要动态集合结构,它至少需要支持Insert,search和delete字典操作.散列表(hash table)是实现字典操作的一种有效的数据结构. 2. 直接寻址表 在介绍散列 ...

  6. 虚拟dom与diff算法 分析

    好文集合: 深入浅出React(四):虚拟DOM Diff算法解析 全面理解虚拟DOM,实现虚拟DOM

  7. 简单有效的kmp算法

    以前看过kmp算法,当时接触后总感觉好深奥啊,抱着数据结构的数啃了一中午,最终才大致看懂,后来提起kmp也只剩下“奥,它是做模式匹配的”这点干货.最近有空,翻出来算法导论看看,原来就是这么简单(先不说 ...

  8. 神经网络、logistic回归等分类算法简单实现

    最近在github上看到一个很有趣的项目,通过文本训练可以让计算机写出特定风格的文章,有人就专门写了一个小项目生成汪峰风格的歌词.看完后有一些自己的小想法,也想做一个玩儿一玩儿.用到的原理是深度学习里 ...

  9. 46张PPT讲述JVM体系结构、GC算法和调优

    本PPT从JVM体系结构概述.GC算法.Hotspot内存管理.Hotspot垃圾回收器.调优和监控工具六大方面进行讲述.(内嵌iframe,建议使用电脑浏览) 好东西当然要分享,PPT已上传可供下载 ...

  10. 【C#代码实战】群蚁算法理论与实践全攻略——旅行商等路径优化问题的新方法

    若干年前读研的时候,学院有一个教授,专门做群蚁算法的,很厉害,偶尔了解了一点点.感觉也是生物智能的一个体现,和遗传算法.神经网络有异曲同工之妙.只不过当时没有实际需求学习,所以没去研究.最近有一个这样 ...

随机推荐

  1. order by用法

    此文来源于CSDN中zxcvg的博文 1.ORDER BY 中关于NULL的处理 缺省处理,Oracle在Order by 时认为null是最大值,所以如果是ASC升序则排在最后,DESC降序则排在最 ...

  2. Apache Lucene学习笔记

    Hadoop概述 Apache lucene: 全球第一个开源的全文检索引擎工具包 完整的查询引擎和搜索引擎 部分文本分析引擎 开发人员在此基础建立完整的全文检索引擎 以下为转载:http://www ...

  3. MyEclipse或者Eclipse内存溢出问题

    对于一些项目,我们经常会遇到内存溢出的问题,这个时候我们就需要进行设置JDK的各个内存的大小了. 如果是运行项目以后出现问题的话,那么主要还是jdk或者是tomcat的内存问题,至于网上说的xxx.i ...

  4. ABP 初探 之 AbpSession 扩展

    Abp的权限管理是基于 Identity,所有的扩展也是基于 claims .claims 有许多默认属性,具体连接 关于 Identity的详细介绍,可以参考园友博客 继承 Microsoft.As ...

  5. 11、ASP.NET MVC入门到精通——AspnetMVC分页

    本系列目录:ASP.NET MVC4入门到精通系列目录汇总 说起分页,这基本上是我们Web开发中遇见得最多的场景,没有之一,可即便如此,要做出比较优雅的分页还是需要技巧的.这里我先说一种ASP.NET ...

  6. WCF入门教程1——WCF简要介绍

    什么是WCF Windows Communication Foundation(WCF)是由微软开发的一系列支持数据通信的应用程序框架,可以翻译为Windows 通讯开发平台. 整合了原有的windo ...

  7. 亿级规模的Elasticsearch优化实战

    Elasticsearch 的基本信息大致如图所示,这里就不具体介绍了. 本次分享主要包含两个方面的实战经验:索引性能和查询性能. 一. 索引性能(Index Performance) 首先要考虑的是 ...

  8. 事件流之事件冒泡与事件捕获<JavaScript高级程序设计>学习笔记

    1.事件流 浏览器开发团队遇到一个很有意思问题:页面的那一部分会拥有特定的事件? 对于理解这个问题您可以想象画在一张纸上的一组同心圆,如果你把手指放在圆心上,那么你的手指指向的其实不是一个圆,而是纸上 ...

  9. iframe高度自适应

    前两天在网上看到了一道面试题,问iframe高度自适应的问题.发现自己之前几乎没有关注过iframe的问题,所以在这里记录一下. 原题目是: 页面A的域名是:http://www.taobao.com ...

  10. 【小贴士】探一探javascript中的replace

    javascript字符串与数组有很多精巧的方法,比如splice.indexOf,而replace在字符串处理中偶尔会产生让人愉悦的效果 比如underscore中的模板引擎替换部分,又如信用卡分割 ...