using System.Collections.Generic; using NTERA.Core; using NTERA.EmuEra.Game.EraEmu.GameData; using NTERA.EmuEra.Game.EraEmu.GameData.Variable; using NTERA.EmuEra.Game.EraEmu.Sub; namespace NTERA.EmuEra.Game.EraEmu.GameProc { internal sealed class HeaderFileLoader { public HeaderFileLoader(IConsole main, IdentifierDictionary idDic, Process proc) { output = main; parentProcess = proc; this.idDic = idDic; } readonly Process parentProcess; readonly IConsole output; readonly IdentifierDictionary idDic; bool noError = true; /// /// /// /// /// /// public bool LoadHeaderFiles(string headerDir, bool displayReport) { List> headerFiles = Config.Config.GetFiles(headerDir, "*.ERH"); bool noError = true; try { for (int i = 0; i < headerFiles.Count; i++) { string filename = headerFiles[i].Key; string file = headerFiles[i].Value; if (displayReport) output.PrintSystemLine("Loading " + filename + "..."); noError = loadHeaderFile(file, filename); if (!noError) break; } } finally { ParserMediator.FlushWarningList(); } return noError; } private bool loadHeaderFile(string filepath, string filename) { StringStream st = null; ScriptPosition position = null; //EraStreamReader eReader = new EraStreamReader(false); //1815修正 _rename.csvの適用 //eramakerEXの仕様的には.ERHに適用するのはおかしいけど、もうEmueraの仕様になっちゃってるのでしかたないか EraStreamReader eReader = new EraStreamReader(true); if (!eReader.Open(filepath, filename)) { throw new CodeEE(eReader.Filename + "のオープンに失敗しました"); //return false; } try { while ((st = eReader.ReadEnabledLine()) != null) { if (!noError) return false; position = new ScriptPosition(filename, eReader.LineNo, st.RowString); LexicalAnalyzer.SkipWhiteSpace(st); if (st.Current != '#') throw new CodeEE("ヘッダーの中に#で始まらない行があります", position); st.ShiftNext(); string sharpID = LexicalAnalyzer.ReadSingleIdentifier(st); if (sharpID == null) { ParserMediator.Warn("解釈できない#行です", position, 1); return false; } if (Config.Config.ICFunction) sharpID = sharpID.ToUpper(); LexicalAnalyzer.SkipWhiteSpace(st); switch (sharpID) { case "DEFINE": analyzeSharpDefine(st, position); break; case "FUNCTION": case "FUNCTIONS": analyzeSharpFunction(st, position, sharpID == "FUNCTIONS"); break; case "DIM": case "DIMS": analyzeSharpDim(st, position, sharpID == "DIMS"); break; default: throw new CodeEE("#" + sharpID + "は解釈できないプリプロセッサです", position); } } } catch (CodeEE e) { if (e.Position != null) position = e.Position; ParserMediator.Warn(e.Message, position, 2); return false; } finally { eReader.Close(); } return true; } //#define FOO (~~) id to wc //#define BAR($1) (~~) idwithargs to wc(replaced) //#diseble FOOBAR //#dim piyo, i //#dims puyo, j //static List keywordsList = new List(); private void analyzeSharpDefine(StringStream st, ScriptPosition position) { //LexicalAnalyzer.SkipWhiteSpace(st);呼び出し前に行う。 string srcID = LexicalAnalyzer.ReadSingleIdentifier(st); if (srcID == null) throw new CodeEE("置換元の識別子がありません", position); if (Config.Config.ICVariable) srcID = srcID.ToUpper(); //ここで名称重複判定しないと、大変なことになる string errMes = ""; int errLevel = -1; idDic.CheckUserMacroName(ref errMes, ref errLevel, srcID); if (errLevel >= 0) { ParserMediator.Warn(errMes, position, errLevel); if (errLevel >= 2) { noError = false; return; } } bool hasArg = st.Current == '(';//引数を指定する場合には直後に(が続いていなければならない。ホワイトスペースも禁止。 //1808a3 代入演算子許可(関数宣言用) WordCollection wc = LexicalAnalyzer.Analyse(st, LexEndWith.EoL, LexAnalyzeFlag.AllowAssignment); if (wc.EOL) { //throw new CodeEE("置換先の式がありません", position); //1808a3 空マクロの許可 DefineMacro nullmac = new DefineMacro(srcID, new WordCollection(), 0); idDic.AddMacro(nullmac); return; } List argID = new List(); if (hasArg)//関数型マクロの引数解析 { wc.ShiftNext();//'('を読み飛ばす if (wc.Current.Type == ')') throw new CodeEE("関数型マクロの引数を0個にすることはできません", position); while (!wc.EOL) { IdentifierWord word = wc.Current as IdentifierWord; if (word == null) throw new CodeEE("置換元の引数指定の書式が間違っています", position); word.SetIsMacro(); string id = word.Code; if (argID.Contains(id)) throw new CodeEE("置換元の引数に同じ文字が2回以上使われています", position); argID.Add(id); wc.ShiftNext(); if (wc.Current.Type == ',') { wc.ShiftNext(); continue; } if (wc.Current.Type == ')') break; throw new CodeEE("置換元の引数指定の書式が間違っています", position); } if (wc.EOL) throw new CodeEE("')'が閉じられていません", position); wc.ShiftNext(); } if (wc.EOL) throw new CodeEE("置換先の式がありません", position); WordCollection destWc = new WordCollection(); while (!wc.EOL) { destWc.Add(wc.Current); wc.ShiftNext(); } if (hasArg)//関数型マクロの引数セット { while (!destWc.EOL) { IdentifierWord word = destWc.Current as IdentifierWord; if (word == null) { destWc.ShiftNext(); continue; } for (int i = 0; i < argID.Count; i++) { if (string.Equals(word.Code, argID[i], Config.Config.SCVariable)) { destWc.Remove(); destWc.Insert(new MacroWord(i)); break; } } destWc.ShiftNext(); } destWc.Pointer = 0; } if (hasArg)//1808a3 関数型マクロの封印 throw new CodeEE("関数型マクロは宣言できません", position); DefineMacro mac = new DefineMacro(srcID, destWc, argID.Count); idDic.AddMacro(mac); } private void analyzeSharpDim(StringStream st, ScriptPosition position, bool dims) { WordCollection wc = LexicalAnalyzer.Analyse(st, LexEndWith.EoL, LexAnalyzeFlag.AllowAssignment); UserDefinedVariableData data = UserDefinedVariableData.Create(wc, dims, false, position); if (data.Reference) throw new NotImplCodeEE(); VariableToken var = null; if (data.CharaData) var = parentProcess.VEvaluator.VariableData.CreateUserDefCharaVariable(data); else var = parentProcess.VEvaluator.VariableData.CreateUserDefVariable(data); idDic.AddUseDefinedVariable(var); } private void analyzeSharpFunction(StringStream st, ScriptPosition position, bool funcs) { throw new NotImplCodeEE(); //WordCollection wc = LexicalAnalyzer.Analyse(st, LexEndWith.EoL, LexAnalyzeFlag.AllowAssignment); //UserDefinedFunctionData data = UserDefinedFunctionData.Create(wc, funcs, position); //idDic.AddRefMethod(UserDefinedRefMethod.Create(data)); } } }