天天看點

《ANTLR 4權威指南 》一2.2 實作一個文法分析器

本節書摘來自華章出版社《antlr 4權威指南 》一書中的第2章,第2.2節,[美] 特恩斯·帕爾(terence parr) 著張 博 譯,更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。

antlr工具依據類似于我們之前看到的assign的文法規則,産生一個遞歸下降的文法分析器(recursive-descent parser)。遞歸下降的文法分析器實際上是若幹遞歸方法的集合,每個方法對應一條規則。下降的過程就是從文法分析樹的根節點開始,朝着葉節點(詞法符号)進行解析的過程。首先調用的規則,即語義符号的起始點,就會成為文法分析樹的根節點。在前一節的例子中,就是調用stat()方法作為起始點的。這種解析過程的更廣為人知的名字是“自上而下的解析”,遞歸下降的文法分析器僅僅是自上而下的文法分析器的一種實作。

下面是一個antlr根據assign規則生成的方法(稍微經過格式整理),用于展示遞歸下降的文法分析器的實作細節:

《ANTLR 4權威指南 》一2.2 實作一個文法分析器

遞歸下降的文法分析器最神奇的地方在于,通過方法stat()、assign()和expr()的調用描繪出的調用路線圖映射到了文法分析樹的節點上(請迅速回顧一下圖2-1)。調用match()對應了文法分析樹的葉子節點。在手工構造的文法分析器中,我們需要在每條規則對應的方法的開始位置插入“增加一個新的子樹根節點”這樣的操作,在match()方法中插入“增加一個新的葉子節點”這樣的操作。

assign()方法僅僅驗證所有的詞彙符号都存在且順序正确。當文法分析器進入assign()方法的内部時,僅有一個備選分支(alternative),無須做出選擇。一個備選分支指的是規則的右側定義的多個方案之一。例如,除了assign之外,下面的stat規則還可能對應其他多種語句。

《ANTLR 4權威指南 》一2.2 實作一個文法分析器

對stat文法規則的解析像是一個switch語句:

《ANTLR 4權威指南 》一2.2 實作一個文法分析器

stat()方法必須通過檢查下一個詞法符号來做出文法分析決策(parsing decision)或者預測(prediction)。做出決策的過程實際上就是判斷哪一個備選分支是正确的。在上面的例子中,一個while關鍵字意味着它選擇stat規則的第三個備選分支。是以,stat()方法将調用whilestat()方法。你可能聽說過前瞻詞法符号(lookahead token)這個術語,它其實就是下一個輸入的詞法符号。一個前瞻詞法符号是指任何一個在被比對和消費之前就由文法分析器嗅探出的詞法符号。有些時候,文法分析器需要很多個前瞻詞法符号來判斷語義規則的哪個方案是正确的,甚至可能要從目前的詞法符号的位置開始,一直分析到檔案末尾才能做出判斷!antlr默默地幫你完成了所有的這些工作,不過,對其決策過程的基本了解将會有助于調試antlr自動生成的文法分析器。

為了讓文法分析的決策過程可視化,想象一個迷宮,它隻有一個入口和一個出口,迷宮的地闆上寫着單詞。每個從入口到出口的路徑上的單詞序列代表一個語句。這個迷宮的結構就好比是一種語言所定義的全部文法規則。為了測試一個語句是不是合法,我們将這個語句中的單詞和迷宮的地闆上的單詞比較,然後沿着這個語句的單詞所描述的路徑在迷宮中前進。如果我們能夠通過這個語句中的單詞序列指定的路徑到達出口,那麼這個語句就是合法的。

為了到達迷宮的出口,我們必須在每個分岔路口選擇一條正确的路徑,就好像一個文法分析器要在多個備選分支中做出選擇一樣。我們必須将語句中接下來的若幹個單詞與站在路口所看到的不同岔路地闆上的單詞相比較,進而決定走哪條岔路。我們站在路口所看到的地闆上的單詞就好像是前瞻詞法符号。顯然,若每條岔路都以一個獨一無二的單詞開始,做出選擇就會容易許多。在上例中的stat規則中,每個備選分支都是以一個獨一無二的詞法符号開始的,是以stat()方法可以通過檢查第一個前瞻詞法符号來區分不同的備選分支。

當每條岔路的起始單詞有重複的時候,文法分析器就需要更多地進行前瞻,即通過掃描更多的單詞來區分不同的備選分支。在每次文法分析決策中,antlr能夠根據情況自動調整前瞻的數量。如果通過前瞻,我們能夠經多條路徑抵達迷宮出口(檔案末尾),那就意味着能夠用多種語義去解釋目前的輸入文本。解決這種歧義是我們下一節的任務,之後,我們将會學習如何使用文法分析樹來建構語言類應用程式。

繼續閱讀