编译原理-5-LL(1)语法分析器

LL(1)语法分析器

1. 什么是LL(1)语法分析器

  1. 自顶向下的、递归下降的、预测分析的、适用于LL(1)文法的LL(1)语法分析器
  2. 自顶向下构建语法分析树
    1. 根节点是文法的起始符号 S S S
    2. 每个中间节点表示对某个非终结符应用于某个产生式进行推导
    3. 叶节点是词法单元流$w$$
  3. 仅包含终结符号与特殊的文件结束符$$$
  4. 递归下降算法的实现框架

  1. 为每个非终结符写一个递归函数:但是工作量会比较大
  2. 内部按需调用其它非终结符对应的递归函数

1.1. 语法树生成例子

S → F S → ( S + F ) F → a \begin{array}{l} S \rightarrow F \\ S \rightarrow (S+F) \\ F \rightarrow a \\ \end{array} SFS(S+F)Fa

演示递归下降过程(指针移动):针对结构 w = ( ( a + a ) + a ) w=((a+a)+a) w=((a+a)+a)

  1. 首先进入S的递归函数,我们选择一条产生式(假设已经选择好),我们选择的是 S → ( S + F ) S \rightarrow (S + F) S(S+F)
  2. 然后我们发现还是非终结符,我们仍然选择 S → ( S + F ) S \rightarrow (S + F) S(S+F)
  3. 然后我们发现还是非终结符,我们选择 S → F S \rightarrow F SF
  4. 然后我们发现是终结符,检查 F → a F \rightarrow a Fa得到的结果是否和当前指针指向的位置的值,匹配则继续,否则报错。
  5. 之后省略,注意右括号被匹配意味相应部分递归结束。
    以上的过程在本质上是DFS的过程。

  1. 每次都选择语法分析树最左边非终结符进行展开,所以得到最左推导
  2. Q:同样是展开非终结符S,为什么前两次选择了 S → ( S + F ) S \rightarrow (S + F) S(S+F), 而第三次选择了 S → F S \rightarrow F SF?
  3. A:因为只有选择 S → ( S + F ) S \rightarrow (S + F) S(S+F)才能生成一个左括号开头的式子,这个是由文法决定的,也就是因为它们面对的当前词法单元不同

1.2. 使用预测分析表确定产生式

  1. 指明了每个非终结符在面对不同的词法单元或文件结束符时,该选择哪个产生式(按编号进行索引)或者报错
  2. 预测分析表如下图所示

  1. 例子:根据当前值选择使用不同的产生式
    1. (选择2号产生式
    2. a且S则选择1号产生式
    3. a且F则选择3号产生式
    4. 上表中的空白标记记为报错。
  2. 问题:如何构造上面的表格?

1.3. Definition (LL(1) 文法)

  1. 如果文法G的预测分析表无冲突的, 则G是LL(1)文法。
  2. 无冲突: 每个单元格里只有一个生成式(编号),不然就会出现选择问题。

  1. 对于当前选择的非终结符,仅根据输入中当前的词法单元即可确定需要使用哪条产生式
  2. 递归下降的、预测分析实现方法

1.4. 实现LL(1)算法的具体代码

1.4.1. 解析 S ( ) S() S()

1: procedure S()
2:    if token = '(' then
3:       MATCH('(')
4:       S()
5:       MATCH('+')
6:       F()
7:       MATCH(')')
8:    else if token ='a' then
9:       F()
10:   else
11:      ERROR(token, {'(', 'a'})

1.4.2. 解析 F ( ) F() F()

1: procedure F()
2:    if token = 'a' then
3:       MATCH('a')
4:    else
5:       ERROR(token, {'a'})

1.4.3. 解析 M A T C H ( ) MATCH() MATCH()

1: procedure MATCH(t)
2:    if token = t then
3:       token <- NEXT-TOKEN
4:    else 
5:       ERROR(token, t)

2. 如何计算给定文法G的预测分析表?

下文则会重点解释如何计算给定文法G的预测分析表

2.1. Definition( F i r s t ( α ) First(\alpha) First(α)集合)

对于任意的(产生式的右部) α ∈ ( N ∪ T ) ∗ \alpha \in (N \cup T)^* α(NT)
F I R S T ( α ) = t ∈ T ∪ ϵ ∣ α ⇒ ∗ t β ∧ α ⇒ ∗ ϵ FIRST(\alpha) = {t \in T \cup {\epsilon} | \alpha \xRightarrow{*} t\beta \wedge \alpha \xRightarrow{*}\epsilon} FIRST(α)=tTϵα tβα ϵ

  1. F i r s t ( α ) First(\alpha) First(α) 是可从 α \alpha α推导得到的句型的首终结符号的集合
  2. T T T是终结符集合, t t t可能是终结符,也可能是 ϵ \epsilon ϵ
  3. 考虑非终结符A的所有产生式 A → α 1 , A → α 2 , . . . , A → α m A \rightarrow \alpha_1,A \rightarrow \alpha_2, ... ,A \rightarrow \alpha_m Aα1,Aα2,...,Aαm,如果它们对应的 F i r s t ( α i ) First(\alpha_i) First(αi) 集合互不相交,则只需查看当前输入词法单元, 即可确定选择哪个产生式(或报错),如果相交,则不是LL(1)文法。

2.2. Definition( F o l l o w ( A ) Follow(A) Follow(A)集合)

对于任意的(产生式的左部) 非终结符 A ∈ N A \in N AN
F o l l o w ( A ) = { t ∈ T ∪ { $ } ∣ ∃ w . S ⇒ ∗ w = β A t γ } Follow(A) = \{t \in T \cup \{\$\} | \exist w.S \xRightarrow{*} w = \beta A t \gamma\} Follow(A)={tT{$}w.S w=βAtγ}

  1. F o l l o w ( A ) Follow(A) Follow(A)是可能在某些句型中紧跟在A右边的终结符的集合
  2. t t t可以是终结符和文件终止符。
  3. 考虑产生式: A → a A \rightarrow a Aa,如果从 α \alpha α可能推导出空串( α ⇒ ∗ ϵ \alpha \xRightarrow{*} \epsilon α ϵ),则只有当当前词法单元 t ∈ F o l l o w ( A ) t \in Follow(A) tFollow(A), 才可以选择该产生式:因为 A A A可能推导没了,然后就是 t t t了,我们期望 t t t能够匹配当前位置上的对应符号。

2.3. 计算 F i r s t First First集合

2.3.1. 先计算每个符号X的 F i r s t ( X ) First(X) First(X)集合

  1. 如果 Y 1 . . . Y i − 1 Y_1...Y_{i-1} Y1...Yi1都可以推导成为空串,那么 Y i Y_i Yi的首终结符应该也是X的首终结符。
  2. 不断应用上面的规则, 直到每个 F i r s t ( X ) First(X) First(X)都不再变化(闭包!!!)尤其注意递归。

2.3.2. 再计算每个符号串 α \alpha α F i r s t ( α ) First(\alpha) First(α)集合

α = X β F i r s t ( α ) = { F i r s t ( X ) ϵ ∈ L ( X ) F i t s t ( X ) ∪ F i r s t ( β ) ϵ ∉ L ( X ) \begin{array}{l} \alpha = X \beta \\ First(\alpha) = \begin{cases} First(X) & \epsilon \in L(X) \\ Fitst(X)\cup First(\beta) & \epsilon \notin L(X) \\ \end{cases} \end{array} α=XβFirst(α)={First(X)Fitst(X)First(β)ϵL(X)ϵ/L(X)

2.3.3. 求解 F i r s t ( α ) First(\alpha) First(α)的例子

( 1 ) X → Y ( 2 ) X → a ( 3 ) Y → ϵ ( 4 ) Y → c ( 5 ) Z → d ( 6 ) Z → X Y Z \begin{array}{l} (1) & X \rightarrow Y \\ (2) & X \rightarrow a \\ (3) & Y \rightarrow \epsilon \\ (4) & Y \rightarrow c \\ (5) & Z \rightarrow d \\ (6) & Z \rightarrow XYZ \\ \end{array} (1)(2)(3)(4)(5)(6)XYXaYϵYcZdZXYZ

F I R S T ( X ) = { a , c , ϵ } F I R S T ( Y ) = { c , ϵ } F I R S T ( Z ) = { a , c , d } F I R S T ( X Y Z ) = F I R S T ( X ) ∪ F I S R T ( Y Z ) = F I R S T ( X ) ∪ F I R S T ( Y ) ∪ F I R S T ( Z ) = { a , c , d } \begin{array}{l} FIRST(X) = \{a,c,\epsilon\} \\ FIRST(Y) = \{c, \epsilon\} \\ FIRST(Z) = \{a, c, d\} \\ FIRST(XYZ) = FIRST(X) \cup FISRT(YZ) \\ = FIRST(X) \cup FIRST(Y) \cup FIRST(Z) = \{a, c, d\}\\ \end{array} FIRST(X)={a,c,ϵ}FIRST(Y)={c,ϵ}FIRST(Z)={a,c,d}FIRST(XYZ)=FIRST(X)FISRT(YZ)=FIRST(X)FIRST(Y)FIRST(Z)={a,c,d}

注意不要忘记和 ϵ \epsilon ϵ相关的操作。

2.4. 为每个非终结符X计算 F o l l o w ( X ) Follow(X) Follow(X)集合

  1. 不断应用上面的规则, 直到每个Follow(X) 都不再变化(闭包!!!)
  2. Follow例子:注意闭包,可以无限扩充

( 1 ) X → Y ( 2 ) X → a ( 3 ) Y → ϵ ( 4 ) Y → c ( 5 ) Z → d ( 6 ) Z → X Y Z \begin{array}{l} (1) & X \rightarrow Y \\ (2) & X \rightarrow a \\ (3) & Y \rightarrow \epsilon \\ (4) & Y \rightarrow c \\ (5) & Z \rightarrow d \\ (6) & Z \rightarrow XYZ \\ \end{array} (1)(2)(3)(4)(5)(6)XYXaYϵYcZdZXYZ

F O L L O W ( X ) = { a , c , d , $ } F O L L O W ( Y ) = { a , c , d , $ } F O L L O W ( Z ) = ∅ \begin{array}{l} FOLLOW(X) = \{a, c, d, \$\} \\ FOLLOW(Y) = \{a, c, d, \$\} \\ FOLLOW(Z) = \emptyset \\ \end{array} FOLLOW(X)={a,c,d,$}FOLLOW(Y)={a,c,d,$}FOLLOW(Z)=

2.5. 如何根据 F i r s t First First F o l l o w Follow Follow集合计算给定文法G的预测分析表?

按照以下规则, 在表格[A, t] 中填入生成式 A → α ( 编 号 ) A \rightarrow \alpha(编号) Aα()

t ∈ F i r s t ( α ) ( 1 ) α ⇒ ∗ ϵ ∧ t ∈ F o l l o w ( A ) ( 2 ) \begin{array}{l} t \in First(\alpha) & (1)\\ \alpha \xRightarrow{*} \epsilon \wedge t \in Follow(A) & (2)\\ \end{array} tFirst(α)α ϵtFollow(A)(1)(2)

对于每一个生成式只要满足上面一条规则即可(或关系),首先,在下单元格中可以填写 A → α A \rightarrow \alpha Aα,则可以推导出 α ⇒ ∗ ϵ ∧ t ∈ F o l l o w ( A ) \alpha \xRightarrow{*} \epsilon \wedge t \in Follow(A) α ϵtFollow(A)(必要条件),但是由于是LL(1)文法的唯一性,那么必要条件等价于充分条件,也就是这是一个充要条件。

t t t
A A A A → α A \rightarrow \alpha Aα

2.6. Definition (LL(1) 文法)

如果文法G的预测分析表无冲突的, 则G是LL(1)文法。

( 1 ) X → Y ( 2 ) X → a ( 3 ) Y → ϵ ( 4 ) Y → c ( 5 ) Z → d ( 6 ) Z → X Y Z \begin{array}{l} (1) & X \rightarrow Y \\ (2) & X \rightarrow a \\ (3) & Y \rightarrow \epsilon \\ (4) & Y \rightarrow c \\ (5) & Z \rightarrow d \\ (6) & Z \rightarrow XYZ \\ \end{array} (1)(2)(3)(4)(5)(6)XYXaYϵYcZdZXYZ
F I R S T ( X ) = { a , c , ϵ } F I R S T ( Y ) = { c , ϵ } F I R S T ( Z ) = { a , c , d } F I R S T ( X Y Z ) = F I R S T ( X ) ∪ F I S R T ( Y Z ) = F I R S T ( X ) ∪ F I R S T ( Y ) ∪ F I R S T ( Z ) = { a , c , d } \begin{array}{l} FIRST(X) = \{a,c,\epsilon\} \\ FIRST(Y) = \{c, \epsilon\} \\ FIRST(Z) = \{a, c, d\} \\ FIRST(XYZ) = FIRST(X) \cup FISRT(YZ) \\ = FIRST(X) \cup FIRST(Y) \cup FIRST(Z) = \{a, c, d\}\\ \end{array} FIRST(X)={a,c,ϵ}FIRST(Y)={c,ϵ}FIRST(Z)={a,c,d}FIRST(XYZ)=FIRST(X)FISRT(YZ)=FIRST(X)FIRST(Y)FIRST(Z)={a,c,d}
F O L L O W ( X ) = { a , c , d , $ } F O L L O W ( Y ) = { a , c , d , $ } F O L L O W ( Z ) = ∅ \begin{array}{l} FOLLOW(X) = \{a, c, d, \$\} \\ FOLLOW(Y) = \{a, c, d, \$\} \\ FOLLOW(Z) = \emptyset \\ \end{array} FOLLOW(X)={a,c,d,$}FOLLOW(Y)={a,c,d,$}FOLLOW(Z)=

3. LL(1) 语法分析器

  1. L:从左向右(left-to-right) 扫描输入
  2. L:构建最左(leftmost) 推导
  3. 1:只需向前看一个输入符号便可确定使用哪条产生式

3.1. 非递归的预测分析方法

非递归算法效率会高一些


3.2. 改造文法成为LL(1)文法

  1. 改造它
    1. 消除左递归
    2. 提取左公因子
  2. 有左递归,有左公因子,则必然不是LL(1)文法
  3. 没有左递归,没有左公因子,则未必是LL(1)文法

3.2.1. 左递归

E → E + T ∣ E − T ∣ T T → T ∗ F ∣ T / F ∣ F F → ( E ) ∣ i d ∣ n u m \begin{array}{l} E \rightarrow E + T | E - T | T \\ T \rightarrow T * F | T / F | F \\ F \rightarrow (E) | id | num \\ \end{array} EE+TETTTTFT/FFF(E)idnum

  1. E 在不消耗任何词法单元的情况下, 直接递归调用E, 造成死循环,E左侧没有非终结符,不能消耗符号。
  2. 存在 F I R S T ( E + T ) ∩ F I R S T ( T ) ≠ ∅ FIRST(E + T) \cap FIRST(T) \neq \emptyset FIRST(E+T)FIRST(T)=,不是LL(1)文法
  3. 消除左递归

3.2.2. 消除左递归

  1. 左递归:

E → E + T ∣ T E \rightarrow E + T | T EE+TT

  1. 消除左递归(至少会消耗一个+)
    E → T E ′ E ′ → + T E ′ ∣ ϵ \begin{array}{l} E \rightarrow TE' \\ E' \rightarrow +TE' | \epsilon \\ \end{array} ETEE+TEϵ

  2. 将左递归转为右递归,注: 右递归对应右结合; 需要在后续阶段进行额外处理,至少语法分析可以通过。

3.2.3. 左递归例子

A → A α 1 ∣ A α 2 ∣ . . . A α m ∣ β 1 ∣ β 2 ∣ . . . β n \begin{array}{l} A \rightarrow A\alpha_1 | A\alpha_2 |...A\alpha_m|\beta_1|\beta_2|...\beta_n \\ \end{array} AAα1Aα2...Aαmβ1β2...βn

  • β i \beta_i βi都不以A开发

A → β 1 A ′ ∣ β 2 A ′ ∣ . . . ∣ β n A ′ A ′ → α 1 A ′ ∣ α 2 A ′ ∣ . . . ∣ α m A ′ ∣ ϵ \begin{array}{l} A \rightarrow \beta_1A' | \beta_2A' | ... | \beta_nA' \\ A' \rightarrow \alpha_1A'|\alpha_2A'|...|\alpha_mA'|\epsilon \\ \end{array} Aβ1Aβ2A...βnAAα1Aα2A...αmAϵ

3.2.4. 左递归例子II

E → E + T ∣ T T → T ∗ F ∣ F F → ( E ) ∣ i d \begin{array}{l} E \rightarrow E + T|T \\ T \rightarrow T * F|F \\ F \rightarrow (E) | id \\ \end{array} EE+TTTTFFF(E)id

  • 消除左递归

E → T E ′ E ′ → + T E ′ ∣ ϵ T → F T ′ T ′ → ∗ F T ′ ∣ ϵ F → ( E ) ∣ i d ∣ n u m \begin{array}{l} E \rightarrow TE' \\ E' \rightarrow +TE' | \epsilon \\ T \rightarrow FT' \\ T' \rightarrow *FT' | \epsilon \\ F \rightarrow (E)|id|num \\ \end{array} ETEE+TEϵTFTTFTϵF(E)idnum

3.2.5. 非直接左递归

S → A a ∣ b A → A c ∣ S b ∣ ϵ S ⇒ A a ⇒ S d a \begin{array}{l} S \rightarrow Aa|b \\ A \rightarrow Ac|Sb|\epsilon\\ S \Rightarrow Aa \Rightarrow Sda \\ \end{array} SAabAAcSbϵSAaSda

3.2.6. 消除左递归算法

A k → A l α ⇒ l > k A_k \rightarrow A_l\alpha \Rightarrow l > k AkAlαl>k

  1. 不会出现左递归,也不会出现间接左递归:因为不会回到自己
  2. 例子:

S → A a ∣ b A → A c ∣ S b ∣ ϵ \begin{array}{l} S \rightarrow Aa|b \\ A \rightarrow Ac|Sb|\epsilon \\ \end{array} SAabAAcSbϵ

考虑1号非终结符S,替换掉A中的S

A → A c ∣ A a d ∣ b d ∣ ϵ A \rightarrow Ac|Aad|bd|\epsilon AAcAadbdϵ

考虑2号非终结符A,使用A’进行替换,首先找不含A的生成A’,然后交换包含A的位置

S → A a ∣ b A → b d A ′ ∣ A ′ A ′ → c A ′ ∣ a d A ′ ∣ ϵ \begin{array}{l} S \rightarrow Aa|b \\ A \rightarrow bdA'|A' \\ A' \rightarrow cA'|adA'|\epsilon \\ \end{array} SAabAbdAAAcAadAϵ

3.2.7. 消除左递归的例子

注意"("等部分首终结符,最好选择一个顺序:比如从下往上算。

E → T E ′ E ′ → + T E ′ ∣ ϵ T → F T ′ T ′ → ∗ F T ′ ∣ ϵ F → ( E ) ∣ i d ∣ n u m \begin{array}{l} E \rightarrow TE' \\ E' \rightarrow +TE' | \epsilon \\ T \rightarrow FT' \\ T' \rightarrow *FT' | \epsilon \\ F \rightarrow (E)|id|num \\ \end{array} ETEE+TEϵTFTTFTϵF(E)idnum

F i r s t 从 左 侧 开 始 找 F i r s t ( F ) = { ( , i d } F i r s t ( T ′ ) = { ∗ , ϵ } F i r s t ( T ) = { ( , i d } F i r s t ( E ) = { ( , i d } F i r s t ( E ′ ) = { + , ϵ } F o l l o w 从 右 侧 开 始 找 F o l l o w ( E ) = { ) , $ } F o l l o w ( E ′ ) = { ) , $ } F o l l o w ( T ) = { + , ) , $ } F o l l o w ( T ′ ) = { + , ) , $ } F o l l o w ( F ) = { + , ∗ , ) , $ } \begin{array}{l} First从左侧开始找 \\ First(F) = \{(,id\} \\ First(T') = \{*,\epsilon\} \\ First(T) = \{(,id\} \\ First(E) = \{(,id\} \\ First(E') = \{+ , \epsilon\} \\ Follow从右侧开始找 \\ Follow(E) = \{), \$\} \\ Follow(E') = \{), \$\} \\ Follow(T) = \{+, ), \$\} \\ Follow(T') = \{+, ), \$\} \\ Follow(F) = \{+, ∗, ), \$\} \\ \end{array} FirstFirst(F)={(,id}First(T)={,ϵ}First(T)={(,id}First(E)={(,id}First(E)={+,ϵ}FollowFollow(E)={),$}Follow(E)={),$}Follow(T)={+,),$}Follow(T)={+,),$}Follow(F)={+,,),$}

3.2.8. 提取左公因子

包含左公因子
S → i E t S ∣ i E t S e S ∣ a E → b \begin{array}{l} S \rightarrow iEtS|iEtSeS|a \\ E \rightarrow b \end{array} SiEtSiEtSeSaEb

提取左公因子
S → i E t S S ′ ∣ a S ′ → e S ∣ ϵ E → b \begin{array}{l} S \rightarrow iEtSS'|a \\ S' \rightarrow eS|\epsilon \\ E \rightarrow b \\ \end{array} SiEtSSaSeSϵEb

解决二义性(人为解决): 选择 S ′ → e S S' \rightarrow eS SeS, 将else与前面最近的then关联起来

3.2.9. $$$符号的必要性

  • 1
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值