的問題是,你忽略移位/減少衝突你從你的解析器發生器獲得。雖然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