用pyparsing 初步解析python風(fēng)格IF,IFELSE條件句

    前兩個月在公司接到項目抛人,要做一個簡易的Python腳本解釋器。工具穷遂,構(gòu)架都是從0碼起函匕,也找不到開源的項目參考,只好閉門造車?yán)豺胶凇;撕荛L時間找能寫Parser 的庫中剩,比較起來pyparsing比較好理解忌穿,所以就從這里碼起了。

    當(dāng)時看了一些所謂教你做編譯器的教程结啼,滿心歡喜的看完四則運(yùn)算掠剑,期待后面的內(nèi)容能講到條件句的解析。結(jié)果郊愧,講到四則運(yùn)算之后就沒有然后了朴译,感覺這后面可能是個大坑井佑。之后查文檔,自己寫代碼眠寿,重復(fù)修改躬翁,終于做出條件句的分詞器。

    個人感覺對條件句做分詞盯拱,基本用到了pyparsing所有常用功能盒发。所以把我的代碼放上來,能幫后面做相同工作的同學(xué)省些上手的時間狡逢。


解析條件句主要考慮以下幾塊:

1.條件語句:

   主要是大于小于等于這種邏輯判斷

2.執(zhí)行語句

   要支持賦值宁舰,function,四則運(yùn)算這些格式

3.IF∩莼搿/÷琛IFELSE格式

搭好架子

IF(條件){執(zhí)行}

IF(條件){執(zhí)行}ELSE{執(zhí)行}

4.{執(zhí)行}內(nèi)支持嵌套



那么我們就開始了

碼之前先把庫加上

from pyparsing import *


1.條件語句

先想想條件句長什么樣,可能是和數(shù)值比較(A>5)雀彼,也可能是和變量比較(A==B)

所以符號右側(cè)可能是字母也是數(shù)字印荔。

在這里我們用Word(alphanums)涵蓋可能是數(shù)字也可能是字母的情況。

我們把符號兩邊比較的東西叫做Variable详羡,那么它的語法是

Variable=Word(alphanums)

這樣不管要比的是∪月伞ABC還是123就都不怕了

下面來定義邏輯運(yùn)算符,我們把符號稱作Operator,它的語法定義如下

Operator=Literal("==")^Literal("!=")^Literal(">")^Literal("<")^Literal(">=")^Literal("<=")

這一行說的是Operator可以是“==”实柠,“>”,"<"...這些符號里的任意一個水泉。因為是特殊符號,所以要用Literal()擴(kuò)好窒盐,中間用^連接草则,相當(dāng)于OR。

這些組件都做好之后蟹漓,就可以把它們拼起來解析完整的條件句啦炕横,我們叫它condition。

condition=Variable+Operator+Variable

現(xiàn)在可以用它解析∑狭!A==C這樣的條件句份殿,但是如果有用戶寫成 A∷越弧==∏涑啊B可能會出錯,所以你可以預(yù)留出一些可能出現(xiàn)的空格夫壁,像這樣:

condition=Variable+Optional(" ")+Operator+Optional(" ")+Variable

Optional( )里面可以寫一些可有可無的內(nèi)容拾枣,不影響整體。

此時,解析C==0的結(jié)果是這樣的

[ 'C', ‘==’梅肤, ‘0’ ]

如果你覺得這樣太瑣碎司蔬,可以在condition最外層加一個combine(),就像這樣

condition=Combine(Variable+Optional(" ")+Operator+Optional(" ")+Variable)

此時得到的結(jié)果就是一個完整的語句

["C==0"]

值此條件句就完成了,你可以把它封到功能里隨用隨調(diào)

def Condition():

? ? ? ? ? ? Variable=Word(alphanums)#Variable pattern: number or alphabets

? ? ? ? ? ? Operator=Literal("==")^Literal("!=")^Literal(">")^Literal("<")^Literal(">=")^Literal("<=")#logical operator defined? ? ? ? ? ?

? ? ? ? ? ? condition=Combine(Variable+Optional(" ")+Operator+Optional(" ")+Variable)#condition pattern

??????????? return condition

2. 執(zhí)行語句

這里需要支持function調(diào)用姨蝴,設(shè)值俊啼,四則運(yùn)算這么幾類語句,用到的功能和上面條件句大同小異似扔,所以就不一一解釋了

def command():

    ### function:XXX()

    llp="("

    rrp=")"

    command=Combine(Word(alphanums)+llp+Word(nums)+rrp)


    ###? setValue:C=0

    Variable=Word(alphanums)

    Value=Word(alphanums)

    setValue=Combine(Variable+"="+Value)


    ### operation: A=3+B

    Operator=Literal("+")^Literal("-")^Literal("*")^Literal("/")

    operation=Combine(Variable+"="+Variable+Operator+Variable)

    commandLine=OneOrMore(command^setValue^operation)

    return commandLine

需要說明的是OneOrMore()這個功能吨些,從字面上看是一個或多個的意思。

commandLine=OneOrMore(command^setValue^operation)

這句可以解釋為你在IF執(zhí)行的部分可以是一句過多句命令或賦值或運(yùn)算

這樣 IF? C<2:

????????????? speed(0);

????????????? B=6

????????????? C=2+B

縮進(jìn)的三行內(nèi)容就都可以被提取出來

3.IF/IFELSE 格式

先寫IF的格式

ifSt="if"+condition()+Suppress(":")

這里用到Suppress()炒辉,是希望分詞器不要抓取 “『朗:”,因為不是什么關(guān)鍵內(nèi)容黔寇,可以忽略

這樣你的輸出是 [ 'if' ,'C==0']

同理

elseSt="else"+Suppress(":")

到這里你就可以做出基本的IF/IFELSE語法了

indentStack=[1]

indentBody=indentedBlock(command),indentStack)

if_Grammar=ifSt+indentBody+Optional(elseSt+indentBody)

你會發(fā)現(xiàn)我把command()放到縮進(jìn)功能indentedBlock里了偶器,else變成可選的一項,這樣語法可以同時應(yīng)付IF,IFELSE

4. {執(zhí)行}內(nèi)支持嵌套

這里要用到遞歸缝裤,修改上面的代碼

indentStack=[1]

IF_ALL=Forward()

indentBody=indentedBlock(execution+Group(Optional(IF_ALL)),indentStack)

IF_ALL<<ifSt+indentBody+Optional(elseSt+indentBody)

Forward()為你可能出現(xiàn)嵌套的位置去占一個位,所以要把它加在縮進(jìn)的位置里屏轰,但嵌套不是每次都會出現(xiàn),所以第三行IF_ALL外面套了Optional().

為了讓輸出的結(jié)果也體現(xiàn)出嵌套的格式憋飞,需要用Group()把他們括起來霎苗,這樣你的輸出是:

[ IF 1 [ IF2?? [ IF 3]? ]]

為了實現(xiàn)完整的遞歸,記得寫

IF_ALL<<ifSt+indentBody+Optional(elseSt+indentBody)

這樣榛做,當(dāng)前IF可以嵌套在更高一層IF里

最后別忘了把語法封到function里唁盏,名為IF_grammar()

使用你編寫的語法


input='''

if M>=1:

   A=3+2

   if N==2:

      B=2

'''

parseTree=IF_ALL().scanString(input)

parseTree=list(parseTree)

這樣你可以看到解析的列表。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末检眯,一起剝皮案震驚了整個濱河市厘擂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌锰瘸,老刑警劉巖刽严,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異避凝,居然都是意外死亡舞萄,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進(jìn)店門恕曲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鹏氧,“玉大人,你說我怎么就攤上這事佩谣。” “怎么了实蓬?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵茸俭,是天一觀的道長吊履。 經(jīng)常有香客問我,道長调鬓,這世上最難降的妖魔是什么艇炎? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮腾窝,結(jié)果婚禮上缀踪,老公的妹妹穿的比我還像新娘。我一直安慰自己虹脯,他們只是感情好驴娃,可當(dāng)我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著循集,像睡著了一般唇敞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上咒彤,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天疆柔,我揣著相機(jī)與錄音,去河邊找鬼镶柱。 笑死旷档,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的歇拆。 我是一名探鬼主播鞋屈,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼查吊!你這毒婦竟也來了谐区?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤逻卖,失蹤者是張志新(化名)和其女友劉穎宋列,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體评也,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡炼杖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了盗迟。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坤邪。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖罚缕,靈堂內(nèi)的尸體忽然破棺而出艇纺,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布黔衡,位于F島的核電站蚓聘,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏盟劫。R本人自食惡果不足惜夜牡,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望侣签。 院中可真熱鬧塘装,春花似錦、人聲如沸影所。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽型檀。三九已至冗尤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間胀溺,已是汗流浹背裂七。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留仓坞,地道東北人背零。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像无埃,于是被迫代替她去往敵國和親徙瓶。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,047評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 很實用的編程英語詞庫嫉称,共收錄一千五百余條詞匯侦镇。 第一部分: application 應(yīng)用程式 應(yīng)用、應(yīng)用程序app...
    春天的蜜蜂閱讀 1,362評論 0 22
  • 計算機(jī)英語(編程詞匯大全) application 應(yīng)用程式 應(yīng)用织阅、應(yīng)用程序 application framew...
    朱森閱讀 597評論 0 1
  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問題, 分享了一些自己做題目的經(jīng)驗壳繁。 張土汪:刷leetcod...
    土汪閱讀 12,747評論 0 33
  • 為何叫做 shell ? shell prompt(PS1) 與 Carriage Return(CR) 的關(guān)系荔棉?...
    Zero___閱讀 3,153評論 3 49
  • 2017年7月20日 每天自問 1.今天留意時間怎么花掉的闹炉。 5:40-7:20跑步10公里。8:20-10:10...
    雪狼K閱讀 183評論 0 0