posts - 495,comments - 227,trackbacks - 0

          http://blog.csdn.net/hunkcai/article/details/6125963


          前言

          表達式的計算是一個一般性的問題。在報表領域,經常會出現支持計算公式的需求。MS Office Excel中的函數計算就是一個很好的參考例子。

          本文提供一個表達式引擎的設計方案,能夠滿足報表領域的復雜計算要求。

           

          一個良好的表達式引擎應該支持基本的二元運算和函數調用,而且二元運算能夠嵌套函數調用,函數調用也能夠嵌套二元運算,比如:

          例子1:=2>1&&((Num(1)+2*Num((Num(2)+2)*3/Num(2)))/2>0||2>1)&&0>1,執行結果:0

          例子2:=Switch(Num(1),是, Num(0),否),執行結果:是

          例子3:=Switch(20<10,1 ,20>=10, 20 + 20*0.1),執行結果:22

           

          當然,實際的應用里,表達式中要支持變量的綁定,比如:

          例子1(計算稅后金額):=Fields!數量.Value * Fields!單價.Value*(1 + Fields!稅率.Value / 100)

          例子2(不同價格不同稅后金額):=Fields!數量.Value*Fields!單價.Value*Switch(Fields!單 價.Value<100, 1.1, Fields!單價.Value<500, 1.08, Fields!單價.Value<800, 1.07)

           

          至于常用的一元運算,能夠通過函數調用就很方便的實現,例如:取非,Not(exp1)。

           

          表達式的定義

          要支持二元運算能夠嵌套函數調用,函數調用也能夠嵌套二元運算,需要采用解析器設計模式,定義數個表達式對象,用表達式對象樹來描述表達式字符串。

          值表達式:用來描述一個常量或變量,例如:1.1,Fields!數量.Value,Parameters!經手人.Value,字符串

          二元表達式:用來描述一個二元運算,例如:exp1 + exp2,exp1

          函數表達式:用來描述一個函數調用,例如:Num(exp1),Sum(exp1), Switch(cond1, proc1, cond2, proc2…)

           

          運算符優先級

          運算符優先級很重要,決定了運算的順序,特別是括號,能夠改變表達式的運算順序。

          優先級

          運算符

          說明

          -1

          (

          左括號

          -1

          )

          右括號

          -2

          ^

          冪運算

          -3

          *

          -3

          /

          -3

          %

          取余

          -4

          +

          -4

          -

          -5

          <

          小于

          -5

          <=

          小于等于

          -5

          >

          大于

          -5

          >=

          大于等于

          -6

          ==

          等于

          -6

          !=

          不等于

          -7

          &&

          邏輯與

          -8

          ||

          邏輯或

           

          表達式引擎的工作流程

           

          二元運算解析生成后綴表達式數組的過程

          中綴表達式解析成后綴表達式的方法如下,要借用一個臨時堆棧stack,輸出是后綴表達式數組output:

          (1)從右向左依次讀取表達式字符串str。

          (2)如果str是操作數(常量或變量),輸出到output。

          (3)如果str是運算符(含左右括號),則做以下判斷:

              a) 如果str = '(',放入堆棧stack。

              b)如果str = ')',依次彈出堆棧stack中的運算符輸出到output,直到遇到'('為止。

              c)如果str不是')'或者'(',那么就和堆棧stack頂點位置的運算符top做優先級比較。

                1)如果top是'('或者str優先級比top高,那么將str放入堆棧stack。

                2)如果str優先級低于或者等于top,那么輸出top到output,然后將str放入堆棧stack。

          (4)如果表達式字符串已經讀取完成,而堆棧stack中還有運算符時,依次由頂端輸出到output。

           

          后綴表達式數組生成表達式對象樹的過程

          計算后綴表達式的方法如下,要借用一個臨時堆棧stack:

          (1)從左向右掃描后綴表達式數組,依次取出一個數組元素data。

          (2)如果data是表達式,就壓入堆棧stack。

          (3)如果data是運算符,就從堆棧stack中彈出此運算符需要用到的表達式的個數(二元運算符需要2個),創建一個新二元表達式,然后把二元表達式壓入堆棧stack。

          (4)如果數組處理完畢,堆棧stack中最后剩余的表達式就是最終結果。

           

          例如,表達式=(Num(1)+2*Num(Num(2)+2*3/Num(2)))/2,生成的后綴表達式數組如下:

          0:    Method{num, [Const(1)]}

          1:    Const(2)

          2:    Method{num, [Binary{+, Method{num, [Const(2)]}, Binary{/, Binary{*, Const(2), Const(3)}, Method{num, [Const(2)]}}}]}

          3:    *

          4:    +

          5:    Const(2)

          6:    /

          該后綴表達式數組生成的表達式對象樹如下:

          Binary{/, Binary{+, Method{num, [Const(1)]}, Binary{*, Const(2), Method{num, [Binary{+, Method{num, [Const(2)]}, Binary{/, Binary{*, Const(2), Const(3)}, Method{num, [Const(2)]}}}]}}}, Const(2)}

           

          剩下的工作就是執行表達式對象樹,輸出結果。

          posted on 2012-11-05 17:32 SIMONE 閱讀(687) 評論(0)  編輯  收藏 所屬分類: JAVA
          主站蜘蛛池模板: 建湖县| 班戈县| 富蕴县| 沿河| 宝丰县| 黄浦区| 许昌县| 六安市| 岫岩| 柘城县| 类乌齐县| 永州市| 中西区| 阜新市| 姜堰市| 天门市| 贵定县| 塔城市| 盐城市| 依兰县| 呼伦贝尔市| 厦门市| 翼城县| 张北县| 阿拉尔市| 根河市| 博湖县| 时尚| 英德市| 康平县| 宁南县| 海盐县| 马尔康县| 济南市| 仪陇县| 冀州市| 嵊泗县| 苍梧县| 玛曲县| 肥东县| 涡阳县|