Process.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Windows.Forms;
  5. using NTERA.Core;
  6. using NTERA.EmuEra.Game.EraEmu.Config;
  7. using NTERA.EmuEra.Game.EraEmu.Content;
  8. using NTERA.EmuEra.Game.EraEmu.GameData;
  9. using NTERA.EmuEra.Game.EraEmu.GameData.Expression;
  10. using NTERA.EmuEra.Game.EraEmu.GameData.Function;
  11. using NTERA.EmuEra.Game.EraEmu.GameData.Variable;
  12. using NTERA.EmuEra.Game.EraEmu.GameProc.Function;
  13. using NTERA.EmuEra.Game.EraEmu.Sub;
  14. namespace NTERA.EmuEra.Game.EraEmu.GameProc
  15. {
  16. internal sealed partial class Process
  17. {
  18. public Process(IConsole view)
  19. {
  20. console = view;
  21. }
  22. public LogicalLine getCurrentLine => state.CurrentLine;
  23. /// <summary>
  24. /// @~~と$~~を集めたもの。CALL命令などで使う
  25. /// 実行順序はLogicalLine自身が保持する。
  26. /// </summary>
  27. LabelDictionary labelDic;
  28. public LabelDictionary LabelDictionary => labelDic;
  29. /// <summary>
  30. /// 変数全部。スクリプト中で必要になる変数は(ユーザーが直接触れないものも含め)この中にいれる
  31. /// </summary>
  32. private VariableEvaluator vEvaluator;
  33. public VariableEvaluator VEvaluator => vEvaluator;
  34. private ExpressionMediator exm;
  35. private GameBase gamebase;
  36. readonly IConsole console;
  37. private IdentifierDictionary idDic;
  38. ProcessState state;
  39. ProcessState originalState;//リセットする時のために
  40. bool noError;
  41. //色々あって復活させてみる
  42. bool initialiing;
  43. public bool inInitializeing => initialiing;
  44. public bool Initialize()
  45. {
  46. LexicalAnalyzer.UseMacro = false;
  47. state = new ProcessState(console);
  48. originalState = state;
  49. initialiing = true;
  50. #if !DEBUG
  51. try
  52. {
  53. #endif
  54. ParserMediator.Initialize(console);
  55. if (ParserMediator.HasWarning)
  56. {
  57. ParserMediator.FlushWarningList();
  58. if(MessageBox.Show("There is a problem with the config file.\nWould you like to close Emuera?","Config Error", MessageBoxButtons.YesNo)
  59. == DialogResult.Yes)
  60. {
  61. console.PrintSystemLine("Processing was terminated because there was a problem with the config file and exit was selected");
  62. return false;
  63. }
  64. }
  65. AppContents.LoadContents();
  66. if (Config.Config.UseKeyMacro && !Program.AnalysisMode)
  67. {
  68. if (File.Exists(Program.ExeDir + "macro.txt"))
  69. {
  70. if (Config.Config.DisplayReport)
  71. console.PrintSystemLine("Loading macro.txt...");
  72. KeyMacro.LoadMacroFile(Program.ExeDir + "macro.txt");
  73. }
  74. }
  75. if (Config.Config.UseReplaceFile && !Program.AnalysisMode)
  76. {
  77. if (File.Exists(Program.CsvDir + "_Replace.csv"))
  78. {
  79. if (Config.Config.DisplayReport)
  80. console.PrintSystemLine("Loading _Replace.csv...");
  81. ConfigData.Instance.LoadReplaceFile(Program.CsvDir + "_Replace.csv");
  82. if (ParserMediator.HasWarning)
  83. {
  84. ParserMediator.FlushWarningList();
  85. if (MessageBox.Show("Abnormality is found in _Replace.csv.\nWould you like to close Emuera?", "_Replace.csv Error", MessageBoxButtons.YesNo)
  86. == DialogResult.Yes)
  87. {
  88. console.PrintSystemLine("Processing was terminated because _Replace.csv file had an error and exit was selected");
  89. return false;
  90. }
  91. }
  92. }
  93. }
  94. Config.Config.SetReplace(ConfigData.Instance);
  95. //ここでBARを設定すれば、いいことに気づいた予感
  96. console.setStBar(Config.Config.DrawLineString);
  97. if (Config.Config.UseRenameFile)
  98. {
  99. if (File.Exists(Program.CsvDir + "_Rename.csv"))
  100. {
  101. if (Config.Config.DisplayReport || Program.AnalysisMode)
  102. console.PrintSystemLine("Loading _Rename.csv...");
  103. ParserMediator.LoadEraExRenameFile(Program.CsvDir + "_Rename.csv");
  104. }
  105. else
  106. console.PrintError("csv\\_Rename.csv is missing");
  107. }
  108. if (!Config.Config.DisplayReport)
  109. {
  110. console.PrintSingleLine(Config.Config.LoadLabel);
  111. console.RefreshStrings(true);
  112. }
  113. gamebase = new GameBase();
  114. if (!gamebase.LoadGameBaseCsv(Program.CsvDir + "GAMEBASE.CSV"))
  115. {
  116. console.PrintSystemLine("Processing was terminated because a problem occurred while loading GAMEBASE.CSV");
  117. return false;
  118. }
  119. console.SetWindowTitle(gamebase.ScriptWindowTitle);
  120. GlobalStatic.GameBaseData = gamebase;
  121. ConstantData constant = new ConstantData(gamebase);
  122. constant.LoadData(Program.CsvDir, console, Config.Config.DisplayReport);
  123. GlobalStatic.ConstantData = constant;
  124. _trainName = constant.GetCsvNameList(VariableCode.TRAINNAME);
  125. vEvaluator = new VariableEvaluator(gamebase, constant);
  126. GlobalStatic.VEvaluator = vEvaluator;
  127. idDic = new IdentifierDictionary(vEvaluator.VariableData);
  128. GlobalStatic.IdentifierDictionary = idDic;
  129. StrForm.Initialize();
  130. VariableParser.Initialize();
  131. exm = new ExpressionMediator(this, vEvaluator, console);
  132. GlobalStatic.EMediator = exm;
  133. labelDic = new LabelDictionary();
  134. GlobalStatic.LabelDictionary = labelDic;
  135. HeaderFileLoader hLoader = new HeaderFileLoader(console, idDic, this);
  136. LexicalAnalyzer.UseMacro = false;
  137. if (!hLoader.LoadHeaderFiles(Program.ErbDir, Config.Config.DisplayReport))
  138. {
  139. console.PrintSystemLine("Processing was terminated because a problem occurred while loading ERH files");
  140. return false;
  141. }
  142. LexicalAnalyzer.UseMacro = idDic.UseMacro();
  143. ErbLoader loader = new ErbLoader(console, exm, this);
  144. if (Program.AnalysisMode)
  145. noError = loader.LoadErbs(Program.AnalysisFiles, labelDic);
  146. else
  147. noError = loader.LoadErbFiles(Program.ErbDir, Config.Config.DisplayReport, labelDic);
  148. InitSystemProcess();
  149. initialiing = false;
  150. #if !DEBUG
  151. }
  152. catch (Exception e)
  153. {
  154. handleException(e, null, true);
  155. console.PrintSystemLine("Processing was terminated because a fatal error has occurred during initialization");
  156. return false;
  157. }
  158. #endif
  159. if (labelDic == null)
  160. {
  161. return false;
  162. }
  163. state.Begin(BeginType.TITLE);
  164. GC.Collect();
  165. return true;
  166. }
  167. public void ReloadErb()
  168. {
  169. saveCurrentState(false);
  170. state.SystemState = SystemStateCode.System_Reloaderb;
  171. ErbLoader loader = new ErbLoader(console, exm, this);
  172. loader.LoadErbFiles(Program.ErbDir, false, labelDic);
  173. console.ReadAnyKey();
  174. }
  175. public void ReloadPartialErb(List<string> path)
  176. {
  177. saveCurrentState(false);
  178. state.SystemState = SystemStateCode.System_Reloaderb;
  179. ErbLoader loader = new ErbLoader(console, exm, this);
  180. loader.LoadErbs(path, labelDic);
  181. console.ReadAnyKey();
  182. }
  183. public void SetCommnds(Int64 count)
  184. {
  185. coms = new List<long>((int)count);
  186. isCTrain = true;
  187. Int64[] selectcom = vEvaluator.SELECTCOM_ARRAY;
  188. if (count >= selectcom.Length)
  189. {
  190. throw new CodeEE("The value of the arguments of the CALLTRAIN instruction exceeds the number of SELECTCOM elements");
  191. }
  192. for (int i = 0; i < (int)count; i++)
  193. {
  194. coms.Add(selectcom[i + 1]);
  195. }
  196. }
  197. public bool ClearCommands()
  198. {
  199. coms.Clear();
  200. count = 0;
  201. isCTrain = false;
  202. skipPrint = true;
  203. return (CallFunction("CALLTRAINEND", false, false));
  204. }
  205. public void InputInteger(Int64 i)
  206. {
  207. vEvaluator.RESULT = i;
  208. }
  209. public void InputSystemInteger(Int64 i)
  210. {
  211. _systemResult = i;
  212. }
  213. public void InputString(string s)
  214. {
  215. vEvaluator.RESULTS = s;
  216. }
  217. public void DoScript()
  218. {
  219. state.lineCount = 0;
  220. bool systemProcRunning = true;
  221. try
  222. {
  223. while (true)
  224. {
  225. methodStack = 0;
  226. systemProcRunning = true;
  227. while (state.ScriptEnd && console.IsRunning)
  228. RunSystemProc();
  229. if (!console.IsRunning)
  230. break;
  231. systemProcRunning = false;
  232. runScriptProc(true);
  233. }
  234. }
  235. catch (Exception ec)
  236. {
  237. LogicalLine currentLine = state.ErrorLine;
  238. if (currentLine != null && currentLine is NullLine)
  239. currentLine = null;
  240. if (systemProcRunning)
  241. handleExceptionInSystemProc(ec, currentLine, true);
  242. else
  243. handleException(ec, currentLine, true);
  244. }
  245. }
  246. public void BeginTitle()
  247. {
  248. vEvaluator.ResetData();
  249. state = originalState;
  250. state.Begin(BeginType.TITLE);
  251. }
  252. private void checkInfiniteLoop()
  253. {
  254. //うまく動かない。BEEP音が鳴るのを止められないのでこの処理なかったことに(1.51)
  255. ////フリーズ防止。処理中でも履歴を見たりできる
  256. //System.Windows.Forms.Application.DoEvents();
  257. ////System.Threading.Thread.Sleep(0);
  258. //if (!console.Enabled)
  259. //{
  260. // //DoEvents()の間にウインドウが閉じられたらおしまい。
  261. // console.ReadAnyKey();
  262. // return;
  263. //}
  264. //uint time = WinmmTimer.TickCount - startTime;
  265. //if (time < Config.InfiniteLoopAlertTime)
  266. // return;
  267. //LogicalLine currentLine = state.CurrentLine;
  268. //if ((currentLine == null) || (currentLine is NullLine))
  269. // return;//現在の行が特殊な状態ならスルー
  270. //if (!console.Enabled)
  271. // return;//クローズしてるとMessageBox.Showができないので。
  272. //string caption = "There is a possibility of an infinite loop";
  273. //string text = string.Format(
  274. // "Currently {1} line at {0} is being executed.\nSince the last input {3} milliseconds has passed and the line was executed {2} times.\nWould you like to forcibly terminate processing?",
  275. // currentLine.Position.Filename, currentLine.Position.LineNo, state.lineCount, time);
  276. //DialogResult result = MessageBox.Show(text, caption, MessageBoxButtons.YesNo);
  277. //if (result == DialogResult.Yes)
  278. //{
  279. // throw new CodeEE("Forced termination was selected due to suspected infinite loop");
  280. //}
  281. //state.lineCount = 0;
  282. //startTime = WinmmTimer.TickCount;
  283. }
  284. int methodStack;
  285. public SingleTerm GetValue(SuperUserDefinedMethodTerm udmt,bool translate = false)
  286. {
  287. methodStack++;
  288. if (methodStack > 100)
  289. {
  290. //StackOverflowExceptionはcatchできない上に再現性がないので発生前に一定数で打ち切る。
  291. //環境によっては100以前にStackOverflowExceptionがでるかも?
  292. throw new CodeEE("Call stack of the function has overflowed (is it being recursively called indefinitely?)");
  293. }
  294. SingleTerm ret = null;
  295. int temp_current = state.currentMin;
  296. state.currentMin = state.functionCount;
  297. udmt.Call.updateRetAddress(state.CurrentLine);
  298. try
  299. {
  300. state.IntoFunction(udmt.Call, udmt.Argument, exm);
  301. //do whileの中でthrow されたエラーはここではキャッチされない。
  302. //#functionを全て抜けてDoScriptでキャッチされる。
  303. runScriptProc(translate);
  304. ret = state.MethodReturnValue;
  305. }
  306. finally
  307. {
  308. if (udmt.Call.TopLabel.hasPrivDynamicVar)
  309. udmt.Call.TopLabel.Out();
  310. //1756beta2+v3:こいつらはここにないとデバッグコンソールで式中関数が事故った時に大事故になる
  311. state.currentMin = temp_current;
  312. methodStack--;
  313. }
  314. return ret;
  315. }
  316. public void clearMethodStack()
  317. {
  318. methodStack = 0;
  319. }
  320. public int MethodStack()
  321. {
  322. return methodStack;
  323. }
  324. public ScriptPosition GetRunningPosition()
  325. {
  326. LogicalLine line = state.ErrorLine;
  327. if (line == null)
  328. return null;
  329. return line.Position;
  330. }
  331. private readonly string scaningScope = null;
  332. private string GetScaningScope()
  333. {
  334. if (scaningScope != null)
  335. return scaningScope;
  336. return state.Scope;
  337. }
  338. public LogicalLine scaningLine = null;
  339. internal LogicalLine GetScaningLine()
  340. {
  341. if (scaningLine != null)
  342. return scaningLine;
  343. LogicalLine line = state.ErrorLine;
  344. if (line == null)
  345. return null;
  346. return line;
  347. }
  348. private void handleExceptionInSystemProc(Exception exc, LogicalLine current, bool playSound)
  349. {
  350. console.ThrowError(playSound);
  351. if (exc is CodeEE)
  352. {
  353. console.PrintError("An error has occurred at the end of the function: " + Program.ExeName);
  354. console.PrintError(exc.Message);
  355. }
  356. else if (exc is ExeEE)
  357. {
  358. console.PrintError("An Emuera error has occurred at the end of the function: " + Program.ExeName);
  359. console.PrintError(exc.Message);
  360. }
  361. else
  362. {
  363. console.PrintError("An unexpected error has occurred at the end of the function: " + Program.ExeName);
  364. console.PrintError(exc.GetType() + ":" + exc.Message);
  365. string[] stack = exc.StackTrace.Split('\n');
  366. for (int i = 0; i < stack.Length; i++)
  367. {
  368. console.PrintError(stack[i]);
  369. }
  370. }
  371. }
  372. private void handleException(Exception exc, LogicalLine current, bool playSound)
  373. {
  374. console.ThrowError(playSound);
  375. ScriptPosition position = null;
  376. EmueraException ee = exc as EmueraException;
  377. if((ee != null) && (ee.Position != null))
  378. position = ee.Position;
  379. else if ((current != null) && (current.Position != null))
  380. position = current.Position;
  381. string posString = "";
  382. if (position != null)
  383. {
  384. if (position.LineNo >= 0)
  385. posString = position.Filename + " at line " + position.LineNo + " ";
  386. else
  387. posString = position.Filename + "で";
  388. }
  389. if (exc is CodeEE)
  390. {
  391. if (position != null)
  392. {
  393. InstructionLine procline = current as InstructionLine;
  394. if (procline != null && procline.FunctionCode == FunctionCode.THROW)
  395. {
  396. console.PrintErrorButton(posString + "THROW has occurred");
  397. if (position.RowLine != null)
  398. console.PrintError(position.RowLine);
  399. console.PrintError("THROW contents: " + exc.Message);
  400. }
  401. else
  402. {
  403. console.PrintErrorButton(posString + "Error has occurred:" + Program.ExeName);
  404. if (position.RowLine != null)
  405. console.PrintError(position.RowLine);
  406. console.PrintError("Error description: " + exc.Message);
  407. }
  408. console.PrintError("Function: @" + current.ParentLabelLine.LabelName + "(file:" + current.ParentLabelLine.Position.Filename + " in line " + current.ParentLabelLine.Position.LineNo + ")");
  409. console.PrintError("Function call stack: ");
  410. LogicalLine parent = null;
  411. int depth = 0;
  412. while ((parent = state.GetReturnAddressSequensial(depth++)) != null)
  413. {
  414. if (parent.Position != null)
  415. {
  416. console.PrintErrorButton("↑" + parent.Position.Filename + " at line " + parent.Position.LineNo + "(function@" + parent.ParentLabelLine.LabelName + ")");
  417. }
  418. }
  419. }
  420. else
  421. {
  422. console.PrintError(posString + "Error has occurred: " + Program.ExeName);
  423. console.PrintError(exc.Message);
  424. }
  425. }
  426. else if (exc is ExeEE)
  427. {
  428. console.PrintError(posString + "Emuera has encountered an error: " + Program.ExeName);
  429. console.PrintError(exc.Message);
  430. }
  431. else
  432. {
  433. console.PrintError(posString + "Unexpected error has occurred: " + Program.ExeName);
  434. console.PrintError(exc.GetType() + ":" + exc.Message);
  435. string[] stack = exc.StackTrace.Split('\n');
  436. for (int i = 0; i < stack.Length; i++)
  437. {
  438. console.PrintError(stack[i]);
  439. }
  440. }
  441. }
  442. }
  443. }