下面是一个只包含符号 a 和 b 的正则表达式文法。它使用 + 替代表示并运算的字符 | ,以避免和文法中作为元符号使用的竖线相混淆:
rexpr -> rexpr + rterm | rterm
rterm -> rterm rfactor | rfactor
rfactor -> rfactor * | rprimary
rprimary -> a | b
消除左递归
rexpr -> rterm A
A -> + rterm A | ε
rterm -> rfactor B
B -> rfactor B | ε
rfactor -> rprimary C
C -> * C | ε
rprimary -> a | b
适合?
对下面的文法重复练习 4.3.1
S -> S S + | S S * | a
提取左公因子
S -> S S A | a
A -> + | *
不适合
消除左递归
// initial status
1)S -> S S A | a
2) A -> + | *
// i = 1
1) S -> a B
2) B -> S A B | ε
3) A -> + | *
// i = 2, j = 1
1) S -> a B
2) B -> a B A B | ε
3) A -> + | *
// i = 3, j = 1 ~ 2
// nothing changed
S -> 0 S 1 | 0 1
提取左公因子
S -> 0 A
A -> S 1 | 1
不适合,有间接左递归
消除左递归
// initial status
1) S -> 0 A
2) A -> S 1 | 1
// i = 1
// nothing changed
// i = 2, j = 1
1) S -> 0 A
2) A -> 0 A 1 | 1
S -> S (S) S | ε
消除左递归
// initial status
1) S -> S (S) S | ε
// i = 1
1) S -> A
2) A -> (S) S A | ε
// i = 2, j = 1
// nothing changed
S -> (L) | a 以及 L -> L, S | S
消除左递归
// initial status
1) S -> (L) | a
2) L -> L, S | S
// i = 1
// nothing changed
// i = 2, j = 1
1) S -> (L) | a
2) L -> (L) A | a A
3) A -> , S A | ε
// i = 3, j = 1~2
// nothing changed
下面文法的目的是消除 4.3.2 节中讨论的 “悬空-else 二义性”:
stmt -> if expr then stmt
| matchedStmt
matchedStmt -> if expr then matchedStmt else stmt
| other
说明这个文法仍然是二义性的。
看一段示范代码,我们通过缩进来表示代码解析的层次结构
if expr
then
if expr
then matchedStmt
else
if expr
then matchedStmt
else stmt
这段代码还可以被解析成
if expr
then
if expr
then matchedStmt
else
if expr
then matchedStmt
else stmt
所以这仍然是一个二义性的文法。原因在于 matchedStmt -> if expr then matchedStmt else stmt
中的最后一个 stmt
,如果包含 else
语句的话,既可以认为是属于这个 stmt
的,也可以认为是属于包含这个 matchedStmt
的语句的。