仿查詢分析器的C#計(jì)算器——1.初步分析
計(jì)算器是很多編程初學(xué)者都做過的,從最簡(jiǎn)單的控制臺(tái)程序開始,輸入值,輸入運(yùn)算符,再輸入值,得到一個(gè)結(jié)果。帶界面的基本上是模仿Windows操作系統(tǒng)的計(jì)算器,通過按鈕輸入值和運(yùn)算符,然后給出運(yùn)算結(jié)果。能不能直接輸入表達(dá)式,或者能夠?qū)脦讉€(gè)表達(dá)式進(jìn)行計(jì)算,或者選擇表達(dá)式中的一部分進(jìn)行計(jì)算,如果輸入錯(cuò)誤能不能指出表達(dá)式中的錯(cuò)誤位置?這樣的要求類似于MS SQL的查詢分析器,本系列文章將介紹如何實(shí)現(xiàn)這樣一個(gè)計(jì)算器。(這些內(nèi)容已經(jīng)涉及到編譯原理,但本人并非計(jì)算機(jī)專業(yè)畢業(yè),只是稍微看了一下編譯原理的資料,專業(yè)詞匯比如有限狀態(tài)機(jī)之類就不提了,咱也不是很pro,呵呵。)
首先給出一個(gè)表達(dá)式5*3+12/4,我們拿到這個(gè)表達(dá)式之后會(huì)得到如下分析:
1.乘法的優(yōu)先級(jí)高后面的加法,先算乘法,乘號(hào)兩邊的數(shù)分別是5和3,執(zhí)行乘法5*3=15
2.加法的優(yōu)先級(jí)沒有后面的除法優(yōu)先級(jí)高,先算除法,除號(hào)兩邊的數(shù)是12和4,執(zhí)行除法12/4=3
3.乘除法做完之后再做加法,這時(shí)候加法并不需要知道兩邊到底怎么計(jì)算的,只需要知道兩邊計(jì)算后的值就可以了,乘法的值是15,除法的值是3,執(zhí)行加法15+3=18
在這個(gè)表達(dá)式后面再加一個(gè)步驟:5*3+12/4-8,這時(shí)候只不過多了一步操作
4.做完加法后做減法,減號(hào)也不需要知道兩邊怎么計(jì)算的,向兩邊請(qǐng)求值,得到加法的值是18,另一邊是一個(gè)數(shù)字8,不需要計(jì)算就直接給它,執(zhí)行減法18-8=10
再稍微改變一下:5*3+12/4-8/2,計(jì)算過程就是
4.做完加法準(zhǔn)備做減法,但后面的除法優(yōu)先級(jí)高,先做除法,除號(hào)兩邊的數(shù)是8和2,執(zhí)行除法得到4
5.然后執(zhí)行減法,減法左邊是執(zhí)行加法后的值18,右邊是執(zhí)行除法后的值4,執(zhí)行減法18-4=14
到此會(huì)發(fā)現(xiàn),其實(shí)可以把每一個(gè)操作符理解成一個(gè)數(shù)值存儲(chǔ)單元,并且該單元可以根據(jù)它兩邊的數(shù)值進(jìn)行一定的計(jì)算得到自身的值。它只關(guān)心兩邊的值,而不需要關(guān)心值是通過什么算法得來的。這樣就有了二叉樹的味道,一個(gè)結(jié)點(diǎn)下面可以有兩個(gè)子結(jié)點(diǎn)。因此,不管表達(dá)式多復(fù)雜,最終都只有一個(gè)結(jié)果,這個(gè)結(jié)果就是最后一個(gè)操作符對(duì)它兩邊的值進(jìn)行計(jì)算得到的,而最后一個(gè)操作符就可以理解成根節(jié)點(diǎn)。下面,就把表達(dá)式按照樹的形狀分解:

這里減法就是根節(jié)點(diǎn),它向下請(qǐng)求值并進(jìn)行計(jì)算。它的下級(jí)也是采用同樣的方法向下請(qǐng)求值,請(qǐng)求到值后就執(zhí)行自身的計(jì)算,把計(jì)算結(jié)果存儲(chǔ)在自己的存儲(chǔ)單元里,然后讓上一級(jí)調(diào)用自身的值。最后由根節(jié)點(diǎn)計(jì)算其下級(jí)的值得到整個(gè)表達(dá)式的值。最終計(jì)算完的樹結(jié)構(gòu)如下:
我在實(shí)際編程中就是采用這種方法對(duì)表達(dá)式進(jìn)行分析和計(jì)算的,如圖:

輸入界面(選擇部分表達(dá)式計(jì)算)

至于如何將表達(dá)式分析成樹形結(jié)構(gòu),以及如何調(diào)用下級(jí)節(jié)點(diǎn)求值,在以后的文章中詳細(xì)介紹。
代碼下載:https://files.cnblogs.com/conexpress/ConExpress_MyCalculator.rar
(本程序還有一些細(xì)節(jié)上的bug,有興趣的朋友可以完善一下。)

浙公網(wǎng)安備 33010602011771號(hào)