你的語法正確無誤的,據我所看到的。但它不是有限的前瞻,更不是LR(1)。
LR(k)解析器必須能夠根據對下一個令牌的檢查,預測非終端完成時輸入點處的縮減。
現在考慮輸入包含A
令牌的大數字(相對於k),後面跟着B
。如果輸入最終匹配Y
,那麼解析器現在必須減少Y → A
,然後可能會減少Y → A Y
的一個或多個實例,LR解析的從左到右的性質意味着這些減少必須立即發生。
但是沒有看到整個輸入的其餘部分並計算B
s的數量,無法知道要減少多少個實例。此外,輸入完全可能與X
匹配,在這種情況下,B
必須移位,因爲減少到Y
不正確。再次,沒有足夠的信息來做出這個決定,直到輸入結束。
通過將-v
選項傳遞給yacc/bison生成的狀態表中顯示了這些難題。例如,我們可以看到:
State 1
4 X: A . X B
7 Y: A . Y B
8 | A . Y
9 | A .
A shift, and go to state 1
B shift, and go to state 2
B [reduce using rule 9 (Y)]
$default reduce using rule 9 (Y)
X go to state 7
Y go to state 8
表達的是否最後A
降低到Y
假設的問題,有更多的A
總比B
S,或到第一B
準備轉變爲將其減少到X
,假設有更多B
s比A
s。
(衝突由前瞻B
的兩種不同動作表示,減號動作包含在括號內([reduce using rule 9 (Y)]
),表明野牛通過選擇總是移動來解決衝突。當然,這不是總是正確的分辨率,所以你的解析器將不能正確識別需要縮減操作的輸入。)
該語言確實有LR(1)語法。訣竅是首先識別A
s和B
的內部平衡序列,而不強制解析器確定它遇到的句子類型。如果遇到B
與A
不匹配,或者在某些A
尚未匹配時發現句子結尾,則可以作出該決定。
這裏,AB
是A
s和B
s的平衡序列。AAB
一個或多個A
,然後是AB
;而ABB
是AB
後跟一個或多個B
s。
stmt: tail NL
| C tail NL
tail: AAB
| ABB
AAB : A AB
| A AAB
ABB : AB B
| ABB B
AB : /* empty */
| A AB B
人們很容易寫
AAB : AA AB
AA : A
| A AA
,但它不會工作,因爲它需要解析器來決定的A
是否爲AA
的一部分,它曾經看到一個B
前。如上所述,A
總是移入堆棧,並且在解析器堆棧展開時作出決定。
在另一方面,它會因爲解析器到達第一無與倫比B
所有相關決定已經作出的時間是不可能有書面的生產ABB
以這種方式(ABB: AB BB; BB: B | BB B
)。我選擇像上面那樣做對稱。
對不起,我沒有得到它,請你提供解決方案。 – Hailey
@海利:好的,增加了解決方案。如果敘述不能使這個過程足夠明顯,我建議你使用[野牛的追蹤功能](https://www.gnu.org/software/bison/manual/bison.html#Tracing),這可能會有所幫助你可以看到解析器在做什麼。 LR解析的一個很好的參考也可能是有用的。 – rici