Click here to Skip to main content
Click here to Skip to main content
Articles » Languages » MSIL » General » Downloads
 
Add your own
alternative version

Using Reflection.Emit to Precompile Expressions to MSIL

, 6 Jan 2009 CPOL
The classes in this project allow you to parse text expressions entered by a user and compile them to a .NET assembly. This assembly can be executed on the fly, or saved to a DLL.
MSILParserProject.zip
MSILParserProject
MSILParser
bin
Debug
MSILParser.vshost.exe
ClassDiagram1.cd
ildasm.exe
MSILParser.csproj.user
MSILParser_TemporaryKey.pfx
Properties
Settings.settings
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection.Emit;
using System.Reflection;
using System.Diagnostics;
using System.Diagnostics.SymbolStore;

namespace MSILParser
{
    /// <summary>
    /// MSILParser implements the abstract RuleParser class and compiles 
    /// the statement to a dynamic method
    /// </summary>
    public class MsilParser : RuleParser
    {
        private ILGenerator il;
        public delegate TReturn ExpressionInvoker<TReturn>();
       
        /// <summary>
        /// This is just a test function that supplies variables with values
        /// </summary>
        public static double GetVar(string var)
        {
            switch (var)
            {
                case "a": return 100;
                case "b": return 200;
                case "c": return 300;
                case "d": return 400;
                default: return 500;
            }
        }
        
        /// <summary>
        /// Builds and returns a dynamic assembly
        /// </summary>
        public Type CompileMsil(string expr)
        {

            // Build the dynamic assembly
            string assemblyName = "Expression";
            string modName = "expression.dll";
            string typeName = "Expression";
            string methodName = "RunExpression";
            AssemblyName name = new AssemblyName(assemblyName);
            AppDomain domain = System.Threading.Thread.GetDomain();
            AssemblyBuilder builder = domain.DefineDynamicAssembly(
              name, AssemblyBuilderAccess.RunAndSave);
            ModuleBuilder module = builder.DefineDynamicModule
              (modName, true);
            TypeBuilder typeBuilder = module.DefineType(typeName,
              TypeAttributes.Public | TypeAttributes.Class);
            MethodBuilder methodBuilder = typeBuilder.DefineMethod(methodName,
              MethodAttributes.HideBySig | MethodAttributes.Static
              | MethodAttributes.Public,
              typeof(Object), new Type[] {  });

            // Create the ILGenerator to insert code into our method body
            ILGenerator ilGenerator = methodBuilder.GetILGenerator();
            this.il = ilGenerator;

            // Parse the expression.  This will insert MSIL instructions
            this.Run(expr);

            // Finish the method by boxing the result as Double
            this.il.Emit(OpCodes.Conv_R8);
            this.il.Emit(OpCodes.Box, typeof(Double));
            this.il.Emit(OpCodes.Ret);

            // Create and save the Assembly and return the type
            Type myClass = typeBuilder.CreateType();
            builder.Save(modName);
            return myClass;
        }

        #region Semantic Actions for Parse Functions
        
        protected override void matchAnd()
        {
            this.il.Emit(OpCodes.And);
        }

        protected override void matchOr()
        {
            this.il.Emit(OpCodes.Or);
        }

        protected override void matchAdd()
        {
            this.il.Emit(OpCodes.Add);
        }

        protected override void matchComma()
        {
            throw new NotImplementedException();
        }

        protected override void matchDiv()
        {
            this.il.Emit(OpCodes.Div);
        }

        protected override void matchDot()
        {
            throw new NotImplementedException();
        }

        protected override void matchEqual()
        {
            this.il.Emit(OpCodes.Ceq);
        }

        protected override void matchFunc()
        {
            throw new NotImplementedException();
        }

        protected override void matchGE()
        {
            throw new NotImplementedException();
        }

        protected override void matchGT()
        {
            this.il.Emit(OpCodes.Cgt);
        }

        protected override void matchLE()
        {
            throw new NotImplementedException();
        }

        protected override void matchLT()
        {
            this.il.Emit(OpCodes.Clt);
        }

        protected override void matchMod()
        {
            throw new NotImplementedException();
        }

        protected override void matchMult()
        {
            this.il.Emit(OpCodes.Mul);
        }

        protected override void matchNeg()
        {
            this.il.Emit(OpCodes.Neg);
        }

        protected override void matchNegate()
        {
            throw new NotImplementedException();
        }

        protected override void matchNotEqual()
        {
            throw new NotImplementedException();
        }

        protected override void matchParen()
        {
            // No action required
        }

        protected override void matchSub()
        {
            this.il.Emit(OpCodes.Sub);
        }

        protected override void matchVal()
        {
            switch (this.tokenValue.Type)
            {
                case VariantType.BOOL:
                    this.il.Emit(OpCodes.Ldc_I4, Convert.ToInt32(this.tokenValue.Value));
                    break;
                case VariantType.DOUBLE:
                    this.il.Emit(OpCodes.Ldc_R8, Convert.ToDouble(this.tokenValue.Value));
                    //this.il.Emit(OpCodes.Box, typeof(Double));
                    break;
                case VariantType.INT:
                    this.il.Emit(OpCodes.Ldc_R8, Convert.ToDouble(this.tokenValue.Value));
                    break;
                case VariantType.STRING:
                    this.il.Emit(OpCodes.Ldstr, Convert.ToString(this.tokenValue.Value));
                    break;
                default:
                    throw new Exception("Invalid TokenType");
            }
        }

        protected override void matchVar()
        {
            string s = tokenValue.ToString();
            il.Emit(OpCodes.Ldstr, s);
            il.Emit(OpCodes.Call, typeof(MsilParser).GetMethod("GetVar", new Type[] { typeof(string) }));
        }

        protected override void matchXor()
        {
            this.il.Emit(OpCodes.Xor);
        }
        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Steve Marsh
Software Developer (Senior)
United States United States
Stephen Marsh has over 10 years of experience developing enterprise applications built on the .Net framework. He specializes in building expert systems that serve the financial industry.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141220.1 | Last Updated 6 Jan 2009
Article Copyright 2009 by Steve Marsh
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid