14,662,530 members
Articles » General Programming » Algorithms & Recipes » General
Article
Posted 21 Apr 2003

205.2K views
81 bookmarked

# Evaluating Mathematical Expressions by Compiling C# Code at Runtime

Rate this:
21 Apr 2003
A completely new way of making a mathematical expression evaluator.

## Introduction

There are many articles on creating mathematical expression parsers (i.e. for displaying 3D functions where user inputs the formulas manually). Most of them are based on lexical analysis, grammar definitions etc. With C# there is a solution for making mathematical expression evaluator in a completely new way: by compiling code at runtime.

Let's assume that we want to create an application that would calculate 3D function like that:

z = f(x,y)

But we want to let the user input function formula manually (we don't know what the formula will look like).

A solution to deal with that task in 10 minutes is:

1. Let the user input the function
2. Compile that function into memory
3. Run the function with given x and y
4. Do something with result z value

To do that in a couple of minutes we would need a class with virtual method:

`namespace MathEval<BR>{<BR> public class MyClassBase<BR> {<BR>  public MyClassBase()<BR>  {<BR>  }<BR>  public virtual double eval(double x,double y)<BR>  {<BR>   return 0.0;<BR>  }<BR> }<BR>}<BR>`

all we need more is a parser/evaluator class which would compile function body into assembly (created in memory) and calculate function result:

`<BR>using System;<BR>using System.Reflection;<BR>using System.Windows.Forms;<BR>namespace MathEval<BR>{<BR> public class MathExpressionParser<BR> {<BR>  MyClassBase myobj = null;<BR>  public MathExpressionParser()<BR>  {<BR>  }<BR>  public bool init(string expr)<BR>  {<BR>   Microsoft.CSharp.CSharpCodeProvider cp<BR>                                = new Microsoft.CSharp.CSharpCodeProvider();<BR>   System.CodeDom.Compiler.ICodeCompiler ic = cp.CreateCompiler();<BR>   System.CodeDom.Compiler.CompilerParameters cpar<BR>                         = new System.CodeDom.Compiler.CompilerParameters();<BR>   cpar.GenerateInMemory = true;<BR>   cpar.GenerateExecutable = false;<BR>   cpar.ReferencedAssemblies.Add("system.dll");<BR>   cpar.ReferencedAssemblies.Add("matheval.exe"); <BR>   string src = "using System;"+<BR>    "class myclass:MathEval.MyClassBase" + <BR>    "{"+<BR>    "public myclass(){}"+<BR>    "public override double eval(double x,double y)"+<BR>    "{"+<BR>    "return "+ expr +";"+<BR>    "}"+<BR>    "}";<BR>   System.CodeDom.Compiler.CompilerResults cr<BR>                                   = ic.CompileAssemblyFromSource(cpar,src);<BR>   foreach (System.CodeDom.Compiler.CompilerError ce in cr.Errors)<BR>    MessageBox.Show(ce.ErrorText); <BR><BR>   if (cr.Errors.Count == 0 && cr.CompiledAssembly != null)<BR>   {<BR>    Type ObjType = cr.CompiledAssembly.GetType("myclass");<BR>    try<BR>    {<BR>     if (ObjType != null)<BR>     {<BR>      myobj = (MyClassBase)Activator.CreateInstance(ObjType);<BR>     }<BR>    }<BR>    catch (Exception ex)<BR>    {<BR>     MessageBox.Show(ex.Message);<BR>    }<BR>    return true;<BR>   }<BR>   else <BR>    return false;<BR>  }<BR>  public double eval(double x,double y)<BR>  {<BR>   double val = 0.0;<BR>   if (myobj != null)<BR>   {<BR>     val = myobj.eval(x,y);<BR>   }<BR>   return val;<BR>  }<BR> }<BR>}<BR>`

Take a look at the init() method. All we need it to do is to create an assembly(in memory) with a class "myclass" derived from MyBaseClass. Note that "eval" method contains the formula given by the user at runtime. Also note that cpar.ReferencedAssemblies.Add("matheval.exe"); defines a reference to the application currently being created.
Then we can call myclass.eval method as many times as we want to:

`<BR>MathExpressionParser mp = new MathExpressionParser();<BR>mp.init("Math.Sin(x)*y");<BR><BR><BR>for(int i=0;i<1000000;i++)<BR>{<BR> mp.eval((double)i,(double)i);<BR>}<BR>`

Compiled code is of course much faster than any other solution used to parse and evaluate expressions.

A few things to do:

• Let the user input formulas as "xy*sin(x+y)" or "x^2+y^2" and convert them to c# "x*y*Math.Sin(x+y)" "x*x + y*y" etc...
• Do some error checking/handling other than compiler errors.
• Freeing and recreating the in-memory-assembly with another formula.
• Enjoy the code :)

PS: special thanks to AcidRain for some ideas :)

A list of licenses authors might use can be found here

## Share

 Architect Poland
No Biography provided

 First Prev Next
 Compile function in memory in objective-c for mac wonkypuh1018-Jun-11 12:17 wonkypuh10 18-Jun-11 12:17
 Completely New? Dewey21-Jan-08 14:28 Dewey 21-Jan-08 14:28
 Re: Completely New? Marcin Cuprjak23-Jan-08 9:33 Marcin Cuprjak 23-Jan-08 9:33
 What is wrong with double FuncN (params double[] x) ? hreba22-Nov-06 3:40 hreba 22-Nov-06 3:40
 Good Work! Jacek Gajek3-Oct-06 2:17 Jacek Gajek 3-Oct-06 2:17
 Not applicable for ASP.NET2 applications ZuZuKin23-Feb-06 9:10 ZuZuKin 23-Feb-06 9:10
 Very Nice msaroka20-Apr-05 12:48 msaroka 20-Apr-05 12:48
 "matheval.exe" Noro Korny17-Apr-05 0:11 Noro Korny 17-Apr-05 0:11
 Extremely insecure! ekolis14-Jun-04 15:59 ekolis 14-Jun-04 15:59
 How to unload an assembly? Member 21683830-Jul-03 10:48 Member 216838 30-Jul-03 10:48
 It is cool to create a piece of code, compile and run it on fly. We can pass different expressions to the init method to create many instances and used in different parts of a running program. My question is how is the memory be managed. Is there a way to unload one of the assemblies that no longer needed?
 Re: How to unload an assembly? tuxic7-Mar-05 9:01 tuxic 7-Mar-05 9:01
 What about Microsoft.JScript.Eval()? onc29-Apr-03 3:59 onc 29-Apr-03 3:59
 Generate IL directly hsauro22-Apr-03 19:48 hsauro 22-Apr-03 19:48
 Re: Generate IL directly `leppie`23-Apr-03 7:02 `leppie` 23-Apr-03 7:02
 Re: Generate IL directly Kris Vandermotten29-Apr-03 4:25 Kris Vandermotten 29-Apr-03 4:25
 Compiling In Memory Blake Coverett22-Apr-03 16:26 Blake Coverett 22-Apr-03 16:26
 Re: Compiling In Memory Jonathan de Halleux22-Apr-03 23:02 Jonathan de Halleux 22-Apr-03 23:02
 Re: Compiling In Memory Rama Krishna Vavilala23-Apr-03 3:12 Rama Krishna Vavilala 23-Apr-03 3:12
 Re: Compiling In Memory `leppie`23-Apr-03 7:00 `leppie` 23-Apr-03 7:00
 Re: Compiling In Memory Rama Krishna Vavilala23-Apr-03 7:06 Rama Krishna Vavilala 23-Apr-03 7:06
 Re: Compiling In Memory Blake Coverett23-Apr-03 16:48 Blake Coverett 23-Apr-03 16:48
 Re: Compiling In Memory Rama Krishna Vavilala24-Apr-03 1:46 Rama Krishna Vavilala 24-Apr-03 1:46
 Re: Compiling In Memory Blake Coverett24-Apr-03 13:41 Blake Coverett 24-Apr-03 13:41
 Last Visit: 22-Oct-20 20:14     Last Update: 22-Oct-20 20:14 Refresh 1