文法的左递归性和回溯的消除
1. 文法左递归的消除
当一个文法是左递归文法时,采用自上而下分析法会使分析过程进入无穷循环之中。文法左递归是指文法中的某个非终结符 A 存在推导 A ⇒+ Aα ,而自上而下分析法是施行最左推导,即每次替换都是当前句型中的最左非终结符,当试图用非终结符 A 去匹配输入串时,结果使当前句型的最左非终结符仍然为 A ,也就是说,在没有读进任何输入符号的情况下,又重新要求 A 去进行新的匹配,于是造成无穷循环。所以采用自上而下分析法进行语法分析需要消除文法的左递归性。
对含直接左递归的规则进行等价变换,消除左递归。
(1 )引进一个新的非终结符,把含左递归的规则改写成右递归。
设关于非终结符 A 的直接左递归的规则为
A → Aα | β
其中 α ,β 是任意的符号串,且 β 不以 A开头,对 A 的规则可改写成如下右递归形式:
A → β A'
A' → αA' | ε
改写以后的形式和原来形式是等价的。也就是说,从 A 推出的符号串的集合是相同的。
一般情况下,设文法中关于 A 的规则为
A → Aα 1 | Aα 2 | … | Aα m | β 1 | β 2 | … | β n
其中每个 α 都不等于 ε ,而每个 β 都不以 A 开头,消除直接左递归后改写为
A → β 1 A' | β 2 A' | … | β n A'
A' → α 1 A' | α 2 A' | … | α m A' | ε
【例 4.2 】设有文法 G [ E ]:
E → E + T | E - T | T
T → T * F | T / F | F
F → ( E ) | id
消去非终结符 E , T 的直接左递归后,文法 G [ E ]改写为
E → TE'
E' →+ TE' |- TE' | ε
T → FT'
T' → * FT' | / FT' | ε
F → ( E ) | id
【例 4.3 】设有文法 G [ A ]:
A → Ac | Aad | bd | e
消去直接左递归后文法 G [ A ]改写为
A → bdA' | eA'
A' → cA' | adA' | ε
(2 )采用扩充 BNF 表示法改写含直接左递归的规则。
在扩充的 BNF 表示中,有如下约定:
① 使用花括号{ α }表示符号串 α 的出现可 0 次或多次,即表示 α* 。
例如,定义标识符的文法<标识符> → l | <标识符> l | <标识符>d ,使用扩充 BNF 表示可改写成<标识符> → l {l | d }形式。
② 使用方括号[ α ]表示 α 的出现可有可无,它用来表示可供选择的符号串。例如,定义 C 语
言中条件语句的文法是
<条件语句> →if <布尔表达式><语句> |if <布尔表达式><语句>; else <语句>
用扩充 BNF 表示可改写成如下形式:
<条件语句> →if <布尔表达式><语句>[; else <语句>]
③ 使用圆括号可在规则中提取因子。例如
A → xα 1 | xα 2 | … | xα m 可写为 A → x ( α 1 | α 2 | … | αm )
【例 4.4 】对例 4.2 中文法用扩充 BNF 表示法对其进行改写。
分析 规则 E → E + T | E - T | T 和 T → T * F | T / F | F 表示了 E 所生成的符号串由 T 开头且后跟 0 个或多个 + T 或 - T ; T 所生成的符号串由 F 开头且后面跟 0 个或多个 * F或/ F ,所以原文法可改写成如下形式:
E → T { + T |- T }
T → F { * F | / F }
F → ( E ) | id
【例 4.5 】对例 4.3 中文法用扩充 BNF 表示法对其进行改写。
分析 规则 A → Ac | Aad | bd | e 表示了 A 所生成的符号串是以 bd 或 e 开头,后面跟 0个或多个 c 或 ad ,所以原文法可以改写成如下形式:
A → ( bd | e ){ c | ad }