A simple java expression evaluator


Introduction


In this article, I describe a simple Java expression evaluator thaty evaluates algebraic expressions including a limited number of trigonometric, logarithmic, transcendental and exponential functions. The expression evaluator described here functions by generating and caching custom Java expression evaluation classes per expression. The custom classes implement the following interface:



Expression evaluation classes are generated by a generator class (MathEvalGenerator). The "generate" method of this class accepts a String expression representing the expression to be evaluated, and returns an IMathEval object that evaluates the expression:


The "generate" method has to perform several steps in order to create an IMathEval object for the expression.


Generating evaluators for expressions


The "generate" method of MathEvalGenerator seeks to generate the source code of a class that implements IMathEval, compiling the generated source code, loading the bytes of the resulting CLASS file into an anonymous class loader, and, finally, returning an instance of this class. Let us walk through these steps using an example expression: "sin(x)+cos(x)".


The generator class caches the names of all public methods of the "java.lang.Math" class during (static) initialization. Given an expression (sin(x)+cos(x) in our example), the generater class first replaces all occurences of method names in its cache of appearing in the expression, with the expression "Math."+methodname. For our sample expression (six(x)+cos(x)), the resulting expression becomes "Math.sin(x)+Math.cos(x)".


Next, for performance reasons, the generater class checks an internal cache of classes it has already generated to check if the class for this expression is present. If so, meaning that the generater class has already generated the class for this expression before, it directly instantiates the cached class and returns the evaluation object without further ado.


If the generater class does not find a cahced evaluation class for this expression, it proceeds to generating the source code of the evaluation class. For our example, the source code of the evaluation class looks like this:




Here, note that the class name "Eval0" is automatically generated to ensure uniqueness. Also, note that invoking "new Eval0().eval(0.25,0.5)" returns the value of the expression sin(0.25) + cos(0.5).


Having generated the source code, the generater class compiles it using the new compiler API provided by Java 1.6. The following steps are used to accomplish this:



  1. Create a temporary directory under the directory returned by "System.getProperty("java.io.tmpdir")".

  2. Save the generated source code to this directory.

  3. Export the source code of the IMathEval interface to this directory.

  4. Invoke the compiler on these two source files.

  5. Read the contents of the generated CLASS file (for the implementation class).

  6. Load these into an anonymous class loader.

  7. Instantiate the class and return the instance.


Critique


While the technique shown here to evaluate expressions is simple, it is probably "too simple". For example, it sometimes requires an "ugly" expression syntax: (pow(sin(x),2)+pow(cos(x),2)) to evaluate "sin^2(x) + cos^2(x)". For another, it is limited to supporting only those expressions that the java.lang.Math  class supports out of the box.


It is possible to improve the generator class by allowing it to save (and reload) generated classes between process lifetimes. Thus, the generater class could be extended so that it stored all generated class bytes in a repository (such as a ZIP file), and reloaded these during initialization.


Complete source code for this project is available here.


 

What did you think of this article?




Trackbacks
  • No trackbacks exist for this post.
Comments
  • No comments exist for this post.
Leave a comment

Submitted comments are subject to moderation before being displayed.

 Enter the above security code (required)

 Name

 Email (will not be published)

 Website

Your comment is 0 characters limited to 3000 characters.