【转】使用EBNF相对于BNF表示的优越性

1. 有二义性的文法(虽然考虑了运算符的结合性,但却忽略了优先级)

expr -> expr + term
| expr - term
| expr * term
| expr / term
| term

term -> NUMBER
| ( expr )

2. 有二义性的文法(虽然考虑了运算符的优先级,但却忽略了结合性)

expr -> term + term
| term - term
| term

term -> factor * factor
| factor / factor
| factor

factor -> NUMBER
| ( expr )

3. 正确的但没有消除左递归的文法(同时考虑到了运算符的优先级和结合性)

expr -> expr + term
| expr - term
| term

term -> term * factor
| term / factor
| factor

factor -> NUMBER
| ( expr )

4. 消除了左递归后的正确文法
消除直接左递归的方法:
假设原文法 A –> Aα1|Aα2...|Aαm12|...|βn

其中,每个βi都不以A开头。然后用下面的产生式代替A产生式:

A –> β1A'|β2A'|...|βnA'

A' –> α1A'|α2A'|...|αmA'|ε

这样就消除了直接左递归。

expr –> term moreterms

moreterms –> + term moreterms

| – term moreterms

| ε

term –> factor morefactors

morefactors –> * factor morefactors

| / factor morefactors

| ε

factor –> NUMBER

| ( expr )

前面都是使用的BNF表示法描述的文法,下面来看一下用EBNF表示法来描述的计算器程序的文法。

5. 使用EBNF来表述的计算器程序的文法

expr –> term { + term }

| term { – term }

term –> factor { * factor }

| factor { / factor }

factor –> NUMBER

| ( expr )

在这里,花括号表示为0个或多个的意思。比如 expr –> term { + term } 就表示0个或多个"+ term”附加到左边的term上,所以表示运算符的结合性是左结合的。通过这样,运算符的结合性就很自然的表达了出来,而不用通过BNF那样需要显示的表示为 expr –> expr + term 来表示,而且在BNF里面这样的表述是有左递归的,还需要进一步的消除左递归,而消除左递归后的文法已经面目全非,失去了美感…… 最后,EBNF这样的表述的优点还在于翻译代码时可以简化代码,比如: { + term } 可以翻译为循环,而同样的在消除了左递归的BNF表示法当中,此处要多调用一个moreterms函数。

 

posted @ 2012-11-29 05:39  何解一直犯相同错误?  阅读(732)  评论(0编辑  收藏  举报