• 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 }
    View Code

    题目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 }
    View Code
  • 相关阅读:
    第3关:求三位数各位数字的和
    第4关:求三角形的面积
    第6关:输出杨辉三角
    最短路 模板 【bellman-ford,dijkstra,floyd-warshall】
    hdu 1874 畅通工程 【spfa and dijkstra实现】
    01背包问题 总结关于为什么01背包优化成1维数组后,内层循环是逆序的?
    Stein算法求最大公约数
    hdu 1576 A/B 【扩展欧几里德】
    树状数组之 ——区间更新,单点查询;区间更新,区间查询;
    差分数组
  • 原文地址:https://www.cnblogs.com/liugl7/p/5341044.html
Copyright © 2020-2023  润新知