LR编写grammar中的问题和解决方法
本文主要说明LR解析过程中关于BNF的典型冲突如何在LR中解决
冲突一般分为两种:
- shift/reduce错误
- redure/redure错误
下面分别解释两种冲突
1. shift/reduce错误
这种错误是因为 分析器在这种情况下不知道是归约还是移进导致的。
2. redure/redure错误
这种错误是因为,解析器在解析栈中规则时发现有多个规则可以进行归约。rejected rule
会指出跟哪个rule冲突
我们首先举个例子。
例子1
文法如下: 这是一个简单的解析
"<><><><>"
"<>"
""
class classnam {}
def p_start(p):
'''
start : typeArguments
'''
def p_typeArguments(p):
'''
typeArguments : typeArgument
| typeArguments typeArgument
'''
def p_typeArgument(p):
'''
typeArgument : LESS MORE
| empty
'''
def p_empty( p ):
'''empty : '''
这时产生的错误。
WARNING:
WARNING: Conflicts:
WARNING:
WARNING: shift/reduce conflict for LESS in state 0 resolved as shift
WARNING: shift/reduce conflict for LESS in state 2 resolved as shift
WARNING: reduce/reduce conflict in state 2 resolved using rule (start -> typeArguments)
WARNING: rejected rule (empty -> <empty>) in state 2
那么下面看看如何来解决这个问题。
def p_start(p):
'''
start : typeArguments
| empty
'''
def p_typeArguments(p):
'''
typeArguments : typeArgument
| typeArguments typeArgument
'''
def p_typeArgument(p):
'''
typeArgument : LESS MORE
'''
def p_empty( p ):
'''empty : '''
这个问题出现在
def p_typeArgument(p):
'''
typeArgument : LESS MORE
| empty
'''
身上,因为empty比较特殊可以告诉yacc可以reduce,因为结束了。而LESS还需要shift.
而在 typeArgument 身上也出现了一个问题就是到底 typeArgument是redure成empty还是 LESS MORE形式。
例子2
def p_start(p):
'''
start : typeArguments
'''
def p_typeArguments(p):
'''
typeArguments : typeArgument
| typeArguments typeArgument
'''
def p_typeArgument(p):
'''
typeArgument : LESS MORE
| list
'''
def p_list(p):
'''
list : LESS MORE
'''
def p_empty( p ):
'''empty : '''
这个问题是比较典型的redure冲突
出现在 typeArgument和list的冲突上。
WARNING:
WARNING: Conflicts:
WARNING:
WARNING: reduce/reduce conflict in state 7 resolved using rule (typeArgument -> LESS MORE)
WARNING: rejected rule (list -> LESS MORE) in state 7
WARNING: Rule (list -> LESS MORE) is never reduced
这种情况就是因为在一个规则树中出现了两个同样的规则在同一个里面。
例子3
这个例子算是一个较为经典的shift/redure的问题。
expression : expression PLUS expression
| expression MINUS expression
| expression TIMES expression
| expression DIVIDE expression
| LPAREN expression RPAREN
| NUMBER
如果我们不只用优先级来定义,那么我们可以如下方法解决优先级别的问题:
def p_start(p):
'''
start : expression
'''
def p_expression(p):
'''
expression : multExpression
| expression PLUS multExpression
| expression MINUS multExpression
'''
def p_multExpression(p):
'''
multExpression : subExpression
| multExpression TIMES subExpression
| multExpression DIVIDE subExpression
'''
def p_subExpression(p):
'''
subExpression : LPAREN expression RPAREN
| primary
'''
def p_primary(p):
'''
primary : NUMBER
'''
在java中也可以使用如上方法来定义一个expression来完成整个expression树的解析过程。因为过于复杂,所以这里不就写了,有兴趣的可以看java 7 lanaguage
上面3个例子都比较典型,基本能把大部分书写LR文法的时候遇到的问题解决掉。
参考:https://www.ituring.com.cn/article/52229