 |
|
 |
Hi,
how can i do that for osx or ios for iphone ?
I need to compile mathematical expressions (maybe into memory).
Because i need it faster for looping.
How can i do that ?
do i need assembler code ?
Thanks a lot !
Chris
|
|
|
|
 |
|
|
 |
|
 |
Didn't you notice that the article was created in 2003 and the approach was quite new at that time...
|
|
|
|
 |
|
 |
First of all, thanks for the article, it works perfectly for functions like double Func1 (double x). But when I try double FuncN (params double[] x), I get the error message "Metadata file 'FuncLabGUI.exe' could not be found" ('FuncLabGUI' is my main program). If anybody has a hint, please formulate it as simply as possible, I don't know very well what I am doing, I simply followed the pattern of Dracula's article and adapted it a little bit, according to the suggestions of .Net 2.0 (using CSharpCodeProvider's CompileAssemblyFromSource method instead of creating a compiler).
|
|
|
|
 |
|
 |
Good idea, easy to expand. What a pity c# does not support macrodefinitions like in C!
|
|
|
|
 |
|
 |
Better go this way:
using System;
using System.Collections;
using System.Reflection;
public class MathExpressionParser
{
public object myobj = null;
public ArrayList errorMessages;
public MathExpressionParser()
{
errorMessages = new ArrayList();
}
public bool init(string expr)
{
Microsoft.CSharp.CSharpCodeProvider cp
= new Microsoft.CSharp.CSharpCodeProvider();
System.CodeDom.Compiler.ICodeCompiler ic = cp.CreateCompiler();
System.CodeDom.Compiler.CompilerParameters cpar
= new System.CodeDom.Compiler.CompilerParameters();
cpar.GenerateInMemory = true;
cpar.GenerateExecutable = false;
cpar.ReferencedAssemblies.Add("system.dll");
string src = "using System;" +
"class myclass " +
"{ " +
"public myclass(){} " +
"public static double eval(double x) " +
"{ " +
"return " + expr + "; " +
"} " +
"} ";
System.CodeDom.Compiler.CompilerResults cr
= ic.CompileAssemblyFromSource(cpar, src);
foreach (System.CodeDom.Compiler.CompilerError ce in cr.Errors)
errorMessages.Add(ce.ErrorText);
if (cr.Errors.Count == 0 && cr.CompiledAssembly != null)
{
Type ObjType = cr.CompiledAssembly.GetType("myclass");
try
{
if (ObjType != null)
{
myobj = Activator.CreateInstance(ObjType);
}
}
catch (Exception ex)
{
errorMessages.Add(ex.Message);
}
return true;
}
else
return false;
}
public double eval(double x)
{
double val = 0.0;
Object[] myParams = new Object[1] { x };
if (myobj != null)
{
System.Reflection.MethodInfo evalMethod = myobj.GetType().GetMethod("eval");
val = (double)evalMethod.Invoke(myobj, myParams);
}
return val;
}
}
Usage:
MathExpressionParser mp = new MathExpressionParser();
mp.init(txtFormula.Text.Trim());
if (mp.errorMessages.Count != 0)
{
theMessageBox.Show("Expression is not valid.");
for (int i = 1; i <= mp.errorMessages.Count; i++)
{
theMessageBox.Show(mp.errorMessages[i - 1].ToString());
}
return;
}
theMessageBox.Show(str(mp.eval((double)5)));
|
|
|
|
 |
|
 |
This is excelent. It has a lot of uses, more then just math.
|
|
|
|
 |
|
 |
great exapmle!
a little thing i'd correct : for sake of modularity i'd use something like
AppDomain.CurrentDomain.FriendlyName
instead of "matheval.exe"
|
|
|
|
 |
|
 |
Isn't this method extremely insecure? Either that or you'd have to filter out everything that's not math code, and if you do that, you've already written a parser!
|
|
|
|
 |
|
 |
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?
|
|
|
|
 |
|
 |
That can't be done. Instead AppDomains can be unloaded, however to communicate with a classes/instances in another AppDomain you have to use remoting. (Intra-process remoting is supposedly fast)
|
|
|
|
 |
|
 |
I think using Microsoft.JScript.Eval() (or simple helper class in JScript compiled into separate assembly) for this purpose is much simpler and more efficient than emmiting and compiling code in-memory or not.
|
|
|
|
 |
|
 |
There is example code at the borland site which shows how to generate IL directly, this might be a more efficient way to evaulate expressions. http://dotnet.borland.com/samples/Dynamic.CIL.demo.zip Herbert Sauro
|
|
|
|
 |
|
 |
Eventually just mapping all the functions to .NET functions and building an evaluation stack would be the fasted.
I rated this article 2 by mistake. It deserves more. I wanted to get to the second page... - vjedlicka 3:33 25 Nov '02
|
|
|
|
 |
|
 |
Generating IL directly has many advantages.
Of course, what you are really doing is writing a compiler for your own expression language. This article basically suggests the alternative of not writing your own compiler, but using the C# one. Consider this approach as being "quick and dirty", but it works.
Anyway, if you want to know about IL generation, have a look at the excellent paper at http://www.dina.dk/~sestoft/rtcg/rtcg.pdf . This paper discusses runtime code generation in a partial evaluation context, as an optimization technique. It also lists benchmark results.
|
|
|
|
 |
|
 |
Don't let the way the CodeDom interfaces appear to work fool you though - when you 'compile in memory' like that it still just creates temp files and spawns csc.exe as a whole separate process. I found that rather depressing.
The resulting lesson is, while it's efficient to eval that in a tight loop the compilation process is even more expensive than you might guess.
--
-Blake (com/bcdev/blake)
|
|
|
|
 |
|
 |
Could you give more details about that ?
Jonathan de Halleux.
|
|
|
|
 |
|
|
 |
|
 |
That will launch csc too
I rated this article 2 by mistake. It deserves more. I wanted to get to the second page... - vjedlicka 3:33 25 Nov '02
|
|
|
|
 |
|
 |
Nope.
CSC internally uses that class.
Meg Rules
|
|
|
|
 |
|
 |
No, leppie is quite correct. Both the CodeDom and the C# specific interfaces just end up launching csc.exe. Yes, this seems unlikely but it is quite true, try it for yourself.
The easiest experiment it to write a snippet of code using either interface, ensure it operates as expected, and then rename csc.exe and discover it no longer works. You can also just dig around in the IL disassembly for the classes, that's what I did a year or two ago. It was a surprise to me at the time as well.
--
-Blake (com/bcdev/blake)
|
|
|
|
 |
|
 |
It is not true with the Microsoft.CSharp.Compiler class. It does compile InMemory. Actually it calls InMemoryCompile function is cscompd.dll. Which is what csc.exe ends up calling. Look at csc.exe using dependency viewer. And also look at the diassembly of the Microsoft.CSharp.Compiler class. Rememeber This is not a CodeDOM class.
Meg Rules
|
|
|
|
 |
|
 |
I went back and looked again - and you are right, the problem with the Microsoft.CSharp.Compiler class isn't exactly the way I remembered it. It does invoke the unmanaged compiler code via a function shim not by launching csc.exe in another process - but it doesn't expose a way to compile in memory. (Which is what this thread was originally about.)
In summary:
If you use the CodeDom interface you get the appearance of compiling in memory, but really it uses temp files and a separate process.
If you use the CSharp.Compiler class it doesn't spawn another process but there's no illusion of compiling into memory at all. You have to provide a full path to the output assembly on disk. (Meaning you can't even use isolated storage.)
The combination of these two made compiling on the fly much less appealing that I'd originally thought for the problem domains I was dealing with.
regards,
-Blake
|
|
|
|
 |