zoukankan      html  css  js  c++  java
  • MSIL实用指南-生成if...else...语句


    if...else...语句是非常重要的选择语句,它的生成一般需要ILGenerator的DefineLabel方法和
    MarkLabel方法,以及Brtrue_S和Br_S指令。

    一、DefineLabel方法
    简单调用ILGenerator的DefineLabel方法会得到一个Label结构体。Label结构体没有复杂的功能,
    只是简单做一个标签。
    实例代码:

    Label label1 = ilGenerator.DefineLabel();

    二、MarkLabel方法
    MarkLabel方法的参数只有一个,就是Label结构体。
    用DefineLabel方法得到的Label结构体并没有指定它的位置,为了指定这个标签的位置,必须要调用、
    LGenerator的MarkLabel方法。
    实例代码:

    ilGenerator.MarkLabel(label1);

    三、Brtrue_S和Brtrue指令
    Brtrue指令的意思是,如果栈上的值是 true 、不为null、或非零值,当前执行顺序则会跳转到指定的标签
    上。
    Brtrue_S的意思和Brtrue一样,只是它跳转的标签是短格式。
    一般一段程序内的标签都没有超过255个,所以都用Brtrue_S指令。
    实例代码:

    ilGenerator.Emit(OpCodes.Br_S, labelEnd);

    四、Br和Br_S指令
    Br指令是无条件跳转到指定标签,Br_S指令和它一样,只是跳转标签是短格式的。
    和上面一样,一般用Br_S指令

    五、生成步骤

    public static void Test(bool flag, bool flag2)
    {
        if (flag)
        {
            Console.WriteLine("a");
        }
        else if (flag2)
        {
            Console.WriteLine("b");
        }
        else
        {
            Console.WriteLine("else");
        }
    }

    我们要实现生成上面的代码,需要进行如下步骤。

    1.确定label的数量
    if...else语句块总会有结束的地方,所以首先要有一个结束标签。
    语句块有多少个判断条件,就需要多少个标签;上面有两个逻辑判断条件,所以还要加两个标签。
    else语句部分不需要标签。
    上面的语句需要三个标签,要先写下声明标签的程序

    Label label1 = ilGenerator.DefineLabel();
    Label label2 = ilGenerator.DefineLabel();
    Label labelEnd = ilGenerator.DefineLabel();

    2.生成判断条件
    "if"和"else"buf都有判断条件,首先生成它们的判断条件,再生成Brtrue_S指令。
    注意它们的判断结果是false才跳转,如果为true不会跳转。if表达式的结果是和
    false比较的。
    比如第一个if生成是

    ilGenerator.Emit(OpCodes.Ldarg_0);
    ilGenerator.Emit(OpCodes.Ldc_I4_0);
    ilGenerator.Emit(OpCodes.Ceq);
    ilGenerator.Emit(OpCodes.Stloc_0);
    ilGenerator.Emit(OpCodes.Ldloc_0);
    
    ilGenerator.Emit(OpCodes.Brtrue_S, label1);

    3.生成条件为true时的语句块
    在Brtrue_S时指令后面是条件为true的语句,生成它之后要跳到语句块结束标签,
    之后依次给非结束标签指定位置。
    例如

    ilGenerator.Emit(OpCodes.Ldstr,"a");
    ilGenerator.Emit(OpCodes.Call, writeStringLineMethod);
    
    ilGenerator.Emit(OpCodes.Br_S, labelEnd);
    ilGenerator.MarkLabel(label1);

    4.else部分
    else是语句块的最后部分,是上面条件都为false才执行的,之后语句块就结束了,所以不需要跳转。


    完整的程序如下:

    using System;
    using System.Reflection;
    using System.Reflection.Emit;
    
    namespace LX1_ILDemo
    {
        class Demo23_IfElse
        {
            static string binaryName = "Demo23_IfElse.exe";
            static string namespaceName = "LX1_ILDemo";
            static string typeName = "DemoIfElse";
    
            static AssemblyBuilder assemblyBuilder;
            static ModuleBuilder moduleBuilder;
            static TypeBuilder typeBuilder;
            static MethodBuilder mainMethod;
            static MethodBuilder testMethod;
    
            static void Emit_TestMethod()
            {
                testMethod = typeBuilder.DefineMethod("Test", MethodAttributes.Public
                   | MethodAttributes.Static, typeof(void), new Type[] { typeof(bool), typeof(bool) });
                ILGenerator ilGenerator = testMethod.GetILGenerator();
    
                Label label1 = ilGenerator.DefineLabel();
                Label label2 = ilGenerator.DefineLabel();
                Label labelEnd = ilGenerator.DefineLabel();
                MethodInfo writeStringLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });
    
                LocalBuilder local1 = ilGenerator.DeclareLocal(typeof(bool));
                //if(a)
                ilGenerator.Emit(OpCodes.Ldarg_0);
                ilGenerator.Emit(OpCodes.Ldc_I4_0);
                ilGenerator.Emit(OpCodes.Ceq);
                ilGenerator.Emit(OpCodes.Stloc_0);
                ilGenerator.Emit(OpCodes.Ldloc_0);
                ilGenerator.Emit(OpCodes.Brtrue_S, label1);
                ilGenerator.Emit(OpCodes.Ldstr,"a");
                ilGenerator.Emit(OpCodes.Call, writeStringLineMethod);
                ilGenerator.Emit(OpCodes.Br_S, labelEnd);
                ilGenerator.MarkLabel(label1);
                //else if(b)
                ilGenerator.Emit(OpCodes.Ldarg_1);
                ilGenerator.Emit(OpCodes.Ldc_I4_0);
                ilGenerator.Emit(OpCodes.Ceq);
                ilGenerator.Emit(OpCodes.Stloc_0);
                ilGenerator.Emit(OpCodes.Ldloc_0);
                ilGenerator.Emit(OpCodes.Brtrue_S, label2);
                ilGenerator.Emit(OpCodes.Ldstr, "b");
                ilGenerator.Emit(OpCodes.Call, writeStringLineMethod);
                ilGenerator.Emit(OpCodes.Br_S, labelEnd);
                ilGenerator.MarkLabel(label2);
                //else
                ilGenerator.Emit(OpCodes.Ldstr, "else");
                ilGenerator.Emit(OpCodes.Call, writeStringLineMethod);
                ilGenerator.MarkLabel(labelEnd);
                ilGenerator.Emit(OpCodes.Ret);
            }
             
            public static void Generate()
            {
                InitAssembly();
                typeBuilder = moduleBuilder.DefineType(namespaceName + "." + typeName, TypeAttributes.Public);
    
                Emit_TestMethod();
                GenerateMain();
    
                assemblyBuilder.SetEntryPoint(mainMethod, PEFileKinds.ConsoleApplication);
                SaveAssembly();
                Console.WriteLine("生成成功");
            }
    
            static void GenerateMain()
            {
                mainMethod = typeBuilder.DefineMethod("Main", MethodAttributes.Public
                    | MethodAttributes.Static, typeof(void), new Type[] { });
                var ilGenerator = mainMethod.GetILGenerator();
                ilGenerator.Emit(OpCodes.Ldc_I4_0);
                ilGenerator.Emit(OpCodes.Ldc_I4_0);
                ilGenerator.Emit(OpCodes.Call, testMethod);
         
                MethodInfo readKeyMethod = typeof(Console).GetMethod("ReadKey", new Type[] { });
                ilGenerator.Emit(OpCodes.Call, readKeyMethod);
                ilGenerator.Emit(OpCodes.Pop);
    
                ilGenerator.Emit(OpCodes.Ret);
            }
    
            static void InitAssembly()
            {
                AssemblyName assemblyName = new AssemblyName(namespaceName);
                assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
                moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, binaryName);
            }
    
            static void SaveAssembly()
            {
                Type t = typeBuilder.CreateType(); //完成Type,这是必须的
                assemblyBuilder.Save(binaryName);
            }
        }
    }
    View Code
  • 相关阅读:
    va_list va_start va_end va_arg 解决变参问题
    标准输出文件
    Qt QDataTime QString 两个类的使用
    联合开发网站
    iOS LLDB调试器和断点调试
    Wireshark 网络抓包工具Wireshark的使用
    linux 操作系统下c语言编程入门
    iOS 应用崩溃日志分析
    iOS sqlite3数据库解析
    iOS 解析手势识别(Gesture Recognizers)
  • 原文地址:https://www.cnblogs.com/tkt2016/p/8759902.html
Copyright © 2011-2022 走看看