编译原理-LL(1)算法

     最近上编译原理课老师让实现语法分析的LL(1),算法可以参考龙书三,经过两天的奋斗,终于调试成功了。

 

1 问题描述

  设计一个由正规文法生成First集和Follow集并能输出测试字符串的预测分析过程。(算法参见教材)

【基本要求】

  模拟算法的基本功能是:

(1)    输入一个文法G

(2)    消除左循环;

(3)    输出FIRST集;

(4)    输出FOLLOW集;

(5)    输出SELECT集合;

(6)    输出预测分析表;

(7)    输出预测分析过程。

2 详细设计

2.1 数据结构

  2.1.1 终结符号:    vector<CString>

  2.1.2 非终结符号: vector<CString>

  2.1.3 文法:           vector<CString>     每条文法定义为一个CString

  2.1.4 First集合:    vector<LEFT_GATHER> LEFT_GATHER{(非终结符),(vector}

  2.1.5 Follow集合: vector<LEFT_GATHER> LEFT_GATHER{(非终结符),(vector}

  2.1.6 Select集合: vector<LEFT_GATHER> LEFT_GATHER{(文法),(vector}

  2.1.7 LEFT_GATHER

  typedef struct  LEFT_GATHER

 {

      CString start;

      vector<CString> end_gather;

 }LEFT_GATHER;

2.2 算法思想

2.2.1 判断文法合法性:

    满足条件:

   1)左部以非终结符开始,并且只有一个

   2)右部必须有非终结符,并且只能用零个或多个终结符和非终结符组成

    不合法情况

   1  形如 A->A

   2  形如 A->(已包括)

  2.2.2 消除左递归:

  1、消除直接左递归

   原文法: E --> E a1 | E a2 | ... | E an | b1 | b2 | ... | bn

   消除后: E --> b1 E' | b2 E' | ... | bn E'

              E'--> a1 E' | a2 E' | ... | an E' | epsilon

  2、消除间接左递归

   a)  把所有非终结符号按一定序列排序为E1, E2, ... En

   b) for i=1 to n do /*依次处理每个非终结符号*/

         for j=1 to i-1 do /*处理第1个到i-1*/

           Ei --> Ej r

               则改为Ei --> S1 r | S2 r | ... | Sk r

               其中Ej --> S1 | S2 | ... | Sk

   c) Ei消除直接左递归。

 

  2.2.3 获得First集合:

    例如求FirstA),那么先扫描文法集合,找到左部是A的文法,接着进行如下判断

   (1)对于形如A->aD

        如果右边第一个字符如a是终结符,直接将a加入FirstA),前提是a不在FirstA)中

   2)对于形如A->Bd

        如果右边第一个字符如B不是终结符,那么继续求BFirstB)【递归】,并将FirstB)放到FirstA)中,前提是

        FirstA)中元素不能重复。

   3)这样不断扫描,知道所有非终结符的First都求完。

  2.2.4 获得Follow集合:

    例如求FollowA),那么先扫描文法,找到右部含有A的文法,接着进行如下判断

   (1)对于形如B->aA

        如果A右边没有字符,那么将FollowB)【递归】加到FollowA)中  

   (2)对于形如B->aAX

       如果X是终结符,直接将X放到FollowA)中

       如果X是非终结符

     (a)   将除ε的FirstX)放到FollowA)中。

     (b)   如果ε在FirstX),那么也将FollowX)【递归】加到FollowA)中。

   3)这样不断扫描,知道所有非终结符的Follow都求完。

  2.2.5获得Select集合:

    例如求文法SelectA->XaB

   (1)   如果X是终结符,直接将X加到SelectA->XaB

       (a  如果ε在FirstX),并且$ FollowX)中,那么将FollowX)加到SelectA->XaB

   (2)   如果X不是终结符,那么将FirstX)加到SelectA->XaB

       (a)   如果ε在FirstX),并且$ FollowX)中,那么将FollowX)加到SelectA->XaB

   3   这样不断扫描,知道所有非终结符的Follow都求完。

  2.2.6 判断是不是LL1):

   (1)文法中每个非终结符A满足

        A→α|α||αn     :

        FIRST(αi)FIRST(αj)=Ø (ij)

   (2) 文法中每个非终结符A , 若它存在某个候选First集包含ε,

        FIRST(A)FOLLOW(A) = Ø

  2.2.7 获得预测分析表:

      根据Select集合得到。 

  2.2.8 获得预测分析执行步骤:

    1)文法的开始符号X进栈,测试第一个字符ip

    2)遍历栈

        aX=ip:弹栈操作,ip向前移一个字符。

        bX是终结符号:错误。

        cM[X,a] 是报错条目即不含有开头是X的文法:错误 。

        d)找到文法左部含有X的文法集合,并进行弹栈操作。

           I  如果SELECTXX)中含有ip,将该文法右部字符进栈(最左边字符在栈顶)。

           II 否则选择第一个文法,将该文法右部字符进栈(最左边字符在栈顶)。

        e)非终结符ε不进栈。

        fX等于栈顶元素。

 

3 示例操作

题目:编写识别由下列文法所定义的表达式的预测分析程序。

E->E+T|T

T->T*F|F

F->(E)|i

输入:每行含一个表达式的文本文件。

输出:分析成功或不成功信息。

解答:

1)分析            

a) E->E+T|T存在左递归。用直接改写法消除左递归,得到如下:

E->TE'

T->FT'

F->i

F->(E)

E'->@

E'->+TE'

T'->@

T'->*FT'

对于以上改进的方法。可得:

对于EFIRSTE=FIRSTTE'=FIRSTT=FIRSTF= {i , ( }

对于E’FIRST( E’ )=FIRST(+TE'){@}={+@

对于T’FIRST( T’ )=FIRST(*FT'){@}={*@

 

由此我们容易得出各非终结符的FOLLOW集合如下:

  FOLLOW(E) = {) , $ }

  FOLLOW(E') = {) , $ }

  FOLLOW(T) = {) , $ , + }

  FOLLOW(T') = {) , $ , + }

  FOLLOW(F) = {) , $ , + , * }

由以上FOLLOW集可以我们可以得出SELECT集如下:

  对E       SELECTE->TE’=FIRST(TE’)=FIRST(T)={ (i }

  对E’      SELECTE’ ->+TE’={ + } 

              SELECTE’ ->@={$)}

  对T       SELECTT->FT’={(i}

  对T’      SELECTT’ ->*FT’={ * }  

              SELECTT’ ->@={$+) }

  对F       SELECTF->(E) ={ ( }

              SELECTF->i={ i }

SELECT(E’ ->+TE’)∩SELECTE’ ->ε=F

    SELECT(T’ ->*FT’)∩SELECTT’ ->ε=F

    SELECTF->(E) ∩SELECTF->i= F

由上可知,有相同左部产生式的SELECT集合的交集为空,所以文法是LL1)文法。

2010-12-12

 

 

 

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页