EXTSEngine.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. using Island.StandardLib;
  2. using Island.StandardLib.Math;
  3. using System;
  4. using System.Collections.Generic;
  5. namespace EXTS
  6. {
  7. public class EXTSEngine
  8. {
  9. internal static EXTSEngine CompilingEngine;
  10. public const string ValError = "err";
  11. public const string ValDefault = "non";
  12. public Dictionary<string, EValue> stdval;
  13. public Dictionary<string, FuncStatement> funcs;
  14. public Dictionary<string, FuncStatement> funcptrs;
  15. public BodyFuncStatement BodyStatement;
  16. public EXTSEngine()
  17. {
  18. stdval = new Dictionary<string, EValue>();
  19. funcs = new Dictionary<string, FuncStatement>();
  20. BodyStatement = new BodyFuncStatement(new Statement[0]);
  21. }
  22. public T AddStatement<T>(T statement) where T : Statement
  23. {
  24. BodyStatement.statements.Add(statement);
  25. return statement;
  26. }
  27. public FuncStatement AddStatement(string name, FuncStatement statement)
  28. {
  29. funcs.Add(name, statement);
  30. return statement;
  31. }
  32. internal Stack<string> func_invoke_stack;
  33. void CheckStackSafe()
  34. {
  35. if (func_invoke_stack.Count > 256)
  36. {
  37. Console.WriteLine("\n-------------------- 运行时错误 --------------------");
  38. Console.WriteLine("当前堆栈深度已超过堆栈的最大允许值为 256 ,程序中存在太多未回收的函数调用。请检查是否存在无限循环递归。");
  39. Console.WriteLine("堆栈列表:");
  40. Console.WriteLine(StkName(func_invoke_stack, true, " -> "));
  41. throw new RuntimeException("当前堆栈深度已超过堆栈的最大允许值为 256 ,程序中存在太多函数调用。请检查是否存在无限循环递归。");
  42. }
  43. }
  44. public EValue RunFuncPtr(string funcptr, EValue[] parameters)
  45. {
  46. if (!funcptrs.ContainsKey(funcptr))
  47. throw new RuntimeException("funcptr not founded.");
  48. FuncStatement fs = funcptrs[funcptr];
  49. fs.runfunc = true;
  50. func_invoke_stack.Push("{ AnonymousFunction }");
  51. CheckStackSafe();
  52. EValue ret = fs.Eval(parameters);
  53. func_invoke_stack.Pop();
  54. fs.runfunc = false;
  55. return ret;
  56. }
  57. public EValue RunFuncBase(string funcName, EValue[] parameters)
  58. {
  59. if (funcName.Contains(":"))
  60. {
  61. string val = funcName.Split(':')[0];
  62. string method = funcName.Split(':')[1];
  63. EValue value = StatementList.runningStatement[val];
  64. if (!value.Defined) throw new RuntimeException($"variable {val} not defined.");
  65. return value.Instance.PassCall(method, parameters);
  66. }
  67. switch (funcName)
  68. {
  69. case "Number":
  70. {
  71. if (parameters.Length == 0)
  72. return new EValue(new ENumber(0));
  73. else if (parameters.Length == 1)
  74. {
  75. ENumber n = parameters[0].As<ENumber>();
  76. if (n == null) throw new RuntimeException("Only can init CLASS with CLASS.");
  77. return new EValue(new ENumber(n.Value));
  78. }
  79. throw new RuntimeException("Number init usage error.");
  80. }
  81. case "Vec3":
  82. {
  83. if (parameters.Length == 0)
  84. return new EValue(new EVec3(new Vector3(0, 0, 0)));
  85. else if (parameters.Length == 1)
  86. {
  87. EVec3 n = parameters[0].As<EVec3>();
  88. if (n == null) throw new RuntimeException("Only can init CLASS with CLASS.");
  89. return new EValue(new EVec3(n.Value));
  90. }
  91. else if (parameters.Length == 3)
  92. {
  93. ENumber[] xyz = parameters.Do((val) => val.As<ENumber>());
  94. if (xyz.Contain(null)) throw new RuntimeException("[Vec3 x,y,z] Request Number parameters");
  95. }
  96. throw new RuntimeException("Vec3 init usage error.");
  97. }
  98. case "String":
  99. {
  100. if (parameters.Length == 0)
  101. return new EValue(new EString(""));
  102. else if (parameters.Length == 1)
  103. {
  104. EString n = parameters[0].As<EString>();
  105. if (n == null) throw new RuntimeException("Only can init CLASS with CLASS.");
  106. return new EValue(new EString(n.Value));
  107. }
  108. throw new RuntimeException("Vec3 init usage error.");
  109. }
  110. case "static":
  111. {
  112. if (parameters.Length == 1)
  113. {
  114. EString v = parameters[0].As<EString>();
  115. if (v == null) throw new RuntimeException("static varname request String class.");
  116. return stdval.Get(v.Value, new EValue());
  117. }
  118. else if (parameters.Length == 2)
  119. {
  120. EString v = parameters[0].As<EString>();
  121. if (v == null) throw new RuntimeException("static varname request String class.");
  122. stdval.Set(v.Value, parameters[1]);
  123. return parameters[1];
  124. }
  125. else throw new RuntimeException("static Usage Error.");
  126. }
  127. case "callfuncptr":
  128. {
  129. if (parameters.Length == 0) throw new RuntimeException("callfuncptr request a parameters.");
  130. EString v = parameters[0].As<EString>();
  131. if (v == null) throw new RuntimeException("callfuncptr usage error.");
  132. return RunFuncPtr(v.Value, parameters.Sub(1, parameters.Length));
  133. }
  134. case "stackinfo":
  135. {
  136. return new EValue(new EString(StkName(func_invoke_stack, true, " -> ")));
  137. }
  138. default:
  139. {
  140. FuncStatement fs = funcs.Get(funcName);
  141. if (fs == null) throw new RuntimeException($"Func {funcName} Not founded");
  142. func_invoke_stack.Push(funcName);
  143. CheckStackSafe();
  144. EValue ret = fs.Eval(parameters);
  145. func_invoke_stack.Pop();
  146. return ret;
  147. }
  148. }
  149. }
  150. string compilingCode;
  151. int compilingPos;
  152. const char EOF = (char)0;
  153. bool InList(char ch, char[] add)
  154. {
  155. for (int i = 0; i < add.Length; i++)
  156. if (ch == add[i]) return true;
  157. return false;
  158. }
  159. bool ChBlank(char ch)
  160. {
  161. if (ch == ' ' || ch == '\t' || ch == '\n') return true;
  162. else return false;
  163. }
  164. bool ChBlankTEOFA(char ch, char[] add)
  165. {
  166. if (ch == ' ' || ch == '\t' || ch == '\n' || ch == EOF || ch == ']') return true;
  167. return InList(ch, add);
  168. }
  169. char Peek()
  170. {
  171. if (compilingPos < compilingCode.Length)
  172. return compilingCode[compilingPos++];
  173. else
  174. {
  175. compilingPos++;
  176. return EOF;
  177. }
  178. }
  179. const string symallowed = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
  180. bool SymAllowed(char c, bool loc)
  181. {
  182. if (loc && (c == '.' || c == ':')) return true;
  183. for (int i = 0; i < symallowed.Length; i++)
  184. if (c == symallowed[i]) return true;
  185. return false;
  186. }
  187. /// <summary>
  188. /// 读取当前位置的字符,直到遇到空白字符和 excludelist 中的字符
  189. /// </summary>
  190. /// <param name="excludelist">被识别为空白字符的附加字符</param>
  191. /// <returns></returns>
  192. string PeekToBlank(params char[] excludelist)
  193. {
  194. string str = "";
  195. char ch;
  196. while (!ChBlankTEOFA(ch = Peek(), excludelist)) str += ch;
  197. compilingPos--;
  198. return str;
  199. }
  200. /// <summary>
  201. /// 读取当前位置的字符,直到遇到空白字符和 excludelist 中的字符,只允许字母数字和下划线输入
  202. /// </summary>
  203. /// <param name="excludelist">被识别为空白字符的附加字符</param>
  204. /// <returns></returns>
  205. string PeekToBlankSym(params char[] excludelist)
  206. {
  207. string str = "";
  208. char ch;
  209. while (!ChBlankTEOFA(ch = Peek(), excludelist))
  210. {
  211. if (!SymAllowed(ch, false)) throw new SyntaxException("在符号定义中,不允许出现字符 " + ch, compilingPos);
  212. str += ch;
  213. }
  214. compilingPos--;
  215. return str;
  216. }
  217. string PeekToBlankLocSym(params char[] excludelist)
  218. {
  219. string str = "";
  220. char ch;
  221. while (!ChBlankTEOFA(ch = Peek(), excludelist))
  222. {
  223. if (!SymAllowed(ch, true)) throw new SyntaxException("在符号定义中,不允许出现字符 " + ch, compilingPos);
  224. str += ch;
  225. }
  226. compilingPos--;
  227. return str;
  228. }
  229. /// <summary>
  230. /// 跳过空白字符和 includelist 中的字符,转到下一个字的前一个位置
  231. /// </summary>
  232. /// <param name="includelist">被识别为空白字符的附加字符</param>
  233. void PeekToWord(params char[] includelist)
  234. {
  235. char ch;
  236. while (ChBlank(ch = Peek()) || InList(ch, includelist)) ;
  237. compilingPos--;
  238. }
  239. string PeekString()
  240. {
  241. string str = "";
  242. char ch;
  243. while (true)
  244. {
  245. ch = Peek();
  246. if (ch == '\\')
  247. {
  248. char ct = Peek();
  249. switch (ct)
  250. {
  251. case 'n': str += '\n'; break;
  252. case 't': str += '\t'; break;
  253. case '\"': str += '\"'; break;
  254. case '\\': str += '\\'; break;
  255. default: throw new SyntaxException("未识别的转义符。", compilingPos);
  256. }
  257. }
  258. if (ch == EOF) throw new SyntaxException("字符串直到文件结尾都未结束,请检查引号是否完整。", compilingPos);
  259. if (ch == '\"')
  260. {
  261. break;
  262. }
  263. str += ch;
  264. }
  265. return str;
  266. }
  267. ImmediateStatement CompileImmediateStatementF()
  268. {
  269. string valstr = PeekToBlank(';');
  270. ImmediateStatement statement = new ImmediateStatement(valstr);
  271. PeekToWord();
  272. return statement;
  273. }
  274. ImmediateStatement CompileImmediateStatementS()
  275. {
  276. ImmediateStatement statement = new ImmediateStatement(PeekString());
  277. PeekToWord();
  278. return statement;
  279. }
  280. GetValStatement CompileGetValStatement()
  281. {
  282. GetValStatement statement = new GetValStatement(currentfunc.Peek(), PeekToBlankSym(';'));
  283. PeekToWord();
  284. return statement;
  285. }
  286. CallFuncStatement CompileCallFuncStatement()
  287. {
  288. List<Statement> pmts = new List<Statement>();
  289. PeekToWord();
  290. string calName = PeekToBlankLocSym('[');
  291. if (calName.Length > 0)
  292. {
  293. if (calName[0] == '.')
  294. {
  295. calName = calName.Substring(1);
  296. func_compile_stack.Push(calName);
  297. calName = StkName(func_compile_stack, true);
  298. func_compile_stack.Pop();
  299. }
  300. }
  301. PeekToWord();
  302. while (true)
  303. {
  304. switch (Peek())
  305. {
  306. case '[': pmts.Add(CompileCallFuncStatement()); break;
  307. case '$': pmts.Add(CompileImmediateStatementF()); break;
  308. case '\"': pmts.Add(CompileImmediateStatementS()); break;
  309. case ':':
  310. {
  311. compilingPos--;
  312. pmts.Add(CompileFuncStatement(currentfunc.Peek() as FuncStatement, true));
  313. break;
  314. }
  315. case ']': return new CallFuncStatement(calName, pmts.ToArray());
  316. case ';': throw new SyntaxException("在函数调用中,意外的语句结束。", compilingPos);
  317. case EOF: throw new SyntaxException("函数调用直到文件结尾都未结束,请检查方括号是否匹配。", compilingPos);
  318. default: compilingPos--; pmts.Add(CompileGetValStatement()); break;
  319. }
  320. PeekToWord();
  321. }
  322. }
  323. SetValStatement CompileSetValStatement(string name)
  324. {
  325. PeekToWord();
  326. Statement valst;
  327. switch (Peek())
  328. {
  329. case '[': valst = CompileCallFuncStatement(); break;
  330. case '$': valst = CompileImmediateStatementF(); break;
  331. case '\"': valst = CompileImmediateStatementS(); break;
  332. case ']': throw new SyntaxException("在赋值语句中,意外的符号 ]。", compilingPos);
  333. case ';': throw new SyntaxException("在赋值语句中,意外的语句结束。", compilingPos);
  334. case EOF: throw new SyntaxException("赋值语句直到文件结尾都未结束,请检查方括号是否匹配。", compilingPos);
  335. default: compilingPos--; valst = CompileGetValStatement(); break;
  336. }
  337. PeekToWord();
  338. char ch = Peek();
  339. if (ch == ';') return new SetValStatement(currentfunc.Peek(), name, valst);
  340. throw new SyntaxException("赋值语句结束后仍然出现语句,请检查是否缺少分号。", compilingPos);
  341. }
  342. string StkName(Stack<string> stk, bool reverse, string link = ".")
  343. {
  344. string b = "";
  345. List<string> r = new List<string>();
  346. foreach (string st in stk)
  347. r.Add(st);
  348. if (reverse) r.Reverse();
  349. for (int i = 0; i < r.Count; i++)
  350. b += r[i] + link;
  351. if (b.Length != 0)
  352. b = b.Substring(0, b.Length - link.Length);
  353. return b;
  354. }
  355. Statement CompileStatement()
  356. {
  357. PeekToWord();
  358. char ch = Peek();
  359. switch (ch)
  360. {
  361. case EOF: throw new SyntaxException("语句直到文件结尾都未结束。", compilingPos);
  362. case ';': throw new SyntaxException("不可分析的语句结尾。", compilingPos);
  363. case '[': return CompileCallFuncStatement();
  364. case '$': return CompileImmediateStatementF();
  365. case '\"': return CompileImmediateStatementS();
  366. default:
  367. {
  368. string name = ch + PeekToBlankSym('=', ';');
  369. PeekToWord();
  370. char p = Peek();
  371. if (p == EOF) throw new SyntaxException("不可分析的文件结尾。", compilingPos);
  372. else if (p == '=') return CompileSetValStatement(name);
  373. else
  374. {
  375. compilingPos--;
  376. return new GetValStatement(currentfunc.Peek(), name);
  377. }
  378. }
  379. }
  380. }
  381. FuncStatement CompileFuncStatement(FuncStatement parent, bool isAnonymousFunc)
  382. {
  383. string funcname = PeekToBlankSym(':', '{');
  384. FuncStatement func = new FuncStatement();
  385. func.runfunc = !isAnonymousFunc;
  386. func.parentVarlst = parent;
  387. currentfunc.Push(func);
  388. func_compile_stack.Push(funcname);
  389. string fullfuncname = StkName(func_compile_stack, true);
  390. func.name = fullfuncname;
  391. PeekToWord();
  392. char t = Peek();
  393. if (t == ':')
  394. {
  395. int i = 0;
  396. while (true)
  397. {
  398. PeekToWord();
  399. char p = Peek();
  400. if (p == EOF) throw new SyntaxException("函数的参数列表直到文件结尾都未结束,请检查函数 " + funcname + " 的定义。", compilingPos);
  401. if (p == '{') break;
  402. compilingPos--;
  403. string varname = PeekToBlankSym();
  404. func.AddStatement(new SetValStatement(func, varname, new GetValStatement(func, "pmt" + i)));
  405. i++;
  406. }
  407. PeekToWord();
  408. }
  409. else if (t == '{')
  410. PeekToWord();
  411. else throw new SyntaxException("错误的函数表达式形式。", compilingPos);
  412. char ch;
  413. while (true)
  414. {
  415. PeekToWord();
  416. ch = Peek();
  417. switch (ch)
  418. {
  419. case EOF:
  420. throw new SyntaxException("函数 " + funcname + " 直到文件结尾都未结束,请检查大括号是否匹配。", compilingPos);
  421. case '}':
  422. func_compile_stack.Pop();
  423. currentfunc.Pop();
  424. if (!isAnonymousFunc)
  425. {
  426. if (funcs.ContainsKey(fullfuncname))
  427. throw new SyntaxException("有一个重复的函数 " + fullfuncname + " 。是否使用重载函数?", compilingPos);
  428. funcs.Add(fullfuncname, func);
  429. }
  430. return func;
  431. case '[':
  432. func.AddStatement(CompileCallFuncStatement());
  433. PeekToWord();
  434. if (Peek() != ';') throw new SyntaxException("函数调用结束后仍然出现语句,请检查是否缺少分号。", compilingPos);
  435. break;
  436. default:
  437. {
  438. string name = ch + PeekToBlankSym('=', ';');
  439. PeekToWord();
  440. char p = Peek();
  441. if (p == EOF) throw new SyntaxException("不可分析的文件结尾。", compilingPos);
  442. else if (p == '=') func.AddStatement(CompileSetValStatement(name));
  443. else
  444. {
  445. compilingPos--;
  446. if (name == "func")
  447. {
  448. if (isAnonymousFunc)
  449. throw new SyntaxException("当前EXTS版本中,在一个匿名函数中定义一个非匿名函数是没有意义的,因为无法确定这个函数的访问标识符,不排除以后的版本中xc会实现。", compilingPos);
  450. CompileFuncStatement(func, isAnonymousFunc);
  451. }
  452. else if (name == "return")
  453. {
  454. PeekToWord();
  455. char e = Peek();
  456. if (e == ';')
  457. {
  458. func.AddStatement(new ReturnStatement());
  459. }
  460. else
  461. {
  462. compilingPos--;
  463. func.AddStatement(new SetValStatement(func, "return", CompileStatement()));
  464. func.AddStatement(new ReturnStatement());
  465. }
  466. }
  467. }
  468. }
  469. break;
  470. }
  471. }
  472. }
  473. Stack<StatementList> currentfunc;
  474. Stack<string> func_compile_stack;
  475. public void Compile(string str)
  476. {
  477. str = str.Replace("\0", "").Replace("\r", "");
  478. CompilingEngine = this;
  479. compilingCode = str;
  480. compilingPos = 0;
  481. currentfunc = new Stack<StatementList>();
  482. currentfunc.Push(BodyStatement);
  483. func_compile_stack = new Stack<string>();
  484. char ch;
  485. while (true)
  486. {
  487. PeekToWord();
  488. ch = Peek();
  489. switch (ch)
  490. {
  491. case EOF:
  492. CompilingEngine = null;
  493. return;
  494. case '[':
  495. currentfunc.Peek().AddStatement(CompileCallFuncStatement());
  496. PeekToWord();
  497. if (Peek() != ';') throw new SyntaxException("函数调用结束后仍然出现语句,请检查是否缺少分号。", compilingPos);
  498. break;
  499. default:
  500. {
  501. string name = ch + PeekToBlankSym('=');
  502. PeekToWord();
  503. char p = Peek();
  504. if (p == EOF) throw new SyntaxException("不可分析的文件结尾。", compilingPos);
  505. else if (p == '=') currentfunc.Peek().AddStatement(CompileSetValStatement(name));
  506. else
  507. {
  508. compilingPos--;
  509. if (name == "func")
  510. {
  511. CompileFuncStatement(null, false);
  512. }
  513. }
  514. }
  515. break;
  516. }
  517. }
  518. }
  519. public void Reset()
  520. {
  521. BodyStatement = new BodyFuncStatement();
  522. funcs = new Dictionary<string, FuncStatement>();
  523. funcptrs = new Dictionary<string, FuncStatement>();
  524. }
  525. public EValue Run(params KeyValuePair<string, EValue>[] pmts)
  526. {
  527. stdval.Clear();
  528. funcptrs = new Dictionary<string, FuncStatement>();
  529. func_invoke_stack = new Stack<string>();
  530. EValue val = BodyStatement.Eval(pmts);
  531. StatementList.runningStatement = null;
  532. return val;
  533. }
  534. }
  535. }