KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > util > ExprCalc


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10 package org.mmbase.util;
11
12 import java.util.*;
13 import org.mmbase.util.logging.*;
14
15
16 /**
17  * Class to calculate expressions. It implements a simple LL(1)
18  * grammar to calculate simple expressions with the basic
19  * operators +,-,*,/ and brackets.
20  * <br />
21  * The grammar in EBNF notation:
22  * <br />
23  * &lt;expr&gt; -&gt; &lt;term&gt; { '+' &lt;term&gt; } | &lt;term&gt; { '-' &lt;term&gt; } <br />
24  * &lt;term&gt; -&gt; &lt;fact&gt; { '*' &lt;fact&gt; } | &lt;fact&gt; { '/' &lt;fact&gt; } <br />
25  * &lt;fact&gt; -&gt; &lt;nmeral&gt; | '(' &lt;expr&gt; ')' <br />
26  *
27  * @author Arnold Beck
28  * @version $Id: ExprCalc.java,v 1.12 2004/09/29 14:29:24 pierre Exp $
29  */

30 public class ExprCalc {
31     private static final int MC_SYMB=1;
32     private static final int MC_NUM =2;
33     private static final int MC_NONE=0;
34     private static final int MC_EOT =-1;
35
36     private static final Logger log = Logging.getLoggerInstance(ExprCalc.class);
37
38     // a token is represented by an tokencode (MCode)
39
// and a tokenvalue (MSym or MNum) depending on
40
// the tokencode
41

42     private StringTokenizer tokenizer;
43     private String JavaDoc input;
44
45     private int mCode;
46     private char mSymb;
47     private double mNum;
48
49     private double result;
50
51     /**
52      * Constructor of ExrpCalc
53      * @param input a <code>String</code> representing the expression
54      */

55     public ExprCalc(String JavaDoc input) {
56         this.input = input;
57         tokenizer = new StringTokenizer(input, "+-*/()% \t", true);
58         mCode = MC_NONE;
59         result = expr();
60         if (mCode != MC_EOT) {
61             log.error("Could not evaluate expression: '" + input + "'");
62         }
63     }
64
65     /**
66      * Returns the calculated value of the expression
67      */

68     public double getResult() {
69         return result;
70     }
71
72     /**
73      * The lexer to produce a token when mCode is MC_NONE
74      */

75     private boolean lex() {
76         String JavaDoc token;
77         if (mCode==MC_NONE) {
78             mCode=MC_EOT;mSymb='\0';mNum=0.0;
79             try {
80                 do {
81                   token = tokenizer.nextToken();
82                 } while (token.equals(" ")||token.equals("\t"));
83             } catch(NoSuchElementException e) {
84                 return false;
85             }
86             // numeral
87
if (Character.isDigit(token.charAt(0))) {
88                 int i;
89                 for(i=0;i<token.length() &&
90                     (Character.isDigit(token.charAt(i)) ||
91                      token.charAt(i)=='.');i++) { };
92                 if (i!=token.length()) {
93                     log.error("Could not evaluate expression '" + token + "' of '" + input + "'");
94                 }
95                 try {
96                     mNum=(Double.valueOf(token)).doubleValue();
97                 } catch (NumberFormatException JavaDoc e) {
98                     log.error("Could not evaluate expression ('" + token + "' not a number) of '" + input + "'");
99                 }
100                 mCode=MC_NUM;
101             } else { // symbol
102
mSymb=token.charAt(0);
103                 mCode=MC_SYMB;
104             }
105         }
106         return true;
107     }
108
109     /**
110      * expr implements the rule: <br />
111      * &lt;expr&gt; -&lt; &lt;term&gt; { '+' &lt;term&gt; } | &lt;term&gt; { '-' &lt;term&gt; } .
112      */

113     private double expr() {
114         double tmp = term();
115         while (lex() && mCode == MC_SYMB && (mSymb == '+' || mSymb == '-')) {
116             mCode=MC_NONE;
117             if (mSymb=='+') {
118                 tmp += term();
119             } else {
120                 tmp -= term();
121             }
122         }
123         if (mCode==MC_SYMB && mSymb=='('
124             || mCode==MC_SYMB && mSymb==')'
125             || mCode==MC_EOT) {
126
127         } else {
128             log.error("expr: Could not evaluate expression '" + input + "'");
129         }
130         return tmp;
131     }
132
133     /**
134      * term implements the rule: <br />
135      * &lt;term&gt; -&lt; &lt;fact&gt; { '*' &lt;fact&gt; } | &lt;fact&gt; { '/' &lt;fact&gt; } .
136      */

137     private double term() {
138         double tmp=fac();
139         while (lex() && mCode==MC_SYMB && (mSymb=='*' || mSymb=='/' || mSymb=='%')) {
140           mCode=MC_NONE;
141           if (mSymb=='*') {
142             tmp *= fac();
143           } else if (mSymb=='/') {
144             tmp /= fac();
145           } else {
146             tmp %= fac();
147           }
148         }
149         return tmp;
150     }
151
152     /**
153      * fac implements the rule <br />
154      * &lt;fact&gt; -&lt; &lt;nmeral&gt; | '(' &lt;expr&gt; ')' .
155      */

156     private double fac() {
157         double tmp =- 1;
158         boolean minus=false;
159
160         if(lex()&& mCode==MC_SYMB && mSymb=='-') {
161             mCode = MC_NONE;
162             minus = true;
163         }
164         if(lex() && mCode==MC_SYMB && mSymb=='(') {
165             mCode = MC_NONE;
166             tmp = expr();
167             if(lex() && mCode!=MC_SYMB || mSymb!=')') {
168                 log.error("fac1: Could not evaluate expression '" + input + "'");
169             }
170             mCode=MC_NONE;
171         } else if (mCode==MC_NUM) {
172             mCode=MC_NONE;
173             tmp=mNum;
174         } else {
175             log.error("fac2: Could not evaluate expression '" + input + "'");
176         }
177         if (minus) tmp = -tmp;
178         return tmp;
179     }
180 }
181
Popular Tags