返回顶部

第四章 自顶向下语法分析方法

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


自顶向下语法分析方法

确定的自顶向下语法分析思想

  • 从分析树的顶部(根节点)向底部(叶节点)方向构造分析树,可以看成是从文法开始符号S推导出词串w的过程。

  • 每一步推导中,都需要做两个选择

    • 替换当前句型中的那个非终结符
    • 用该非终结符的那个候选式进行替换
  • 非终结符的选择:最左推导(left most)

    • 总是选择每个句型的最左非终结符进行替换
  • 候选产生式的选择

    • 根据输入流中的下一个终结符,选择最左非终结符的一个候选式
    • 不确定的自顶向下:穷举产生式
    • 确定的自顶向下:选择唯一可能推导出输入串w的规则进行推导

FIRST(α)-串首(终结)符号集

定义:设文法G=(VN,VT,P,S),则

FIRST(α)={αaβ,aVT,α,βV}

特别地,αε,约定εFIRST(α)

  • 同一非终结符的多个产生式,若右部的FIRST集无交集,则推导是确定的。

【例】

设文法G[S]:SAp|Bq,AcA|a,BdB|b,则

  1. FIRST(Ap) = {c , a}
  2. FIRST(Bq) = {d , b}
  3. FIRST(cA) = {c}
  4. FIRST(A) = {c , a}

FOLLOW(A)-非终结符的后继(终结)符号集

定义:设文法G=(VN,VT,P,S),AVN,则

FOLLOW(A)={a|SαAβ,aVT,aFIRST(β),α,βV}

或者FOLLOW(A)={a|S...Aa...,aVT};若S...A或者上述模式中的βε,则句末符#FOLLOW(A)

  • FOLLOW(A)是由任意句型中紧邻非终结符号A之后出现的终结符号a组成的集合。
  • 如果对非终结符A,有一条空规则,则AFOLLOW集合和A的非空右部的FIRST集合两两相交为空,可以使用确定的最左推导。

【例】

SELECT(A α)-产生式的可选集

使用统一的方法来选择使用规则,即当某规则右部能推导出空时,将其FIRSTFOLLOW这两个集合合并考虑,以确定在什么情况下选择该规则。

定义:设文法G=(VN,VT,P,S),AVN,AαP,则

SELECT(Aα)={FIRST(α)αε(FIRST(α){ε})FOLLOW(A)αε

SELECT(Aα)称为规则Aα的选择集,它是FIRST(α)FOLLOW(α)组成,是终结符号集VT的子集。

LL(1)文法

定义:文法GLL(1)的,当且仅当对每个VN,A的两个不同产生式Aα,Aβ,满足SELECT(Aα)SELECT(Aβ)=,其中α,β不能同时推导出ε

  • L——Left to right parsing 从左至右分析token;
  • L——Left-most derivation 最左推导;
  • 1——只需向右看1个符号便可以决定选择那个产生式进行推导。
  • 确定的,无二义的。

LL(1)文法的判别

判别依据:依定义,文法GLL(1)的,当且仅当任意两个左部相同的产生式其SELECT集的交集为空。

若存在非终结符的多个产生式,必须计算SELECT()集。

SELECT(Aα)={FIRST(α)αε(FIRST(α){ε})FOLLOW(A)αε

为此,需要:

  • 判别αε,仅当α中所有非终结符全部可推导出空,且α无非空的终结符;
  • 求产生式右部FIRST集,若产生式右部可推导出ε,则还需要计算产生式左部FOLLOW集。

以下的各种计算,应当视为一般性算法,而不是判别该文法的必需步骤

判定非终结符是否能推出空串

以文法G[S]:SAB,SbC,Ab,Aε,BaD,Bε,CAD,Cb,DaS,Dc为例;建立如图所示的表:

  • ε的非终结符,直接标记Yes,并划掉其所有产生式;
  • 若干一个非终结符的所有产生式右侧至少有一个非ε的终结符,它就不可能推导出ε。直接标记为No,并划掉其所有产生式。剩下的产生式中,但凡右侧有一个非ε的终结符,也不可能推导出ε。这样的产生式也划掉。
  • 在余下的产生式中,把所有能ε的非终结符,替换成ε。化简,结果为ε的,标记为Yes,否则标记为No

求FIRST(X)的算法

假定XV

  1. XVT,FIRST(X)={X}

  2. Xε,FIRST(X)={ε}

  3. 对于所有形如Xa...规则,且aVT,FIRST(X)={a}

  4. 对于所有形如XY1Y2...Yn规则,YiVN

    如果Y1ε,Y2ε,...,Yi1ε(in),则FIRST(X)=(FIRST(Y1)...FIRST(Yi)){ε}

    如果Y1ε,Y2ε,...,Ynε,则FIRST(X)=(FIRST(Y1)...FIRST(Yn)){ε}

  5. 重复步骤4,直到FIRST()不再扩大为止。

求FIRST(α)的算法

前提:αV,|α|=n

α=Y1Y2...Yn(VNVT),置FIRST(α)=。计算FIRST(α)

  • 如果Y1VT,则FIRST(α)={Y1}

  • 如果Y1ε,Y2ε,...,Yi1ε(1<in)

    FIRST(α)=(FIRST(Y1)...FIRST(Yi)){ε}

  • 如果Y1ε,Y2ε,...,Ynε

    FIRST(α)=(FIRST(Y1)...FIRST(Yn)){ε}

求FOLLOW(A)的算法

  1. FOLLOW(A)=;置FOLLOW(S)={#}
  2. 若有产生式BαAβ,AVN,则FOLLOW(A)=(FIRST(β){ε})
  3. 若有产生式BαABαAβ,且βε,则FOLLOW(A)=FOLLOW(B)
  4. 重复2、3,直到FOLLOW(A)不再扩大为止。

非LL(1)文法到LL(1)文法的等价变换

非LL(1)文法

  • 若文法含有左公共因子,一定不是LL(1)文法
  • 若文法含有直接或间接左递归,一定不是LL(1)文法

LL(1)文法LL(1)文法的等价变换:

  • 提取左公共因子
  • 消除左递归
    • 消除直接左递归
    • 消除间接左递归

提取左公因子

  • 对形如Aαβ|αγ进行等价变换为:Aα(β|γ),进一步变换为:AαA,Aβ|γ
  • 对形如Aαβ1|...|αβn进行等价变换为:AαA,Aβ1|...|βn
  • 注:若Aβ1|...|βn中仍含左公共因子,再次提取,直至所有的产生式不再有左公共因子。

【例】

文法中不含左公共因子只是LL(1)文法的必要条件

  • LL(1)文法一定不含有左公共因子
  • 不含左公共因子的文法不一定是LL(1)文法

递归文法

设文法G=(VN,VT,P,S),形如AαAβ的规则称为文法G的直接递归规则。特别地,如果α=ε时则称为文法G的直接左递归规则。如果β=ε时,则称为文法G的直接有递归规则。

设文法G=(VN,VT,P,S),如果存在推导AαλAμ,则规则Aα称为文法G的间接递归规则。特别地,如果λ=ε时则称为文法G的间接左递归规则。如果μ=ε时,则称为文法G的间接有递归规则。

  • 递归规则,左递归规则,右递归规则
  • 递归文法,左递归文法,有递归文法

消除直接左递归:

  • 把直接左递归改为右递归
  • G[A]:AAα1|...|Aαn,Aβ1|...|βnL={β1,...,βn}{α1,...,αn}
  • 改为:G[A]:Aβ1A|...|βnA,Aα1A|...|αnA,Aε

【例】

消除间接左递归:

  • 间接左递归 直接左递归右递归

消除文法中一切左递归的算法(无有害规则,无空产生式)

VN中的(非终结)符号按任意顺序线性排列,如A1,...,An

for(i = 1 ; i <= n ; ++i){
	for(j = 1 ; j <= i - 1 ; ++j){//以A1 , A2 , ... , Ai-1的产生式代入Ai产生式
		若Ai的产生式为: Ai → δ1|...|δk
		则形如Ai → Ajλ的产生式变为:Ai → δ1λ|...|δkλ
	}
	消除Ai的直接左递归
}
删除无用产生式

【例】

递归下降分析法

基本思想:

  • 将每个非终结符编写成一个递归子程序,完成选择规则、推导和匹配的功能;
  • 若非终结符A有多个产生式,则根据产生式的SELECT集选择相应的规则推导,对规则AY1Y2...Yn依次调用右部非终结符的子程序或匹配终结符,Yi为非终结符则调用Yi对应的子程序,若Yi为终结符,则与当前token匹配。匹配成功则调用词法分析程序取下一个token,匹配失败或当前token不属于任何SELECT集时,报告语法错误。
  • 按照递归子程序法构造的语法分析程序是由一个总控子程序和一组非终结符对应的递归子程序组成的。

表驱动分析法

  • 输入栈I:以串末端为底,栈内为未匹配部分;初始状态为w#w为要是别的串;
  • 分析栈S:推导过程产生的句型未匹配部分;初始状态为#S
  • 分析表M:若aSELECT(Aα),则M[A,a]=(Aα)
  • 输出:w的最左推导或报告语法错误。

【例】

posted @   cherish-lgb  阅读(191)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示