UserDefinedFunction.cs 5.2 KB

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