簡體   English   中英

shift reduce 解析器如何知道應用什么規則?

[英]How does a shift reduce parser know what rule to apply?

在編寫 shift reduce 解析器時,shift reduce 如何找出有效應用的規則? 例如,如果我有以下規則

S –> S + S 
S –> id

解析器如何快速確定在以下解析堆棧中應用的規則?

$ id        # id -> S
$ S         # shift
$ S +       # shift
$ S + id    # id -> S
$ S + S     # S + S -> S
$ S

我看到的所有示例都只是從無處提取了正確的規則,但是選擇規則背后的代碼是什么? 偽代碼將不勝感激。

我已經從這里獲取了示例,但是我在網上找到的幾乎所有減少轉換的文章只是神奇地知道要使用什么規則,而不是展示如何選擇它們。

規則編號在解析表中。 換句話說,它是在創建解析表時預先計算好的。

LR 狀態是一組 LR 項,其中每個項是一個產生式和產生式的索引,通常用 • 編寫。 當您從一種狀態轉換到下一種狀態時,您將所有符合條件的項目中的 • one 符號移到右側。 對於shift動作,如果 • 之后的符號是被移動的標記,則項符合條件;對於在歸約結束時發生的goto動作,如果 • 之后的符號是非終結符,則項符合條件。只是減少了。

通常不是一個州的所有項目都符合條件,除非該州只有一項。 但也有可能有兩個或更多符合條件的項目; 這表明語法可能不是 LL。 無論如何,沒關系。 解析器生成器獲取所有符合條件的項目並使用它們來創建新狀態(或查找已構建的狀態)。 新構造的狀態由“ε-closure”完成,這是一種奇特的說法,即在新狀態中為每個跟隨在 • 之后的非終結符添加所有產生式。 (遞歸地,這就是它被稱為閉包的原因。)

當解析器達到 • 位於項目末尾的狀態時,它可以歸約該特定項目,這正是將被歸約的產生式。 減少項目基本上意味着備份解析器,直到您到達項目生產的開始,這 8 秒解析器堆棧用於:每個堆棧條目都是一個轉換,當您彈出堆棧時,您會在解析歷史記錄中向后移動。 一旦到達項目的開頭,您必須處於在生產的非終端上具有goto操作的狀態。 一定是這種情況,因為在 ε-閉包期間添加了以 • 開頭的項目,這僅在狀態中的某些項目在該非終結符之前具有 • 時才會發生。 然后您執行goto操作,該操作記錄了該非終端的實例剛剛被識別的事實,並從那里繼續。 所以沒有魔法。

每個可約項目都有一個前瞻集,該集也是在表構建期間計算的,由接下來可能出現的可能標記組成。 如果實際的下一個標記——前瞻標記——在該集合中,則允許發生減少。 如果在當前狀態下,前瞻標記跟隨在 • 之后,則允許進行移位操作。 如果一個狀態在同一個記號上同時有可能的歸約動作和可能的移位動作,則表存在解析沖突,語法不是LR。 如果兩個不同的項目在相同的前瞻中都可以在該狀態下歸約,則相同。 對於要成為 LR 的語法,每個狀態對於每個不同的前瞻標記最多可以有一個可能的操作。 (如果當前前瞻沒有可能的操作,則解析失敗並報告語法錯誤。)

在我看來,你不能通過閱讀來真正學習這個算法,盡管我已經嘗試過編寫它。 要了解它是如何工作的,您需要構建(或借用)一個解析表並運行解析器,並配備一塊白板或一張大紙來跟蹤解析堆棧。 如果您可以找到(或構建)未刪除項目的解析表,您可能會發現它更容易遵循,盡管它占用更多空間。 (G2G和很多“教程”一樣,刪除了項目,可能讓它看起來像魔法。但還有其他資源,比如臭名昭著的龍之書。)

解析器本身不需要查看項目; 所有相關信息都已匯總在解析表中,我想這就是為什么像 G2G 這樣的網站不顯示它們的原因。 它們確實造成了很多混亂。 Bison 可以為解析自動機的圖像生成 Graphview 源; 如果要查看每個狀態的 ε-closure,則需要提供--report=all命令行選項。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM