开发自己的编程语言(九)—— 生成EXE文件

本章介绍

将Snail脚本编译成EXE文件的原型框架,其主要原理是利用Reflection.Emit逐一转换Snail的每条语句。之所以称为原型框架,是因为目前版本只支持:将一个变量赋值为整数,然后将这个整数变量输出。

a = 1001
print(a)
利用上面的两条语句生成一个exe文件,同时将结果输出,得到的exe文件大小只有2k。实现了这个原型之后,其他内容的实现就是时间和体力的问题了。

代码讲解


1)初始化相关模块

        public TransToCIL()
        {
            string assemblyName = "SnailCilAsm";
            modName = "SnailCil.exe";
            string typeName = "SnailCilType";
            string methodName = "Main";
            AssemblyName name = new AssemblyName(assemblyName);
            AppDomain domain = System.Threading.Thread.GetDomain();
            builder = domain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave);
            module = builder.DefineDynamicModule(modName, true);
            typeBuilder = module.DefineType(typeName, TypeAttributes.Public | TypeAttributes.Class);
            methodBuilder = typeBuilder.DefineMethod(methodName, MethodAttributes.Public | MethodAttributes.Static, typeof(void), new[] { typeof(string[]) });
        }

2)从Snail到Cil的翻译

public dynamic ToCil(Node n)
        {
            switch (n.Name)
            {
                case "Script":
                    {
                        foreach (var node in n.Nodes)
                        {
                            ToCil(node);
                        }
                        return 0;
                    }
                case "Expression":
                    return 0;
                case "Identifier":
                    {
                        int index = Script.GlobleEnv.CIL_GetIndex(n.Text);
                        if (index == -1)throw new Exception("不存在变量"+n.Text);
                        return index;
                    }
                case "AssignExpr":
                    {
                        string varname = n[0].Text;
                        if (Script.GlobleEnv.CIL_SetVar(varname))
                        {
                            IL.DeclareLocal(typeof(int));
                        }
                        int index = Script.GlobleEnv.CIL_GetIndex(varname); //变量的索引
                        var right = ToCil(n[1]);  //变量将要赋成的值


                        IL.Emit(OpCodes.Ldc_I4, (Int32)right);
                        IL.Emit(OpCodes.Stloc, index);
                        return 0;
                    }
                case "Integer":
                    {
                        return Int64.Parse(n.Text);
                    }
                case "PrintExpr":
                    {
                        int index = (int)ToCil(n[0]);
                        IL.Emit(OpCodes.Ldloc, index);
                        IL.EmitCall(OpCodes.Call, WriteLine, null);
                        return 0;
                    }
                default:
                    throw new Exception("还没有实现"+n.Name);
            }
        }
case " AssignExpr": 实现了对一个局部变量的赋值。最后转成两句Cil:

    IL.Emit(OpCodes.Ldc_I4, (Int32)right);
    IL.Emit(OpCodes.Stloc, index);

case "PrintExpr": 将相应变量的值(通过索引)压入栈中,然后调用WriteLine输出。

case "Identifier": 负责记录变量名及其索引值。


3)执行exe得到结果

        public string Excute()
        {
            Process p = new Process();
            p.StartInfo.FileName = "SnailCil.exe";
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            p.Start();
            string s = p.StandardOutput.ReadToEnd();
            p.WaitForExit();
            p.Close();
            return s;
        }


软件下载

执行时请先在编译-> 生成EXE前面打勾默认已经置上
http://download.csdn.net/detail/u012813593/6867833

测试代码:

a = 100

print(a)


你可能感兴趣的:(开发自己的编程语言(九)—— 生成EXE文件)