[英]Bison Shift/Reduce conflict for simple grammar
我正在為我設計的語言構建一個解析器,其中類型名稱以大寫字母開頭,變量名稱以小寫字母開頭,以便詞法分析器可以區分兩者並提供不同的標記。 同樣,字符串“ this”由詞法分析器(它是一種OOP語言)識別,並作為單獨的令牌傳遞。 最后,只能在“ this”對象上訪問數據成員,因此我這樣構建了語法:
%token TYPENAME
%token VARNAME
%token THIS
%%
start:
Expression
;
Expression:
THIS
| THIS '.' VARNAME
| Expression '.' TYPENAME
;
%%
Expression的第一個規則允許用戶將“ this”作為值傳遞(例如,從方法返回它或傳遞給方法調用)。 第二個是用於訪問“ this”上的數據。 第三條規則用於調用方法,但是我刪除了方括號和參數,因為它們與問題無關。 最初的語法顯然要大得多,但是這是產生相同錯誤(最小的Shift / Reduce沖突)的最小部分-我將其隔離到自己的解析器文件中並進行了驗證,因此該錯誤與任何錯誤無關其他符號。
據我所知,這里給出的語法是明確的,因此不會產生任何錯誤。 如果刪除這三個規則中的任何一個或將第二個規則更改為
Expression '.' VARNAME
沒有沖突。 無論如何,我可能都需要有人清楚地說明發生這種沖突的原因以及如何解決它。
問題在於語法只能向前看。 因此,當您看到一個THIS
一個.
,您處於第2行( Expression: THIS '.' VARNAME
)還是第3行( Expression: Expression '.' TYPENAME
,根據第1行進行了歸約)。
語法可以減少這種情況THIS.
Expression.
然后尋找TYPENAME
或將其移至THIS.
並尋找一個VARNAME
,但是它必須決定什么時候到達.
。
我嘗試避免y.output,但有時確實有幫助。 我看了看它產生的文件。
state 1
2 Expression: THIS. [$end, '.']
3 | THIS . '.' VARNAME
'.' shift, and go to state 4
'.' [reduce using rule 2 (Expression)]
$default reduce using rule 2 (Expression)
基本上是說看到“。” 並可以減少或移動。 減少有時使我煩惱,因為它們很難罰款。 移位是規則3,很明顯(但輸出未提及規則#)。 減少的地方是“。” 在這種情況下是線
| Expression '.' TYPENAME
當它關系到表達它着眼於下一個字母(的“”),去的現在看到。 THIS |
因此,當到達該語句的末尾時,它期望為“。” 當它離開或錯誤時。 但是,它看到此“。” 而在此和“。”之間 (因此,out文件中的點)會減少規則,因此會出現路徑沖突。 我相信您可以使用%glr-parser
來嘗試兩者,但是沖突越多,您越有可能獲得意外的輸出或歧義錯誤。 我過去有歧義錯誤。 他們很煩人,尤其是如果您不記得是什么規則導致或影響了他們。 建議避免沖突。
在嘗試使用野牛之前,我強烈推薦這本書 。
我想不出一個“偉大的”解決方案,但這沒有沖突
start:
ExpressionLoop
;
ExpressionLoop:
Expression
| ExpressionLoop ';' Expression
;
Expression:
rval
| rval '.' TYPENAME
| THIS //trick is moving this AWAY so it doesnt reduce
rval:
THIS '.' VARNAME
或者,您可以通過向規則中添加更多內容來使其稍后減少,從而使其不會立即減少,或者在之后或之前添加令牌以明確采用哪個路徑或失敗(請記住,在減少任何路徑之前,它必須知道)
start:
ExpressionLoop
;
ExpressionLoop:
Expression
| ExpressionLoop ';' Expression
;
Expression:
rval
| rval '.' TYPENAME
rval:
THIS '@'
| THIS '.' VARNAME
%%
-edit-請注意,如果我想執行func param
並type varname
無法進行,因為根據詞法分析器func的類型是Var(也是A-Za-z09_)。 param和varname都是var的,所以這會導致我減少/減少沖突。 您不能將它們寫成它們的樣子,只能寫成它們的外觀。 因此,在編寫時請記住這一點。 您必須編寫一個令牌來區分兩者,或將其寫為兩者之一,但在代碼中(規則右側{}中的部分)編寫其他邏輯,以檢查它是否為funcname或並處理這兩種情況。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.