返回顶部

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

自顶向下语法分析方法

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

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

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

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

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

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

FIRST(\(\alpha\))-串首(终结)符号集

定义:设文法\(G = (V_N , V_T , P , S)\),则

\[FIRST(\alpha) = \{\alpha \stackrel{*}{\Rightarrow} a\beta , a \in V_T , \alpha , \beta \in V^*\} \]

特别地,\(\alpha \stackrel{*}{\Rightarrow} \varepsilon\),约定\(\varepsilon \in FIRST(\alpha)\)

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

【例】

设文法\(G[S]: S\to Ap | Bq , A \to cA | a , B \to dB | b\),则

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

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

定义:设文法\(G = (V_N , V_T , P , S) , A \in V_N\),则

\[FOLLOW(A) = \{a | S \stackrel{*}{\Rightarrow}\alpha A\beta , a \in V_T , a \in FIRST(\beta) , \alpha , \beta \in V^*\} \]

或者\(FOLLOW(A) = \{a | S \stackrel{*}{\Rightarrow}...Aa...,a \in V_T\}\);若\(S \stackrel{*}{\Rightarrow}...A\)或者上述模式中的\(\beta \stackrel{*}{\Rightarrow} \varepsilon\),则句末符\(\# \in FOLLOW(A)\)

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

【例】

SELECT(A \(\to \alpha\))-产生式的可选集

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

定义:设文法\(G = (V_N , V_T , P , S) , A \in V_N , A \to \alpha \in P\),则

\[SELECT(A \to \alpha) = \begin{cases} FIRST(\alpha)\;&\alpha \stackrel{*}{\not\Rightarrow} \varepsilon \\ (FIRST(\alpha) - \{\varepsilon\})\cup FOLLOW(A)\;&\alpha \stackrel{*}{\Rightarrow} \varepsilon \end{cases} \]

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

LL(1)文法

定义:文法\(G\)\(LL(1)\)的,当且仅当对每个\(V_N , A\)的两个不同产生式\(A \to \alpha , A \to \beta\),满足\(SELECT(A \to \alpha) \cap SELECT(A\to \beta) = \empty\),其中\(\alpha, \beta\)不能同时推导出\(\varepsilon\)

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

LL(1)文法的判别

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

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

\[SELECT(A \to \alpha) = \begin{cases} FIRST(\alpha)\;&\alpha \stackrel{*}{\not\Rightarrow} \varepsilon \\ (FIRST(\alpha) - \{\varepsilon\})\cup FOLLOW(A)\;&\alpha \stackrel{*}{\Rightarrow} \varepsilon \end{cases} \]

为此,需要:

  • 判别\(\alpha \stackrel{*}{\Rightarrow} \varepsilon\),仅当\(\alpha\)中所有非终结符全部可推导出空,且\(\alpha\)无非空的终结符;
  • 求产生式右部FIRST集,若产生式右部可推导出\(\varepsilon\),则还需要计算产生式左部FOLLOW集。

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

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

以文法\(G[S] : S \to AB ,S \to bC ,A \to b,A \to \varepsilon , B \to aD , B \to \varepsilon , C \to AD , C \to b , D \to aS , D \to c\)为例;建立如图所示的表:

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

求FIRST(X)的算法

假定\(X \in V\)

  1. \(X \in V_T , FIRST(X) = \{X\}\)

  2. \(X \to \varepsilon , FIRST(X) \cup= \{\varepsilon\}\)

  3. 对于所有形如\(X \to a...\)规则,且\(a \in V_T , FIRST(X) \cup=\{a\}\)

  4. 对于所有形如\(X\to Y_1Y_2...Y_n\)规则,\(Y_i \in V_N\)

    如果\(Y_1 \stackrel{*}{\Rightarrow} \varepsilon,Y_2 \stackrel{*}{\Rightarrow} \varepsilon , ... , Y_{i - 1} \stackrel{*}{\Rightarrow} \varepsilon\;(i \leq n)\),则\(FIRST(X)\cup=(FIRST(Y_1) \cup...\cup FIRST(Y_i)) -\{\varepsilon\}\)

    如果\(Y_1 \stackrel{*}{\Rightarrow} \varepsilon,Y_2 \stackrel{*}{\Rightarrow} \varepsilon , ... , Y_{n} \stackrel{*}{\Rightarrow} \varepsilon\),则\(FIRST(X)\cup=(FIRST(Y_1) \cup...\cup FIRST(Y_n)) \cup \{\varepsilon\}\)

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

求FIRST(\(\alpha\))的算法

前提:\(\alpha \in V^*,|\alpha| = n\)

\(\alpha = Y_1Y_2...Y_n \in (V_N \cup V_T)^*\),置\(FIRST(\alpha) = \empty\)。计算\(FIRST(\alpha)\)

  • 如果\(Y_1 \in V_T\),则\(FIRST(\alpha) = \{Y_1\}\)

  • 如果\(Y_1 \stackrel{*}{\Rightarrow} \varepsilon,Y_2 \stackrel{*}{\Rightarrow} \varepsilon , ... , Y_{i - 1} \stackrel{*}{\Rightarrow} \varepsilon\;(1 < i \leq n)\)

    \[FIRST(\alpha) = (FIRST(Y_1) \cup...\cup FIRST(Y_i)) -\{\varepsilon\} \]

  • 如果\(Y_1 \stackrel{*}{\Rightarrow} \varepsilon,Y_2 \stackrel{*}{\Rightarrow} \varepsilon , ... , Y_{n} \stackrel{*}{\Rightarrow} \varepsilon\)

    \[FIRST(\alpha) = (FIRST(Y_1) \cup...\cup FIRST(Y_n)) \cup \{\varepsilon\} \]

求FOLLOW(A)的算法

  1. \(FOLLOW(A) = \empty\);置\(FOLLOW(S) = \{\#\}\)
  2. 若有产生式\(B \to \alpha A\beta , A \in V_N\),则\(FOLLOW(A) \cup = (FIRST(\beta) - \{\varepsilon\})\)
  3. 若有产生式\(B \to \alpha A\)\(B \to \alpha A \beta\),且\(\beta \stackrel{*}{\Rightarrow} \varepsilon\),则\(FOLLOW(A) \cup= FOLLOW(B)\)
  4. 重复2、3,直到\(FOLLOW(A)\)不再扩大为止。

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

非LL(1)文法

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

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

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

提取左公因子

  • 对形如\(A \to \alpha \beta | \alpha \gamma\)进行等价变换为:\(A \to \alpha (\beta|\gamma)\),进一步变换为:\(A \to \alpha A' , A' \to \beta | \gamma\)
  • 对形如\(A \to \alpha\beta_1|...|\alpha\beta_n\)进行等价变换为:\(A\to \alpha A' , A' \to \beta_1|...| \beta_n\)
  • 注:若\(A'\to \beta_1|...|\beta_n\)中仍含左公共因子,再次提取,直至所有的产生式不再有左公共因子。

【例】

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

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

递归文法

设文法\(G = (V_N , V_T , P , S)\),形如\(A \to \alpha A \beta\)的规则称为文法\(G\)的直接递归规则。特别地,如果\(\alpha = \varepsilon\)时则称为文法\(G\)的直接左递归规则。如果\(\beta = \varepsilon\)时,则称为文法\(G\)的直接有递归规则。

设文法\(G=(V_N , V_T , P , S)\),如果存在推导\(A \to \alpha \stackrel{*}{\Rightarrow} \lambda A \mu\),则规则\(A \to \alpha\)称为文法\(G\)的间接递归规则。特别地,如果\(\lambda = \varepsilon\)时则称为文法\(G\)的间接左递归规则。如果\(\mu = \varepsilon\)时,则称为文法\(G\)的间接有递归规则。

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

消除直接左递归:

  • 把直接左递归改为右递归
  • \(G[A] : A \to A\alpha_1 |... |A \alpha_n , A \to \beta_1 |... | \beta_n\)\(L = \{\beta_1 , ... , \beta_n\}\{\alpha_1 , ... , \alpha_n\}^*\)
  • 改为:\(G'[A]: A \to \beta_1A'|...|\beta_nA' , A' \to \alpha_1A'|...|\alpha_nA' , A' \to \varepsilon\)

【例】

消除间接左递归:

  • 间接左递归\(\Rightarrow\) 直接左递归\(\Rightarrow\)右递归

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

\(V_N\)中的(非终结)符号按任意顺序线性排列,如\(A_1 , ... , A_n\)

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集选择相应的规则推导,对规则\(A \to Y_1Y_2...Y_n\)依次调用右部非终结符的子程序或匹配终结符,\(Y_i\)为非终结符则调用\(Y_i\)对应的子程序,若\(Y_i\)为终结符,则与当前token匹配。匹配成功则调用词法分析程序取下一个token,匹配失败或当前token不属于任何SELECT集时,报告语法错误。
  • 按照递归子程序法构造的语法分析程序是由一个总控子程序和一组非终结符对应的递归子程序组成的。

表驱动分析法

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

【例】

posted @ 2022-06-14 16:18  cherish-lgb  阅读(139)  评论(0编辑  收藏  举报