返回顶部

第六章 LR分析

作者:@cherish.
课程学习内容为作者从学校的PPT处摘抄,仅供自己学习参考,若需转载请注明出处:https://www.cnblogs.com/cherish-/p/16382392.html


LR分析

LR分析概述

  • LR(k):L(Left to right parsing)R(right-most derivation in reverse)K(look ahead k token(s))

  • 移进-归约法(shift-reduce);

  • 框架:总控程序、分析栈和分析表三个组成部分

【例】

假设文法G[S]和分析表M,状态(0,#)为开始状态,(q,a)为栈顶元素(q为状态,a为输入符号),则总控程序的算法如下:

  • 初始化:(0,#)进栈S

  • 读下一个输入符号a,根据ACTION(q , a)的值执行不同动作;

    • 移进:if(ACTION[q,a]==Sj),则(j,a)入分析栈S

    • 归约:if(ACTION[q,a]==ri),采用规则i归约;

      • 设规则iAα,将|α|个状态和符号弹出分析栈S

      • if(GOTO[q,A]==null)ERR();

        else(GOTO[q,A],A)入分析栈S

    • 报错:if(ACTION[q,a]==null)ERR()

    • 接受:if(ACTION[q,a]==acc)接受并结束。

    • 反复执行移进-归约,直到接受或报错。

【例】

LR(0)分析

定义:将符号串的任意含有头符号的子串称为前缀。特别地,空串ε为任意串的前缀。

定义:设文法G[S],如果SαAωαβω是句型αβω的规范推导,则αβ称为可归前缀αβ的前缀称为活前缀

【例】

识别活前缀DFA技术路线是根据文法G,构造识别活前缀NFA M。之后通过子集法,将NFA M确定化,得到识别活前缀DFA M

识别G=(VN,VT,P,S)活前缀的NFA

  • 文法G等价改写成G:文法G=(VN{S},VT,P{SS},S)VN{S}=

  • 每个规则Aα构造等价一个NFAMAα

    α=x1x2...xn,增加n+1个状态q1,q2,...,qn+1

    f(qi,xi)={qi+1}(1in)q1为开始状态,qn+1为结束状态,={x1,x2,...,xn}

  • 合并所有规则的NFAMα,构造成一个NFA M

    如果MAαf(q,B)={p},BVN,且NFABBβ对应开始状态为q,增加转换f(q,ε){q};最后仅保留NFAMSS的开始状态为NFA M的开始状态。

【例】

M(Aα)的状态可以直接由Aα规则来命名,对于规则:Aαβγ有:

通过LR(0)项目集(规范族)直接构造识别活前缀的DFA

LR(0)项目的分类:

  • 移进项目:Aαaβ
  • 待约项目:AαXβ
  • 归约项目:Aα
  • 接受项目:Sα
  • 其中α,β(VNVT),aVT,XVN
  • 特别地,空规则Aε对应LR(0)项目为A

DFALR(0)分析表:

LR(0)项目的MOVE运算定义

定义:设I是文法GLR(0)项目子集,则MOVE(I,X)定义如下:

MOVE(I,X)={AαXβ|AαXβI}

【例】

I={SaAcBe,AAb,Ab}

MOVE(I,A)={SaAcBe,AAb}

MOVE(I,b)=Ab

LR(0)项目的CLOSURE运算

定义:设I是文法GLR(0)项目子集,则closure(I)定义如下:

  • Iclosure(I)
  • {Bγ|AαBβclosure(I)}closure(I)
  • 重复上一步,直到closure(I)不再扩大为止。

【例】

I={SaAcBe}

closure(I)={SaAcBe,AAb,Ab}

LR(0)识别活前缀DFA M构造方法

设文法G=(VN,VT,P,S),且已等价改写成文法G,即G=(VN{S},VT,P{SS},S)VN{S}=;则识别活前缀DFAM=(K,,f,S,Z),其中:

  • Kp,(LR(0)项目集);
  • =VNVT
  • f(I,X)=closure(MOVE(I,X)),IK,X
  • S=closure(SS)
  • Z={q|qK,q};

定义:文法G的识别活前缀DFAM的状态集称为文法GLR(0)项目集规范族。

【例】

LR(0)分析表的构造

设文法GLR(0)项目集规范族C={I0,I1,...,In},且f为转换函数,则对每一个LR(0)项目,依据下列情况分别填分析表:

  • 如果移进项目AαaβIk,f(Ik,a)=Ij,则置ACTION[k,a]=Sj
  • 如果归约项目AαIk,Aα标号为ia(VT{#}),置ACTION[k,a]=ri
  • 如果接受项目SSIk,则置ACTION[k,#]=acc
  • 如果f(Ik,A)=Ii,AVN,则置GOTO[k,A]=j

凡按上述过程没能填入分析表元素ACTION[k,a]GOTO[k,a]置为ett为错误编号。

【例】

移进-归约冲突:项目集中同时出现移进和归约项目如Aαaβ,Bγ

归约-归约冲突:项目集中同时出现多个归约项目如Aα,Bβ

定义:如果文法GLR(0)项目集规范族不存在移进-归约冲突或归约-归约冲突的项目集,则文法G称为LR(0)文法。

  • 如果文法GLR(0)文法,则G可采用LR(0)分析法。
  • 如果文法GLR(0)文法,则G是无二义性的。
  • LR(0)分析表ACTION表中每格仅会是移进、归约和报错3种动作之一。

SLR(1)分析

不是LR(0)文法时,可以采用简单地向后看1个输入符号的方法,解决移进-归约冲突或归约-归约冲突。

假设文法LR(0)项目集规范族有一个并存移进-归约或归约-归约冲突的项目集Ik={Aαaβ,Aγ,Bδ,...};若{a}FOLLOW(A)FOLLOW(B)=则冲突可解决:

  • 如果下一个符号ai,移入;
  • 如果下一个符号aiFOLLOW(A),用Aγ归约;
  • 如果下一个符号aiFOLLOW(B),用Bδ归约。

这种分析方法称为SLR(1)分析法

SLR(1)分析表的构造

对每一个LR(0)项目,依据下列情况分别填分析表:

  • 如果移进项目AαaβIk,f(Ik,a)=Ij,则置ACTION[k,a]=Sj
  • 如果归约项目AαIk,Aα标号为iaFOLLOW(A),则置ACTION[k,a]=ri
  • 如果接受项目SSIk,则置ACTION[k,#]=acc
  • 如果f(Ik,A)=Ij,AVN,则置GOTO[k,A]=j

凡按上述步骤没能填入分析表元素ACTION[k,a]GOTO[k,a],置为ett为错误编号。

定义:设文法GLR(0)项目集规范族C中任意含有m个移进项目和n个归约项目的冲突项目集Ik的一般形式为:Ik={A1α1a1β1,...,Amαmamβm,B1γ1,...,Bnγn,...};其中Ai,BjVN,aiVT,αi,βj,γq(VNVT),...表示剩下的待约项目。

如果移进符号集a1,a2,...,αmFOLLOW(B1),FOLLOW(B2),...,FOLLOW(Bn)两两相交均为空集,则文法G称为SLR(1)文法

  • SLR(1)文法,可用SLR(1)分析法;
  • SLR(1)文法,是无二义性的;
  • LR(0)文法,一定也是SLR(1)文法

【例】

LR(1)分析

SLR(1)分析法存在的问题

  • SLR只是简单地考察下一个输入符号b是否属于与规约项目Aα相关联的FOLLOW(A),但bFOLLOW(A)只是归约α的一个必要条件,而非充分条件;
  • 对于产生式Aα的归约,在不同的使用位置,A会要求不同的后继符号;
  • 在特定位置,A的后继符号集合是FOLLOW(A)的子集。

LR(1)分析法在构造项目时,将特定位置的后继符信息一并纳入考量范围。

LR(1)的基本思想

在状态Ii:下一个符号属于FOLLOW(B)而不属于FIRST(β),即便归约到B,最终也会面临此路不通。

FIRST(β)作为产生式作为Bγ归约时向前查看的符号集合(向前搜索符号集,前瞻符号集),代替SLR(1)分析法中的FOLLOW(B),并将向前搜索符号集也放在LR(0)项目的后面:

[Aαβ,a]a称为向前搜索符(展望符)-LR(1)项目

LR(1)项目

定义:附加搜索符(VT{#})的LR(0)项目称为LR(1)项目。记为[LR(0)]LR(1)项目中LR(0)项目部分称为LR(1)项目的心。对于同心的LR(1)项目简记为[LR(0)1|2|...|m]。后者称为搜索集。

形如[Aα,a]的项表示仅在下一个输入符号等于a时才可以按照Aα进行归约。

这样的a的集合总是FOLLOW(A)的子集,通常是真子集。

P68

定义:设I是文法GLR(1)项目子集,则MOVE1(I,X)定义如下:

MOVE1(I,X)={[AαXβ,a]|[AαXβ,a]I}

定义:设I是文法GLR(1)项目子集,closure1(I)定义如下:

  • Iclosure1(I)
  • {[Bγ]|[AαBβ,a]closure1(I),bFIRST(βa)}closure1(I)
  • 重复上一步,直到closure1(I)不再扩大为止。

LR(1)识别活前缀的DFA M构造

设文法G=(VN,VT,P,S),等价改写文法G=(VN{S},VT,P{SS},S);其中VN{S}=,则识别活前缀DFAM=(K,,f,S,Z),其中:

  • Kp(LR(1)项目集);
  • =VNVT
  • f(I,X)=closure(MOVE1(I,X)),IL,X
  • S=closure1([SS,#])
  • Z={q,qK,q}

定义:文法GLR(1)识别活前缀DFA M的状态集称为文法GLR(1)项目规范族。

LR(1)分析表的构造

设文法GLR(1)项目集规范族C={I0,I1,...,In}

C中每个Ii构造得到状态i,状态i的语法分析动作按照下面的方法决定:

  • 如果[Aαaβ,b]Ii并且f(Ii,a)=Ij,则ACTION[i,a]=Sj
  • 如果[AαBβ,b]Ii并且f(Ii,B)=Ij,则ACTION[i,B]=Sj
  • 如果[Aα,a]Ii并且AS,则ACTION[i,a]=rj;(j是产生式 的编号)
  • 如果[SS,#]Ii,则ACTION[i,#]=acc
  • 所有没有定义的条目都设置为ett是错误编号。

定义:设文法GLR(1)项目集规范族C中任意含有m个移进项目和n个归约项目的冲突项目集Ik的一般形式为:Ik={[A1α1a1β1,S1],...,[Amαmamβm,Sm],[B1γ1,S1],...,[Bnγn,Sn],...}

其中Ai,BjVN,aiVT,αi,βj,γq(VNVT),...表示剩下的待约项目,Si,Sj为搜索集。

如果移进符号集{a1,a2,...,αm}和搜索集S1,...,Sn两两相交均为空集,则文法G称为LR(1)文法。

  • 如果文法GLR(1)文法,则G可采用LR(1)分析法;
  • 如果文法GLR(1)文法,则G是无二义性的;
  • 如果文法GSLR(1)文法,则G一定是LR(1)

【例】

LALR(1)分析

定义:如果采用同心项目集合并方法,进行合并后的文法GLR(1)项目集规范族,没有LR(1)项目冲突,则称文法GLALR(1)文法。

关于LALR(1)文法,可以得出下列几个结论:

  • 如果文法GLALR(1)文法,则G可采用LALR(1)分析法;
  • 如果文法GLALR(1)文法,则G是无二义性的;
  • 如果文法GLALR(1)文法,则G一定是LR(1)文法。

【例】

LALR(1)的特点

  • 形式上与LR(1)相同;
  • 大小上与LR(0)/SLR相当;
  • 分析能力介于SLRLR(1)二者之间;
  • 合并后的向前搜索符集合仍为FOLLOW集的子集。
posted @   cherish-lgb  阅读(566)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示