語言及語法定義
布爾表達(dá)式包含:邏輯表達(dá)式 and or not斋射,關(guān)系表達(dá)式 >, >=, ==, <=, <
源碼位置:https://github.com/wangdxh/eopl3-in-python ? let 文件夾下面 pyand.py
簡單的布爾表達(dá)式如下:
我們使用“l(fā)et ?變量定義 ?in ?布爾表達(dá)式 ” 這樣的語句來引入變量的定義育勺,可以在布爾表達(dá)式中引用定義的變量,實(shí)例如下:
在《Oreilly-Getting-Started-with-Pyparsing》一書中罗岖,49頁有一個(gè)邏輯表達(dá)式的BNF定義涧至,如下:
在這個(gè)定義中,定義了邏輯表達(dá)式的優(yōu)先級(jí) not > ?and > or 并且是一個(gè)遞歸的定義桑包,Term的定義包含 可選的 not南蓬,然后是 單個(gè)單詞,字符串(quotedString)哑了,或者括號(hào)括起來的另一個(gè)表達(dá)式赘方。這里and or not 兩邊并不是關(guān)系表達(dá)式贩绕,而是單詞是钥,字符串性锭,是書中的一個(gè)例子逢勾,后面我們會(huì)將其修改為關(guān)系表達(dá)式。
And表達(dá)式的定義為 Term 跟著 可選的 多個(gè)and Term抗悍。布爾表達(dá)式定義為 And 表達(dá)式加上 可選的 多個(gè)or And表達(dá)式岸浑。這樣解析的時(shí)候泼返,a && b || c 出現(xiàn)||的時(shí)候,左右兩邊被解析為and表達(dá)式币叹,&&的兩邊被解析為term表達(dá)式润歉,優(yōu)先級(jí)比較明確。
下圖是使用pyparsing語法定義的 表達(dá)式:
解析的時(shí)候套硼,term 中包含的子表達(dá)式被包含在一個(gè)列表內(nèi)卡辰,多個(gè)并列的and語句包含在一個(gè)列表內(nèi)。
and or not 邏輯表達(dá)式有優(yōu)先級(jí)邪意,和一元二元區(qū)分,and和or是二元反砌,not是一元雾鬼,pyparsing提供了一個(gè)簡單的操作符優(yōu)先級(jí)的語法定義:如下
將Term修改為只有 單詞和字符串的定義,
多個(gè)操作符定義為列表宴树,第一個(gè)元素為定義的邏輯符號(hào)策菜,第二個(gè)元素說明是一元還是二元,第三個(gè)元素是說明操作符是left- or right-associative酒贬。使用操作符優(yōu)先級(jí)定義比較簡潔又憨,效果等同于上一段的pyparsing定義。省略了遞歸定義锭吨,和()操作符的定義蠢莺。
下面是我們定義的關(guān)系表達(dá)式的語法,關(guān)系表達(dá)式中可以使用變量零如,數(shù)值躏将,字符串,支持>,== <,>=, <=.(少了一個(gè)!=)
每個(gè)關(guān)系表達(dá)式封裝在一個(gè)子列表內(nèi)考蕾。BoolTerm 可以是任何一個(gè)關(guān)系表達(dá)式祸憋。使用操作符優(yōu)先級(jí)進(jìn)行定義:
定義let表達(dá)式:原來 in 后面跟著的body,修改為boolexpr肖卧。變量定義中變量的值只能賦值為item蚯窥,上面item定義為變量,數(shù)值塞帐,字符串拦赠,所以在擴(kuò)展環(huán)境中的變量的值的時(shí)候,直接擴(kuò)展壁榕,不需要對(duì)item進(jìn)行解析計(jì)算了矛紫。
解釋執(zhí)行
let的語句執(zhí)行時(shí),對(duì)于變量定義列表牌里,varvalue的值都是直接的值颊咬,直接擴(kuò)展到環(huán)境中去务甥,然后返回boolexp的解析結(jié)果
布爾表達(dá)式,首先是以and 和 or 分割的list喳篇,not 或者 關(guān)系表達(dá)式都被封裝在更深一層的list內(nèi)部敞临,所以頂級(jí)有&& 或者 || 出現(xiàn)的時(shí)候,總是 一個(gè)或者多個(gè) && || 組成的列表麸澜,在列表的1,3,5奇數(shù)位上總是 &&或||挺尿,0,2,4是 關(guān)系表達(dá)式,或者子布爾表達(dá)式炊邦。同一級(jí)的表達(dá)式如果出現(xiàn)多個(gè)||编矾,則計(jì)算每一個(gè)的值,碰到第一個(gè)為真馁害,就返回窄俏,表達(dá)式都執(zhí)行沒有返回,就返回假碘菜。 多個(gè)&&時(shí)凹蜈,碰到第一個(gè)為假就返回,多個(gè)表達(dá)式計(jì)算完成沒有返回忍啸,就返回真仰坦。
如果是not表達(dá)式,則exp的第一個(gè)字符是not 计雌!悄晃,直接返回 第二個(gè)元素的反值。not表達(dá)式解析為一個(gè)獨(dú)立的list白粉,所以元素為2传泊,后面跟著not的對(duì)象。
剩余的就是計(jì)算關(guān)系表達(dá)式的值了:關(guān)系表達(dá)式都是有3個(gè)元素的鸭巴,所以解析出來的list結(jié)果眷细,每一個(gè)list都是至少有2個(gè)元素的,所以下面直接通過索引判斷l(xiāng)ist的取值鹃祖,并不會(huì)越界溪椎。
關(guān)系表達(dá)式的解釋:關(guān)系表達(dá)式都是二元的,所以取值的時(shí)候只要取出0,2,的值即可恬口,1號(hào)位的元素肯定是字符串的關(guān)系符號(hào)校读。0和2號(hào)位,如果不是以“開頭的字符串說明它是一個(gè)變量祖能,這里有個(gè)注意的地方歉秫,pyparsing解析出來的字符串,如果不設(shè)置setParseAction時(shí)养铸,removeQuotes解析出來的結(jié)果是帶引號(hào)的雁芙,這里我們通過引號(hào)來區(qū)分其實(shí)字符串類型還是變量類型轧膘。變量和字符串的類型區(qū)分,后續(xù)會(huì)用其他方法進(jìn)行區(qū)分兔甘。
真正解釋關(guān)系表達(dá)式的時(shí)候谎碍,是將每個(gè)關(guān)系表達(dá)式轉(zhuǎn)換成字符串,然后調(diào)用eval直接當(dāng)成python語言進(jìn)行計(jì)算洞焙。如果關(guān)系表達(dá)式中包含變量的時(shí)候蟆淀,提前將其的值從環(huán)境中查找出來 apply_env。然后再組成字符串澡匪。
遺留問題:只通過解析出來的list元素值熔任,不太好區(qū)分 變量 和 字符串 的定義∠沈龋可以通過設(shè)置setResultsName別名來區(qū)分笋敞,但是效果不是很好。