的问题是,你忽略移位/减少冲突你从你的解析器发生器获得。虽然yacc/bison(可能是PLY)会为您解决错误,但是该解决方案可能无法达到您想要的效果,并且可能会导致解析器解析除您正在尝试解析的语言之外的语言。
无论您何时从LR解析器生成器发生移位/减少(或减少/减少)冲突,您都需要了解冲突是什么(以及为什么会发生),以了解是否可以忽略它或者是否需要要解决这个问题。所以让我们通过摆脱“黑客”(这显然是错误的,而不是要分析的东西),以及无用的“空”规则的修正你的语法(这只会带来混乱):
%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
视为(start_position
的一部分)或减少(给出空的start_position
)。这是因为它需要更多的前瞻性来看看是否有第二个位置可以用作end_position
来知道该怎么做,所以仅仅忽略冲突就会导致解析器无法解析大量有效的东西(基本上,任何空的start_position
和capture
)。
解决涉及像这样的空白生产(或几乎任何涉及空的生产的冲突)的预测相关转换 - 减少冲突的最佳方式是对语法不利 - 摆脱空的规则并且复制任何使用非终端的规则,不管是否使用它。在你的情况,这给你的规则:
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
规则的问题。因此,我们认为unfactor以及:
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'
现在野牛报告没有更多的冲突,所以我们可以有理由相信它会分析我们想要的方式。您可以通过删除capture
规则并在algebraic_notation
规则中使用文字'x'
来简化它。我个人更喜欢这个,因为我认为它是更清晰的,以避免不必要的间接:
%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*/
是yacc也许矫枉过正这个问题? – Cam 2010-12-02 00:40:16
@cam也许吧。但手动解析字符串在我的经验中并不那么清晰或可读。 – Matthew 2010-12-02 03:32:32
另外,即使BNF对于这个特定的应用程序来说是过度的,它仍然有可能在更复杂的语法中遇到这个问题。无论如何,我有一个解决方法/破解;我只是想尽可能使用更好的解决方案。 – Matthew 2010-12-04 17:30:48