? “ Python貓 ” ,一個值得加星標的 公眾號
現(xiàn)在,我把譯文提到 Github 上了( guido_blog_translation ),希望有熱心腸的同學(xué)能來幫忙審閱指正,或者認領(lǐng)翻譯任務(wù)吧。最后,提前祝大家中秋節(jié)快樂,闔家團圓,諸事和美。
如果你在語法規(guī)則中還可以添加(某些)語義,那么語法就會更好。特別是對于我正在構(gòu)建的 Python 解析器,我需要控制每個備選項返回的 AST 節(jié)點,因為 AST 的格式已經(jīng)規(guī)定好。
許多語法都有支持給規(guī)則添加動作的約定,通常是 { 花括號 } 內(nèi)的一段代碼塊。更確切地說,行動與備選項相關(guān)聯(lián)。動作塊中的代碼通常與編寫編譯器的語言相同,如 C 語言,增加一些工具,用于引用備選項中的條目。在 Python 原始的 pgen 中,我沒有添加此功能,但對于這個新項目,我希望使用它。
對于在這一系列博客文章中開發(fā)的簡化版解析器生成器,下面是我們采用的做法。
一般而言,動作的語法如下:
rule:?item?item?item?{?action?1?}?|?item?item?{?action?2?}
因為它會使語法變得冗長,所以解析器生成器通常支持跨行分割規(guī)則,例如:
rule:?item?item?item?{?action?1?}
????|?item?item?{?action?2}
它會使語法分析器變得復(fù)雜,但可讀性更重要,所以我會使用這種方式。
一個永恒的問題是何時執(zhí)行動作塊。在 Yacc / Bison 中,因為沒有回溯,一旦規(guī)則被解析器識別到,就會執(zhí)行動作塊。每個動作會立即執(zhí)行,這意味著即使操作具有全局副作用,還是會順利執(zhí)行(例如更新符號表或其它編譯器數(shù)據(jù)結(jié)構(gòu))。
-
延遲所有動作,直到解析完所有內(nèi)容。這對我的目的沒有用,因為我想在解析期間構(gòu)造一個 AST。
-
只要識別出動作所對應(yīng)的備選項就執(zhí)行之,但要求操作代碼是冪等的(即無論執(zhí)行多少次,都具有相同的效果)。這意味著可以執(zhí)行某個動作,但其結(jié)果最終會被丟棄。
-
緩存動作的結(jié)果,因此只有第一次在給定位置識別到備選項時,對應(yīng)的動作才執(zhí)行。
我要采用第三個選項——正好我們用 packrat 算法緩存東西,所以我們也可以緩存動作的結(jié)果。
關(guān)于 {花括號} 里面的內(nèi)容,傳統(tǒng)上是使用 C 語言,它約定用
$
符號來引用已識別的備選項(例如,
$1
引用第一個條目),并賦值給
$$
以指示動作的結(jié)果。
在我看來這太老古董了(我記得曾在 Algol-60 中使用對函數(shù)名的賦值,來指定返回值),所以我會用一些更 Pythonic 的方式:在括號內(nèi),你需要放置一個單一的表達式,它的值是動作的值,而條目的引用則是一些簡單的名稱,給出著條目的文本。
舉個例子,這是一個簡單計算器,可作加減法:
start:?expr?NEWLINE?{?expr?}
expr:?expr?'+'?term?{?expr?+?term?}
????|?expr?'-'?term?{?expr?-?term?}
????|?term?{?term?}
term:?NUMBER?{?float(number.string)?}
當(dāng)我們運行時,給定輸入
100+50-38-70
,它會識別出各部分并計算答案,計算成
((100+50)-38)-70
,當(dāng)然得出結(jié)果為 42。
一個小細節(jié):在
term
的動作中,變量
number
保存了一個
TokenInfo
對象,因此該動作必須使用其
.string
屬性來獲取字符串形式的標識符。
當(dāng)一個備選項中多次出現(xiàn)相同的規(guī)則名稱時,我們該怎么辦?對同一備選項中出現(xiàn)的規(guī)則,解析器生成器會給出唯一的名稱,即在隨后出現(xiàn)的規(guī)則上添加 1、2 等等。例如:
factor:?atom?'**'?atom?{?atom?**?atom1?}
??????|?atom?{?atom?}
它的實現(xiàn)很無聊,所以我請你們 check out 代碼 ,自己看看。試試這個:
python3.8?-m?story5.driver?story5/calc.txt?-g?story5.calc.CalcParser
可視化功能現(xiàn)在支持使用左右箭頭鍵來回移動!
優(yōu)質(zhì)文章,推薦閱讀:
Python 的整數(shù)與 Numpy 的數(shù)據(jù)溢出
編程語言之問:何時該借用,何時該創(chuàng)造?
GIL 已經(jīng)被殺死了么?
Python進階:設(shè)計模式之迭代器模式
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

