解决 ply yacc 中的 shift/reduce 冲突

Resolving shift/reduce conflicts in ply yacc

Ply 报告说它在使用我输入的构建 LALR 解析器的语法时遇到了很多 shift/reduce 冲突。

现在我正在努力解决这些冲突,但无论我做什么都会让情况变得更糟。首先,我使用 C 语言(我的语法几乎与编程语言语法相同,例如 C 和 Python 的混合)优先级 table 在我的解析器中设置 precedence tuple 与该顺序相同:

precedence = (
        # ('left', 'ELSE'),
        # ('left', 'ID')
        # ('left', 'INTEGERNUMBER')
        # ('left', 'FLOATNUMBER')
        # ('left', 'SEMICOLON')
        # ('left', 'ERROR')
        ('left', 'COMMA'),
        ('right', 'ASSIGN'),
        ('left', 'OR'),
        ('left', 'AND'),
        ('left', 'EQ', 'NE'),
        ('left', 'GE', 'GT'),
        ('left', 'LE', 'LT'),
        ('left', 'SUM', 'SUB'),
        ('left', 'MUL', 'DIV', 'MOD'),
        ('right', 'NOT'),
        ('left', 'LCB', 'RCB'), #left curly brace...
        ('left', 'LSB', 'RSB'), #left square bracket..
        ('left', 'LRB', 'RRB'), #left round bracket...
    )

它确实有帮助并消除了 90 次冲突中的大约 40 次。下一步我试图从包含左递归的语法中删除左递归。我使用在线工具为一两个作品做了这个,但它增加了很多 shift-reduce 冲突和一些 reduce/reduce 冲突,我不太擅长这些事情所以我怀疑我是否应该继续消除所有产品中的所有左递归以查看结果或早期的不良结果是一个停止标志。

我也进行了一些搜索,了解到左递归不会破坏 LALR 语法,precedenceassociativity 足以解决这些冲突。

以下是其中有数十起冲突的州之一:

state 82

    (45) exp -> exp operator exp .
    (45) exp -> exp . operator exp
    (46) exp -> exp . relop exp
    (54) operator -> . OR
    (55) operator -> . AND
    (56) operator -> . SUM
    (57) operator -> . SUB
    (58) operator -> . MUL
    (59) operator -> . DIV
    (60) operator -> . MOD
    (65) relop -> . GT
    (66) relop -> . LT
    (67) relop -> . NE
    (68) relop -> . EQ
    (69) relop -> . LE
    (70) relop -> . GE

  ! shift/reduce conflict for OR resolved as shift
  ! shift/reduce conflict for AND resolved as shift
  ! shift/reduce conflict for SUM resolved as shift
  ! shift/reduce conflict for SUB resolved as shift
  ! shift/reduce conflict for MUL resolved as shift
  ! shift/reduce conflict for DIV resolved as shift
  ! shift/reduce conflict for MOD resolved as shift
  ! shift/reduce conflict for GT resolved as shift
  ! shift/reduce conflict for LT resolved as shift
  ! shift/reduce conflict for NE resolved as shift
  ! shift/reduce conflict for EQ resolved as shift
  ! shift/reduce conflict for LE resolved as shift
  ! shift/reduce conflict for GE resolved as shift
    RSB             reduce using rule 45 (exp -> exp operator exp .)
    SEMICOLON       reduce using rule 45 (exp -> exp operator exp .)
    COMMA           reduce using rule 45 (exp -> exp operator exp .)
    RRB             reduce using rule 45 (exp -> exp operator exp .)
    OR              shift and go to state 54
    AND             shift and go to state 55
    SUM             shift and go to state 56
    SUB             shift and go to state 57
    MUL             shift and go to state 58
    DIV             shift and go to state 59
    MOD             shift and go to state 60
    GT              shift and go to state 61
    LT              shift and go to state 62
    NE              shift and go to state 63
    EQ              shift and go to state 64
    LE              shift and go to state 65
    GE              shift and go to state 66

  ! OR              [ reduce using rule 45 (exp -> exp operator exp .) ]
  ! AND             [ reduce using rule 45 (exp -> exp operator exp .) ]
  ! SUM             [ reduce using rule 45 (exp -> exp operator exp .) ]
  ! SUB             [ reduce using rule 45 (exp -> exp operator exp .) ]
  ! MUL             [ reduce using rule 45 (exp -> exp operator exp .) ]
  ! DIV             [ reduce using rule 45 (exp -> exp operator exp .) ]
  ! MOD             [ reduce using rule 45 (exp -> exp operator exp .) ]
  ! GT              [ reduce using rule 45 (exp -> exp operator exp .) ]
  ! LT              [ reduce using rule 45 (exp -> exp operator exp .) ]
  ! NE              [ reduce using rule 45 (exp -> exp operator exp .) ]
  ! EQ              [ reduce using rule 45 (exp -> exp operator exp .) ]
  ! LE              [ reduce using rule 45 (exp -> exp operator exp .) ]
  ! GE              [ reduce using rule 45 (exp -> exp operator exp .) ]

    operator                       shift and go to state 52
    relop                          shift and go to state 53  

以下是我认为与上述状态相关的一些作品:

exp → lvalue=exp | exp operator exp |exp relop exp|
const | lvalue | ID(explist) | LRB exp RRB | ID() | SUB exp | NOT exp

operator → OR | AND | SUM | SUB | MUL | DIV | MOD

relop → GE | LT | NE | EQ | LE | GE

const → INTEGERNUMBER | FLOATNUMBER | TRUE | FALSE

lvalue → ID | ID LSB exp RSB

编辑: 下面是完整的警告列表:

WARNING: Conflicts:
WARNING: 
WARNING: shift/reduce conflict for VOID in state 0 resolved as shift
WARNING: shift/reduce conflict for INTEGER in state 0 resolved as shift
WARNING: shift/reduce conflict for FLOAT in state 0 resolved as shift
WARNING: shift/reduce conflict for BOOLEAN in state 0 resolved as shift
WARNING: shift/reduce conflict for INTEGER in state 45 resolved as shift
WARNING: shift/reduce conflict for FLOAT in state 45 resolved as shift
WARNING: shift/reduce conflict for BOOLEAN in state 45 resolved as shift
WARNING: shift/reduce conflict for RETURN in state 72 resolved as shift
WARNING: shift/reduce conflict for WHILE in state 72 resolved as shift
WARNING: shift/reduce conflict for FOR in state 72 resolved as shift
WARNING: shift/reduce conflict for IF in state 72 resolved as shift
WARNING: shift/reduce conflict for PRINT in state 72 resolved as shift
WARNING: shift/reduce conflict for ID in state 72 resolved as shift
WARNING: shift/reduce conflict for LRB in state 72 resolved as shift
WARNING: shift/reduce conflict for SUB in state 72 resolved as shift
WARNING: shift/reduce conflict for NOT in state 72 resolved as shift
WARNING: shift/reduce conflict for LCB in state 72 resolved as shift
WARNING: shift/reduce conflict for INTEGERNUMBER in state 72 resolved as shift
WARNING: shift/reduce conflict for FLOATNUMBER in state 72 resolved as shift
WARNING: shift/reduce conflict for TRUE in state 72 resolved as shift
WARNING: shift/reduce conflict for FALSE in state 72 resolved as shift
WARNING: shift/reduce conflict for OR in state 82 resolved as shift
WARNING: shift/reduce conflict for AND in state 82 resolved as shift
WARNING: shift/reduce conflict for SUM in state 82 resolved as shift
WARNING: shift/reduce conflict for SUB in state 82 resolved as shift
WARNING: shift/reduce conflict for MUL in state 82 resolved as shift
WARNING: shift/reduce conflict for DIV in state 82 resolved as shift
WARNING: shift/reduce conflict for MOD in state 82 resolved as shift
WARNING: shift/reduce conflict for GT in state 82 resolved as shift
WARNING: shift/reduce conflict for LT in state 82 resolved as shift
WARNING: shift/reduce conflict for NE in state 82 resolved as shift
WARNING: shift/reduce conflict for EQ in state 82 resolved as shift
WARNING: shift/reduce conflict for LE in state 82 resolved as shift
WARNING: shift/reduce conflict for GE in state 82 resolved as shift
WARNING: shift/reduce conflict for OR in state 83 resolved as shift
WARNING: shift/reduce conflict for AND in state 83 resolved as shift
WARNING: shift/reduce conflict for SUM in state 83 resolved as shift
WARNING: shift/reduce conflict for SUB in state 83 resolved as shift
WARNING: shift/reduce conflict for MUL in state 83 resolved as shift
WARNING: shift/reduce conflict for DIV in state 83 resolved as shift
WARNING: shift/reduce conflict for MOD in state 83 resolved as shift
WARNING: shift/reduce conflict for GT in state 83 resolved as shift
WARNING: shift/reduce conflict for LT in state 83 resolved as shift
WARNING: shift/reduce conflict for NE in state 83 resolved as shift
WARNING: shift/reduce conflict for EQ in state 83 resolved as shift
WARNING: shift/reduce conflict for LE in state 83 resolved as shift
WARNING: shift/reduce conflict for GE in state 83 resolved as shift
WARNING: shift/reduce conflict for ELIF in state 121 resolved as shift

在此先感谢您。

由于 +* 在句法上不同,您不能将它们归为一个句法类别 (operator)。

它们在语法上的不同正是因为运算符具有不同的优先级。 (或者,更准确地说,我们通常将句法差异描述为优先级差异)。例如,表达式 a - b * ca - b - c 在句法上 不同,因为在第一个表达式中, N - N 的语法允许第二个 N 覆盖 b * c,而在第二个 b - c 中不允许作为第二个 N 的扩展。因此,将所有运算符收集到一个 operator 非终结符中会以某种方式混淆不同的句法结构,从而无法使用语法生成正确的解析。

为了使用优先声明来解决歧义语法,您必须使实际的运算符标记在产生式中可见:

exp: exp '+' exp | exp '-' exp | exp '*' exp …

(注意:我在上面使用了引用的文字标记,而不是坚持使用名称。文字标记的使用更具可读性,并且在您的词法分析器描述中需要更少的样板文件。它还允许 Ply 创建更高效​​的词法分析器。见 the Ply manual.)

不要试图消除左递归。没有左递归,就无法正确编写左结合运算符(也就是说,大多数运算符)的语法。 LALR 解析器更喜欢左递归规则。他们不是你的问题。