KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > nfunk > jep > JEP


1 /*****************************************************************************
2
3 JEP - Java Math Expression Parser 2.3.0
4       October 3 2004
5       (c) Copyright 2004, Nathan Funk and Richard Morris
6       See LICENSE.txt for license information.
7
8 *****************************************************************************/

9
10 package org.nfunk.jep;
11
12 import java.io.*;
13 import java.util.*;
14 import org.nfunk.jep.function.*;
15 import org.nfunk.jep.type.*;
16
17 /**
18  * The JEP class is the main interface with which the user should
19  * interact. It contains all neccessary methods to parse and evaluate
20  * expressions.
21  * <p>
22  * The most important methods are parseExpression(String), for parsing the
23  * mathematical expression, and getValue() for obtaining the value of the
24  * expression.
25  * <p>
26  * Visit <a HREF="http://www.singularsys.com/jep">http://www.singularsys.com/jep</a>
27  * for the newest version of JEP, and complete documentation.
28  *
29  * @author Nathan Funk
30  */

31 public class JEP {
32
33     /** Debug flag for extra command line output */
34     private static final boolean debug = false;
35     
36     /** Traverse option */
37     private boolean traverse;
38     
39     /** Allow undeclared variables option */
40     protected boolean allowUndeclared;
41     
42     /** Allow undeclared variables option */
43     protected boolean allowAssignment;
44     
45     /** Implicit multiplication option */
46     protected boolean implicitMul;
47     
48     /** Symbol Table */
49     protected SymbolTable symTab;
50
51     /** Function Table */
52     protected FunctionTable funTab;
53     
54     /** Error List */
55     protected Vector errorList;
56     
57     /** The parser object */
58     protected Parser parser;
59     
60     /** Node at the top of the parse tree */
61     private Node topNode;
62
63     /** Evaluator */
64     protected EvaluatorVisitor ev;
65     
66     /** Number factory */
67     protected NumberFactory numberFactory;
68
69     /** OperatorSet */
70     protected OperatorSet opSet;
71     
72     /**
73      * Creates a new JEP instance with the default settings.
74      * <p>
75      * Traverse = false<br>
76      * Allow undeclared variables = false<br>
77      * Implicit multiplication = false<br>
78      * Number Factory = DoubleNumberFactory
79      */

80     public JEP() {
81         topNode = null;
82         traverse = false;
83         allowUndeclared = false;
84         allowAssignment = false;
85         implicitMul = false;
86         numberFactory = new DoubleNumberFactory();
87         opSet = new OperatorSet();
88         initSymTab();
89         initFunTab();
90         errorList = new Vector();
91         ev = new EvaluatorVisitor();
92         parser = new Parser(new StringReader(""));
93
94         //Ensure errors are reported for the initial expression
95
//e.g. No expression entered
96
//parseExpression("");
97
}
98
99     /**
100      * Creates a new JEP instance with custom settings. If the
101      * numberFactory_in is null, the default number factory is used.
102      * @param traverse_in The traverse option.
103      * @param allowUndeclared_in The "allow undeclared variables" option.
104      * @param implicitMul_in The implicit multiplication option.
105      * @param numberFactory_in The number factory to be used.
106      */

107     public JEP(boolean traverse_in,
108                boolean allowUndeclared_in,
109                boolean implicitMul_in,
110                NumberFactory numberFactory_in) {
111         topNode = null;
112         traverse = traverse_in;
113         allowUndeclared = allowUndeclared_in;
114         implicitMul = implicitMul_in;
115         if (numberFactory_in == null) {
116             numberFactory = new DoubleNumberFactory();
117         } else {
118             numberFactory = numberFactory_in;
119         }
120         initSymTab();
121         initFunTab();
122         errorList = new Vector();
123         ev = new EvaluatorVisitor();
124         parser = new Parser(new StringReader(""));
125
126         //Ensure errors are reported for the initial expression
127
//e.g. No expression entered
128
parseExpression("");
129     }
130
131     /** This constructor copies the SymbolTable and other components
132      * of the arguments to the new instance. Subclasses can call this
133      * protected constructor and set the individual components
134      * themselves.
135      * @since 2.3.0 alpha
136      */

137     protected JEP(JEP j)
138     {
139         this.topNode = null;
140         this.traverse = j.traverse;
141         this.allowUndeclared = j.allowUndeclared;
142         this.allowAssignment = j.allowAssignment;
143         this.implicitMul = j.implicitMul;
144         this.ev = j.ev;
145         this.funTab = j.funTab;
146         this.numberFactory = j.numberFactory;
147         this.parser = j.parser;
148         this.symTab = j.symTab;
149         this.errorList = j.errorList;
150     }
151
152     /**
153      * Creates a new SymbolTable object as symTab.
154      */

155     public void initSymTab() {
156         //Init SymbolTable
157
symTab = new SymbolTable(new VariableFactory());
158     }
159
160     /**
161      * Creates a new FunctionTable object as funTab.
162      */

163     public void initFunTab() {
164         //Init FunctionTable
165
funTab = new FunctionTable();
166     }
167
168     /**
169      * Adds the standard functions to the parser. If this function is not called
170      * before parsing an expression, functions such as sin() or cos() would
171      * produce an "Unrecognized function..." error.
172      * In most cases, this method should be called immediately after the JEP
173      * object is created.
174      * @since 2.3.0 alpha added if and exp functions
175      * @since 2.3.0 beta 1 added str function
176      */

177     public void addStandardFunctions() {
178         //add functions to Function Table
179
funTab.put("sin", new Sine());
180         funTab.put("cos", new Cosine());
181         funTab.put("tan", new Tangent());
182         funTab.put("asin", new ArcSine());
183         funTab.put("acos", new ArcCosine());
184         funTab.put("atan", new ArcTangent());
185         funTab.put("atan2", new ArcTangent2());
186
187         funTab.put("sinh", new SineH());
188         funTab.put("cosh", new CosineH());
189         funTab.put("tanh", new TanH());
190         funTab.put("asinh", new ArcSineH());
191         funTab.put("acosh", new ArcCosineH());
192         funTab.put("atanh", new ArcTanH());
193
194         funTab.put("log", new Logarithm());
195         funTab.put("ln", new NaturalLogarithm());
196         funTab.put("exp", new Exp());
197
198         funTab.put("sqrt",new SquareRoot());
199         funTab.put("abs", new Abs());
200         funTab.put("mod", new Modulus());
201         funTab.put("sum", new Sum());
202
203         funTab.put("rand", new org.nfunk.jep.function.Random());
204         
205         // rjm additions
206
funTab.put("if", new If());
207         funTab.put("str", new Str());
208     }
209
210     /**
211      * Adds the constants pi and e to the parser. As addStandardFunctions(),
212      * this method should be called immediatly after the JEP object is
213      * created.
214      */

215     public void addStandardConstants() {
216         //add constants to Symbol Table
217
symTab.addConstant("pi", new Double JavaDoc(Math.PI));
218         symTab.addConstant("e", new Double JavaDoc(Math.E));
219     }
220     
221     /**
222      * Call this function if you want to parse expressions which involve
223      * complex numbers. This method specifies "i" as the imaginary unit
224      * (0,1). Two functions re() and im() are also added for extracting the
225      * real or imaginary components of a complex number respectively.
226      *<p>
227      * @since 2.3.0 alpha The functions cmod and arg are added to get the modulus and argument.
228      * @since 2.3.0 beta 1 The functions complex and polar to convert x,y and r,theta to Complex.
229      */

230     public void addComplex() {
231         //add constants to Symbol Table
232
symTab.addConstant("i", new Complex(0,1));
233         funTab.put("re", new Real());
234         funTab.put("im", new Imaginary());
235         funTab.put("arg", new Arg());
236         funTab.put("cmod", new Abs());
237         funTab.put("complex", new ComplexPFMC());
238         funTab.put("polar", new Polar());
239     }
240
241     /**
242      * Adds a new function to the parser. This must be done before parsing
243      * an expression so the parser is aware that the new function may be
244      * contained in the expression.
245      * @param functionName The name of the function
246      * @param function The function object that is used for evaluating the
247      * function
248      */

249     public void addFunction(String JavaDoc functionName,
250                             PostfixMathCommandI function) {
251         funTab.put(functionName, function);
252     }
253
254     /**
255      * Adds a new variable to the parser, or updates the value of an
256      * existing variable. This must be done before parsing
257      * an expression so the parser is aware that the new variable may be
258      * contained in the expression.
259      * @param name Name of the variable to be added
260      * @param value Initial value or new value for the variable
261      * @return Double object of the variable
262      */

263     public Double JavaDoc addVariable(String JavaDoc name, double value) {
264         Double JavaDoc object = new Double JavaDoc(value);
265         symTab.makeVarIfNeeded(name, object);
266         return object;
267     }
268
269     /** Adds a constant.
270      * This is a variable whos value cannot be changed.
271      * @since 2.3.0 beta 1
272      */

273     public void addConstant(String JavaDoc name,Object JavaDoc value) {
274         symTab.addConstant(name, value);
275     }
276     /**
277      * Adds a new complex variable to the parser, or updates the value of an
278      * existing variable. This must be done before parsing
279      * an expression so the parser is aware that the new variable may be
280      * contained in the expression.
281      * @param name Name of the variable to be added
282      * @param re Initial real value or new real value for the variable
283      * @param im Initial imaginary value or new imaginary value for the variable
284      * @return Complex object of the variable
285      */

286     public Complex addVariable(String JavaDoc name, double re, double im) {
287         Complex object = new Complex(re,im);
288         symTab.makeVarIfNeeded(name, object);
289         return object;
290     }
291         
292     /**
293      * Adds a new variable to the parser as an object, or updates the value of an
294      * existing variable. This must be done before parsing
295      * an expression so the parser is aware that the new variable may be
296      * contained in the expression.
297      * @param name Name of the variable to be added
298      * @param object Initial value or new value for the variable
299      */

300     public void addVariable(String JavaDoc name, Object JavaDoc object) {
301         symTab.makeVarIfNeeded(name, object);
302     }
303     
304     /**
305      * Removes a variable from the parser. For example after calling
306      * addStandardConstants(), removeVariable("e") might be called to remove
307      * the euler constant from the set of variables.
308      *
309      * @return The value of the variable if it was added earlier. If
310      * the variable is not in the table of variables, <code>null</code> is
311      * returned.
312      */

313     public Object JavaDoc removeVariable(String JavaDoc name) {
314         return symTab.remove(name);
315     }
316     /**
317      * Returns the value of the varible with given name.
318      * @param name name of the variable.
319      * @return the current value of the variable.
320      * @since 2.3.0 alpha
321      */

322     public Object JavaDoc getVarValue(String JavaDoc name) {
323         return symTab.getVar(name).getValue();
324     }
325     /**
326      * Sets the value of a variable.
327      * Returns false if variable does not exist or if its value cannot be changed.
328      * @param name name of the variable.
329      * @param val the initial value of the variable.
330      * @return false if variable does not exist or if its value cannot be changed.
331      * @since 2.3.0 alpha
332      */

333     public boolean setVarValue(String JavaDoc name,Object JavaDoc val) {
334         return symTab.setVarValue(name,val);
335     }
336     /**
337      * Gets the object representing the variable with a given name.
338      * @param name the name of the variable to find.
339      * @return the Variable object or null if name not found.
340      * @since 2.3.0 alpha
341      */

342     public Variable getVar(String JavaDoc name) {
343         return symTab.getVar(name);
344     }
345     
346     /**
347      * Removes a function from the parser.
348      *
349      * @return If the function was added earlier, the function class instance
350      * is returned. If the function was not present, <code>null</code>
351      * is returned.
352      */

353     public Object JavaDoc removeFunction(String JavaDoc name) {
354         return funTab.remove(name);
355     }
356
357     /**
358      * Sets the value of the traverse option. setTraverse is useful for
359      * debugging purposes. When traverse is set to true, the parse-tree
360      * will be dumped to the standard ouput device.
361      * <p>
362      * The default value is false.
363      * @param value The boolean traversal option.
364      */

365     public void setTraverse(boolean value) {
366         traverse = value;
367     }
368     
369     /**
370      * Returns the value of the traverse option.
371      * @return True if the traverse option is enabled. False otherwise.
372      */

373     public boolean getTraverse() { return traverse; }
374
375     /**
376      * Sets the value of the implicit multiplication option.
377      * If this option is set to true before parsing, implicit multiplication
378      * will be allowed. That means that an expression such as
379      * <pre>"1 2"</pre> is valid and is interpreted as <pre>"1*2"</pre>.
380      * <p>
381      * The default value is false.
382      * @param value The boolean implicit multiplication option.
383      */

384     public void setImplicitMul(boolean value) {
385         implicitMul = value;
386     }
387     
388     /**
389      * Returns the value of the implicit multiplication option.
390      * @return True if the implicit multiplication option is enabled. False otherwise.
391      */

392     public boolean getImplicitMul() { return implicitMul; }
393     
394     /**
395      * Sets the value for the undeclared variables option. If this option
396      * is set to true, expressions containing variables that were not
397      * previously added to JEP will not produce an "Unrecognized Symbol"
398      * error. The new variables will automatically be added while parsing,
399      * and initialized to 0.
400      * <p>
401      * If this option is set to false, variables that were not previously
402      * added to JEP will produce an error while parsing.
403      * <p>
404      * The default value is false.
405      * @param value The boolean option for allowing undeclared variables.
406      */

407     public void setAllowUndeclared(boolean value) {
408         allowUndeclared = value;
409     }
410
411     /**
412      * Returns the value of the allowUndeclared option.
413      * @return True if the allowUndeclared option is enabled. False otherwise.
414      */

415     public boolean getAllowUndeclared() { return allowUndeclared; }
416     
417     /** Sets wheter assignment equations like <tt>y=x+1</tt> are allowed.
418      * @since 2.3.0 alpha
419      */

420     public void setAllowAssignment(boolean value) {
421         allowAssignment = value;
422     }
423
424     /**
425      * Whether assignment equation <tt>y=x+1</tt> equations are allowed.
426      * @since 2.3.0 alpha
427      */

428     public boolean getAllowAssignment() { return allowAssignment; }
429
430
431     /**
432      * Parses the expression. If there are errors in the expression,
433      * they are added to the <code>errorList</code> member.
434      * @param expression_in The input expression string
435      */

436     public void parseExpression(String JavaDoc expression_in) {
437         Reader reader = new StringReader(expression_in);
438         
439         try {
440             // try parsing
441
errorList.removeAllElements();
442             topNode = parser.parseStream(reader, this);
443         }
444         catch (Throwable JavaDoc e)
445         {
446             // an exception was thrown, so there is no parse tree
447
topNode = null;
448             
449             // check the type of error
450
if (e instanceof ParseException) {
451                 // the ParseException object contains additional error
452
// information
453
errorList.addElement(((ParseException)e).getMessage());
454                 //getErrorInfo());
455
} else {
456                 // if the exception was not a ParseException, it was most
457
// likely a syntax error
458
if (debug) {
459                     System.out.println(e.getMessage());
460                     e.printStackTrace();
461                 }
462                 errorList.addElement("Syntax error");
463             }
464         }
465         
466                 
467         // If traversing is enabled, print a dump of the tree to
468
// standard output
469
if (traverse && !hasError()) {
470             ParserVisitor v = new ParserDumpVisitor();
471             try
472             {
473                 topNode.jjtAccept(v, null);
474             }
475             catch(ParseException e)
476             {
477                 errorList.addElement(e.getMessage());
478             }
479         }
480     }
481
482     /**
483      * Parses an expression.
484      * Returns a object of type Node, does not catch errors.
485      * Does not set the topNode variable of the JEP instance.
486      * This method should generally be used with the {@link #evaluate evaluate}
487      * method rather than getValueAsObject.
488      * @param expression represented as a string.
489      * @return The top node of an tree representing the parsed expression.
490      * @throws ParseException
491      * @since 2.3.0 alpha
492      */

493     public Node parse(String JavaDoc expression) throws ParseException
494     {
495         java.io.StringReader JavaDoc sr = new java.io.StringReader JavaDoc(expression);
496         Node node = parser.parseStream(sr, this);
497         return node;
498     }
499
500     /**
501      * Evaluate an expression. This method evaluates the argument
502      * rather than the topNode of the JEP instance.
503      * It should be used in conjunction with {@link #parse parse}
504      * rather than {@link #parseExpression parseExpression}.
505      * @param node the top node of the tree representing the expression.
506      * @return The value of the expression
507      * @throws Exception if for some reason the expression could not be evaluated
508      * @since 2.3.0 alpha
509      */

510     public Object JavaDoc evaluate(Node node) throws Exception JavaDoc
511     {
512         return ev.getValue(node, new Vector(), this.symTab);
513     }
514
515     /**
516      * Evaluates and returns the value of the expression as a double number.
517      * @return The calculated value of the expression as a double number.
518      * If the type of the value does not implement the Number interface
519      * (e.g. Complex), NaN is returned. If an error occurs during evaluation,
520      * NaN is returned and hasError() will return true.
521      *
522      * @see #getComplexValue()
523      */

524     public double getValue() {
525         Object JavaDoc value = getValueAsObject();
526         
527         if(value == null) return Double.NaN;
528         
529         if(value instanceof Complex)
530         {
531             Complex c = (Complex) value;
532             if( c.im() != 0.0) return Double.NaN;
533             return c.re();
534         }
535         if (value != null && value instanceof Number JavaDoc) {
536             return ((Number JavaDoc)value).doubleValue();
537         }
538         
539         return Double.NaN;
540     }
541
542
543     /**
544      * Evaluates and returns the value of the expression as a complex number.
545      * @return The calculated value of the expression as a complex number if
546      * no errors occur. Returns null otherwise.
547      */

548     public Complex getComplexValue() {
549         Object JavaDoc value = getValueAsObject();
550         
551         if (value == null) {
552             return null;
553         } else if (value instanceof Complex) {
554             return (Complex)value;
555         } else if (value instanceof Number JavaDoc) {
556             return new Complex(((Number JavaDoc)value).doubleValue(), 0);
557         } else {
558             return null;
559         }
560     }
561
562
563
564     /**
565      * Evaluates and returns the value of the expression as an object.
566      * The EvaluatorVisitor member ev is used to do the evaluation procedure.
567      * This method is useful when the type of the value is unknown, or
568      * not important.
569      * @return The calculated value of the expression if no errors occur.
570      * Returns null otherwise.
571      */

572     public Object JavaDoc getValueAsObject() {
573         Object JavaDoc result;
574         
575         if (topNode != null && !hasError()) {
576             // evaluate the expression
577
try {
578                 result = ev.getValue(topNode,errorList,symTab);
579             } catch (Exception JavaDoc e) {
580                 if (debug) System.out.println(e);
581                 errorList.addElement("Error during evaluation");
582                 return null;
583             }
584             
585             return result;
586         } else {
587             return null;
588         }
589     }
590
591     /**
592      * Returns true if an error occured during the most recent
593      * action (parsing or evaluation).
594      * @return Returns <code>true</code> if an error occured during the most
595      * recent action (parsing or evaluation).
596      */

597     public boolean hasError() {
598         return !errorList.isEmpty();
599     }
600
601     /**
602      * Reports information on the errors that occured during the most recent
603      * action.
604      * @return A string containing information on the errors, each separated
605      * by a newline character; null if no error has occured
606      */

607     public String JavaDoc getErrorInfo() {
608         if (hasError()) {
609             String JavaDoc str = "";
610             
611             // iterate through all errors and add them to the return string
612
for (int i=0; i<errorList.size(); i++) {
613                 str += errorList.elementAt(i) + "\n";
614             }
615             
616             return str;
617         } else {
618             return null;
619         }
620     }
621
622     /**
623      * Returns the top node of the expression tree. Because all nodes are
624      * pointed to either directly or indirectly, the entire expression tree
625      * can be accessed through this node. It may be used to manipulate the
626      * expression, and subsequently evaluate it manually.
627      * @return The top node of the expression tree
628      */

629     public Node getTopNode() {
630         return topNode;
631     }
632
633     /**
634      * Returns the symbol table (the list of all variables that the parser
635      * recognises).
636      * @return The symbol table
637      */

638     public SymbolTable getSymbolTable() {
639         return symTab;
640     }
641
642     /**
643      * Returns the function table (the list of all functions that the parser
644      * recognises).
645      * @return The function table
646      */

647     public FunctionTable getFunctionTable() {
648             return funTab;
649     }
650
651
652     /**
653      * Returns the number factory.
654      * @return the NumberFactory used by this JEP instance.
655      */

656     public NumberFactory getNumberFactory() {
657         return numberFactory;
658     }
659
660     /**
661      * Returns the operator set.
662      * @return the OperatorSet used by this JEP instance.
663      * @since 2.3.0 alpha
664      */

665     public OperatorSet getOperatorSet() {
666         return opSet;
667     }
668
669     /**
670      * Returns the parse object.
671      * @return the Parse used by this JEP.
672      * @since 2.3.0 beta 1
673      */

674     public Parser getParser() {return parser; }
675 //------------------------------------------------------------------------
676
// Old code
677

678
679 /*
680     /**
681     * Returns the position (vertical) at which the last error occured.
682     /
683     public int getErrorColumn() {
684         if (hasError && parseException != null)
685             return parseException.getColumn();
686         else
687             return 0;
688     }
689
690     /**
691     * Returns the line in which the last error occured.
692     /
693     public int getErrorLine() {
694         if (hasError && parseException != null)
695             return parseException.getLine();
696         else
697             return 0;
698     }
699 */

700 }
701
702
Popular Tags