语法分析---文法转换

需要文法转换的原因

问题1

例如:

文法G:

S a A d a B e S \rightarrow{aAd | aBe}

A c A \rightarrow{c}

B b B \rightarrow{b}

输入

a b c

当同一非终结符的多个候选式存在共同前缀,将导致回溯现象。


问题2

例如:

文法G:
E E + T E T T E \rightarrow{E+T | E-T | T}

T T F T / F F T \rightarrow{T * F | T/F | F}

F ( E ) i d F \rightarrow{(E) | id}

输入:

i d + i d i d id + id * id

推导过程:

E E + T E + T + T E + T + T + T . . . E \Rightarrow{E + T \Rightarrow{E + T + T \Rightarrow{E + T + T + T \Rightarrow{...}}}}

因为文法开始符号的候选式没有以 i d id 开头的,所以选择第一个候选式。而因为输入的符号并没有被匹配,所以在相同的条件下依然还是要选择第一个候选式。由此导致了死循环。

注:

  1. 含有 A A α A \rightarrow{A\alpha} 形式产生式的文法称为是直接左递归(immediate left recursive)的(一步推导)。
  2. 如果一个文法中有一个非终结符A使得对某个串 α \alpha 存在一个推导 A + A α A \Rightarrow ^+{A\alpha} ,那么这个文法就是左递归的。
  3. 经过两步或两步以上推导产生的左递归称为是间接左递归。
  4. 左递归文法会使递归下降分析器陷入无限循环。

消除直接左递归

例如:

A A α β A \rightarrow{A \alpha | \beta} ( a ϵ a \ne \epsilon β \beta 不以A开头)

推导:

A A α A α α . . . A α α α . . . α β α α α . . . α A \Rightarrow{A\alpha \Rightarrow{A\alpha\alpha \Rightarrow{... \Rightarrow{A\alpha\alpha\alpha...\alpha \Rightarrow{\beta\alpha\alpha\alpha...\alpha}}}}}

所以写成正则表达式就是 r = β α r=\beta\alpha^*

那么原来的文法即可转换成 A β A A \rightarrow{\beta A'} A α A ϵ A' \rightarrow{\alpha A' | \epsilon} .

A α A α α A . . . α . . . α α α A α . . . α α α A' \Rightarrow{\alpha A' \Rightarrow{\alpha\alpha A' \Rightarrow{...\Rightarrow{\alpha...\alpha\alpha\alpha A' \Rightarrow{\alpha...\alpha\alpha\alpha}}}}} ,即 A α A' \rightarrow{\alpha ^*}

事实上,这种转换把左递归转换成了右递归。

例子:

E E + T T E \rightarrow{E + T | T}

可把 + T +T 看做 β \beta ,把 T T 看做 β \beta 。直接套用上面的公式,即

E T E E \rightarrow{T E'}

E + T E ϵ E' \rightarrow{+TE' | \epsilon}

消除直接左递归的一般形式

A A α 1 . . . A α 2 A α n β 1 β 2 . . . β n A \rightarrow{A \alpha_1 | ... | A\alpha_2 | A\alpha_n | \beta_1 | \beta_2 | ... | \beta_n}
( a j ϵ a_j \ne \epsilon β j \beta_j 不以A开头)

那么可以转换为

A β 1 A β 2 A . . . β n A A \rightarrow{\beta_1A' | \beta_2A' | ... | \beta_nA'}

A α 1 A α 2 A . . . α n A ϵ A' \rightarrow{\alpha_1A' | \alpha_2A' | ... | \alpha_nA' | \epsilon}

消除左递归是要付出代价的–引进了一些非终结符和 ϵ \epsilon 产生式

消除间接左递归

例:

S A α b S \rightarrow{A \alpha | b}

A A c S d ϵ A \rightarrow{Ac | Sd | \epsilon}

将S的定义带入A-产生式,得:

A A c A a d b d ϵ A \rightarrow{Ac | Aad | bd | \epsilon}

再消除A-产生式得直接左递归,得:

A b d A A A \rightarrow{bdA' | A'}

A c A a d A ϵ A' \rightarrow{cA' | adA' | \epsilon}

提取左公因子

例:

文法G:

S a A d a B e S \rightarrow{aAd | aBe}

A c A \rightarrow{c}

B b B \rightarrow{b}

可转换为,文法G’:

S a S S \rightarrow{aS'}

S A d B e S' \rightarrow{Ad | Be}

A c A \rightarrow{c}

B b B \rightarrow{b}

通过改写产生式来推迟决定,等读入了足够多的输入,获得足够信息后再做出正确的决定。

猜你喜欢

转载自blog.csdn.net/hjc256/article/details/87925949