BNF:输入错误的非终结

时间:2010-12-02 00:37:12

标签: yacc bnf ply

我正在为国际象棋代数符号开发一个BNF并遇到一个有趣的案例,输入到了错误的非终端。

我的开始BNF规则如下(请注意,这故意不包括铸造或备注):

algebraic_notation : piece start_position capture end_position promotion

piecestart_positioncapturepromotion可以为空,从而允许像'd4'这样的移动。问题在于,当输入这样的移动时,输入('d4')由start_position获取,因此导致错误b / c不再有end_position的输入,这不能是空。

明显的黑客/解决方法是允许end_position为空,然后检查我们是否获得了任何输入并采取相应措施。

这确实有效,但我想知道是否有办法解决这个问题。输入是否可能不会转到第一个匹配的符号,如果它导致整个表达式不匹配?

另一个问题是这是否是BNF的标准行为,或者是我正在使用的yaccer的问题:PLY v 3.3。

尝试使用flex / bison并且做了同样的事情。所以它似乎不是PLY特有的。

以下是完整性的所有相关规则:

algebraic_notation : piece start_position capture end_position promotion

piece : KING
        | QUEEN
        | BISHOP
        | KNIGHT
        | ROOK
        | pawn

pawn : empty

start_position : FILE
                | NUMBER
                | FILE NUMBER
                | empty

end_position : FILE NUMBER
                | empty                 // this line is the hack/workaround

capture : CAPTURE
        | empty

promotion : EQUAL QUEEN
            | EQUAL ROOK
            | EQUAL KNIGHT
            | EQUAL BISHOP
            | empty

empty : 

4 个答案:

答案 0 :(得分:1)

问题是你忽略了从解析器生成器获得的转移/减少冲突。虽然yacc / bison(可能是PLY)会为你解决错误,但是这个解决方案可能没有做你想要的,并且可能会导致解析器解析你想要解析的语言之外的语言。

每当你从LR解析器生成器得到转移/减少(或减少/减少)冲突时,你真的需要了解冲突是什么(及其发生的原因),以了解是否可以忽略它或是否需要修理它。因此,让我们通过摆脱'hack'(这显然是错误的而不是你要解析的东西)以及无用的“空”规则(这只会让事情混淆)来修复你的语法:

%token FILE NUMBER
%%
algebraic_notation : piece start_position capture end_position promotion
piece : 'K' | 'Q' | 'B' | 'N' | 'R' | /*pawn*/
start_position : FILE | NUMBER | FILE NUMBER | /*empty*/
end_position : FILE NUMBER
capture : 'x' | /*empty*/
promotion : '=' 'Q' | '=' 'R' | '=' 'N' | '=' 'B' | /*empty*/

现在当你通过'bison -v'运行时(总是使用-v来获取详细的输出文件 - 我不确定PLY的等价物是什么),你得到关于转移/减少冲突的信息,并且如果查看.output文件,您可以看到它是什么:

state 7

    1 algebraic_notation: piece . start_position capture end_position promotion

    FILE    shift, and go to state 9
    NUMBER  shift, and go to state 10

    FILE      [reduce using rule 11 (start_position)]
    $default  reduce using rule 11 (start_position)

    start_position  go to state 11

这告诉您,在看到piece后,当下一个令牌为FILE时,它不知道是否应该转移(将FILE视为(部分) start_position)或减少(给出空start_position)。这是因为它需要更多的前瞻,看看是否有第二个位置用作end_position来知道该怎么做,所以简单地忽略冲突将导致解析器无法解析许多有效的东西(基本上,任何东西)空start_positioncapture)。

解决与前瞻相关的转移 - 减少冲突涉及像这样的空生产(或几乎任何涉及空生产的冲突,真的)的最佳方法是解除语法 - 摆脱空规则并重复任何使用非终端的规则,无论是否使用它。在您的情况下,这为您提供了规则:

algebraic_notation : piece capture end_position promotion
algebraic_notation : piece start_position capture end_position promotion
start_position : FILE | NUMBER | FILE NUMBER 

(其他规则不变) 有了这个,你仍然会有一个减少转移的冲突:

state 7

    1 algebraic_notation: piece . capture end_position promotion
    2                   | piece . start_position capture end_position promotion

    FILE    shift, and go to state 9
    NUMBER  shift, and go to state 10
    'x'     shift, and go to state 11

    FILE  [reduce using rule 14 (capture)]

    start_position  go to state 12
    capture         go to state 13

基本上,我们刚刚将冲突移动了一步,现在出现了空capture规则的问题。所以我们也不理解它:

algebraic_notation : piece end_position promotion
algebraic_notation : piece capture end_position promotion
algebraic_notation : piece start_position end_position promotion
algebraic_notation : piece start_position capture end_position promotion
capture : 'x'

现在bison报告没有更多的冲突,所以我们可以合理地相信它会解析我们想要的方式。您可以通过删除capture规则并在'x'规则中使用文字algebraic_notation来进一步简化它。我个人更喜欢这个,因为我认为避免不必要的间接更清楚:

%token FILE NUMBER
%%
algebraic_notation : piece end_position promotion
algebraic_notation : piece 'x' end_position promotion
algebraic_notation : piece start_position end_position promotion
algebraic_notation : piece start_position 'x' end_position promotion
piece : 'K' | 'Q' | 'B' | 'N' | 'R' | /*pawn*/
start_position : FILE | NUMBER | FILE NUMBER
end_position : FILE NUMBER
promotion : '=' 'Q' | '=' 'R' | '=' 'N' | '=' 'B' | /*empty*/

答案 1 :(得分:0)

我没有使用PLY,并且没有看到你尝试过的完整的flex / bison文件我可能会选择一个非问题,但在我看来,你并没有给解析器一个关于不再有了它的想法对于当前的algebraic_notation规则。你没有说你怎么知道输入'd4'与start_position匹配,但如果解析器知道它有规则的所有标记,并且唯一的非空标记是end_position,它必须匹配'd4'到这一点。

如何引入标记行结束的令牌,如EOL。所以你的第一条规则就是:

algebraic_notation : piece start_position capture end_position promotion EOL

并且解析器现在看到令牌'd4'后跟EOL - 这会改变行为吗?

答案 2 :(得分:0)

如果将start_position capture end_position包装到中间块中,并从start_pos中删除FILE NUMBER,会发生什么情况:

middle: start_pos capture end_pos
      | end_pos capture end_pos
      | capture end_pos

start_pos : FILE
      | NUMBER
      | empty

end_pos : FILE NUMBER

capture : CAPTURE
      | empty

答案 3 :(得分:0)

这个问题很好地说明了一个问题,即计算机科学理论,从语法中删除epsilon(或空)的作品。通过简化语法来移除空制作,可以解决国际象棋符号模糊性的问题(对于yacc或PLY)。在SO / SE和其他网站上有很多这方面的材料。我为感兴趣的读者附上了一份参考书目。

通过对规则进行无意识的转换以消除盲/空/ epsilon制作,我们得到以下CFG:

algebraic_notation : piece start_position capture end_position promotion
                   | piece start_position capture end_position 
                   | piece start_position capture promotion
                   | piece start_position end_position promotion
                   | piece capture end_position promotion
                   | piece start_position capture
                   | piece start_position end_position
                   | piece capture end_position
                   | piece start_position promotion
                   | piece capture promotion
                   | piece end_position promotion
                   | piece promotion
                   | piece end_position 
                   | piece capture 
                   | piece start_position 
                   | piece 
                   | start_position capture end_position promotion
                   | start_position capture end_position
                   | start_position capture promotion
                   | start_position end_position promotion
                   | capture end_position promotion
                   | start_position capture
                   | start_position end_position
                   | capture end_position
                   | end_position promotion
                   | start_position 
                   | capture 
                   | end_position
                   | promotion
piece : KING
        | QUEEN
        | BISHOP
        | KNIGHT
        | ROOK

start_position : FILE
                | NUMBER
                | FILE NUMBER

end_position : FILE NUMBER

capture : CAPTURE

promotion : EQUAL QUEEN
            | EQUAL ROOK
            | EQUAL KNIGHT
            | EQUAL BISHOP

(这可以通过删除国际象棋符号中不会出现的那些组合来简化,但这对读者来说是一种练习。)

参考书目

最好的书籍可能是:

或者只是去看看Jeff Ullman班级的幻灯片:

或者关于SO / SE的一系列相关问题: