在使用Python创建解析器时转移/减少冲突

在使用Python创建解析器时转移/减少冲突,python,parsing,yacc,ply,Python,Parsing,Yacc,Ply,我用sly()编写了一个解析器,但是它毫无理由地有两个shift/reduce冲突。我该怎么解决这个问题 parser.py @_("NAME ASSIGN primary") def statement(self, p): self.variables[p[0]] = p[2] @_("primary") def statement(self, p): return p[0] @_("primary PLUS secund

我用sly()编写了一个解析器,但是它毫无理由地有两个shift/reduce冲突。我该怎么解决这个问题

parser.py

@_("NAME ASSIGN primary")
    def statement(self, p):
        self.variables[p[0]] = p[2]

    @_("primary")
    def statement(self, p):
        return p[0]



    @_("primary PLUS secundary")
    def primary(self, p):
        return p[0] + p[2]

    @_("primary MINUS secundary")
    def primary(self, p):
        return p[0] - p[2]

    @_("secundary")
    def primary(self, p):
        return p[0]





    @_("secundary MULTIPLY tertiary")
    def secundary(self, p):
        return p[0] * p[2]

    @_("secundary FLOORDIV tertiary")
    def secundary(self, p):      
        return p[0] // p[2] 

    @_("secundary DIVIDE tertiary")
    def secundary(self, p):
        return p[0] / p[2]

    @_("secundary MOD tertiary")
    def secundary(self, p):
        return p[0] % p[2]

    @_("tertiary")
    def secundary(self, p):
        return p[0]




    @_("quaternary POWER tertiary")
    def tertiary(self, p):
        return p[0] ** p[2]

    @_("quaternary")
    def tertiary(self, p):
        return p[0]



    @_("tertiary quinary")   
    def quaternary(self, p):      
        return p[0] * p[1]

    @_("quinary")
    def quaternary(self, p):
        return p[0]




    @_("INTEGER")
    def quinary(self, p):
        return p[0]

    @_("LPAREN primary RPAREN")
    def quinary(self, p):
        return p[1]

调试输出

state 27

    (12) tertiary -> quaternary POWER tertiary .
    (14) quaternary -> tertiary . quinary
    (15) quinary -> . LPAREN primary RPAREN
    (16) quinary -> . INTEGER
  ! shift/reduce conflict for LPAREN resolved as shift
  ! shift/reduce conflict for INTEGER resolved as shift
    MOD             reduce using rule 12 (tertiary -> quaternary POWER tertiary .)
    DIVIDE          reduce using rule 12 (tertiary -> quaternary POWER tertiary .)
    FLOORDIV        reduce using rule 12 (tertiary -> quaternary POWER tertiary .)
    MULTIPLY        reduce using rule 12 (tertiary -> quaternary POWER tertiary .)
    MINUS           reduce using rule 12 (tertiary -> quaternary POWER tertiary .)
    PLUS            reduce using rule 12 (tertiary -> quaternary POWER tertiary .)
    $end            reduce using rule 12 (tertiary -> quaternary POWER tertiary .)
    RPAREN          reduce using rule 12 (tertiary -> quaternary POWER tertiary .)
    LPAREN          shift and go to state 8
    INTEGER         shift and go to state 9

    quinary                        shift and go to state 17
我只添加了调试文件的一部分,但是添加了整个语法,因为我认为其他语法都不相关,请告诉我是否应该发布更多代码


我不明白我的语法中怎么会有移位/减少冲突,因为我的规则没有含糊不清的地方

你的语法肯定是模棱两可的,因为
1次幂23
可以被解析为
(1次幂2)*3
1次幂(2*3)
。为了修复语法,您需要确定这两种解释中的哪一种是您想要的,然后更改语法以只允许正确的解释

据我所知,关于隐式乘法运算符的优先级还没有达成共识。许多人认为它应该与显式乘法具有完全相同的优先级和结合性。另一些人认为
2a/7b
应该被解释为
(2*a)/(7*b)
,而不是
((2*a)/7)*b
,这导致了隐式乘法应该结合得更紧密的想法

当引入指数运算时,事情变得更加复杂。在数学中,指数运算通常是用排版效果写成二维的。这使得指数的分组更加明确。对于其余部分,求幂结合更紧密(甚至比一元否定更紧密)的约定是没有问题的,我们有:

  • (1)
    a2b
    =>
    a*(2次电源b)
  • (2)
    a2b
    =>
    a电源(2*b)
  • (3)
    a2b
    =>
    (a电源2)*b
如果没有将指数写为上标所提供的隐式分组,上面的最后两个示例将变得难以区分。如果指数运算符是
^
,则它们都将被写入
a^2b
,解析器需要决定将两种可能的解释中的哪一种分配给字符串

想要将未解析表达式
a2^b
a^2b
解析为(1)和(2)的问题在于优先顺序不同:在情况(1)中,我们以幂运算为优先,而要实现情况(2),隐式乘法必须优先。我相信这就是你的语法试图做的,它失败了,正是因为这种形式的优先级反转非常棘手(通常会导致歧义)。将
a^2b
解释为(3)要简单得多,因为优先级是相同的


所以我建议你接受口译(3)。语言设计的一个重要原则是,计算机难以消除歧义的东西,人类也往往难以消除歧义,因此最好避免困难的消除歧义规则。(作为一个激励的例子,参见C++中的所谓的常见错误,这是许多C和C++编译器在关于语法冲突的完美的法律表达式如“代码”>中发出警告的原因,在分析语法冲突时,看到整个语法是有用的。添加一条说明。@wendelin:第一步是找出您认为正确的解析。@wendelin:整理您的结果,使第三个是左联想隐式乘法,第四个是右联想指数运算。
# This version makes implicit multiplication bind more tightly
# than division. Otherwise, implicit multiplication would just be
# added to secondary.
@_("tertiary quaternary")   
def tertiary(self, p):      
    return p[0] * p[1]

@_("quaternary")
def tertiary(self, p):
    return p[0]

@_("quinary POWER quaternary"
def quaternary(self, p):
    return p[0] ** p[2]

@_("quinary")
def quaternary(self, p):
    return p[0]