在这个文法中 {S, E} 这两个是非终结符号, { +, -, *, /, num, (, ) }这些是终结符号。 但是上面的例子中说的文法并不是一个LL(1)文法。因为他是一个左递归文法。 E -> E + E 产生式头部和产生式体的第一个符号是相同的,就会导致LL(1)文法陷入一个死循环。LL(1)文法是一个文法最左推导过程,从左往右的推导。
当我们看到 S -> E的时候 我们会去推导 产生式体E 当我们看到 E -> E + E 的时候我们会去推导产生式 E + E, 但此时产生式体的第一个符号 E 让我们又陷入了要解析产生式E,然后就陷入一个死循环出不去了。(更详细的大家看书中所说的) 所以当我们看到 E -> E + E 的时候就要消除左递归。(可能还有间接左递归, 具体看我另外一篇文章)
在按照算数表达式优先级(括号优先级最大,其次是乘除法, 在是加减法)我们给出的文法是: S -> E E -> E + T | E - T | T T -> T * F | T / F | F F -> (E) | num
这里的 "|" 是用来分割产生式体的, 这些用 | 分开的产生式他们拥有相同的 左部。 下面的产生式是用我的程序消除左递归后的文法。 S -> E | E -> TE|
T -> FT | F -> (E) | num | E-> +TE | -TE| ε |
T -> *FT| /FT | ε |
S -> ABC A -> a | ε B -> b C -> c 这个文法有4个产生式: S 是文法的开始符号。 这个产生式要匹配一个 abc 或者 bc 的字符串, 也就是终结符a是可以不存在的, 因为非终结符A是可以推导出空串的。那我们看看什么时候应用这个产生式。 当非终结符A可以推导出空串的时候 我们就要获取FOLLOW(A)的值,此时可以跟在A后面的只有B,而FIRST(B)的值是b.就是说当A产生式遇到终结符b时那么就应用 A -> ε这个产生式。