**的編譯是電腦科學的一大命題,其博大精深,難以盡數。這裡
,我們撿著乙個小命題娛樂一下。
程式**中,總是少不了數**算,其實對於我們來說很熟悉的數學計
算,在計算機裡也是要做一些編譯處理的。
例如,4+9*3+7-2這樣乙個簡單的四則運算
,對於人來說就是:
4+9*3+7-2
=4+27+7-2
=31+7-2
=38-2
=36這裡面,我們實際上已經在下意識裡做了很多思考。首先
,大腦會按照運算子劃分開各個子算式,然後找出運算優先順序的子式
,按順序計算完後,將結果填充給下一級,依次遞迴
,直至整個算式完成。
計算機的編譯/解釋過程,其實跟這個很像,也是先找出最高優先順序的
子式,然後依次遞迴構造出乙個語法解析樹,呼叫數**算指令計算每
個節點,返回結果。對於每個單步運算,計算機裡面呼叫一次+、-
、*、/的時候,其實是一次函式操作,每個運算子執行對應的函式
,比如1+1,其實就是+(1, 1)。在編譯時,通常會把這樣的運算翻譯為字尾表示式,+(1, 1)就變成了1 1 -,這樣的好處是計算機逐次讀入每乙個詞,遇到運算元就壓棧
,遇到操作符就把所需個數的運算元從棧裡彈出來計算
,然後再把結果壓進去,這個過程以輕鬆匹配複雜表示式。不過—
—這麼看起來是不很累?特別是複雜算式,就看不清層次了
。我們把它用括號包起來,就成了(1 1 -),這樣清晰一些了吧,我們現在按這種方式把開頭的那個式子寫成
: (((4 (9 3 *)+) 7+) 2 -)
現在,我們用乙個表示堆疊,左邊是棧頂,右邊是棧底
。現在我們模擬計算機的解釋過程。
(((4 (9 3 *)+) 7+) 2 -)
=>[4]
4入棧
=>[9 4] 9入棧
=>[3 9 4] 3入棧
=>* (9 3) [4] 讀到*,彈出最上面兩個數3和9——需要注意,因為堆疊的後入先出
特性,實際上棧頂的元素反而在參數列的右邊
=>[27 4] 把相乘以後的結果27重新壓入棧
=>+ (4 27) 讀到+,彈出最上面兩個數27和4
=>[31] 把相加結果31入棧
=>[7 31] 7入棧
=>+ (31 7) 讀到+,彈出最上面兩個數7和31
=>[38] 把相加以後的結果38入棧
=>[2 38] 2入棧
=>- (38 2) 讀到-,彈出最上面兩個數2和38
=>[36] 把相減結果36入棧
=>36 檢測到運算過程已經完成,把結果從堆疊中彈出返回
以上這個過程對計算機是很方便,但是對於我們讀起來還是有點彆扭
,把運算子放前面不是更好懂麼?編譯原理中,字首表示式也是一種常
見的寫法,於是:
(((4 (9 3 *)+) 7+) 2 -)=>(-(+(+ 4 (* 9 3)) 7) 2)
這個麼,應該有朋友已經發現了,這不就是一段lisp**麼?!
我有很長時間不能很好的理解lisp**,直到有位朋友說
,lisp就是語法解析樹的字首表達……
以此文向他致敬!
表示式解析
1 本文目標 分析用堆疊解析算術表示式的基本方法。給出的示例 能解析任何包括 和0到9數字組成的算術表示式。2 中綴表示式和字尾表示式 中綴表示式就是通常所說的算術表示式,比如 1 2 3 4。字尾表示式是指通過解析後,運算子在運算數之後的表示式,比如上式解析成字尾表示式就是12 3 4 這種表示式...
查詢表示式解析
查詢表示式解析 1 ienumerablequery from s in names where s.length 5 orderby s select s.toupper 在語義上等同於如下 方法風格 基於方法 的查詢 ienumerablequery names where s s.length...
解析算術表示式
現有字串形式的算術表示式,求計算其值。string str1 2000 600 3 300 2 string str2 2000 600.389895334 2 300 2 6 100 求解方法如下 讀取公式,返回結果。param express 算術公式 return 結果字串 保留兩位小數 pu...