KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > teamkonzept > lib > math > Eval


1 package com.teamkonzept.lib.math;
2
3 import java.util.*;
4 import java.io.StringReader JavaDoc;
5 import java.io.IOException JavaDoc;
6
7 public class Eval{
8     
9     public Eval(){}
10
11     public double eval(String JavaDoc expr)
12     throws MalformedExpressionException,
13            IOException JavaDoc, BadOperandTypeException,
14            UnsupportedOperatorException{
15     /* build token list from input */
16     Vector list = parseExpression(removeWhiteSpaces(expr.toLowerCase()));
17     /* extract operator tokens */
18     Vector operators = extractOperators(list);
19     /* sort tokens in order of their priority
20      * ( higher priorities first )
21      */

22     sortOperators(operators);
23     /* apply operators */
24     return evalTokenList(list, operators);
25     }
26
27     Vector parseExpression(String JavaDoc expr)
28     throws MalformedExpressionException, UnsupportedOperatorException,
29            IOException JavaDoc{
30     Vector res = new Vector();
31     Object JavaDoc o = null;
32     StringReader JavaDoc in = new StringReader JavaDoc(expr);
33     res = parseExpression(in, res, -1,
34                   0, true,
35                   true, 0);
36     return res;
37     }
38
39     Vector parseExpression(StringReader JavaDoc in, Vector tokens,
40                int lookAhead,
41                int level, boolean newLevel,
42                boolean lastWasBinaryOpOrOpenParen, int position)
43     throws MalformedExpressionException, UnsupportedOperatorException,
44            IOException JavaDoc{
45     boolean lookedAhead = false;
46     int lookedAheadChar = -1;
47     boolean functionFound = false;
48     // read next char if none given
49
int c = lookAhead;
50     if ( c < 0 ){
51         c = in.read();
52         position++;
53     }
54     // a new Level is started with "("
55
// and might start with "+" or "-"
56
if ( newLevel ){
57         if ( c == '+' ){
58         // ignore it and read next token
59
return parseExpression(in, tokens, -1,
60                        level, false, true, position);
61         }
62         else if ( c == '-' ){
63         // add "0 + "
64
tokens.add(new Double JavaDoc(0.0));
65         tokens.add(new MathBinaryOperator(MathBinaryOperator.MINUS,
66                           level, position));
67         // read next token
68
return parseExpression(in, tokens, -1,
69                        level, false, true, position);
70         }
71     }
72     // if last token was nota a binary op,
73
// the expression can be so
74
// or now can come any binary operator
75
// or a closing paren ( if there was a matching opening paren)
76
if ( !lastWasBinaryOpOrOpenParen ){
77         // end of expression
78
if ( c < 0 ){
79         // all parens closed?
80
if ( level == 0 )
81             return tokens;
82         // else
83
throw new MalformedExpressionException
84             (MalformedExpressionException.MISSING_CLOSING_PAREN, position);
85         }
86         // closing paren
87
else if ( c == ')' ){
88         if ( level-- > 0 )
89             return parseExpression(in, tokens, -1,
90                        level, false, false, position);
91         // else
92
throw new MalformedExpressionException
93             (MalformedExpressionException.MISSING_OPENING_PAREN,
94              position);
95         }
96         // mathematical binary operators
97
else if ( c == '+' ){
98         tokens.add(new MathBinaryOperator(MathBinaryOperator.PLUS,
99                           level, position));
100         return parseExpression(in, tokens, -1,
101                        level, false, true, position);
102         }
103         else if ( c == '-' ){
104         tokens.add(new MathBinaryOperator(MathBinaryOperator.MINUS,
105                           level, position));
106         return parseExpression(in, tokens, -1,
107                        level, false, true, position);
108         }
109         else if ( c == '*' ){
110         tokens.add(new MathBinaryOperator(MathBinaryOperator.MULT,
111                           level, position));
112         return parseExpression(in, tokens, -1,
113                        level, false, true, position);
114         }
115         else if ( c == '/' ){
116         tokens.add(new MathBinaryOperator(MathBinaryOperator.DIV,
117                           level, position));
118         return parseExpression(in, tokens, -1,
119                        level, false, true, position);
120         }
121         else if ( c == '\\' ){
122         tokens.add(new MathBinaryOperator(MathBinaryOperator.INT_DIV,
123                           level, position));
124         return parseExpression(in, tokens, -1,
125                        level, false, true, position);
126         }
127         else if ( c == '%' ){
128         tokens.add(new MathBinaryOperator(MathBinaryOperator.MODULO,
129                           level, position));
130         return parseExpression(in, tokens, -1,
131                        level, false, true, position);
132         }
133         else if ( c == '^' ){
134         tokens.add(new MathBinaryOperator(MathBinaryOperator.POW,
135                           level, position));
136         return parseExpression(in, tokens, -1,
137                        level, false, true, position);
138         }
139         // compare operators
140
// "==" and "!="
141
else if ( c == '=' ){
142         // now must come a "="
143
checkNextChar('=', in, ++position);
144         tokens.add(new CompareOperator(CompareOperator.EQUAL,
145                            level, position));
146         }
147         else if ( c == '!' ){
148         // now must come a "="
149
checkNextChar('=', in, ++position);
150         tokens.add(new CompareOperator(CompareOperator.NOT_EQUAL,
151                            level, position));
152         }
153         // "<", "<=", ">" and ">="
154
else if ( c == '<' ){
155         // now can come a "="
156
lookedAheadChar = in.read();
157         position++;
158         if ( lookedAheadChar == '=' )
159             tokens.add(new CompareOperator(CompareOperator.LESS_OR_EQUAL,
160                            level, position));
161         else{
162             tokens.add(new CompareOperator(CompareOperator.LESS,
163                            level, position));
164             lookedAhead = true;
165         }
166         }
167         else if ( c == '>' ){
168         // now can come a "="
169
lookedAheadChar = in.read();
170         position++;
171         if ( lookedAheadChar == '=' )
172             tokens.add(new CompareOperator(CompareOperator.GREATER_OR_EQUAL,
173                            level, position));
174         else{
175             tokens.add(new CompareOperator(CompareOperator.GREATER,
176                            level, position));
177             lookedAhead = true;
178         }
179         }
180         // binary logical operators
181
// "||" and "&&"
182
else if ( c == '|' ){
183         // now must come the same
184
checkNextChar((char)c, in, ++position);
185         tokens.add(new BinaryLogicalOperator(BinaryLogicalOperator.OR,
186                              level, position));
187         }
188         else if ( c == '&'){
189         // now must come the same
190
checkNextChar((char)c, in, ++position);
191         tokens.add(new BinaryLogicalOperator(BinaryLogicalOperator.AND,
192                              level, position));
193         }
194         // everything else is wrong
195
else
196         throw new MalformedExpressionException
197             (MalformedExpressionException.SYNTAX_ERROR, position);
198         // get next token, can start with - or +
199
if ( lookedAhead )
200         return parseExpression(in, tokens, lookedAheadChar,
201                        level, true, true, position);
202         else
203         return parseExpression(in, tokens, -1,
204                        level, true, true, position);
205     }
206     else{ // !lastWasBinaryOpOrOpenParen
207
// if last operator was a binary one
208
// or now can come any unary operator (except -)
209
// a number, a function or a opening paren
210
// parse number
211
StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
212         if ( Character.isDigit((char)c) || c == '.' ){
213         sb.append((char)c);
214         c = in.read(); position++;
215         while ( Character.isDigit((char)c) || c == '.' ){
216             sb.append((char)c);
217             c = in.read(); position++;
218         }
219         Double JavaDoc d = new Double JavaDoc(sb.toString());
220         // test for 2log 3log ..
221
if ( c == 'l' ){
222             c = in.read(); position++;
223             if ( c == 'o' ){
224             c = in.read(); position++;
225             if ( c == 'g' ){
226                 c = in.read(); position++;
227                 if ( c != '(' )
228                 throw new MalformedExpressionException
229                     (MalformedExpressionException.MISSING_OPENING_PAREN,
230                      position);
231                 else{
232                 tokens.add(new MathFunction(MathFunction.LOG,
233                                 level, position, d));
234                 return parseExpression(in, tokens, -1,
235                                ++level, true, true, position);
236                 }
237             }
238             }
239             // something else than log
240
throw new MalformedExpressionException
241             (MalformedExpressionException.SYNTAX_ERROR, position);
242         }
243         // only a number
244
tokens.add(d);
245         // looked ahead
246
return parseExpression(in, tokens, c,
247                        level, false, false, position);
248         }
249         // test for (
250
else if ( c == '(' ){
251         return parseExpression(in, tokens, -1,
252                        ++level, true, true, position);
253         }
254         // !
255
else if ( c == '!' ){
256         tokens.add(new UnaryLogicalOperator(UnaryLogicalOperator.NOT,
257                             level, position));
258         return parseExpression(in, tokens, -1,
259                        level, true, true, position);
260         }
261         else{ // must be a function
262
functionFound = false;
263         lookedAhead = false;
264         // abs acos asin atan
265
if ( c == 'a' ){
266             c = in.read(); position++;
267             // abs
268
if ( c == 'b' ){
269             c = in.read(); position++;
270             if ( c == 's' ){
271                 tokens.add(new MathFunction(MathFunction.ABS,
272                             level, position));
273                 functionFound = true;
274             }
275             }
276             // acos
277
else if ( c == 'c' ){
278             c = in.read(); position++;
279             if ( c == 'o' ){
280                 c = in.read(); position++;
281                 if ( c == 's' ){
282                 tokens.add(new MathFunction(MathFunction.ACOS,
283                                 level, position));
284                 functionFound = true;
285                 }
286             }
287             }
288             // asin
289
else if ( c == 's' ){
290             c = in.read(); position++;
291             if ( c == 'i' ){
292                 c = in.read(); position++;
293                 if ( c == 'n' ){
294                 tokens.add(new MathFunction(MathFunction.ASIN,
295                                 level, position));
296                 functionFound = true;
297                 }
298             }
299             }
300             // atan
301
else if ( c == 't' ){
302             c = in.read(); position++;
303             if ( c == 'a' ){
304                 c = in.read(); position++;
305                 if ( c == 'n' ){
306                 tokens.add(new MathFunction(MathFunction.ATAN,
307                                 level, position));
308                 functionFound = true;
309                 }
310             }
311             }
312         }
313         // ceil cos cosh cotan
314
else if ( c == 'c' ){
315             c = in.read(); position++;
316             // ceil
317
if ( c == 'e' ){
318             c = in.read(); position++;
319             if ( c == 'i' ){
320                 c = in.read(); position++;
321                 if ( c == 'l' ){
322                 tokens.add(new MathFunction(MathFunction.CEIL,
323                                 level, position));
324                 functionFound = true;
325                 }
326             }
327             }
328             // cos cosh
329
else if ( c == 'o' ){
330             c = in.read(); position++;
331             // cos cosh
332
if ( c == 's' ){
333                 c = in.read(); position++;
334                 // cosh
335
if ( c == 'h' ){
336                 tokens.add(new MathFunction(MathFunction.COSH,
337                                 level, position));
338                 functionFound = true;
339                 }
340                 // cos
341
else {
342                 tokens.add(new MathFunction(MathFunction.COS,
343                                 level, position));
344                 functionFound = true;
345                 lookedAhead = true;
346                 }
347             }
348             // cotan
349
else if ( c == 't' ){
350                 c = in.read(); position++;
351                 if ( c == 'a' ){
352                 c = in.read(); position++;
353                 if ( c == 'n' ){
354                     tokens.add(new MathFunction(MathFunction.COTAN,
355                                 level, position));
356                     functionFound = true;
357                 }
358                 }
359             }
360             }
361         }
362         // exp
363
else if ( c == 'e' ){
364             c = in.read(); position++;
365             if ( c == 'x' ){
366             c = in.read(); position++;
367             if ( c == 'p' ){
368                 tokens.add(new MathFunction(MathFunction.EXP,
369                             level, position));
370                 functionFound = true;
371             }
372             }
373         }
374         // fac floor fpart
375
else if ( c == 'f' ){
376             c = in.read(); position++;
377             // fac
378
if ( c == 'a' ){
379             c = in.read(); position++;
380             if ( c == 'c' ){
381                 tokens.add(new MathFunction(MathFunction.FAC,
382                             level, position));
383                 functionFound = true;
384             }
385             }
386             // floor
387
else if ( c == 'l' ){
388             c = in.read(); position++;
389             if ( c == 'o' ){
390                 c = in.read(); position++;
391                 if ( c == 'o' ){
392                 c = in.read(); position++;
393                 if ( c == 'r' ){
394                     tokens.add(new MathFunction(MathFunction.FLOOR,
395                                 level, position));
396                     functionFound = true;
397                 }
398                 }
399             }
400             }
401             // fpart
402
else if ( c == 'p' ){
403             c = in.read(); position++;
404             if ( c == 'a' ){
405                 c = in.read(); position++;
406                 if ( c == 'r' ){
407                 c = in.read(); position++;
408                 if ( c == 't' ){
409                     tokens.add(new MathFunction(MathFunction.FPART,
410                                 level, position));
411                     functionFound = true;
412                 }
413                 }
414             }
415             }
416         }
417         // ln
418
else if ( c == 'l' ){
419             c = in.read(); position++;
420             if ( c == 'n' ){
421             tokens.add(new MathFunction(MathFunction.LN, level, position));
422             functionFound = true;
423             }
424         }
425         // round
426
else if ( c == 'r' ){
427             c = in.read(); position++;
428             if ( c == 'o' ){
429             c = in.read(); position++;
430             if ( c == 'u' ){
431                 c = in.read(); position++;
432                 if ( c == 'n' ){
433                 c = in.read(); position++;
434                 if ( c == 'd' ){
435                     tokens.add(new MathFunction(MathFunction.ROUND,
436                                 level, position));
437                     functionFound = true;
438                 }
439                 }
440             }
441             }
442         }
443         // sfac sin sinh sqrt
444
else if ( c == 's' ){
445             c = in.read(); position++;
446             // sfac
447
if ( c == 'f' ){
448             c = in.read(); position++;
449             if ( c == 'a' ){
450                 c = in.read(); position++;
451                 if ( c == 'c' ){
452                 tokens.add(new MathFunction(MathFunction.SFAC,
453                                 level, position));
454                 functionFound = true;
455                 }
456             }
457             }
458             // sin sinh
459
else if ( c == 'i' ){
460             c = in.read(); position++;
461             if ( c == 'n' ){
462                 c = in.read(); position++;
463                 // sinh
464
if ( c == 'h' ){
465                 tokens.add(new MathFunction(MathFunction.SINH,
466                                 level, position));
467                 functionFound = true;
468                 }
469                 // sin
470
else {
471                 tokens.add(new MathFunction(MathFunction.SIN,
472                                 level, position));
473                 functionFound = true;
474                 lookedAhead = true;
475                 }
476             }
477             }
478             // sqrt
479
else if ( c == 'q' ){
480             c = in.read(); position++;
481             if ( c == 'r' ){
482                 c = in.read(); position++;
483                 if ( c == 't' ){
484                 tokens.add(new MathFunction(MathFunction.SQRT,
485                                 level, position));
486                 functionFound = true;
487                 }
488             }
489             }
490         }
491         // tan tanh
492
else if ( c == 't' ){
493             c = in.read(); position++;
494             if ( c == 'a' ){
495             c = in.read(); position++;
496             if ( c == 'n' ){
497                 c = in.read(); position++;
498                 // tanh
499
if ( c == 'h' ){
500                 tokens.add(new MathFunction(MathFunction.TANH,
501                                 level, position));
502                 functionFound = true;
503                 }
504                 // tan
505
else {
506                 tokens.add(new MathFunction(MathFunction.TAN,
507                                 level, position));
508                 functionFound = true;
509                 lookedAhead = true;
510                 }
511             }
512             }
513         }
514         }
515         // test if function was found
516
if ( functionFound ){
517         // next must be an open paren
518
if ( !lookedAhead )
519             c = in.read(); position++;
520         if ( c != '(' )
521             throw new MalformedExpressionException
522             (MalformedExpressionException.MISSING_OPENING_PAREN,
523              position);
524         // recursive call
525
return parseExpression(in, tokens, -1,
526                        ++level, true, true, position);
527         }
528         else{ // everything else is an syntax error
529
throw new MalformedExpressionException
530             (MalformedExpressionException.SYNTAX_ERROR,
531              position);
532         }
533     }
534     }
535
536     /**
537      * extract operators form vector
538      */

539     Vector extractOperators(Vector list){
540     Vector result = new Vector();
541     int size = list.size();
542     for ( int i = 0; i < size; i++ ){
543         Object JavaDoc o = list.get(i);
544         if ( o instanceof OperatorPriority )
545         result.add(o);
546     }
547     return result;
548     }
549
550     /* sort tokens in order of their priority
551      * ( higher priorities first )
552      */

553     void sortOperators(Vector list){
554     Collections.sort(list, new Comparator(){
555         public int compare(Object JavaDoc o1, Object JavaDoc o2){
556             return -1 * ((OperatorPriority)o1).compareTo(o2);
557         }
558         public boolean equals(Object JavaDoc obj){
559             return false;
560         }
561         });
562     }
563
564     /**
565      * evaluate the operators in sorted
566      */

567     double evalTokenList(Vector list, Vector sorted)
568     throws BadOperandTypeException, MalformedExpressionException{
569     int size = sorted.size();
570     for ( int i = 0; i < size; i++ ){
571         Object JavaDoc o = sorted.get(i);
572         int listpos = list.indexOf(o);
573         int rightpos = listpos + 1;
574         if ( o instanceof BinaryOperator ){
575         int leftpos = listpos - 1;
576         BinaryOperator op = (BinaryOperator)o;
577         // get operands
578
Object JavaDoc left = list.get(leftpos);
579         Object JavaDoc right = list.get(rightpos);
580         // evaluate
581
Object JavaDoc res = op.evaluate(left, right);
582         // remove operands and operator, insert result
583
list.setElementAt(res, leftpos);
584         list.removeElementAt(listpos);
585         list.removeElementAt(listpos);
586         }
587         else{
588         UnaryOperator op = (UnaryOperator)o;
589         // get operand
590
Object JavaDoc operand = list.get(rightpos);
591         // evaluate
592
Object JavaDoc res = op.evaluate(operand);
593         // remove operand and operator, insert result
594
list.setElementAt(res, listpos);
595         list.removeElementAt(rightpos);
596         }
597     }
598     // now there is only one element left in list
599
if ( list.size() != 1 )
600         throw new MalformedExpressionException
601         (MalformedExpressionException.UNKNOWN_RESULT, -1);
602     Object JavaDoc o = list.get(0);
603     if ( o instanceof Double JavaDoc )
604         return ((Double JavaDoc)o).doubleValue();
605     else if ( o instanceof Boolean JavaDoc ){
606         if ( ((Boolean JavaDoc)o).booleanValue() )
607         return 1.0;
608         else
609         return 0.0;
610     }
611     else
612         throw new MalformedExpressionException
613         (MalformedExpressionException.UNKNOWN_RESULT, -1);
614     }
615
616
617
618
619     public String JavaDoc removeWhiteSpaces(String JavaDoc s){
620     StringBuffer JavaDoc sb = new StringBuffer JavaDoc(s);
621     int l = sb.length();
622     for ( int i = 0; i < l; i++ )
623         if ( sb.charAt(i) == ' ' ){
624         sb.deleteCharAt(i--);
625         l--;
626         }
627     return sb.toString();
628     }
629
630     void checkNextChar(char toRead, StringReader JavaDoc in, int position)
631     throws MalformedExpressionException, IOException JavaDoc{
632     int c = in.read();
633     if ( c != toRead )
634         throw new MalformedExpressionException
635         (MalformedExpressionException.SYNTAX_ERROR, position);
636     }
637 }
638
639
Popular Tags