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; using namespace Luax; 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}); return 0; }} "; // {0} 类名 // {1} 去掉_的函数名 static string method_new = @" // {0}.{1}() LUAX_IMPL_METHOD({0}, _{1}) {{ LUAX_STATE(L); return 0; }} "; 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 int IndexOfChar(string str, char c, int n) { int j = 0; for (int i = 0; i < str.Count(); ++i) { char ch = str[i]; if (ch == c) { if (j == n) return i; ++j; } } return -1; } 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])*\s)[A-Z_0-9]+(?=[\s\=,]+)"; string enums = ""; // 尝试查找下划线索引号,如果没有,代表这个枚举字符串全部都是key string reg_under_line_l = @"(?<=LUAX_DECL_ENUM\s*\(\s*"; string reg_under_line_r = @"\s*,\s*)[0-9]+(?=\s*\))"; 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 underline_index = -1; Match underline = Regex.Match(src, reg_under_line_l + name + reg_under_line_r); if (underline.Success) { underline_index = int.Parse(underline.ToString()); } int maxEname = 0, maxKey = 0; for (int i = 0; i < values.Count; ++i) { enames[i] = values[i].ToString(); if(underline_index != -1) { int start = IndexOfChar(enames[i], '_', underline_index) + 1; keys[i] = enames[i].Substring(start, enames[i].Count() - start); } else { // 表明全部都是key keys[i] = enames[i]; } 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_abclass = @"(?<=LUAX_DECL_ABSTRACT_FACTORY\s*\(\s*)[0-9a-zA-Z]+(?=\s*\))"; string reg_methods = @"(?<=LUAX_DECL_METHOD\()[0-9a-zA-Z_]+(?=\))"; string reg_enums = @"(?<=LUAX_DECL_ENUM\()[0-9a-zA-Z_]+(?=\s*[\),]+)"; 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); string className = ""; if (m.Success) { className = m.ToString(); } if (!m.Success) { // 抽象类,不会继承Portable模板 Match abstract_m = Regex.Match(code, reg_abclass); if (!abstract_m.Success) continue; className = abstract_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); } } } }