jialisoftw

          java實現遞歸下降的表達式解析器

          本算法用java代碼實現數值表達式的解析。

          1、數值表達式的組成:

           

          • 數字
          • 運算符+、-、*、/、^、%、=
          • 圓括號(、)
          • 變量

           

          其中^運算符表示求冪運算符(如10^2=100),=是賦值運算符。

          2、本解析器必須滿足的約束條件:

          1)、所有變量都是單個字母(從A到Z的26個字母),字母不區分大小;

          2)、假定所有的數字都是double類型,可以方便地修改解析器從而處理其他類型的值。

          3、該算法將表達式被視為遞歸的數據結構,表達式定義的規則:

          表達式-->項 [+項] [-項]

          項-->因數 [*因數] [/因數]

          因數-->變量、數字或者表達式

          4、表達式的分解

          例如表達式:A * B - (C + 10)

          包括如下這些獨立的元素:A、*、B、-、(、C、+、10、),這些元素叫做標識符(token),表示表達式中一個不可再分的獨立單元。

          5、代碼

           

          1. <span style="font-size:16px;"><span style="font-family:'Microsoft YaHei';">package com.mmq.expression;  
          2. /** 
          3.  * @use 表達式解析器,支持變量 
          4.  * @ProjectName stuff 
          5.  * @Author <a href="mailto:mhmyqn@126.com">mumaoqiang</a></br> 
          6.  * @Date 2011-11-22 下午12:03:57 </br> 
          7.  * @FullName com.mmq.expression.Parser.java </br> 
          8.  * @JDK 1.6.0 </br> 
          9.  * @Version 1.0 </br> 
          10.  */  
          11. public class Parser {  
          12.     //These are the token types 標識符類型常量  
          13.     /**未定義的標識符*/  
          14.     final int NONE = 0;  
          15.     /**分隔符(包括運算符和括號)*/  
          16.     final int DELIMITER = 1;  
          17.     /**變量*/  
          18.     final int VARIABLE = 2;  
          19.     /**數值*/  
          20.     final int NUMBER = 3;  
          21.       
          22.     //These are the types of the syntax errors 語法錯誤類型常量  
          23.     /**所有導致非正則表達式的錯誤*/  
          24.     final int SYNTAX = 0;  
          25.     /**括號不對稱錯誤*/  
          26.     final int UNBALPARENS = 1;  
          27.     /**沒有表達式*/  
          28.     final int NOEXP = 2;  
          29.     /**除數為0*/  
          30.     final int DIVBYZERO = 3;  
          31.       
          32.     /** 
          33.      * This token indicates end-of-expression 表達式結束標識符  
          34.      * 標志解析器已達到表達式結尾 
          35.      */  
          36.     final String EOE = "\0";  
          37.       
          38.     /**refers to expression string 表達式字符串*/  
          39.     private String exp;  
          40.     /**current index into the expression 表達式中當前標識符的索引*/  
          41.     private int expIdx;  
          42.     /**holds current token 當前標識符*/  
          43.     private String token;  
          44.     /**holds token's type 標識符類型*/  
          45.     private int tokType;  
          46.       
          47.     /**Array for variables 變量數組*/  
          48.     private double vars[] = new double[26];  
          49.       
          50.     /** 
          51.      * Parser entry point 解析器入口 
          52.      * @param expstr 表達式字符串 
          53.      * @return 表達式的值 
          54.      * @throws ParserException 
          55.      */  
          56.     public double evaluate(String expstr) throws ParserException {  
          57.         double result;  
          58.         exp = expstr;  
          59.         expIdx = 0;  
          60.           
          61.         getToken();  
          62.         if(token.equals(EOE)){  
          63.             handleErr(NOEXP);//no expression present  
          64.         }  
          65.           
          66.         //Parse and evaluate the expression  
          67.         result = assignment();  
          68.           
          69.         if(!token.equals(EOE)){//last token must be EOE  
          70.             handleErr(SYNTAX);  
          71.         }  
          72.           
          73.         return result;  
          74.     }  
          75.     /** 
          76.      * Process an assignment 處理賦值語句 
          77.      * @return 
          78.      * @throws ParserException 
          79.      */  
          80.     private double assignment() throws ParserException {  
          81.         double result;  
          82.         int varIdx;  
          83.         int ttokType;  
          84.         String temptoken;  
          85.           
          86.         if(tokType == VARIABLE){  
          87.             //save old token  
          88.             temptoken = new String(token);  
          89.             ttokType = tokType;  
          90.               
          91.             //Compute the index of a variable.  
          92.             varIdx = Character.toUpperCase(token.charAt(0)) - 'A';  
          93.               
          94.             getToken();  
          95.             if(!token.equals("=")){  
          96.                 putBack();//return current token  
          97.                 //restore old token -- not an assignment  
          98.                 token = new String(temptoken);  
          99.                 tokType = ttokType;  
          100.             } else {  
          101.                 getToken();//  
          102.                 result = addOrSubtract();  
          103.                 vars[varIdx] = result;  
          104.                 return result;  
          105.             }  
          106.         }  
          107.           
          108.         return addOrSubtract();  
          109.     }  
          110.     /** 
          111.      * Add or subtract two terms. 兩個數值加或減 
          112.      * @return 
          113.      * @throws ParserException 
          114.      */  
          115.     private double addOrSubtract() throws ParserException {  
          116.         char op;  
          117.         double result;  
          118.         double partialResult;  
          119.           
          120.         result = multiplyOrDivide();  
          121.           
          122.         while((op = token.charAt(0)) == '+' || op == '-'){  
          123.             getToken();  
          124.             partialResult = multiplyOrDivide();  
          125.             switch(op){  
          126.             case '-' :   
          127.                 result = result - partialResult;  
          128.                 break;  
          129.             case '+' :  
          130.                 result = result + partialResult;  
          131.                 break;  
          132.             }  
          133.         }  
          134.           
          135.         return result;  
          136.     }  
          137.       
          138.     /** 
          139.      * Multiply or divide two factors. 兩個數值乘、除或取模 
          140.      * @return 
          141.      * @throws ParserException 
          142.      */  
          143.     private double multiplyOrDivide() throws ParserException {  
          144.         char op;  
          145.         double result;  
          146.         double partialResult;  
          147.           
          148.         result = exponent();  
          149.           
          150.         while((op = token.charAt(0)) == '*' || op == '/' || op == '%'){  
          151.             getToken();  
          152.             partialResult = exponent();  
          153.             switch(op){  
          154.             case '*' :   
          155.                 result = result * partialResult;  
          156.                 break;  
          157.             case '/' :  
          158.                 if(partialResult == 0.0){  
          159.                     handleErr(DIVBYZERO);  
          160.                 }  
          161.                 result = result / partialResult;  
          162.                 break;  
          163.             case '%' :  
          164.                 if(partialResult == 0.0){  
          165.                     handleErr(DIVBYZERO);  
          166.                 }  
          167.                 result = result % partialResult;  
          168.                 break;  
          169.             }  
          170.         }  
          171.           
          172.         return result;  
          173.     }  
          174.     /** 
          175.      * Process an exponent. 指數運算 
          176.      * @return 
          177.      * @throws ParserException 
          178.      */  
          179.     private double exponent() throws ParserException {  
          180.         double result;  
          181.         double partialResult;  
          182.         double ex;  
          183.         int t;  
          184.           
          185.         result = unary();  
          186.           
          187.         if(token.equals("^")){  
          188.             getToken();  
          189.             partialResult = exponent();  
          190.             ex = result;  
          191.             if(partialResult == 0.0){  
          192.                 result = 1.0;  
          193.             } else {  
          194.                 for(t = (int)partialResult - 1; t > 0; t-- ){  
          195.                     result = result * ex;  
          196.                 }  
          197.             }  
          198.         }  
          199.           
          200.         return result;  
          201.     }  
          202.     /** 
          203.      * Evaluate a unary + or -. 一元取正或一元取負運算 
          204.      * @return 
          205.      * @throws ParserException 
          206.      */  
          207.     private double unary() throws ParserException {  
          208.         double result;  
          209.         String op = "";  
          210.         //檢查標識符是否為一元取正或一元取負運算符  
          211.         if(tokType == DELIMITER && token.equals("+") || token.equals("-")){  
          212.             op = token;  
          213.             getToken();  
          214.         }  
          215.           
          216.         result = parenthesize();  
          217.           
          218.         if(op.equals("-")){  
          219.             result = -result;  
          220.         }  
          221.           
          222.         return result;  
          223.     }  
          224.     /** 
          225.      * Process a parenthesized expression. 處理括號表達式 
          226.      * @return 
          227.      * @throws ParserException 
          228.      */  
          229.     private double parenthesize() throws ParserException {  
          230.         double result;  
          231.         //如果讀取的是括號時遞歸調用addOrSubtract()  
          232.         if(token.equals("(")){  
          233.             getToken();  
          234.             result = addOrSubtract();  
          235.             if(!token.equals(")")){  
          236.                 handleErr(UNBALPARENS);  
          237.             }  
          238.             getToken();  
          239.         } else {  
          240.             result = atom();  
          241.         }  
          242.       
          243.         return result;  
          244.     }  
          245.     /** 
          246.      * Get the value of a number or variable. 獲取一個數值字符串或變量的值 
          247.      * @return 
          248.      * @throws ParserException 
          249.      */  
          250.     private double atom() throws ParserException {  
          251.         double result = 0.0;  
          252.           
          253.         switch(tokType){  
          254.         case NUMBER :  
          255.             try {  
          256.                 result = Double.parseDouble(token);  
          257.             } catch (NumberFormatException e) {  
          258.                 handleErr(SYNTAX);  
          259.                 e.printStackTrace();  
          260.             }  
          261.             getToken();  
          262.             break;  
          263.         case VARIABLE :  
          264.             result = findVar(token);  
          265.             getToken();  
          266.             break;  
          267.         default :  
          268.             handleErr(SYNTAX);  
          269.             break;  
          270.         }  
          271.         return result;  
          272.     }  
          273.     /** 
          274.      * Return the value of a variable. 獲取變量的值 
          275.      * @param vname 
          276.      * @return 
          277.      * @throws ParserException 
          278.      */  
          279.     private double findVar(String vname) throws ParserException {  
          280.         if(!Character.isLetter(vname.charAt(0))){  
          281.             handleErr(SYNTAX);  
          282.             return 0.0;  
          283.         }  
          284.         return vars[Character.toUpperCase(vname.charAt(0)) - 'A'];  
          285.     }  
          286.     /** 
          287.      * Return a token to the input stream. 
          288.      * 當標識為'='時,返回到標識符之前的索引位置 
          289.      */  
          290.     private void putBack(){  
          291.         if(token == EOE){  
          292.             return;  
          293.         }  
          294.         for(int i = 0; i < token.length(); i++){  
          295.             expIdx--;  
          296.         }  
          297.     }  
          298.     /** 
          299.      * Handle an error. 錯誤處理 
          300.      * @param error 
          301.      * @throws ParserException 
          302.      */  
          303.     private void handleErr(int error) throws ParserException {  
          304.         String[] err = {  
          305.                 "Unbalanced Parentheses",  
          306.                 "No Expression Parent",  
          307.                 "Division by zero"  
          308.         };  
          309.         throw new ParserException(err[error]);  
          310.     }  
          311.       
          312.     /** 
          313.      * 獲得表達式中的下一個標識符 
          314.      */  
          315.     private void getToken(){  
          316.         tokType = NONE;  
          317.         token = "";  
          318.         //Check for end of expression  
          319.         if(expIdx == exp.length()){  
          320.             token = EOE;  
          321.             return;  
          322.         }  
          323.         //Skip over white space  
          324.         while(expIdx < exp.length() && Character.isWhitespace(exp.charAt(expIdx))){  
          325.             ++expIdx;  
          326.         }  
          327.         //Trailing whitespace ends expression  
          328.         if(expIdx == exp.length()){  
          329.             token = EOE;  
          330.             return;  
          331.         }  
          332.           
          333.         if(isDelim(exp.charAt(expIdx))){//is operator  
          334.             token += exp.charAt(expIdx);  
          335.             expIdx++;  
          336.             tokType = DELIMITER;  
          337.         } else if(Character.isLetter(exp.charAt(expIdx))){//is variable  
          338.             while(!isDelim(exp.charAt(expIdx))){  
          339.                 token += exp.charAt(expIdx);  
          340.                 expIdx++;  
          341.                 if(expIdx >= exp.length()){  
          342.                     break;  
          343.                 }  
          344.             }  
          345.             tokType = VARIABLE;  
          346.         } else if(Character.isDigit(exp.charAt(expIdx))){//is number  
          347.             while(!isDelim(exp.charAt(expIdx))){  
          348.                 token += exp.charAt(expIdx);  
          349.                 expIdx++;  
          350.                 if(expIdx >= exp.length()){  
          351.                     break;  
          352.                 }  
          353.             }  
          354.             tokType = NUMBER;  
          355.         } else {  
          356.             token = EOE;  
          357.             return;  
          358.         }  
          359.           
          360.     }  
          361.     /** 
          362.      * Return true if c is a delimiter. 判斷是不是一個分隔符 
          363.      */  
          364.     private boolean isDelim(char c){  
          365.         if(" +-*/%^=()".indexOf(c) != -1){  
          366.             return true;  
          367.         }  
          368.         return false;  
          369.     }  
          370.       
          371. }</span></span>  

           

          異常處理類:

           

          1. <span style="font-size:16px;"><span style="font-family:'Microsoft YaHei';">package com.mmq.expression;  
          2.   
          3. public class ParserException extends Exception {  
          4.     private static final long serialVersionUID = 8930730209321088339L;  
          5.     String errStr;  
          6.   
          7.     public ParserException(String str) {  
          8.         this.errStr = str;  
          9.     }  
          10.   
          11.     public String toString() {  
          12.         return errStr;  
          13.     }  
          14. }  
          15. </span></span>  

          測試代碼:

           

           

          1. <span style="font-size:16px;"><span style="font-family:'Microsoft YaHei';">package com.mmq.expression;  
          2.   
          3. import java.io.BufferedReader;  
          4. import java.io.IOException;  
          5. import java.io.InputStreamReader;  
          6.   
          7. public class ParserDemo {  
          8.     public static void main(String[] args) throws IOException {  
          9.         String expr;  
          10.         BufferedReader br = new BufferedReader(new InputStreamReader(System.in));  
          11.         Parser p = new Parser();  
          12.           
          13.         System.out.println("Enter an empty expression to stop.");  
          14.         for(;;){  
          15.             System.out.print("Enter expression: ");  
          16.             expr = br.readLine();  
          17.             if("".equals(expr)){  
          18.                 break;  
          19.             }  
          20.             try {  
          21.                 System.out.println("Result: " + p.evaluate(expr));  
          22.                 System.out.println();  
          23.             } catch (ParserException e) {  
          24.                 System.out.println(e);  
          25.             }  
          26.         }  
          27.     }  
          28. }  
          29. </span></span>  

          測試輸出如下:
          Enter an empty expression to stop.
          Enter expression: a=10
          Result: 10.0


          Enter expression: b=5
          Result: 5.0


          Enter expression: a+(b-2)/3-5
          Result: 6.0


          Enter expression: 

          posted on 2012-10-11 09:13 飛豬一號 閱讀(715) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           

          導航

          <2012年10月>
          30123456
          78910111213
          14151617181920
          21222324252627
          28293031123
          45678910

          統計

          常用鏈接

          留言簿

          隨筆檔案

          友情鏈接

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 宜宾市| 五寨县| 白玉县| 开远市| 甘孜县| 色达县| 丰顺县| 乐亭县| 五峰| 诸城市| 安化县| 沙雅县| 霍州市| 登封市| 宣汉县| 西安市| 阿尔山市| 峡江县| 焦作市| 西华县| 潜江市| 醴陵市| 兴山县| 平江县| 武冈市| 武川县| 阿瓦提县| 通榆县| 兴隆县| 正镶白旗| 循化| 湖南省| 敦化市| 洛扎县| 吉水县| 丘北县| 台中县| 乐陵市| 桃园县| 买车| 浦江县|