使用野牛的-v
選項來獲得詳細的輸出,給出生成的分析器中的所有狀態和衝突。如果你這樣做,你會看到一個狀態是這樣的:
state 7
4 G: url . canon
T_acc shift, and go to state 12
:
T_trans shift, and go to state 19
T_user shift, and go to state 20
$end reduce using rule 13 (GH)
$end [reduce using rule 21 (RH)]
$end [reduce using rule 24 (EH)]
$end [reduce using rule 26 (MB)]
T_acc [reduce using rule 13 (GH)]
:
這是告訴你,當解析器已經見到一個url
並期待識別canon
,它不能告訴做什麼 - 它是否應該識別空的GH
,RH
,EH
或MB
,或者它是否應該將令牌轉換爲識別非空的那一個?
都來自於你的語法基本歧義這些衝突 - 你有一個canon
規則,即由0或者多次的GH
,RH
,和/或EH
,每個的這些規則包括0或者多次東西。因此它無法告訴有多少空的東西插入到分析樹中(因爲它們不消耗任何輸入,可以添加任意數量),也不知道是否將類似的東西組合成一個GH
(或RH
或EH
)或多個不同的。
所以要解決這個問題,你需要決定你想要什麼。最可能的是,你不關心GH
/RH
/EH
結構分組,你也不關心空的,所以你只要獲得這些規則擺脫遞歸:
GH:T_con T_akt T_seq|T_date T_akt D|T_trans T;
RH:T_acc T_akt T_seq|T_ref T_akt T_seq|T_user T_akt T_seq;
EH:T_content T_akt T_seq|T_exp T_akt T_seq;
現在每個這些規則將匹配一個結構,並且如果您有多個結構,則它們將按canon
規則分組在一起。這可以解決所有的衝突,但仍然存在潛在的問題 - 您的規則是正確的遞歸,所以在減少任何規則之前將整個輸入吸引到堆棧上(因爲對於右遞歸,它從右到左減少)。您可能想要使規則保持遞歸 - 而野牛的一般規則爲總是使用左遞歸而不是右遞歸,除非由於某種原因您需要正確的遞歸。這給你一個語法:
start : T_get G | T_head G | T_post G ;
G : url canon MB ;
url : T_http T_dslash T_host T_abs_path ;
canon : canon GH | canon RH | canon EH | ;
GH : T_con T_akt T_seq | T_date T_akt D | T_trans T ;
D : T_day T_slash T_month T_slash T_year T_hour T_akt T_min ;
T : T_chunked | T_gzip | T_deflate ;
RH : T_acc T_akt T_seq | T_ref T_akt T_seq | T_user T_akt T_seq ;
EH : T_content T_akt T_seq | T_exp T_akt T_seq ;
MB : T_seq | ;