Program.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Xml;
  6. using System.IO;
  7. namespace spgen
  8. {
  9. public enum ParamType
  10. {
  11. PT_BOOL,
  12. PT_SHORT,
  13. PT_USHORT,
  14. PT_CHAR,
  15. PT_UCHAR,
  16. PT_INT,
  17. PT_UINT,
  18. PT_INT64,
  19. PT_UINT64,
  20. PT_DOUBLE,
  21. PT_FLOAT,
  22. PT_STRING,
  23. PT_WSTRING,
  24. PT_BLOB,
  25. PT_ARRAY_BOOL,
  26. PT_ARRAY_SHORT,
  27. PT_ARRAY_USHORT,
  28. PT_ARRAY_CHAR,
  29. PT_ARRAY_UCHAR,
  30. PT_ARRAY_INT,
  31. PT_ARRAY_UINT,
  32. PT_ARRAY_INT64,
  33. PT_ARRAY_UINT64,
  34. PT_ARRAY_DOUBLE,
  35. PT_ARRAY_FLOAT,
  36. PT_ARRAY_STRING,
  37. PT_ARRAY_WSTRING,
  38. PT_ARRAY_BLOB,
  39. }
  40. public class Param
  41. {
  42. public string Name;
  43. public ParamType Type;
  44. }
  45. public class Method
  46. {
  47. public EntityClass ParentClass = new EntityClass();
  48. public string Name;
  49. public int Id;
  50. public int Signature;
  51. public bool Overlap;
  52. public bool user_define_id;
  53. public bool user_define_sig;
  54. public virtual int CalcSignature()
  55. {
  56. throw new NotImplementedException();
  57. //return 0;
  58. }
  59. }
  60. public class Oneway : Method
  61. {
  62. public List<Param> InfoParamList = new List<Param>();
  63. public override int CalcSignature()
  64. {
  65. StringBuilder sb = new StringBuilder();
  66. sb.Append(this.Name);
  67. foreach (Param i in InfoParamList)
  68. {
  69. sb.Append(i.Name);
  70. sb.Append(i.Type.ToString());
  71. }
  72. return sb.ToString().GetHashCode();
  73. }
  74. }
  75. public class Twoway : Method
  76. {
  77. public List<Param> ReqParamList = new List<Param>();
  78. public List<Param> ResParamList = new List<Param>();
  79. public override int CalcSignature()
  80. {
  81. StringBuilder sb = new StringBuilder();
  82. sb.Append(this.Name);
  83. foreach (Param i in ReqParamList)
  84. {
  85. sb.Append(i.Name);
  86. sb.Append(i.Type.ToString());
  87. }
  88. foreach (Param i in ResParamList)
  89. {
  90. sb.Append(i.Name);
  91. sb.Append(i.Type.ToString());
  92. }
  93. return sb.ToString().GetHashCode();
  94. }
  95. }
  96. public class Subscribe : Method
  97. {
  98. public Oneway Cancel;
  99. public List<Param> SubParamList = new List<Param>();
  100. public Oneway Message;
  101. public override int CalcSignature()
  102. {
  103. StringBuilder sb = new StringBuilder();
  104. sb.Append(Name);
  105. foreach (Param i in SubParamList)
  106. {
  107. sb.Append(i.Name);
  108. sb.Append(i.Type.ToString());
  109. }
  110. foreach (Param i in Cancel.InfoParamList)
  111. {
  112. sb.Append(i.Name);
  113. sb.Append(i.Type.ToString());
  114. }
  115. foreach (Param i in Message.InfoParamList)
  116. {
  117. sb.Append(i.Name);
  118. sb.Append(i.Type.ToString());
  119. }
  120. return sb.ToString().GetHashCode();
  121. }
  122. }
  123. public class EntityClass
  124. {
  125. public string Name;
  126. public bool Exclusive;
  127. public bool Overlap;
  128. public bool NativeOnly;
  129. public List<Method> MethodList = new List<Method>();
  130. }
  131. public class EntityMsg
  132. {
  133. public string Name;
  134. public List<Param> InfoParamList = new List<Param>();
  135. public int Signature;
  136. public int CalcSignature()
  137. {
  138. StringBuilder sb = new StringBuilder();
  139. sb.Append(Name);
  140. foreach (Param i in InfoParamList)
  141. {
  142. sb.Append(i.Name);
  143. sb.Append(i.Type.ToString());
  144. }
  145. return sb.ToString().GetHashCode();
  146. }
  147. }
  148. public class ConstItem
  149. {
  150. public string Name;
  151. public int Value;
  152. }
  153. public class Entity
  154. {
  155. public List<EntityClass> ClassList = new List<EntityClass>();
  156. public string Name;
  157. public List<EntityMsg> MsgList = new List<EntityMsg>();
  158. public List<ConstItem> ConstList = new List<ConstItem>();
  159. public Dictionary<string, string> defineDic = new Dictionary<string, string>();
  160. public static Entity Load(string xmlfile)
  161. {
  162. Entity entity = new Entity();
  163. XmlDocument doc = new XmlDocument();
  164. doc.Load(xmlfile);
  165. XmlNode entitynode = doc.SelectSingleNode("/entity");
  166. entity.Name = entitynode.Attributes["name"].Value;
  167. if (entity.Name == null)
  168. throw new Exception("entity name cannot empty!");
  169. foreach (XmlNode i in entitynode.ChildNodes)
  170. {
  171. if (i.NodeType == XmlNodeType.Element)
  172. {
  173. if (i.Name == "class")
  174. {
  175. entity.ClassList.Add(LoadEntityClass(i));
  176. }
  177. else if (i.Name == "message")
  178. {
  179. entity.MsgList.Add(LoadEntityMsg(i));
  180. }
  181. else if (i.Name == "const")
  182. {
  183. entity.ConstList.Add(LoadConstItem(i));
  184. }
  185. else
  186. {
  187. throw new Exception("invalid /entity/node, must be class or message!");
  188. }
  189. }
  190. }
  191. int index = xmlfile.LastIndexOf('\\');
  192. string curPath = xmlfile.Remove(index, xmlfile.Length - index);
  193. string deffilename = Path.Combine(curPath, string.Format("{0}_def_g.h", entity.Name));
  194. string msgfile = Path.Combine(curPath, string.Format("{0}_msg_g.h", entity.Name));
  195. List<string> defineLines = new List<string>();
  196. if(File.Exists(deffilename))
  197. {
  198. string[] msgLines = File.ReadAllLines(deffilename, Encoding.GetEncoding("gb2312"));
  199. foreach (string line in msgLines)
  200. defineLines.Add(line);
  201. }
  202. if (File.Exists(msgfile))
  203. {
  204. string[] msgLines = File.ReadAllLines(msgfile, Encoding.GetEncoding("gb2312"));
  205. foreach (string line in msgLines)
  206. defineLines.Add(line);
  207. }
  208. foreach (string line in defineLines)
  209. {
  210. if (line.Contains("#define"))
  211. {
  212. string noTrimStr = line.Trim();
  213. string[] splitArr = noTrimStr.Split(' ');
  214. if (3 == splitArr.Length)
  215. {
  216. entity.defineDic.Add(splitArr[1], splitArr[2]);
  217. }
  218. }
  219. }
  220. return entity;
  221. }
  222. static ConstItem LoadConstItem(XmlNode itemNode)
  223. {
  224. ConstItem item = new ConstItem();
  225. item.Name = itemNode.Attributes["name"].Value;
  226. if (item.Name == null)
  227. throw new Exception("item name cannot empty!");
  228. item.Value = Int32.Parse(itemNode.Attributes["value"].Value);
  229. return item;
  230. }
  231. static EntityMsg LoadEntityMsg(XmlNode msgNode)
  232. {
  233. EntityMsg msg = new EntityMsg();
  234. msg.Name = msgNode.Attributes["name"].Value;
  235. if (msg.Name == null)
  236. throw new Exception("msg name cannot empty!");
  237. LoadParamList(msg.InfoParamList, msgNode);
  238. msg.Signature = msg.CalcSignature();
  239. return msg;
  240. }
  241. static EntityClass LoadEntityClass(XmlNode clsNode)
  242. {
  243. int seq = 0;
  244. EntityClass entitycls = new EntityClass();
  245. entitycls.Name = clsNode.Attributes["name"].Value;
  246. if (entitycls.Name == null)
  247. throw new Exception("entity name cannot empty!");
  248. entitycls.Exclusive = clsNode.Attributes["exclusive"].Value != null ? Boolean.Parse(clsNode.Attributes["exclusive"].Value) : false;
  249. entitycls.Overlap = clsNode.Attributes["exclusive"].Value != null ? Boolean.Parse(clsNode.Attributes["overlap"].Value) : true;
  250. if (clsNode.Attributes["native"] != null)
  251. {
  252. entitycls.NativeOnly = clsNode.Attributes["native"].Value != null ? Boolean.Parse(clsNode.Attributes["overlap"].Value) : false;
  253. }
  254. else
  255. {
  256. entitycls.NativeOnly = false;
  257. }
  258. foreach (XmlNode method in clsNode.ChildNodes)
  259. {
  260. if (method.NodeType == XmlNodeType.Element)
  261. {
  262. Method m = LoadMethod(method);
  263. if (!m.user_define_id)
  264. m.Id = seq++;
  265. if (!m.user_define_sig)
  266. m.Signature = m.CalcSignature();
  267. if (typeof(Subscribe).IsInstanceOfType(m))
  268. {
  269. Subscribe sub = m as Subscribe;
  270. sub.Cancel.Id = seq++;
  271. sub.Cancel.Signature = sub.Cancel.CalcSignature();
  272. sub.Message.Id = seq++;
  273. sub.Message.Signature = sub.Message.CalcSignature();
  274. }
  275. entitycls.MethodList.Add(m);
  276. }
  277. }
  278. return entitycls;
  279. }
  280. static Method LoadMethod(XmlNode method)
  281. {
  282. Method m;
  283. string name = method.Attributes["name"].Value;
  284. if (name == null)
  285. throw new Exception("method name cannot empty!");
  286. bool overlap = bool.Parse(method.Attributes["overlap"].Value);
  287. if (string.Compare(method.Name, "oneway", true) == 0)
  288. {
  289. m = LoadOneway(method);
  290. }
  291. else if (string.Compare(method.Name, "twoway", true) == 0)
  292. {
  293. m = LoadTwoway(method);
  294. }
  295. else if (string.Compare(method.Name, "subscribe", true) == 0)
  296. {
  297. m = LoadSubscribe(method);
  298. }
  299. else
  300. {
  301. throw new Exception("unknown method type!");
  302. }
  303. m.Name = name;
  304. m.Overlap = overlap;
  305. if (method.Attributes["method_id"] != null)
  306. {
  307. m.user_define_id = true;
  308. m.Id = Int32.Parse(method.Attributes["method_id"].Value);
  309. }
  310. else
  311. {
  312. m.user_define_id = false;
  313. }
  314. if (method.Attributes["method_sig"] != null)
  315. {
  316. m.user_define_sig = true;
  317. m.Signature = Int32.Parse(method.Attributes["method_sig"].Value);
  318. }
  319. else
  320. {
  321. m.user_define_sig = false;
  322. }
  323. return m;
  324. }
  325. static Method LoadOneway(XmlNode method)
  326. {
  327. Oneway oneway = new Oneway();
  328. LoadParamList(oneway.InfoParamList, method);
  329. return oneway;
  330. }
  331. static Method LoadTwoway(XmlNode method)
  332. {
  333. Twoway twoway = new Twoway();
  334. foreach (XmlNode i in method.ChildNodes)
  335. {
  336. if (i.NodeType == XmlNodeType.Element)
  337. {
  338. if (String.Compare(i.Name, "req", true) == 0)
  339. {
  340. if (twoway.ReqParamList.Count != 0)
  341. throw new Exception("duplicate load of req!");
  342. LoadParamList(twoway.ReqParamList, i);
  343. }
  344. else if (String.Compare(i.Name, "res", true) == 0)
  345. {
  346. if (twoway.ResParamList.Count != 0)
  347. throw new Exception("duplicate load of res!");
  348. LoadParamList(twoway.ResParamList, i);
  349. }
  350. else
  351. {
  352. throw new Exception("unsupported tag!");
  353. }
  354. }
  355. }
  356. return twoway;
  357. }
  358. static Method LoadSubscribe(XmlNode method)
  359. {
  360. Subscribe subscribe = new Subscribe();
  361. LoadParamList(subscribe.SubParamList, method);
  362. foreach (XmlNode i in method.ChildNodes)
  363. {
  364. if (i.NodeType == XmlNodeType.Element)
  365. {
  366. if (string.Compare(i.Name, "cancel") == 0)
  367. {
  368. if (subscribe.Cancel != null)
  369. throw new Exception("duplicate load of cancel");
  370. subscribe.Cancel = new Oneway();
  371. subscribe.Cancel.Name = i.Attributes["name"].Value;
  372. subscribe.Cancel.Overlap = true;
  373. LoadParamList(subscribe.Cancel.InfoParamList, i);
  374. }
  375. if (string.Compare(i.Name, "message") == 0)
  376. {
  377. if (subscribe.Message != null)
  378. throw new Exception("duplicate load of message");
  379. subscribe.Message = new Oneway();
  380. subscribe.Message.Name = i.Attributes["name"].Value;
  381. subscribe.Message.Overlap = true;
  382. LoadParamList(subscribe.Message.InfoParamList, i);
  383. }
  384. }
  385. }
  386. if (subscribe.Message == null)
  387. throw new Exception("Message cannot null");
  388. if (subscribe.Cancel == null)
  389. throw new Exception("Cancel cannot null");
  390. return subscribe;
  391. }
  392. static void LoadParamList(List<Param> ParamList, XmlNode parent)
  393. {
  394. foreach (XmlNode i in parent.ChildNodes)
  395. {
  396. if (i.NodeType == XmlNodeType.Element)
  397. {
  398. if (string.Compare(i.Name, "param", true) == 0)
  399. {
  400. string name = i.Attributes["name"].Value;
  401. if (name == null)
  402. throw new Exception("method name cannot empty!");
  403. string type = i.Attributes["type"].Value;
  404. if (type == null)
  405. throw new Exception("method type cannot empty!");
  406. Param p = new Param();
  407. p.Name = name;
  408. p.Type = ToParamType(type);
  409. ParamList.Add(p);
  410. }
  411. }
  412. }
  413. }
  414. public static ParamType ToParamType(string type)
  415. {
  416. switch (type)
  417. {
  418. case "bool":
  419. return ParamType.PT_BOOL;
  420. case "int":
  421. return ParamType.PT_INT;
  422. case "uint":
  423. return ParamType.PT_UINT;
  424. case "short":
  425. return ParamType.PT_SHORT;
  426. case "ushort":
  427. return ParamType.PT_USHORT;
  428. case "char":
  429. return ParamType.PT_CHAR;
  430. case "uchar":
  431. return ParamType.PT_UCHAR;
  432. case "string":
  433. return ParamType.PT_STRING;
  434. case "wstring":
  435. return ParamType.PT_WSTRING;
  436. case "float":
  437. return ParamType.PT_FLOAT;
  438. case "double":
  439. return ParamType.PT_DOUBLE;
  440. case "blob":
  441. return ParamType.PT_BLOB;
  442. case "int64":
  443. return ParamType.PT_INT64;
  444. case "uint64":
  445. return ParamType.PT_UINT64;
  446. case "array_bool":
  447. return ParamType.PT_ARRAY_BOOL;
  448. case "array_short":
  449. return ParamType.PT_ARRAY_SHORT;
  450. case "array_ushort":
  451. return ParamType.PT_ARRAY_USHORT;
  452. case "array_char":
  453. return ParamType.PT_ARRAY_CHAR;
  454. case "array_uchar":
  455. return ParamType.PT_ARRAY_UCHAR;
  456. case "array_int":
  457. return ParamType.PT_ARRAY_INT;
  458. case "array_uint":
  459. return ParamType.PT_ARRAY_UINT;
  460. case "array_int64":
  461. return ParamType.PT_ARRAY_INT64;
  462. case "array_uint64":
  463. return ParamType.PT_ARRAY_UINT64;
  464. case "array_double":
  465. return ParamType.PT_ARRAY_DOUBLE;
  466. case "array_float":
  467. return ParamType.PT_ARRAY_FLOAT;
  468. case "array_string":
  469. return ParamType.PT_ARRAY_STRING;
  470. case "array_wstring":
  471. return ParamType.PT_ARRAY_WSTRING;
  472. case "array_blob":
  473. return ParamType.PT_ARRAY_BLOB;
  474. default:
  475. throw new Exception("unsupported type!");
  476. }
  477. }
  478. }
  479. public abstract class GeneratorBase
  480. {
  481. public abstract void GenerateCode(string dir, Entity entity);
  482. }
  483. class Program
  484. {
  485. static void Usage()
  486. {
  487. Console.WriteLine("\tUsage: spgen.exe <entity>.xml\n");
  488. }
  489. // spgen.exe print_entity.xml
  490. static void Main(string[] args)
  491. {
  492. if (args.Length != 1)
  493. {
  494. Usage();
  495. return;
  496. }
  497. try
  498. {
  499. string xmlfile = System.IO.Path.Combine(Environment.CurrentDirectory, args[0]);
  500. Entity entity = Entity.Load(xmlfile);
  501. CPPGenerator cppgen = new CPPGenerator();
  502. cppgen.GenerateCode(Environment.CurrentDirectory, entity);
  503. CSGenerator csgen = new CSGenerator();
  504. csgen.GenerateCode(Environment.CurrentDirectory, entity);
  505. Console.WriteLine("generated ok!");
  506. }
  507. catch (Exception e)
  508. {
  509. Console.WriteLine(e);
  510. Usage();
  511. }
  512. }
  513. }
  514. }