using System; using System.Collections.Generic; using System.IO; using System.Windows.Forms; using NTERA.Core; using NTERA.EmuEra.Game.EraEmu.Config; using NTERA.EmuEra.Game.EraEmu.Content; using NTERA.EmuEra.Game.EraEmu.GameData; using NTERA.EmuEra.Game.EraEmu.GameData.Expression; using NTERA.EmuEra.Game.EraEmu.GameData.Function; using NTERA.EmuEra.Game.EraEmu.GameData.Variable; using NTERA.EmuEra.Game.EraEmu.GameProc.Function; using NTERA.EmuEra.Game.EraEmu.Sub; namespace NTERA.EmuEra.Game.EraEmu.GameProc { internal sealed partial class Process { public Process(IConsole view) { console = view; } public LogicalLine getCurrentLine => state.CurrentLine; /// /// @~~と$~~を集めたもの。CALL命令などで使う /// 実行順序はLogicalLine自身が保持する。 /// LabelDictionary labelDic; public LabelDictionary LabelDictionary => labelDic; /// /// 変数全部。スクリプト中で必要になる変数は(ユーザーが直接触れないものも含め)この中にいれる /// private VariableEvaluator vEvaluator; public VariableEvaluator VEvaluator => vEvaluator; private ExpressionMediator exm; private GameBase gamebase; readonly IConsole console; private IdentifierDictionary idDic; ProcessState state; ProcessState originalState;//リセットする時のために bool noError; //色々あって復活させてみる bool initialiing; public bool inInitializeing => initialiing; public bool Initialize() { LexicalAnalyzer.UseMacro = false; state = new ProcessState(console); originalState = state; initialiing = true; #if !DEBUG try { #endif ParserMediator.Initialize(console); if (ParserMediator.HasWarning) { ParserMediator.FlushWarningList(); if(MessageBox.Show("There is a problem with the config file.\nWould you like to close Emuera?","Config Error", MessageBoxButtons.YesNo) == DialogResult.Yes) { console.PrintSystemLine("Processing was terminated because there was a problem with the config file and exit was selected"); return false; } } AppContents.LoadContents(); if (Config.Config.UseKeyMacro && !Program.AnalysisMode) { if (File.Exists(Program.ExeDir + "macro.txt")) { if (Config.Config.DisplayReport) console.PrintSystemLine("Loading macro.txt..."); KeyMacro.LoadMacroFile(Program.ExeDir + "macro.txt"); } } if (Config.Config.UseReplaceFile && !Program.AnalysisMode) { if (File.Exists(Program.CsvDir + "_Replace.csv")) { if (Config.Config.DisplayReport) console.PrintSystemLine("Loading _Replace.csv..."); ConfigData.Instance.LoadReplaceFile(Program.CsvDir + "_Replace.csv"); if (ParserMediator.HasWarning) { ParserMediator.FlushWarningList(); if (MessageBox.Show("Abnormality is found in _Replace.csv.\nWould you like to close Emuera?", "_Replace.csv Error", MessageBoxButtons.YesNo) == DialogResult.Yes) { console.PrintSystemLine("Processing was terminated because _Replace.csv file had an error and exit was selected"); return false; } } } } Config.Config.SetReplace(ConfigData.Instance); //ここでBARを設定すれば、いいことに気づいた予感 console.setStBar(Config.Config.DrawLineString); if (Config.Config.UseRenameFile) { if (File.Exists(Program.CsvDir + "_Rename.csv")) { if (Config.Config.DisplayReport || Program.AnalysisMode) console.PrintSystemLine("Loading _Rename.csv..."); ParserMediator.LoadEraExRenameFile(Program.CsvDir + "_Rename.csv"); } else console.PrintError("csv\\_Rename.csv is missing"); } if (!Config.Config.DisplayReport) { console.PrintSingleLine(Config.Config.LoadLabel); console.RefreshStrings(true); } gamebase = new GameBase(); if (!gamebase.LoadGameBaseCsv(Program.CsvDir + "GAMEBASE.CSV")) { console.PrintSystemLine("Processing was terminated because a problem occurred while loading GAMEBASE.CSV"); return false; } console.SetWindowTitle(gamebase.ScriptWindowTitle); GlobalStatic.GameBaseData = gamebase; ConstantData constant = new ConstantData(gamebase); constant.LoadData(Program.CsvDir, console, Config.Config.DisplayReport); GlobalStatic.ConstantData = constant; _trainName = constant.GetCsvNameList(VariableCode.TRAINNAME); vEvaluator = new VariableEvaluator(gamebase, constant); GlobalStatic.VEvaluator = vEvaluator; idDic = new IdentifierDictionary(vEvaluator.VariableData); GlobalStatic.IdentifierDictionary = idDic; StrForm.Initialize(); VariableParser.Initialize(); exm = new ExpressionMediator(this, vEvaluator, console); GlobalStatic.EMediator = exm; labelDic = new LabelDictionary(); GlobalStatic.LabelDictionary = labelDic; HeaderFileLoader hLoader = new HeaderFileLoader(console, idDic, this); LexicalAnalyzer.UseMacro = false; if (!hLoader.LoadHeaderFiles(Program.ErbDir, Config.Config.DisplayReport)) { console.PrintSystemLine("Processing was terminated because a problem occurred while loading ERH files"); return false; } LexicalAnalyzer.UseMacro = idDic.UseMacro(); ErbLoader loader = new ErbLoader(console, exm, this); if (Program.AnalysisMode) noError = loader.LoadErbs(Program.AnalysisFiles, labelDic); else noError = loader.LoadErbFiles(Program.ErbDir, Config.Config.DisplayReport, labelDic); InitSystemProcess(); initialiing = false; #if !DEBUG } catch (Exception e) { handleException(e, null, true); console.PrintSystemLine("Processing was terminated because a fatal error has occurred during initialization"); return false; } #endif if (labelDic == null) { return false; } state.Begin(BeginType.TITLE); GC.Collect(); return true; } public void ReloadErb() { saveCurrentState(false); state.SystemState = SystemStateCode.System_Reloaderb; ErbLoader loader = new ErbLoader(console, exm, this); loader.LoadErbFiles(Program.ErbDir, false, labelDic); console.ReadAnyKey(); } public void ReloadPartialErb(List path) { saveCurrentState(false); state.SystemState = SystemStateCode.System_Reloaderb; ErbLoader loader = new ErbLoader(console, exm, this); loader.LoadErbs(path, labelDic); console.ReadAnyKey(); } public void SetCommnds(Int64 count) { coms = new List((int)count); isCTrain = true; Int64[] selectcom = vEvaluator.SELECTCOM_ARRAY; if (count >= selectcom.Length) { throw new CodeEE("The value of the arguments of the CALLTRAIN instruction exceeds the number of SELECTCOM elements"); } for (int i = 0; i < (int)count; i++) { coms.Add(selectcom[i + 1]); } } public bool ClearCommands() { coms.Clear(); count = 0; isCTrain = false; skipPrint = true; return (CallFunction("CALLTRAINEND", false, false)); } public void InputInteger(Int64 i) { vEvaluator.RESULT = i; } public void InputSystemInteger(Int64 i) { _systemResult = i; } public void InputString(string s) { vEvaluator.RESULTS = s; } public void DoScript() { state.lineCount = 0; bool systemProcRunning = true; try { while (true) { methodStack = 0; systemProcRunning = true; while (state.ScriptEnd && console.IsRunning) RunSystemProc(); if (!console.IsRunning) break; systemProcRunning = false; runScriptProc(true); } } catch (Exception ec) { LogicalLine currentLine = state.ErrorLine; if (currentLine != null && currentLine is NullLine) currentLine = null; if (systemProcRunning) handleExceptionInSystemProc(ec, currentLine, true); else handleException(ec, currentLine, true); } } public void BeginTitle() { vEvaluator.ResetData(); state = originalState; state.Begin(BeginType.TITLE); } private void checkInfiniteLoop() { //うまく動かない。BEEP音が鳴るのを止められないのでこの処理なかったことに(1.51) ////フリーズ防止。処理中でも履歴を見たりできる //System.Windows.Forms.Application.DoEvents(); ////System.Threading.Thread.Sleep(0); //if (!console.Enabled) //{ // //DoEvents()の間にウインドウが閉じられたらおしまい。 // console.ReadAnyKey(); // return; //} //uint time = WinmmTimer.TickCount - startTime; //if (time < Config.InfiniteLoopAlertTime) // return; //LogicalLine currentLine = state.CurrentLine; //if ((currentLine == null) || (currentLine is NullLine)) // return;//現在の行が特殊な状態ならスルー //if (!console.Enabled) // return;//クローズしてるとMessageBox.Showができないので。 //string caption = "There is a possibility of an infinite loop"; //string text = string.Format( // "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?", // currentLine.Position.Filename, currentLine.Position.LineNo, state.lineCount, time); //DialogResult result = MessageBox.Show(text, caption, MessageBoxButtons.YesNo); //if (result == DialogResult.Yes) //{ // throw new CodeEE("Forced termination was selected due to suspected infinite loop"); //} //state.lineCount = 0; //startTime = WinmmTimer.TickCount; } int methodStack; public SingleTerm GetValue(SuperUserDefinedMethodTerm udmt,bool translate = false) { methodStack++; if (methodStack > 100) { //StackOverflowExceptionはcatchできない上に再現性がないので発生前に一定数で打ち切る。 //環境によっては100以前にStackOverflowExceptionがでるかも? throw new CodeEE("Call stack of the function has overflowed (is it being recursively called indefinitely?)"); } SingleTerm ret = null; int temp_current = state.currentMin; state.currentMin = state.functionCount; udmt.Call.updateRetAddress(state.CurrentLine); try { state.IntoFunction(udmt.Call, udmt.Argument, exm); //do whileの中でthrow されたエラーはここではキャッチされない。 //#functionを全て抜けてDoScriptでキャッチされる。 runScriptProc(translate); ret = state.MethodReturnValue; } finally { if (udmt.Call.TopLabel.hasPrivDynamicVar) udmt.Call.TopLabel.Out(); //1756beta2+v3:こいつらはここにないとデバッグコンソールで式中関数が事故った時に大事故になる state.currentMin = temp_current; methodStack--; } return ret; } public void clearMethodStack() { methodStack = 0; } public int MethodStack() { return methodStack; } public ScriptPosition GetRunningPosition() { LogicalLine line = state.ErrorLine; if (line == null) return null; return line.Position; } private readonly string scaningScope = null; private string GetScaningScope() { if (scaningScope != null) return scaningScope; return state.Scope; } public LogicalLine scaningLine = null; internal LogicalLine GetScaningLine() { if (scaningLine != null) return scaningLine; LogicalLine line = state.ErrorLine; if (line == null) return null; return line; } private void handleExceptionInSystemProc(Exception exc, LogicalLine current, bool playSound) { console.ThrowError(playSound); if (exc is CodeEE) { console.PrintError("An error has occurred at the end of the function: " + Program.ExeName); console.PrintError(exc.Message); } else if (exc is ExeEE) { console.PrintError("An Emuera error has occurred at the end of the function: " + Program.ExeName); console.PrintError(exc.Message); } else { console.PrintError("An unexpected error has occurred at the end of the function: " + Program.ExeName); console.PrintError(exc.GetType() + ":" + exc.Message); string[] stack = exc.StackTrace.Split('\n'); for (int i = 0; i < stack.Length; i++) { console.PrintError(stack[i]); } } } private void handleException(Exception exc, LogicalLine current, bool playSound) { console.ThrowError(playSound); ScriptPosition position = null; EmueraException ee = exc as EmueraException; if((ee != null) && (ee.Position != null)) position = ee.Position; else if ((current != null) && (current.Position != null)) position = current.Position; string posString = ""; if (position != null) { if (position.LineNo >= 0) posString = position.Filename + " at line " + position.LineNo + " "; else posString = position.Filename + "で"; } if (exc is CodeEE) { if (position != null) { InstructionLine procline = current as InstructionLine; if (procline != null && procline.FunctionCode == FunctionCode.THROW) { console.PrintErrorButton(posString + "THROW has occurred"); if (position.RowLine != null) console.PrintError(position.RowLine); console.PrintError("THROW contents: " + exc.Message); } else { console.PrintErrorButton(posString + "Error has occurred:" + Program.ExeName); if (position.RowLine != null) console.PrintError(position.RowLine); console.PrintError("Error description: " + exc.Message); } console.PrintError("Function: @" + current.ParentLabelLine.LabelName + "(file:" + current.ParentLabelLine.Position.Filename + " in line " + current.ParentLabelLine.Position.LineNo + ")"); console.PrintError("Function call stack: "); LogicalLine parent = null; int depth = 0; while ((parent = state.GetReturnAddressSequensial(depth++)) != null) { if (parent.Position != null) { console.PrintErrorButton("↑" + parent.Position.Filename + " at line " + parent.Position.LineNo + "(function@" + parent.ParentLabelLine.LabelName + ")"); } } } else { console.PrintError(posString + "Error has occurred: " + Program.ExeName); console.PrintError(exc.Message); } } else if (exc is ExeEE) { console.PrintError(posString + "Emuera has encountered an error: " + Program.ExeName); console.PrintError(exc.Message); } else { console.PrintError(posString + "Unexpected error has occurred: " + Program.ExeName); console.PrintError(exc.GetType() + ":" + exc.Message); string[] stack = exc.StackTrace.Split('\n'); for (int i = 0; i < stack.Length; i++) { console.PrintError(stack[i]); } } } } }