Process.CalledFunction.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. using System;
  2. using System.Collections.Generic;
  3. using NTERA.EmuEra.Game.EraEmu.Config;
  4. using NTERA.EmuEra.Game.EraEmu.GameData.Expression;
  5. using NTERA.EmuEra.Game.EraEmu.GameData.Function;
  6. using NTERA.EmuEra.Game.EraEmu.GameData.Variable;
  7. using NTERA.EmuEra.Game.EraEmu.Sub;
  8. namespace NTERA.EmuEra.Game.EraEmu.GameProc
  9. {
  10. internal sealed class UserDefinedFunctionArgument
  11. {
  12. public UserDefinedFunctionArgument(IOperandTerm[] srcArgs, VariableTerm[] destArgs)
  13. {
  14. Arguments = srcArgs;
  15. TransporterInt = new Int64[Arguments.Length];
  16. TransporterStr = new string[Arguments.Length];
  17. TransporterRef = new Array[Arguments.Length];
  18. isRef = new bool[Arguments.Length];
  19. for (int i = 0; i < Arguments.Length; i++)
  20. {
  21. isRef[i] = destArgs[i].Identifier.IsReference;
  22. }
  23. }
  24. public readonly IOperandTerm[] Arguments;
  25. public readonly Int64[] TransporterInt;
  26. public readonly string[] TransporterStr;
  27. public readonly Array[] TransporterRef;
  28. public readonly bool[] isRef;
  29. public void SetTransporter(ExpressionMediator exm)
  30. {
  31. for (int i = 0; i < Arguments.Length; i++)
  32. {
  33. if (Arguments[i] == null)
  34. continue;
  35. if (isRef[i])
  36. {
  37. VariableTerm vTerm = (VariableTerm)Arguments[i];
  38. if (vTerm.Identifier.IsCharacterData)
  39. {
  40. Int64 charaNo = vTerm.GetElementInt(0, exm);
  41. if ((charaNo < 0) || (charaNo >= GlobalStatic.VariableData.CharacterList.Count))
  42. throw new CodeEE("Character array variable " + vTerm.Identifier.Name + " at the first argument (" + charaNo + ") is out of range of the character registration number");
  43. TransporterRef[i] = (Array)vTerm.Identifier.GetArrayChara((int)charaNo);
  44. }
  45. else
  46. TransporterRef[i] = (Array)vTerm.Identifier.GetArray();
  47. }
  48. else if (Arguments[i].GetOperandType() == typeof(Int64))
  49. TransporterInt[i] = Arguments[i].GetIntValue(exm);
  50. else
  51. TransporterStr[i] = Arguments[i].GetStrValue(exm);
  52. }
  53. }
  54. public UserDefinedFunctionArgument Restructure(ExpressionMediator exm, bool tryTranslate=false)
  55. {
  56. for (int i = 0; i < Arguments.Length; i++)
  57. {
  58. if (Arguments[i] == null)
  59. continue;
  60. if(isRef[i])
  61. Arguments[i].Restructure(exm);
  62. else
  63. Arguments[i] = Arguments[i].Restructure(exm);
  64. }
  65. return this;
  66. }
  67. }
  68. /// <summary>
  69. /// 現在呼び出し中の関数
  70. /// イベント関数を除いて実行中に内部状態は変化しないので使いまわしても良い
  71. /// </summary>
  72. internal sealed class CalledFunction
  73. {
  74. private CalledFunction(string label) { FunctionName = label; }
  75. public static CalledFunction CallEventFunction(Process parent, string label, LogicalLine retAddress)
  76. {
  77. CalledFunction called = new CalledFunction(label);
  78. List<FunctionLabelLine> newLabelList = new List<FunctionLabelLine>();
  79. called.Finished = false;
  80. called.eventLabelList = parent.LabelDictionary.GetEventLabels(label);
  81. if (called.eventLabelList == null)
  82. {
  83. FunctionLabelLine line = parent.LabelDictionary.GetNonEventLabel(label);
  84. if (parent.LabelDictionary.GetNonEventLabel(label) != null)
  85. {
  86. throw new CodeEE("イベント関数でない関数@" + label + "(" + line.Position.Filename + ":" + line.Position.LineNo + "行目)に対しEVENT呼び出しが行われました");
  87. }
  88. return null;
  89. }
  90. called.counter = -1;
  91. called.group = 0;
  92. called.ShiftNext();
  93. called.TopLabel = called.CurrentLabel;
  94. called.returnAddress = retAddress;
  95. called.IsEvent = true;
  96. return called;
  97. }
  98. public static CalledFunction CallFunction(Process parent, string label, LogicalLine retAddress)
  99. {
  100. CalledFunction called = new CalledFunction(label);
  101. called.Finished = false;
  102. FunctionLabelLine labelline = parent.LabelDictionary.GetNonEventLabel(label);
  103. if (labelline == null)
  104. {
  105. if (parent.LabelDictionary.GetEventLabels(label) != null)
  106. {
  107. throw new CodeEE("イベント関数@" + label + "に対し通常のCALLが行われました(このエラーは互換性オプション「" + Config.Config.GetConfigName(ConfigCode.CompatiCallEvent) + "」により無視できます)");
  108. }
  109. return null;
  110. }
  111. if (labelline.IsMethod)
  112. {
  113. throw new CodeEE("#FUCNTION(S)が定義された関数@" + labelline.LabelName + "(" + labelline.Position.Filename + ":" + labelline.Position.LineNo + "行目)に対し通常のCALLが行われました");
  114. }
  115. called.TopLabel = labelline;
  116. called.CurrentLabel = labelline;
  117. called.returnAddress = retAddress;
  118. called.IsEvent = false;
  119. return called;
  120. }
  121. public static CalledFunction CreateCalledFunctionMethod(FunctionLabelLine labelline, string label)
  122. {
  123. CalledFunction called = new CalledFunction(label);
  124. called.TopLabel = labelline;
  125. called.CurrentLabel = labelline;
  126. called.returnAddress = null;
  127. called.IsEvent = false;
  128. return called;
  129. }
  130. static FunctionMethod tostrMethod;
  131. /// <summary>
  132. /// 1803beta005 予め引数の数を合わせて規定値を代入しておく
  133. /// 1806+v6.99 式中関数の引数に無効な#DIM変数を与えている場合に例外になるのを修正
  134. /// 1808beta009 REF型に対応
  135. /// </summary>
  136. public UserDefinedFunctionArgument ConvertArg(IOperandTerm[] srcArgs, out string errMes)
  137. {
  138. errMes = null;
  139. if (TopLabel.IsError)
  140. {
  141. errMes = TopLabel.ErrMes;
  142. return null;
  143. }
  144. FunctionLabelLine func = TopLabel;
  145. IOperandTerm[] convertedArg = new IOperandTerm[func.Arg.Length];
  146. if(convertedArg.Length < srcArgs.Length)
  147. {
  148. errMes = "引数の数が関数\"@" + func.LabelName + "\"に設定された数を超えています";
  149. return null;
  150. }
  151. IOperandTerm term = null;
  152. VariableTerm destArg = null;
  153. bool isString = false;
  154. for (int i = 0; i < func.Arg.Length; i++)
  155. {
  156. term = (i < srcArgs.Length) ? srcArgs[i] : null;
  157. destArg = func.Arg[i];
  158. isString = destArg.IsString;
  159. if (destArg.Identifier.IsReference)//参照渡しの場合
  160. {
  161. if (term == null)
  162. {
  163. errMes = "\"@" + func.LabelName + "\"の" + (i + 1) + "番目の引数は参照渡しのため省略できません";
  164. return null;
  165. }
  166. VariableTerm vTerm = term as VariableTerm;
  167. if (vTerm == null || vTerm.Identifier.Dimension == 0)
  168. {
  169. errMes = "\"@" + func.LabelName + "\"の" + (i + 1) + "番目の引数は参照渡しのための配列変数でなければなりません";
  170. return null;
  171. }
  172. //TODO 1810alpha007 キャラ型を認めるかどうかはっきりしたい 今のところ認めない方向
  173. //型チェック
  174. if (!((ReferenceToken)destArg.Identifier).MatchType(vTerm.Identifier, false, out errMes))
  175. {
  176. errMes = "\"@" + func.LabelName + "\"の" + (i + 1) + "番目の引数:" + errMes;
  177. return null;
  178. }
  179. }
  180. else if (term == null)//引数が省略されたとき
  181. {
  182. term = func.Def[i];//デフォルト値を代入
  183. //1808beta001 デフォルト値がない場合はエラーにする
  184. //一応逃がす
  185. if (term == null && !Config.Config.CompatiFuncArgOptional)
  186. {
  187. errMes = "\"@" + func.LabelName + "\"の" + (i + 1) + "番目の引数は省略できません(この警告は互換性オプション「" + Config.Config.GetConfigName(ConfigCode.CompatiFuncArgOptional) + "」により無視できます)";
  188. return null;
  189. }
  190. }
  191. else if (term.GetOperandType() != destArg.GetOperandType())
  192. {
  193. if (term.GetOperandType() == typeof(string))
  194. {
  195. errMes = "\"@" + func.LabelName + "\"の" + (i + 1) + "番目の引数を文字列型から整数型に変換できません";
  196. return null;
  197. }
  198. if (!Config.Config.CompatiFuncArgAutoConvert)
  199. {
  200. errMes = "\"@" + func.LabelName + "\"の" + (i + 1) + "番目の引数を整数型から文字列型に変換できません(この警告は互換性オプション「" + Config.Config.GetConfigName(ConfigCode.CompatiFuncArgAutoConvert) + "」により無視できます)";
  201. return null;
  202. }
  203. if (tostrMethod == null)
  204. tostrMethod = FunctionMethodCreator.GetMethodList()["TOSTR"];
  205. term = new FunctionMethodTerm(tostrMethod, new[] { term });
  206. }
  207. convertedArg[i] = term;
  208. }
  209. return new UserDefinedFunctionArgument(convertedArg, func.Arg);
  210. }
  211. public LogicalLine CallLabel(Process parent, string label)
  212. {
  213. return parent.LabelDictionary.GetLabelDollar(label, CurrentLabel);
  214. }
  215. public void updateRetAddress(LogicalLine line)
  216. {
  217. returnAddress = line;
  218. }
  219. public CalledFunction Clone()
  220. {
  221. CalledFunction called = new CalledFunction(FunctionName);
  222. called.eventLabelList = eventLabelList;
  223. called.CurrentLabel = CurrentLabel;
  224. called.TopLabel = TopLabel;
  225. called.group = group;
  226. called.IsEvent = IsEvent;
  227. called.counter = counter;
  228. called.returnAddress = returnAddress;
  229. return called;
  230. }
  231. List<FunctionLabelLine>[] eventLabelList;
  232. public FunctionLabelLine CurrentLabel { get; private set; }
  233. public FunctionLabelLine TopLabel { get; private set; }
  234. int counter = -1;
  235. int group;
  236. LogicalLine returnAddress;
  237. public readonly string FunctionName = "";
  238. public bool IsJump { get; set; }
  239. public bool Finished { get; private set; }
  240. public LogicalLine ReturnAddress => returnAddress;
  241. public bool IsEvent{get; private set;}
  242. public bool HasSingleFlag
  243. {
  244. get
  245. {
  246. if (CurrentLabel == null)
  247. return false;
  248. return CurrentLabel.IsSingle;
  249. }
  250. }
  251. #region イベント関数専用
  252. public void ShiftNext()
  253. {
  254. while (true)
  255. {
  256. counter++;
  257. if (eventLabelList[group].Count > counter)
  258. {
  259. CurrentLabel = (eventLabelList[group])[counter];
  260. return;
  261. }
  262. group++;
  263. counter = -1;
  264. if (group >= 4)
  265. {
  266. CurrentLabel = null;
  267. return;
  268. }
  269. }
  270. }
  271. public void ShiftNextGroup()
  272. {
  273. counter = -1;
  274. group++;
  275. if (group >= 4)
  276. {
  277. CurrentLabel = null;
  278. return;
  279. }
  280. ShiftNext();
  281. }
  282. public void FinishEvent()
  283. {
  284. group = 4;
  285. counter = -1;
  286. CurrentLabel = null;
  287. }
  288. public bool IsOnly => CurrentLabel.IsOnly;
  289. #endregion
  290. }
  291. }