1. 程式人生 > >Python 之父的解析器系列之六:給 PEG 語法新增動作

Python 之父的解析器系列之六:給 PEG 語法新增動作

原題 | Adding Actions to a PEG Grammar

作者 | Guido van Rossum(Python之父)

譯者 | 豌豆花下貓(“Python貓”公眾號作者)

宣告 | 本翻譯是出於交流學習的目的,基於 CC BY-NC-SA 4.0 授權協議。為便於閱讀,內容略有改動。

如果你在語法規則中還可以新增(某些)語義,那麼語法就會更好。特別是對於我正在構建的 Python 解析器,我需要控制每個備選項返回的 AST 節點,因為 AST 的格式已經規定好。

【這是我的 PEG 系列的第 6 部分。其餘部分請參閱系列概述 】(譯註:本系列的譯文已在 Github 開源,專案地址:

https://github.com/chinesehuazhou/guido_blog_translation

許多語法都有支援給規則新增動作的約定,通常是 { 花括號 } 內的一段程式碼塊。更確切地說,行動與備選項相關聯。動作塊中的程式碼通常與編寫編譯器的語言相同,如 C 語言,增加一些工具,用於引用備選項中的條目。在 Python 原始的 pgen 中,我沒有新增此功能,但對於這個新專案,我希望使用它。

對於在這一系列部落格文章中開發的簡化版解析器生成器,下面是我們採用的做法。

一般而言,動作的語法如下:

rule: item item item { action 1 } | item item { action 2 }

因為它會使語法變得冗長,所以解析器生成器通常支援跨行分割規則,例如:

rule: item item item { action 1 }
    | item item { action 2}

它會使語法分析器變得複雜,但可讀性更重要,所以我會使用這種方式。

一個永恆的問題是何時執行動作塊。在 Yacc / Bison 中,因為沒有回溯,一旦規則被解析器識別到,就會執行動作塊。每個動作會立即執行,這意味著即使操作具有全域性副作用,還是會順利執行(例如更新符號表或其它編譯器資料結構)。

在 PEG 解析器中,因為有無限回溯,我們有其它的選擇:

  • 延遲所有動作,直到解析完所有內容。這對我的目的沒有用,因為我想在解析期間構造一個 AST。
  • 只要識別出動作所對應的備選項就執行之,但要求操作程式碼是冪等的(即無論執行多少次,都具有相同的效果)。這意味著可以執行某個動作,但其結果最終會被丟棄。
  • 快取動作的結果,因此只有第一次在給定位置識別到備選項時,對應的動作才執行。

我要採用第三個選項——正好我們用 packrat 演算法快取東西,所以我們也可以快取動作的結果。

關於 {花括號} 裡面的內容,傳統上是使用 C 語言,它約定用 $ 符號來引用已識別的備選項(例如,$1 引用第一個條目),並賦值給 $$ 以指示動作的結果。

在我看來這太老古董了(我記得曾在 Algol-60 中使用對函式名的賦值,來指定返回值),所以我會用一些更 Pythonic 的方式:在括號內,你需要放置一個單一的表示式,它的值是動作的值,而條目的引用則是一些簡單的名稱,給出著條目的文字。

舉個例子,這是一個簡單的計算器,可以作加減法:

start: expr NEWLINE { expr }
expr: expr '+' term { expr + term }
    | expr '-' term { expr - term }
    | term { term }
term: NUMBER { float(number.string) }

當我們執行時,給定輸入 100+50-38-70 ,它會識別出各部分並計算答案,計算成((100+50)-38)-70 ,當然得出結果為 42。

一個小細節:在term 的動作中,變數number 儲存了一個TokenInfo 物件,因此該動作必須使用其.string 屬性來獲取字串形式的識別符號。

當一個備選項中多次出現相同的規則名稱時,我們該怎麼辦?對同一備選項中出現的規則,解析器生成器會給出唯一的名稱,即在隨後出現的規則上新增 1、2 等等。例如:

factor: atom '**' atom { atom ** atom1 }
      | atom { atom }

它的實現很無聊,所以我請你們 check out 程式碼 ,自己看看。試試這個:

python3.8 -m story5.driver story5/calc.txt -g story5.calc.CalcParser

視覺化功能現在支援使用左右箭頭鍵來回移動!

本文內容與示例程式碼的授權協議:CC BY-NC-SA 4.0

公眾號【Python貓】, 本號連載優質的系列文章,有喵星哲學貓系列、Python進階系列、好書推薦系列、技術寫作、優質英文推薦與翻譯等等