将Snail脚本编译成EXE文件的原型框架,其主要原理是利用Reflection.Emit逐一转换Snail的每条语句。之所以称为原型框架,是因为目前版本只支持:将一个变量赋值为整数,然后将这个整数变量输出。
a = 1001 print(a)利用上面的两条语句生成一个exe文件,同时将结果输出,得到的exe文件大小只有2k。实现了这个原型之后,其他内容的实现就是时间和体力的问题了。
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[]) }); }
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": 负责记录变量名及其索引值。
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)