一起來寫一個簡單的解釋器(3)
1 人贊了文章
本系列文章參考國外編程高手魯斯蘭的博客文章《Let』s Build A Simple Interpreter》。
在之前的文章中,我們一起學習了如何實現對兩個數字加減法表達式的解釋。
這一篇文章,我們一起來學習對多個數字加減法表達式的解釋。
例如:12 + 8 – 6 – 10
在編寫代碼之前,我們先來看一張圖。
這張圖是語法圖。
語法圖是表示一種程序設計語言語法規則的示意圖。
實際上,語法圖體現了語法分析器(Parser)的運行規則。
一張語法圖能夠直觀地體現在我們的程序設計語言中,允許使用哪些語句和不允許使用哪些語句。
那麼,怎麼閱讀這張語法圖呢?
我們只需跟隨箭頭所指的路徑去了解程序的運行。
在語法圖中,有些路徑表示選擇,例如:加法表達式和減法表達式需要選擇不同的路徑。
另外,有的路徑表示循環,例如:多次進行加減運算的過程。
為了把這張圖看的更明白,我將不同的表達式對應語法圖中的路徑,做了幾張示意圖。
其中橙色路徑就是當前表達式運行的路徑。
例如:
>>>3
當我們只輸入一個數字,此時程序只找到了一個操作數,那就只需要把這個操作數傳遞出去。
例如:
>>>3+6
當我們輸入了一個完整的兩位數加法表達式,此時程序會先找到一個操作數,然後選擇加法操作符,再找到另外一個操作數,最終識別出一個完整的短語傳遞出去。
例如:
>>>3+5-4-2+6
當我們輸入了一個多個數字的加減法表達式,此時程序會先找到一個操作數,然後選擇加法操作符,再找到另外一個操作數;此時,程序發現還有新的記號,就開始循環的過程;再次選擇操作符,找到操作數,直到找不到新的記號,將完整的短語傳遞出去。
相信到這裡,大家都應該理解了這張語法圖的含義。
那麼,這裡我們看到了一個新的英文單詞「Term」,中文含義是「術語」,但是這很難理解。
不要搞那麼複雜,在這篇文章中,Term就是一個整數。
根據上面的語法圖,以下表達式都是合法的:
- 3
- 5+16
- 33-15+7
實際上,因為在不同的程序設計語言中,四則運算表達式的語法規則十分相似。
所以,在Python的Shell中,我們運行這些表達式看到的結果也沒有什麼區別。
然而,對於我們的解釋器,表達式「3 + 」並不是一個有效的表達式。
因為,根據語法圖,加號後面必須跟著一個Term(整數),否則將會是一個語法錯誤。
在上一篇文章中,我們知道一連串Token(Token流)中識別出一個短語的過程叫做「Parsing」(語法分析)。一個解釋器或者編譯器用於語法分析的部分叫「Parser」(語法分析器)。
其實,「Parsing」也叫做「Syntax Analysis」,而「parser 」也叫做「Syntax Analyzer」。
而且,我們也知道「Parser」和「Interpreter」位於「expr()」方法中。
「Parser」只負責識別結構並確保結構符合規範,當「Parser」成功識別(解析)出結構,Interpreter 會對表達式進行求值計算。
根據上面的語法圖,我們重寫「Parser」部分的代碼。
這裡我們添加一個新的方法「term()」,用於解析一個整數。
示例代碼:
def term(self): self.eat(INTEGER) # 驗證整數def expr(self): self.current_token = self.get_next_token() # 獲取記號 self.term() # 驗證第一個整數 while self.current_token.value_type in (PLUS, MINUS): # 循環 if self.current_token.value_type == PLUS: # 選擇加法運算符 self.eat(PLUS) # 驗證運算符 self.term() # 驗證下一個整數 if self.current_token.value_type == MINUS: # 選擇減法運算符 self.eat(MINUS) # 驗證運算符 self.term() # 驗證下一個整數
上方代碼就是根據語法圖重寫的代碼。
不過很顯然,「Parser」不會完成全部解釋工作,它正確的識別表達式之後沒有任何結果,只有在表達式識別失敗的時候會拋出異常。
提示:大家可以嘗試運行程序,輸入「1+2」和「1+」進行驗證。
因為,Interpreter需要表達式的值,所以,我們可以修改「term()」方法,讓它返回一個整數值。
並且,我們還要修改「expr()」方法,讓它在適當的位置執行加法和減法的計算,並且返回解釋的結果。
示例代碼:
def term(self): token = self.current_token # 獲取記號 self.eat(INTEGER) return token.value # 返回記號中的整數值def expr(self): self.current_token = self.get_next_token() result = self.term() # 獲取第一個整數(Term) while self.current_token.value_type in (PLUS, MINUS): if self.current_token.value_type == PLUS: self.eat(PLUS) result += self.term() # 已有結果加上新獲取的整數(Term) if self.current_token.value_type == MINUS: self.eat(MINUS) # 已有結果減去新獲取的整數(Term) result -= self.term() return result
到這裡,我們的解釋器就可以完成多個數字的加減法表達式運算了。
在這篇內容的基礎上,大家可以嘗試進行以下功能的擴展:
- 畫一個只包含乘法和除法的算術表達式語法圖,例如「7 * 4 / 2 * 3」;(不要認為很簡單就不去做)
- 重寫Interpreter類的所有源代碼,不要再參考寫過的代碼和文章,只靠自己的思考,讓它可以解釋只包含乘法和除法的算術表達式。
而且,當學習完這篇文章,請大家自我檢查一下,是否了解了以下內容:
- 什麼是語法圖?
- 什麼是語法分析?
- 什麼是語法分析器?
在學習中遇到任何問題,可以留言關注一下喔!
推薦閱讀:
※TensorFlow識別知乎驗證碼
※求一本 Python 3 的好書,入門級別或中等級別,求推薦?
※Python筆記--sklearn函數匯總
※深度學習之BP神經網路(三)