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代码:
1 #include <iostream> 2 using namespace std; 3 4 string S=""; //开始符号 5 struct { int number;string sign[20]; string res_LL[20][20]; } not_endsign={0}; //非终结符 6 struct { int number;string sign[20]; } end_sign={0}; //终结符 7 struct { int number;int order[100]; string left[100],right[100]; } production={0}; //产生式 8 struct { int number;int order[100]; string rank[100],col[100];int production_num[100]; } LL={0}; //LL(1)分析表 9 10 void input(); 11 void print(string a); 12 13 int main(){ 14 input(); 15 end_sign.sign[end_sign.number] = "#"; 16 end_sign.number++; 17 18 //刷整个的分析表,将分析表中的数据填入到not_endsign中去 19 for(int i=0;i<LL.number;i++){ 20 //得到LL一条数据的“行”对应的“非终结符” 21 int j; 22 for(j=0;j<not_endsign.number&& not_endsign.sign[j]!=LL.rank[i];j++ ); 23 24 //得到LL一条数据的“列”对应的“终结符” 25 int z; 26 for(z=0;z<end_sign.number&&end_sign.sign[z]!=LL.col[i];z++ ); 27 28 //得到LL一条数据的要赋予的值 29 not_endsign.res_LL[j][z] = production.right[LL.production_num[i]-1 ]; 30 } 31 32 //单独处理“#” 33 34 cout<<" "; 35 for(int i=0;i<end_sign.number;i++){ 36 cout<<" "<<end_sign.sign[i]; 37 } 38 cout<<endl; 39 40 for(int i=0;i<not_endsign.number;i++){ 41 print(not_endsign.sign[i]); 42 cout<<not_endsign.sign[i]; 43 for(int j=0;j<end_sign.number ;j++){ 44 print(not_endsign.res_LL[i][j] ); 45 cout<<not_endsign.res_LL[i][j]; 46 } 47 cout<<endl; 48 } 49 50 return 0; 51 } 52 53 void print(string a){ 54 for(int i=0;i<5-a.length();i++){ 55 cout<<" "; 56 } 57 return ; 58 } 59 void input(){ 60 cin>>S; 61 cin>>not_endsign.number; 62 for(int i=0;i<not_endsign.number;i++){ 63 cin>>not_endsign.sign[i]; 64 } 65 66 cin>>end_sign.number; 67 for(int i=0;i<end_sign.number;i++){ 68 cin>>end_sign.sign[i]; 69 } 70 71 cin>>production.number; 72 for(int i=0;i<production.number;i++){ 73 cin>>production.order[i]>>production.left[i]>>production.right[i]; 74 } 75 76 cin>>LL.number; 77 for(int i=0;i<LL.number;i++){ 78 cin>>LL.order[i]>>LL.rank[i]>>LL.col[i]>>LL.production_num[i]; 79 } 80 return ; 81 }
题目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代码:
1 #include <iostream> 2 #include <stack> 3 using namespace std; 4 5 string S=""; //开始符号 6 struct { int number;string sign[20]; string res_LL[20][20]; } not_endsign={0}; //非终结符 7 struct { int number;string sign[20]; } end_sign={0}; //终结符 8 struct { int number;int order[100]; string left[100],right[100]; } production={0}; //产生式 9 struct { int number;int order[100]; string rank[100],col[100];int production_num[100]; } LL={0}; //LL(1)分析表 10 string test; 11 12 void input(); 13 void print(string left,stack<string > right); 14 15 int main(){ 16 input(); 17 18 //定义输出结果 19 string left; 20 stack<string > right; 21 22 right.push(S) ; 23 print(left,right); 24 25 while(!right.empty()){ 26 string top = right.top(); 27 string firstletter = test.substr(0,1); 28 if(top==firstletter){ 29 left += top; 30 test = test.substr(1,test.length()-1 ); 31 right.pop(); 32 print(left,right); 33 34 continue; 35 } 36 else { 37 //替换掉 top 38 for(int i=0;i<LL.number;i++){ 39 if(LL.rank[i]==top &&LL.col[i]==firstletter ){ 40 right.pop(); 41 string temp = production.right[LL.production_num[i]-1 ]; 42 if(temp=="k") continue; 43 while(temp.length()!=0){ 44 string temp0 = temp.substr( temp.length()-1,1); 45 right.push(temp0); 46 temp = temp.substr(0,temp.length()-1); 47 } 48 49 } 50 } 51 52 } 53 54 print(left,right); 55 } 56 57 return 0; 58 } 59 60 void print(string left,stack<string > right){ 61 cout<<"#"<<left<<" & "; 62 string temp=""; 63 while(!right.empty()){ 64 cout<<right.top(); 65 temp+=right.top(); 66 right.pop(); 67 } 68 cout<<"#"<<endl; 69 70 while(temp.length()!=0){ 71 string temp0 = temp.substr( temp.length()-1,1); 72 right.push(temp0); 73 temp = temp.substr(0,temp.length()-1); 74 } 75 76 return ; 77 } 78 79 void input(){ 80 cin>>S; 81 cin>>not_endsign.number; 82 for(int i=0;i<not_endsign.number;i++){ 83 cin>>not_endsign.sign[i]; 84 } 85 86 cin>>end_sign.number; 87 for(int i=0;i<end_sign.number;i++){ 88 cin>>end_sign.sign[i]; 89 } 90 91 cin>>production.number; 92 for(int i=0;i<production.number;i++){ 93 cin>>production.order[i]>>production.left[i]>>production.right[i]; 94 } 95 96 cin>>LL.number; 97 for(int i=0;i<LL.number;i++){ 98 cin>>LL.order[i]>>LL.rank[i]>>LL.col[i]>>LL.production_num[i]; 99 } 100 101 cin>>test; 102 return ; 103 }