直觉表示方法
expression -> num
| id
| expression + expression
| expression * expression
// expression可以代表:数字、id、加法表达式、乘法表达式
直觉表示法的问题—语法存在二义性
// 推导 3+4*5,先推导为加法
expression -> expression + expression
expression -> num + expresion
expression -> 3 + expresion
expression -> 3 + expression * expression
expression -> 3 + num * expression
expression -> 3 + 4 * num
expression -> 3 + 4 * 5
// 推导 3+4*5,先推导为乘法
expression -> expression * expression
expression -> expression + expression * expression
expression -> num + expression * expression
expression -> num + expression * expression
expression -> 3 + expression * expression
expression -> 3 + num * expression
expression -> 3 + 3 * num
expression -> 3 + 4 * 5
// 推导的时候,开始符号可以推导为加法表达式或者乘法表达式,所以语法具有二义性
语法树表示推导过程
第一次使用加法进行推导,对语法树采用中序遍历的方式得到的表达式为:3+4*5
第二次推导用乘法表达式,对树进行中序遍历,得到的结果是:(3+4)*5,违背了原表达式的意思
语法重写版本一
// 连加,2+3+4 和 连乘的BNF写法2*4*5
primary_expression -> num | id
// 连乘
multiplicative -> multiplicative * primary_expression | primary_expression
// 连加
additive -> addtive + primary_expression | primary_expression
语法重写版本二
// 2+3*4
primary_expression -> num | id
multiplicative -> multiplicative * primary_expression | primary_expression
additive -> additive + multiplicative | multiplicative
// 所谓的BNF就是照猫画虎,找一个表达式用符号进行替换即可,其中要考虑多种的表达式形式
// 2+3+4*5*6,所以additive的产生式左边(additive+multiplicative)是一个additive,不是primary_expression
版本二左递归
- 消除左递归的方法
重写文法
左递归改成右递归(会破会四则运算的结合性)
LR算法,保证四则运算的结合性
// 消除左边递归举例
E -> E + T | T
T -> T*F | F
F -> (E) |i
// 消除左递归后的文法
E -> TE′
E′ -> +TE′ | ε
T -> FT′
T′ -> *FT′ | ε
F -> (E) | i
EBNF的表示方法
<expression> ::= <multiplicative_expression>{"+"<multiplicative_expression>| "-" <multiplicative_expression>}
<multiplicative_expresion> ::= <primary_expression> {"*"<primary_expression> | "/" <primary_expression>}
<primary_expression> :: <INTEGER> | "("expresion")"
总结
- 本文研究了四则运算的BNF的推导过程,了解文法的二义性解决方法–文法重写
- 了解了BNF的实质及迭代过程,BNF是对语言的一种形式上的描述,迭代的过程是形式上的直接的替换,比如:
E -> TE′
E′ -> +TE′ | ε的推导过程如下:
E -> TE′
E -> T+TE′
E -> T+T+TE′
E -> T+T+Tε
E -> T+T+T - 给出了EBNF的四则运算描述,EBNF便于代码描述