自上而下分析法

1. 自上而下分析法思路

从文法开始符号出发,向下推导,推出句子

自上而下分析的主旨

  • 针对输入串,试图用一切可能的办法,从文法开始符号出发,自上而下的为输入串建立一颗语法树

  • 为输入串寻找一个最左推导

2. 自上而下分析法面临的问题

2.1 回溯

当一个非终结符用某一个候选匹配成功时,这种匹配可能是暂时的

如果匹配到后面,发现出错,则必须回溯到前面某一个状态

2.2 左递归问题

如果存在非终结符 PP ,满足 P+PαP \stackrel{+} \Longrightarrow P\alpha ,如果刚好匹配到了 PP 处,则会陷入无限循环中

如果是右递归则不会出现该问题,因为扫描指针会一直在移动,而不是停止不动,只要扫描指针在移动,那么输入串一定会扫描完

3. LL(1) 分析法

两个目标:克服回溯;消除左递归

3.1 消除左递归

一个文法可以消除左递归的条件

  • 不含以 ϵ\epsilon 为右部的产生式

  • 不含回路 P+PP \stackrel{+} \Longrightarrow P

3.1.1 直接消除左递归

引例:

PPαβP \rightarrow P \alpha \mid \beta \longrightarrow PPαPααPααβαα\begin{aligned} P & \Rightarrow P \alpha \\ & \Rightarrow P \alpha \alpha \\ & \Rightarrow \cdots \cdots\\ & \Rightarrow P \alpha \cdots \alpha \\ & \Rightarrow \beta \alpha \cdots \alpha \\ \end{aligned}

消除左递归后: PβPPαPϵ\begin{aligned} P &\rightarrow \beta P' \\ P' &\rightarrow \alpha P' \mid \epsilon \\ \end{aligned} \longrightarrow PβPβαPβααPβααPβαα\begin{aligned} P & \Rightarrow \beta P' \\ & \Rightarrow \beta \alpha P' \\ & \Rightarrow \beta \alpha \alpha P' \\ & \Rightarrow \cdots \cdots\\ & \Rightarrow \beta \alpha \cdots \alpha P' \\ & \Rightarrow \beta \alpha \cdots \alpha \\ \end{aligned}

一般而言,假定 PP ,满足 PPα1Pα2Pαmβ1β2βnP \rightarrow P \alpha_1 \mid P \alpha_2 \mid \dots \mid P \alpha_m \mid \beta_1 \mid \beta_2 \mid \dots \mid \beta_n ,其中,每个 α\alpha 都不等于 ϵ\epsilon ,每个 β\beta 都不以 PP 开头

消除左递归的通式: Pβ1Pβ2PβnPPα1Pα2PαmPϵ\begin{aligned} P & \rightarrow \beta_1 P' \mid \beta_2 P' \mid \dots \mid \beta_n P' \\ P' & \rightarrow \alpha_1 P' \mid \alpha_2 P' \mid \dots \mid \alpha_m P' \mid \epsilon \end{aligned}

例:文法 G(E)G(E)

EE+TTTTFFF(E)i\begin{aligned} E &\rightarrow E + T \mid T \\ T & \rightarrow T * F \mid F \\ F & \rightarrow (E) \mid i \end{aligned} 消除左递归\underrightarrow{\text{消除左递归}} ETEE+TEϵTFTTFTϵF(E)i\begin{aligned} E &\rightarrow T E' \\ E' &\rightarrow +TE' \mid \epsilon \\ T & \rightarrow F T' \\ T' & \rightarrow *FT' \mid \epsilon \\ F & \rightarrow (E) \mid i \\ \end{aligned}

3.1.2 间接消除左递归

对于文法 G(S)G(S)

SQccQRbbRSaa\begin{aligned} S &\rightarrow Q c \mid c \\ Q & \rightarrow R b \mid b \\ R & \rightarrow S a \mid a \\ \end{aligned}

虽然没有直接左递归,但 S、Q、R都是左递归的 SQcRbcSabcS \Rightarrow Qc \Rightarrow Rbc \Rightarrow Sabc

SQccQRbbRSaa\begin{aligned} S &\rightarrow Q c \mid c \\ Q & \rightarrow R b \mid b \\ R & \rightarrow S a \mid a \\ \end{aligned} SQccQSababbRSaa\begin{aligned} S &\rightarrow Q c \mid c \\ Q & \rightarrow Sab \mid a b \mid b \\ R & \rightarrow S a \mid a \\ \end{aligned} SSabcabcbc cQSababbRSaa\begin{aligned} S &\rightarrow Sabc \mid abc \mid bc \mid \ c \\ Q & \rightarrow Sab \mid a b \mid b \\ R & \rightarrow S a \mid a \\ \end{aligned}

3.2 消除左递归算法

  1. 把文法 GG 的所有非终结符按任一种顺序排列成 P1,P2,,Pn;P_1, P_2, \dots,P_n ; 按此顺序执行

  2. FOR i := 1 TO n DO

    BEGIN

    FOR j := 1 TO i - 1 DO

    把形如 PiPjγP_i \rightarrow P_j \gamma 的规则改写成

    Piδ1γδ2γδkγ;P_i \rightarrow \delta_1 \gamma \mid \delta_2 \gamma \mid \dots \mid \delta_k \gamma;

    (其中 Pjδ1δ2δkP_j \rightarrow \delta_1 \mid \delta_2 \mid \dots \mid \delta_k 是关于 PjP_j 的所有规则)

    消除关于 PiP_i 规则的直接左递归性

    END

  3. 化简由 2 所得的文法,去除那些从开始符号出发永远都无法到达的非终结符产生的规则

3.3 举例

P1P2a1P2P3a2PiPn1Pnan1PnP1anγn\begin{aligned} & P_1 &&\rightarrow P_2 a_1 \\ &P_2 &&\rightarrow P_3 a_2 \\ &P_i &&\rightarrow \cdots \\ &P_{n - 1} &&\rightarrow P_n a_{n-1} \\ &P_n &&\rightarrow P_1 a_n \mid \gamma_n \\ \end{aligned}

算法过程:

  • when i : 1 to n -1, no change

    when i = n:

    j = 1; PnP1anγnPnP2a1anγnP_n \rightarrow P_1 a_n \mid \gamma_n \Longrightarrow P_n \rightarrow P_2 a_1a_n \mid \gamma_n

    j = 2; PnP2a1anγnPnP3a2a1anγnP_n \rightarrow P_2 a_1a_n \mid \gamma_n \Longrightarrow P_n \rightarrow P_3 a_2a_1a_n \mid \gamma_n

    \cdots\cdots

    j = n - 1; PnPn1an2an3a1anγnPnPnan1an2a1anγnP_n \rightarrow P_{n-1} a_{n-2}a_{n-3} \cdots a_1a_n \mid \gamma_n \Longrightarrow P_n \rightarrow P_na_{n-1} a_{n-2} \cdots a_1a_n \mid \gamma_n

消除左递归后的结果:

PnγnPnPnan1an2a1anPnϵP_n \rightarrow \gamma_n P_n' \\ P_n' \rightarrow a_{n-1} a_{n-2} \cdots a_1a_n P_n' \mid \epsilon

3.4 消除回溯

确保做出的选择唯一正确,这样就可以避免回溯

在讨论消除回溯时,文法已经不存在左递归了

两个步骤:构建终结首符集 FIRST(α)FIRST(\alpha) 、构建 FOLLOW(A)FOLLOW(A)

构造 FIRST(α)FIRST(\alpha)

FIRST(α)FIRST(\alpha) 的作用是:明确告诉下一个要匹配的字符哪一个非终结符可以推导出来,即保存每个非终结符可以推出的第一个字符的集合。

构造前的处理:提取公共左因子

假设 AA 的规则是: Aδβ1δβ2δβnγ1γ2γmA \rightarrow \delta\beta_1 \mid \delta\beta_2 \mid \dots \mid \delta\beta_n \mid \gamma_1 \mid \gamma_2 \mid \dots \gamma_m ,其中,每个 γ\gamma 不以 δ\delta 开头,那么就可以改写这些规则来消除功能左因子 δ\delta ,改写后为: AδAγ1γ2γmAβ1β2βnA \rightarrow \delta A' \mid \gamma_1 \mid \gamma_2 \mid \dots \gamma_m \\ A' \rightarrow \beta_1 \mid \beta_2 \mid \dots \mid \beta_n

正式构造:唯一原则,把能推出的第一个字符加入集合,如果能推出的第一个是非终结符,则先放着

构造规则:

  • AFIRST(A)={}A \rightarrow * \Longrightarrow FIRST(A) = \{*\}

  • ATFIRST(A)={}A \rightarrow *T \Longrightarrow FIRST(A) = \{*\}

  • ATEFIRST(A)=FIRST(T)A \rightarrow TE \Longrightarrow FIRST(A) = FIRST(T) ,非 ϵ\epsilon 元素

  • ATEFA \rightarrow TEF

    • FIRST(T)FIRST(T) 不含 ϵ\epsilon ,则只把 FIRST(T)FIRST(T) 中的元素加入 FIRST(A)FIRST(A)

    • FIRST(T)FIRST(T) 含有 ϵ\epsilon ,则先把 FIRST(T)FIRST(T) 中非 ϵ\epsilon 元素加入 FIRST(A)FIRST(A) ,再把 FIRST(E)FIRST(E) 中非 ϵ\epsilon 元素加入 FIRST(A)FIRST(A)

    • FIRST(E)FIRST(E) 含有 ϵ\epsilon ,则把 FIRST(F)FIRST(F) 中非 ϵ\epsilon 元素加入 FIRST(A)FIRST(A)

    • 以此类推

    • FIRST(T),FIRST(E),FIRST(F)FIRST(T), FIRST(E), FIRST(F) ,均含 ϵ\epsilon ,则把 ϵ\epsilon 加入 FIRST(A)FIRST(A)

  • 直到所有集合均不发生变化为止

构造 FOLLOW(A)FOLLOW(A)

紧跟非终结符 AA 后面的元素的集合

构造规则:

  • #\# 置于开始符号的 FOLLOWFOLLOW 集合中

  • ETEE \rightarrow TE' ,将 FIRST(E)FIRST(E') 中的元素加入到 FOLLOW(T)FOLLOW(T)

  • AαBβA \rightarrow \alpha B\beta ,若 FIRST(β)FIRST(\beta) 含有 ϵ\epsilon ,则把 FOLLOW(A)FOLLOW(A) 中的元素加入到 FOLLOW(B)FOLLOW(B)

  • AαBA \rightarrow \alpha B ,则把 FOLLOW(A)FOLLOW(A) 中的元素加入到 FOLLOW(B)FOLLOW(B)

  • FOLLOWFOLLOW 集合中永远不加 ϵ\epsilon

3.5 举例

4. 递归下降分析程序构造

前提:必须消除了文法的左递归性、克服了回溯

主要思路:

  • 分析程序由一组递归过程构成,对每一语法变量(非终结符)构造一个相应的子程序,识别对应的语法单位

  • 通过对子程序间的相互调用实现对输入串的识别

  • 这样的分析程序称为递归下降分析器

几个全局过程和变量

  • ADVANCEADVANCE :把输入串指示器 IP 指向下一个输入符号,即读入一个单词符号

  • SYMSYM :IP 当前所指的输入符号

  • ERRORERROR :出错处理子程序

递归下降子程序

ATEBCϵA \rightarrow TE' \mid BC \mid \epsilon

PROCEDURE A;
BEGIN
    IF SYM in FIRST(TE') THEN
        BEGIN T; E' END
    ELSE IF SYM in FIRST(BC) THEN
        BEGIN B; C END
    ELSE IF SYM not in FOLLW(A) THEN
        ERROR
END;

文法的另一种表示法和转换图

在元符号 \rightarrow\mid 的基础上、扩充几个元语言符号:

  • 用花括号 {α}\{\alpha\} 表示闭包运算 α\alpha ^*

  • {α}0n\{\alpha\}_0^n 表示可任意重复 0 次至 n 次

  • 用方括号 [α][\alpha] 表示 {α}01\{\alpha\}_0^1 ,即表示 α\alpha 的出现可有可无(等价于 αϵ\alpha \mid \epsilon

ETE+TTFTFFi(E)E \rightarrow T \mid E + T \\ T \rightarrow F \mid T * F \\ F \rightarrow i \mid (E) \Longrightarrow ET{+T}TF{F}Fi(E)E \rightarrow T\{ +T \} \\ T \rightarrow F\{ *F \} \\ F \rightarrow i \mid (E)

用语法图来表示语言的文法

5. 预测分析程序

LL(1)分析法 ——— 假设要用非终结符 A 进行匹配,面临的输入符号为 aa ,A 的所有产生式为 Aα1α2αnA \rightarrow \alpha_1 \mid \alpha_2 \mid \dots \alpha_n

  1. aFIRST(αi)a \in FIRST(\alpha_i) ,则指派 αi\alpha_i 执行匹配任务

  2. aa 不属于任何一个候选符集,则:

    • ϵ\epsilon 属于某个 FIRST(αi)FIRST(\alpha_i)aFOLLOW(A)a \in FOLLOW(A) ,则让 AAϵ\epsilon 自动匹配

    • 否则,语法错误

5.1 预测分析程序构成

预测分析程序

分析开始时:

总控程序根据现行栈顶符号 X 和当前输入符号 aa ,执行下列三种动作之一:

  1. X=a=#X = a = '\#',则宣布分析成功,停止分析

  2. X=a#X = a \ne '\#' ,则把 X 从 STACK 栈顶逐出,让 aa 指向下一个输入符号

  3. XX 是一个非终结符,则查看分析表 MM

    • M[X,a]M[X, a] 中存放着关于 XX 的一个产生式,把 XX 逐出STACK栈顶,把产生式的右部符号串按反序一一推进STACK栈(若右部符号为 ϵ\epsilon ,则意味不推进任何东西进栈)。在把产生式的右部符号推进栈的同时应做这个产生式相应的语义动作。

    • M[X,a]M[X, a] 中存放着关于出错标志,则调用出错程序 ERROR

5.2 预测分析程序的总控程序

  • FLAG := TRUE;

    WHILE FLAG DO

    BEGIN

    把 STACK 栈顶符号上托出去并放在 X 中;

    IF XVTX \in V_T THEN

    IF X=aX = a THEN 把下一个输入符读进 aa

    ELSE ERROR

    ELSE IF X=#X = '\#' THEN

    IF X=aX = a THEN FLAG := FALSE

    ELSE ERROR

    ELSE IF M[X,a]={XX1,X2,,Xk}M[X, a] = \{ X \rightarrow X_1,X_2,\dots , X_k \} THEN

    Xk,Xk1,,X1X_k,X_{k-1},\dots , X_1 一一推进 STACK 栈

    ELSE ERROE

    END OF WHILE

    STOP

    END

5.3 举例

文法 G(E)G(E)ETEE+TEϵTFTTFTϵF(E)iE \rightarrow TE' \\ E' \rightarrow +TE' \mid \epsilon \\ T \rightarrow FT' \\ T' \rightarrow *FT' \mid \epsilon \\ F \rightarrow (E) \mid i

输入串为 ii+ii * i + i ,预测分析表:

i

+

*

(

)

#

EE

ETEE \rightarrow TE'

ETEE \rightarrow TE'

EE'

E+TEE' \rightarrow +TE'

EϵE' \rightarrow \epsilon

EϵE' \rightarrow \epsilon

TT

TFTT \rightarrow FT'

TFTT \rightarrow FT'

TT'

TϵT' \rightarrow \epsilon

TFTT' \rightarrow *FT'

TϵT' \rightarrow \epsilon

TϵT' \rightarrow \epsilon

FF

FiF \rightarrow i

F(E)F \rightarrow (E)

过程:

步骤

符号栈

输入串

所用产生式

0

#E\#E

ii+i#i * i + i \#

1

#ET\# E'T

ii+i#i * i + i \#

ETEE \rightarrow TE'

2

#ETF\# E'T'F

ii+i#i * i + i \#

TFTT \rightarrow FT'

3

#ETi\# E'T'i

ii+i#i * i + i \#

FiF \rightarrow i

4

#ET\# E'T'

i+i#* i + i \#

5

#ETF\# E'T'F*

i+i#* i + i \#

TFTT' \rightarrow *FT'

6

#ETF\# E'T'F

i+i#i + i \#

7

#ETi\# E'T'i

i+i#i + i \#

FiF \rightarrow i

8

#ET\# E'T'

+i#+ i \#

9

#E\# E'

+i#+ i \#

TϵT' \rightarrow \epsilon

10

#ET+\# E'T+

+i#+ i \#

E+TEE' \rightarrow +TE'

11

#ET\# E'T

i#i \#

12

#ETF\# E'T'F

i#i \#

TFTT \rightarrow FT'

13

#ETi\# E'T'i

i#i \#

FiF \rightarrow i

14

#ET\# E'T'

# \#

15

#E\# E'

# \#

TϵT' \rightarrow \epsilon

16

#\#

# \#

EϵE' \rightarrow \epsilon

5.4 分析表 M[A,a]M[A, a] 的构造

前提:构造 FIRST(α)FIRST(\alpha) FOLLOW(A)FOLLOW(A)

构造分析表步骤:

  1. 对文法 GG 的每个产生式 AαA \rightarrow \alpha 执行第 2 步和第 3 步

  2. 对每个终结符 aFIRST(α)a \in FIRST(\alpha) ,把 AαA \rightarrow \alpha 加至 M[A,a]M[A, a]

  3. ϵFIRST(α)\epsilon \in FIRST(\alpha) ,则对任何 bFOLLOW(A)b \in FOLLOW(A)AαA \rightarrow \alpha 加至 M[A,b]M[A, b]

  4. 把所有无定义的 M[A,a]M[A,a] 标上出错标志

5.5 举例

文法 G(E)G(E)ETEE+TEϵTFTTFTϵF(E)iE \rightarrow TE' \\ E' \rightarrow +TE' \mid \epsilon \\ T \rightarrow FT' \\ T' \rightarrow *FT' \mid \epsilon \\ F \rightarrow (E) \mid i 集合\underrightarrow{\text{集合}}

预测分析表:

i

+

*

(

)

#

EE

ETEE \rightarrow TE'

ETEE \rightarrow TE'

EE'

E+TEE' \rightarrow +TE'

EϵE' \rightarrow \epsilon

EϵE' \rightarrow \epsilon

TT

TFTT \rightarrow FT'

TFTT \rightarrow FT'

TT'

TϵT' \rightarrow \epsilon

TFTT' \rightarrow *FT'

TϵT' \rightarrow \epsilon

TϵT' \rightarrow \epsilon

FF

FiF \rightarrow i

F(E)F \rightarrow (E)

5.6 LL(1) 文法与二义性

若一个文法是左递归或者二义性的,那么,M 至少含有一个多重定义入口

Last updated

Was this helpful?