Python / YACC:解决转移/减少冲突

时间:2010-05-30 18:52:18

标签: python parsing yacc ply

我正在使用PLY。以下是 parser.out

中的一种状态
state 3

    (5) course_data -> course .
    (6) course_data -> course . course_list_tail
    (3) or_phrase -> course . OR_CONJ COURSE_NUMBER
    (7) course_list_tail -> . , COURSE_NUMBER
    (8) course_list_tail -> . , COURSE_NUMBER course_list_tail

  ! shift/reduce conflict for OR_CONJ resolved as shift
    $end            reduce using rule 5 (course_data -> course .)
    OR_CONJ         shift and go to state 7
    ,               shift and go to state 8

  ! OR_CONJ         [ reduce using rule 5 (course_data -> course .) ]

    course_list_tail               shift and go to state 9

我想解决这个问题:

if OR_CONJ is followed by COURSE_NUMBER:
    shift and go to state 7
else:
    reduce using rule 5 (course_data -> course .)

如何修复我的解析器文件以反映这一点?我是否需要通过回溯和尝试不同的规则来处理语法错误?

documentation说:

  

然后使用这些值来附加a   数值优先值和   每个的相关方向   语法规则。这总是如此   通过观察确定   最右边的终端的优先级   符号

如果规则没有终端怎么办?

更新:完整的语法:

Grammar

Rule 0     S' -> statement
Rule 1     statement -> course_data
Rule 2     or_phrase -> statement OR_CONJ statement
Rule 3     or_phrase -> course OR_CONJ COURSE_NUMBER
Rule 4     statement -> or_phrase
Rule 5     course_data -> course
Rule 6     course_data -> course course_list_tail
Rule 7     course_list_tail -> , COURSE_NUMBER
Rule 8     course_list_tail -> , COURSE_NUMBER course_list_tail
Rule 9     course -> DEPT_CODE COURSE_NUMBER

1 个答案:

答案 0 :(得分:4)

你的基本问题是你需要两个前瞻标记来做你想做的事情 - 当到目前为止看到的输入是course并且前瞻是OR_CONJ时你不知道是否将course缩减为course_data或转移,而不在OR_CONJ之后向前看两个令牌。您可以通过多种方式处理此问题

  • 使用LR(2)或LR(k)或GLR解析器生成器 - 任何人都可以解决这个问题。

  • 使用lexer hack进行前瞻 - 基本上让词法分析器返回两个不同的OR_CONJ标记,具体取决于以下标记是否为COURSE_NUMBER

    < / LI>
  • 将语法分解为摆脱冲突,这可能导致语法解析与您想要的略有不同的东西(需要一些额外的解析后检查以拒绝一些无效的构造)并且通常会使语法更难理解。

请注意,您给出的语法也与在单个语句中连接的三门或更多课程关联的方式有关。通过将语法重写为更清晰的左递归形式,可以轻松解决这个问题:

Rule 1    statement -> course
Rule 2    statement -> statement OR_CONJ course
Rule 3    course -> DEPT_CODE course_list
Rule 4    course -> DEPT CODE course_list OR_CONJ COURSE_NUMBER
Rule 5    course_list -> COURSE_NUMBER
Rule 6    course_list -> course_list , COURSE_NUMBER

对于LL解析器生成器,这也可以重写为右递归,但它仍然具有2令牌前瞻问题。重构它以使其消失的一种方法是使COURSE_NUMBER本身成为有效的course并在后传中将其与之前的course重新组合(或者如果出错则给出错误它是course中的第一个statement。然后规则4变为:

Rule 4    course -> COURSE_NUMBER

你没有冲突。