UserDefinedFunction.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. using System.Collections.Generic;
  2. using NTERA.EmuEra.Game.EraEmu.GameData;
  3. using NTERA.EmuEra.Game.EraEmu.Sub;
  4. namespace NTERA.EmuEra.Game.EraEmu.GameProc
  5. {
  6. internal enum UserDifinedFunctionDataArgType
  7. {
  8. Null,
  9. Int = 0x10,
  10. Str = 0x20,
  11. RefInt1 = 0x51,
  12. RefInt2 = 0x52,
  13. RefInt3 = 0x53,
  14. RefStr1 = 0x61,
  15. RefStr2 = 0x62,
  16. RefStr3 = 0x63,
  17. __Ref = 0x40,
  18. __Dimention = 0x0F
  19. }
  20. internal sealed class UserDefinedFunctionData
  21. {
  22. private UserDefinedFunctionData()
  23. {
  24. }
  25. public string Name;
  26. public bool TypeIsStr;
  27. public UserDifinedFunctionDataArgType[] ArgList;
  28. public static UserDefinedFunctionData Create(WordCollection wc, bool dims, ScriptPosition sc)
  29. {
  30. string dimtype = dims ? "#FUNCTION" : "#FUNCTIONS";
  31. UserDefinedFunctionData ret = new UserDefinedFunctionData();
  32. ret.TypeIsStr = dims;
  33. IdentifierWord idw = null;
  34. string keyword = dimtype;
  35. while (!wc.EOL && (idw = wc.Current as IdentifierWord) != null)
  36. {
  37. wc.ShiftNext();
  38. keyword = idw.Code;
  39. if (Config.Config.ICVariable)
  40. keyword = keyword.ToUpper();
  41. switch (keyword)
  42. {
  43. case "CONST":
  44. case "REF":
  45. case "DYNAMIC":
  46. case "STATIC":
  47. case "GLOBAL":
  48. case "SAVEDATA":
  49. case "CHARADATA":
  50. throw new CodeEE(dims + "中では" + keyword + "キーワードは指定できません", sc);
  51. default:
  52. ret.Name = keyword;
  53. goto whilebreak;
  54. }
  55. }
  56. whilebreak:
  57. if (ret.Name == null)
  58. throw new CodeEE(keyword + "の後に有効な識別子が指定されていません", sc);
  59. if (wc.EOL || wc.Current.Type != '(')
  60. throw new CodeEE("識別子の後に引数定義がありません", sc);
  61. string errMes = "";
  62. int errLevel = -1;
  63. GlobalStatic.IdentifierDictionary.CheckUserLabelName(ref errMes, ref errLevel, true, ret.Name);
  64. if (errLevel == 0)//関数と変数の両方からチェック エラーメッセージが微妙だがひとまず気にしない
  65. GlobalStatic.IdentifierDictionary.CheckUserVarName(ref errMes, ref errLevel, ret.Name);
  66. if (errLevel >= 0)
  67. {
  68. if (errLevel >= 2)
  69. throw new CodeEE(errMes, sc);
  70. ParserMediator.Warn(errMes, sc, errLevel);
  71. }
  72. List<UserDifinedFunctionDataArgType> argList = new List<UserDifinedFunctionDataArgType>();
  73. UserDifinedFunctionDataArgType argType = UserDifinedFunctionDataArgType.Null;
  74. int state = 0;
  75. //0=初期状態 1=カンマ括弧閉じ待ち 2=カンマ直後
  76. //3=REF後INTorSTR待ち 4=':'or','待ち 5=':'or '0'or ','待ち
  77. while (true)// REF INT STR 0 '*' ',' ')' のみで構成されるはず
  78. {
  79. wc.ShiftNext();
  80. switch (wc.Current.Type)
  81. {
  82. case '\0':
  83. throw new CodeEE("括弧が閉じられていません", sc);
  84. case ')':
  85. if (state == 0 || state == 1)
  86. goto argend;
  87. if (state == 4 || state == 5)
  88. {
  89. if ((int)(argType & UserDifinedFunctionDataArgType.__Dimention) == 0)
  90. throw new CodeEE("REF引数は配列変数でなければなりません", sc);
  91. state = 2;
  92. argList.Add(argType);
  93. goto argend;
  94. }
  95. throw new CodeEE("予期しない括弧です", sc);
  96. case '0':
  97. if (((LiteralIntegerWord)wc.Current).Int != 0)
  98. goto argerr;
  99. if (state == 5)
  100. {
  101. state = 4;
  102. continue;
  103. }
  104. goto argerr;
  105. case ':':
  106. if (state == 4 || state == 5)
  107. {
  108. state = 5;
  109. argType++; if ((int)(argType & UserDifinedFunctionDataArgType.__Dimention) > 3)
  110. throw new CodeEE("REF引数は4次元以上の配列にできません", sc);
  111. continue;
  112. }
  113. goto argerr;
  114. case ',':
  115. if (state == 1)
  116. {
  117. state = 2;
  118. continue;
  119. }
  120. if (state == 4 || state == 5)
  121. {
  122. if ((int)(argType & UserDifinedFunctionDataArgType.__Dimention) == 0)
  123. throw new CodeEE("REF引数は配列変数でなければなりません", sc);
  124. state = 2;
  125. argList.Add(argType);
  126. continue;
  127. }
  128. goto argerr;
  129. case 'A':
  130. {
  131. string str = ((IdentifierWord)wc.Current).Code;
  132. if (Config.Config.ICVariable)
  133. str = str.ToUpper();
  134. if (str == "REF")
  135. {
  136. if (state == 0 || state == 2)
  137. {
  138. state = 3;
  139. continue;
  140. }
  141. goto argerr;
  142. }
  143. if (str == "INT" || str == "STR")
  144. {
  145. if (str == "INT")
  146. argType = UserDifinedFunctionDataArgType.Int;
  147. else
  148. argType = UserDifinedFunctionDataArgType.Str;
  149. if (state == 0 || state == 2)
  150. {
  151. state = 1;
  152. argList.Add(argType);
  153. continue;
  154. }
  155. if (state == 3)
  156. {
  157. argType = argType | UserDifinedFunctionDataArgType.__Ref;
  158. state = 4;
  159. continue;
  160. }
  161. goto argerr;
  162. }
  163. goto argerr;
  164. }
  165. default:
  166. goto argerr;
  167. }
  168. }
  169. argend:
  170. wc.ShiftNext();
  171. if (!wc.EOL)
  172. throw new CodeEE("宣言の後に余分な文字があります", sc);
  173. ret.ArgList = new UserDifinedFunctionDataArgType[argList.Count];
  174. argList.CopyTo(ret.ArgList);
  175. return ret;
  176. argerr:
  177. if (!wc.EOL)
  178. throw new CodeEE("引数の解析中に予期しないトークン" + wc.Current + "を発見しました", sc);
  179. throw new CodeEE("引数の解析中にエラーが発生しました", sc);
  180. }
  181. }
  182. }