一.提取左公因子
1)提取左公因子是一种文法转换方法,它可以产生适用于预测分析技术或自顶向下分析技术的文法。
2)示例:
如A->αβ1|αβ2
可以化成A->αA’ A’->β1 | β2。
二.消除左递归
1)如果一个文法中有一个非终结符号A使得对某个串α存在一个推导A=>Aα,那么这个文法就是左递归的。
2)由于自顶向下语法分析方法不能处理左递归得到文法,因此需要一个转换方法来消除左递归。
3)示例
①A->Aα | β
消除左递归,A->βA’ A’->αA’ | Σ
②E->E+T | T
消除左递归,E->TE’ E’-> +TE’ | Σ
③T->T*F | F
消除左递归,T->FT’ T’-> *FT’ | Σ
例题一
be->be or bt | bt
bt->bt and bf | bf
bf-> not bf | ( be ) | true | false
解答:第一行文法适用于②或③类,消除左递归
,化为be->bt be’ be’->or bt be’ | Σ
第二行同理,可化为bt->bf bt’ bt’-> and bf bt’ | Σ
第三行无左递归
例题二
re->re + rt | rt
rt->rt rf | rf
rf->rf * | rp
rp->a | b
解答:第一二行适用于②或③类,这里就不多赘述了。
第三行适用于①类,rf->rp rf’ rf’->*rf’ | Σ
第四行无左递归
例题三
S->SS+|SS*|a
先提取左公因子S->SSA | a A->+ | *
第一行适用于①类
消除左递归 S->a S’ S’-> SA S’ | Σ
由于这里的S’-> SA S’ | Σ仍然含有S,所以需要把S->a S’代入进去得到S’-> a S’ A S’ | Σ
三.短语,简单短语,句柄
短语,简单短语都是针对某一句型的,是相对于某个非终结符的。
句柄:任一句型的最左简单短语称为该句型的句柄,一个句型只有一个句柄。
一个句型的语法树中任一子树叶结点所组成的符号串都是该句型的短语。当子树中不包含其他更小的子树时,该子树叶结点所组成的字符串就是该句柄的简单短语。
示例
其简单短语有S,(T),b(注意:d不是,因为d所在以T为根结点的子树存在其他子树,所以不是)
短语有S(对于以左一T为根结点的子树),(T)(对于以S为根节点的子树),b (对于以S为根节点的子树),Sd(T) (对于以左二T为根结点的子树),Sd(T)db (对于以左四T为根结点的子树),(Sd(T)db)(对于以左三S为根结点的子树)。
句柄就是该句型的最左直接短语,即S。
例题
对于文法S->0S1 | 01,指出下面各个最右句型的句柄
1)000111
最右推导S->0S1->00S11->000111
语法树如上:句柄很明显为01
2)00S11
最右推导S->0S1->00S11
语法树
语法树如上:句柄很明显为0S1
求first和follow集
first集合顾名思义就是求一个文法字符串所可能推导出的符号串的第一个终结符的集合。
first(x)就是求x所有推导出的符号串的第一个符号的集合。
follow集合也是顾名思义的,就是文法符号后面可能跟随的终结符的集合(不包含空串)
follow(x)就是求x后面可能跟随的符号集合。
求follow集合可划分为如下几种情况:
①A->…Ua…要求的follow集合的非终结符后跟终结符
这种情况下follow(U)与A没有任何关系,产生式左边是什么都不影响。结论:a属于follow(U)。
②A->…UP…要求的follow集合的非终结符后跟非终结符
根据定义,显然P的第一个符号属于follow(U),也就是说first(P)属于follow(U)(假设first(P)不含有Σ)
③A->…UP 要求的follow集合的非终结符后跟非结尾的终结符,并且结尾非终结符的first集合包含空串。
这其实就是情况③的特例,first(P)-Σ属于follow(U),由于Σ属于first(P),当P推导为空串时,由于follow集合中不准有空串,所以U后面跟随的应该是P后面的东西,可P已经是结束的符号,此时U后面显然就是A后面跟随的东西了。所以这种情况下follow(A)也属于follow(U)。
④A->…U要求的follow集合的非终结符在产生式结尾
这时候需要递归推导,U是A的结尾,所以U后面跟随的东西就是A后面跟随的东西。所以follow(A)属于follow(U)。
教材上的follow求解算法如下,其实和我上面所述的意思基本一样
例题
文法
be->bt be’
be’->or bt be’ | Σ
bt->bf bt’
bt’-> and bf bt’ | Σ
bf-> not bf | ( be ) | true | false
求first集合
first(be)={not, (, true, false}
first(bt)={not, (, true, false}
first(bf)={not, (, true, false}
first(be’)={or, Σ}
first(bt’)={and, Σ}
求follow集合
①非终结符由高到底排序为:be, be’, bt, bt’, bf
②计算follow(be)
右部含有be的产生式为bf->(be),符合情况①,follow(be)={), $}
计算follow(be’)
右部含有be’的产生式有be->bt be’ ,follow(be’) += follow(be)=follow(), $)
还有产生式be’->or bt be’ ,follow(be’)+=follow(be’),无意义
计算follow(bt)
右部含有bt的产生式有be->bt be’, follow(bt) +=first(be’)-Σ={or}
follow(bt)+=follow(be)={or, ), $}
还有产生式be’->or bt be’ ,follow(bt)+=first(be’)-Σ={or, ), $}
follow(bt)+=follow(be’)={or, ), $}
计算follow(bt’)
右部含有bt’的产生式有bt->bf bt’ ,follow(bt’)+=follow(bt)={or, ), $}
bt’-> and bf bt’,follow(bt’)+=follow(bt’),无意义
计算follow(bf)
右部含有bf的产生式有bt->bf bt’,follow(bf)+=first(bt’)-Σ={and, $}
follow(bf)+=follow(bt)={and, or, ), $}
bt’-> and bf bt’ , follow(bf)+=first(bt’)-Σ={and, or, ), $}
follow(bf)+=follow(bt’)={and, or, ), $}
bf-> not bf, follow(bf)+=follow(bf),无意义
例题二
如果是上面的文法没有消除左递归之前的文法
be->be or bt | bt
bt->bt and bf | bf
bf-> not bf | ( be ) | true | false
first集合
first(be)={not, (, true, false}
first(bt)={not, (, true, false}
first(bf)={not, (, true, false}
follow集合
follow(be)={or, ), $}
follow(bt)+=follow(be)+={and}+={and, or, ), $}
follow(bf)+=follow(bt)+={and, or, ), $}
LL(1)文法
LL(1)文法是一种确定的自顶向下的判断文法
判断文法G不是LL(1)文法的条件
例题
文法S->SS + | SS * | a
提取左公因子S->SSA | a A->+ | *
消除左递归
S->aS’ S’->SAS’ | Σ A-> + | *
文法如下
S->aS’
S’->S+S’
S’->S*S’
S’-> Σ
再次提取左公因子
S->aS’
S’->Σ
S’->SP
P->+S’
P->*S’
计算first集合
first(S)={a}
first(S’)={a, Σ}
first(P)={+,*}
计算follow集合
follow(S)+=first(P)={+, *, $}
follow(S’)+=follow(S)+=follow(P)
folllow(P)+=follow(S’)
则
follow(S)={+, *, $}
follow(S’)={+, *, $}
follow(P)={+, *, $}
构建预测分析表
非终结符号 | 输入符号 | |||
+ | * | a | $ | |
S | S->aS’ | |||
S’ | S’->Σ | S’->Σ | S’->SP | S’->Σ |
P | P->+S’ | P->*S’ |
LL(1)预测表中的某个各自中,如果有两个产生式,那么就存在产生式选取冲突问题,说明这个文法就不是LL(1)文法。
LR(0)与SLR(1)
分析过程
SLR(1)的增广文法、写自动机、分析过程表与 LR(0)文法相同。但是由于可能存在移进-归约冲突,所以 SLR分析表可能存在多重入口(即同一格中既有移进又有归约)。
LR(0)文法的判定
如果文法对应的自动机中不存在移进-归约冲突和归约-归约冲突则为 LR(0)文法。换句话说LR(0)文法分析不能解决这两种冲突,所以范围最小。移进-归约冲突就是在同一个项集族中同时出现了可以移进的产生式和可以归约的产生式。归约-归约冲突类似。
SLR(1)文法的判定
SLR文法不存在归约-归约冲突,有可能存在移进-归约冲突,但是如果可以用 follow集解决则是 SLR文法。换句话说,SLR文法分析过程可以解决归约-归约冲突,但是不一定能解决移进-归约冲突。用 follow集来处理即出现移进-归约冲突的两条产生式,如果其 follow集相交为空则为 SLR文法,反之不是。当然,如果以上两种冲突都不存在自然是了。
增广文法
对文法的开始符号S,加一个产生式:S’ ->S。 只有发生这个规约,才说进入接受状态。原因 在于出现E并不代表树生成完毕。
为什么E->E+T这个规约并不代表进入接受状态, 因为id+id+id, 就会有两次E->E+T规约,然后 才进入接受状态。所以需要E’->E。
写自动机
为了区分不同的时间点,可在文法G的每个产生式的右部添加 一个圆点,称为文法G的LR(0)项目。
圆点前面代表“历史”(已识别的串),圆点后面代表“期待”
需要构造 LR(0)自动机,就是加入了一个圆点,圆点后的符号是即将处理的符号,如果圆点后是非终结符时,则要写出该终结符为产生式左部的所有产生式。反复以上过程,直到不再扩大。给它们编号并写出读入下一个符号(即圆点后的符号)会跳转到哪。
例题
文法 S->AaAb | BbBa, A->Σ, B->Σ是 LL(1)文法,但不是 SLR(1)文法
对于LL(1)文法的判定需要求其first和follow集合
first(S)={a,b}
first(A)={Σ}
first(B)={Σ}
follow(S)={$}
因为first(A)={Σ},first(B)={Σ},所以A,B的follow没有任何意义。
预测分析表
是LL(1)文法
因为文法含有Σ,所以不是SLR(1)文法
求分析表
表中一般有sx和rx
对于sx
对于rx
对增广文法进行编号。
if[A->a]∈Ii且A≠S’ then ACTION[i, 集合]=rj(j为编号)。
集合为follow(A)。
例题
文法S->SS+ | SS* | a
化为增广文法
(0)S’->S
(1)S->SS+
(2)S->SS*
(3)S->a
构造项族集,画自动机
GOTO(I0,S)=I1, GOTO(I0,a)=I2 GOTO(I1,S)=I3, GOTO(I1,a)=I2
GOTO(I3,S)=I3, GOTO(I3,+)=I4, GOTO(I3,*)=I5, GOTO(I3,a)=I2
follow(S)={+, *, a, $}
填分析表
基于SLR(1)分析表的语法分析例子
对于输入串id+id*id
id+id*id$
开始时
其实状态栈为0,输入id,由于s5,移入5,状态栈变为05;
对于5和输入+,由于r6,规约弹栈,所以状态栈为0,其中6代表F->id;
对于0和F,GOTO,状态栈变为03;
对于3和输入+,由于r4,规约弹栈,所以状态栈为0,其中4代表T->F;
对于0和T,GOTO,状态栈变为02;
对于2和输入+,由于r2,规约弹栈,所以状态栈为0,其中2代表E->T;
对于0和E,GOTO,状态栈变为01;
对于1和输入+,由于s6,移入6,状态栈为016;
对于6和输入id,由于s5,移入5,状态栈为0165;
对于5和输入*,由于r6,规约弹栈,所以状态栈为016,其中6代表F->id;
对于6和F,GOTO,状态栈变为0163;
对于3和输入*,由于r4,规约弹栈,所以状态栈为016,其中4代表T->F;
对于6和T,GOTO,状态栈变为0169;
对于9和输入*,由于s7,移入7,状态栈为01697
对于7和输入id,由于s5,移入5,状态栈为016975
对于5和输入$,由于r6,规约弹栈,所以状态栈为01697,其中6代表F->id;
对于7和F,GOTO,状态栈变为01697 10;
对于10和输入$,由于r3,规约弹栈,所以状态栈为016(弹三个),其中3代表T->T*F;
对于6和T,GOTO,状态栈变为0169;
对于9和输入$,由于r1,规约弹栈,所以状态栈为0(弹三个),其中3代表E->E+T;
对于0和E,GOTO,状态栈变为01;
对于1和输入$,由于acc,所以结束,状态栈最终为01。
基于LR(0)项集的DFA,进行自底向上,从左到右的语法分析例子。
题目仍然一样,只是这次不是基于分析表,而是自动机图
起始时
状态栈为0,输入id,移入5,所以状态栈变为05;
对于5,输入+,需要规约,按F->id,所以弹出5,对于0与F,移入3,所以状态栈为03;
对于3,输入+,需要规约,按T->F,所以弹出3,对于0与T,移入2,所以状态栈为02;
对于2,输入+,需要规约,按E->T,所以弹出2,对于0与E,移入1,所以状态栈为01;
对于1,输入+,移入6,所以状态栈为016;
对于6,输入id,移入5,所以状态栈为0165;
对于5,输入*,需要规约,按F->id,所以弹出5,对于6与F,移入3,所以状态栈为0163;
对于3,输入*,需要规约,按T->F,所以弹出3,对于6与T,移入9,所以状态栈为0169;
对于9,输入*,移入7,所以状态栈为01697;
对于7,输入id,移入5,所以状态栈为016975;
对于5,输入$, 需要规约,按F->id,所以弹出5,对于7与F,移入10,所以状态栈为01697 10;
对于10,输入$, 需要规约,按T->T*F,所以弹出10 7 9,对于6与T,移入9,所以状态栈为0169;
对于9,输入$, 需要规约,按E->E+T,所以弹出9 6 1,对于0与E,移入1,所以状态栈为01;
对于1,输入$,得到acc,结束。
今天的文章编译原理要点期中复习分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/66257.html