LL(1)算法

时间:2023-03-09 17:40:00
LL(1)算法

编译原理的语法分析中一个入门的算法就是LL(1)算法了,这里做一个总结。首先比较重要的是FIRST集和FOLLOW集合的生成。

先上个例子吧:

    LL(1)算法

  首先说一下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)分析表中去。这样就大功告成了。

不妨再贴一个例子:

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 ;
}