using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Text.RegularExpressions; using System.IO; namespace bindingGen { /// /// 输入目录,在目录下生成./binding目录,存放导出的binding代码 /// class Program { // {0} 文件名 // {1} 第一个名称空间 // {2} 第二个名称空间 // {3} 内容 static string output = @"#include ""../{0}.h"" using namespace std; namespace {1} {{ namespace {2} {{ {3} }} }} "; // {0} 类名 // {1} 内容 static string registry = @" LUAX_REGISTRY({0}) {{ {1} }} "; // {0} 类名 // {1} 内容 static string postprocess = @" LUAX_POSTPROCESS({0}) {{ {1} }} "; // {0} 类名 // {1} 去掉_的函数名 // {2} 小写的类名 static string method = @" // {2}:{1}() LUAX_IMPL_METHOD({0}, _{1}) {{ LUAX_PREPARE(L, {0}); }} "; // {0} 类名 // {1} 去掉_的函数名 static string method_new = @" // {0}.{1}() LUAX_IMPL_METHOD({0}, _{1}) {{ LUAX_STATE(L); }} "; static string make_register_methods(MatchCollection methods) { if (methods.Count == 0) return ""; string register_methods = ""; register_methods += "\t\t\tLUAX_REGISTER_METHODS(state,\n"; int maxlen = 0; foreach(var m in methods) { string method = m.ToString(); if (method.Count() > maxlen) maxlen = method.Count(); } for(int i = 0; i < methods.Count; ++i) { Match m = methods[i]; string method = m.ToString(); register_methods += "\t\t\t\t"; register_methods += "{ "; register_methods += ('"' + method.Substring(1, method.Count() - 1) + "\",").PadRight(maxlen + 3, ' '); register_methods += method.PadRight(maxlen + 1, ' '); register_methods += "}"; if (i != methods.Count - 1) register_methods += ','; register_methods += '\n'; } register_methods += "\t\t\t);"; return register_methods; } static string make_impl_methods(MatchCollection mc, string cname) { if (mc.Count == 0) return ""; string methods = ""; foreach(var m in mc) { string name = m.ToString(); if(name != "_New") { methods += String.Format(method, cname, name.Substring(1, name.Count() - 1), cname.ToLower()); } else { methods += String.Format(method_new, cname, name.Substring(1, name.Count() - 1)); } } return methods; } static string make_register_enum(MatchCollection mc, string src) { if (mc.Count == 0) return ""; string reg_enum_l = @"(?<=enum\s"; string reg_enum_r = @"[\s\n]*\{((?!\{)[\s\S])*)[A-Z_]+(?=\s*,)"; string enums = ""; foreach(var m in mc) { string name = m.ToString(); enums += "\t\t\tLUAX_REGISTER_ENUM(state, "; enums += "\"E" + name + "\",\n"; MatchCollection values = Regex.Matches(src, reg_enum_l + name + reg_enum_r); string[] enames = new string[values.Count]; string[] keys = new string[values.Count]; int maxEname = 0, maxKey = 0; for (int i = 0; i < values.Count; ++i) { enames[i] = values[i].ToString(); keys[i] = enames[i].Substring(enames[i].LastIndexOf('_') + 1, enames[i].Count() - enames[i].LastIndexOf('_') -1); if (enames[i].Count() > maxEname) maxEname = enames[i].Count(); if (keys[i].Count() > maxKey) maxKey = keys[i].Count(); } for(int i = 0; i < values.Count; ++i) { enums += "\t\t\t\t{ "; enums += ('"' + keys[i] + "\",").PadRight(maxKey + 4); enums += enames[i].PadRight(maxEname + 1); enums += "}"; if (i != values.Count - 1) enums += ","; enums += "\n"; } enums += "\t\t\t);\n"; } return enums; } /// /// 用法: /// bindingGen <目录> /// /// static void Main(string[] args) { if (args.Length < 1) return; string dir = args[0]; Console.WriteLine("源目录: " + dir); if (!Directory.Exists(dir)) return; string reg_class = @"(?<=Portable\<)[0-9a-zA-Z]+(?=\>)"; string reg_methods = @"(?<=LUAX_DECL_METHOD\()[0-9a-zA-Z_]+(?=\))"; string reg_enums = @"(?<=LUAX_DECL_ENUM\()[0-9a-zA-Z_]+(?=\))"; string reg_namespace = @"(?<=namespace\s)[0-9a-zA-Z]+(?=[\s\n]*)"; if(!Directory.Exists(dir + "/binding")) { Directory.CreateDirectory(dir + "/binding"); } string[] files = Directory.GetFiles(dir); for(int i = 0; i < files.Count(); ++i) { string file = files[i]; if (!File.Exists(file)) continue; file = file.Replace('\\', '/'); string name = file.Substring(file.LastIndexOf('/') + 1, file.LastIndexOf('.') - file.LastIndexOf('/') - 1); string bindingFile = dir + "/binding/_" + name + ".cpp"; if (File.Exists(bindingFile)) continue; string code = File.ReadAllText(file); // Match m = Regex.Match(code, reg_class); if (!m.Success) continue; string className = m.ToString(); MatchCollection mc = Regex.Matches(code, reg_namespace); // 应该两个名称空间 if(mc.Count != 2) { Console.WriteLine("Error: 源文件没有两个名称空间 " + file); continue; } string namespace1 = mc[0].ToString(); string namespace2 = mc[1].ToString(); // 名称空间内的内容 string content = ""; mc = Regex.Matches(code, reg_methods); content += String.Format(registry, className, make_register_methods(mc)); mc = Regex.Matches(code, reg_enums); content += String.Format(postprocess, className, make_register_enum(mc, code)); mc = Regex.Matches(code, reg_methods); content += make_impl_methods(mc, className); string binding = String.Format(output, name, namespace1, namespace2, content); Console.WriteLine("输出: "+bindingFile); File.WriteAllText(bindingFile, binding); } } } }