UserDefinedVariable.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. using System;
  2. using System.Collections.Generic;
  3. using MinorShift.Emuera.GameData.Expression;
  4. using MinorShift.Emuera.Sub;
  5. namespace MinorShift.Emuera.GameProc
  6. {
  7. internal sealed class UserDefinedVariableData
  8. {
  9. public string Name;
  10. public bool TypeIsStr;
  11. public bool Reference;
  12. public int Dimension = 1;
  13. public int[] Lengths;
  14. public Int64[] DefaultInt;
  15. public string[] DefaultStr;
  16. public bool Global;
  17. public bool Save;
  18. public bool Static = true;
  19. public bool Private;
  20. public bool CharaData;
  21. public bool Const;
  22. public static UserDefinedVariableData Create(WordCollection wc, bool dims, bool isPrivate, ScriptPosition sc)
  23. {
  24. string dimtype = dims ? "#DIM" : "#DIMS";
  25. UserDefinedVariableData ret = new UserDefinedVariableData();
  26. ret.TypeIsStr = dims;
  27. IdentifierWord idw = null;
  28. bool staticDefined = false;
  29. ret.Const = false;
  30. string keyword = dimtype;
  31. List<string> keywords = new List<string>();
  32. while (!wc.EOL && (idw = wc.Current as IdentifierWord) != null)
  33. {
  34. wc.ShiftNext();
  35. keyword = idw.Code;
  36. if (Config.ICVariable)
  37. keyword = keyword.ToUpper();
  38. //TODO ifの数があたまわるい なんとかしたい
  39. switch (keyword)
  40. {
  41. case "CONST":
  42. if (ret.CharaData)
  43. throw new CodeEE(keyword + "とCHARADATAキーワードは同時に指定できません", sc);
  44. if (ret.Global)
  45. throw new CodeEE(keyword + "とGLOBALキーワードは同時に指定できません", sc);
  46. if (ret.Save)
  47. throw new CodeEE(keyword + "とSAVEDATAキーワードは同時に指定できません", sc);
  48. if (ret.Reference)
  49. throw new CodeEE(keyword + "とREFキーワードは同時に指定できません", sc);
  50. if (!ret.Static)
  51. throw new CodeEE(keyword + "とDYNAMICキーワードは同時に指定できません", sc);
  52. if (ret.Const)
  53. throw new CodeEE(keyword + "キーワードが二重に指定されています", sc);
  54. ret.Const = true;
  55. break;
  56. case "REF":
  57. //throw new CodeEE("未実装の機能です", sc);
  58. //if (!isPrivate)
  59. // throw new CodeEE("広域変数の宣言に" + keyword + "キーワードは指定できません", sc);
  60. if (staticDefined && ret.Static)
  61. throw new CodeEE(keyword + "とSTATICキーワードは同時に指定できません", sc);
  62. if (ret.CharaData)
  63. throw new CodeEE(keyword + "とCHARADATAキーワードは同時に指定できません", sc);
  64. if (ret.Global)
  65. throw new CodeEE(keyword + "とGLOBALキーワードは同時に指定できません", sc);
  66. if (ret.Save)
  67. throw new CodeEE(keyword + "とSAVEDATAキーワードは同時に指定できません", sc);
  68. if (ret.Const)
  69. throw new CodeEE(keyword + "とCONSTキーワードは同時に指定できません", sc);
  70. if (ret.Reference)
  71. throw new CodeEE(keyword + "キーワードが二重に指定されています", sc);
  72. ret.Reference = true;
  73. ret.Static = true;
  74. break;
  75. case "DYNAMIC":
  76. if (!isPrivate)
  77. throw new CodeEE("広域変数の宣言に" + keyword + "キーワードは指定できません", sc);
  78. if (ret.CharaData)
  79. throw new CodeEE(keyword + "とCHARADATAキーワードは同時に指定できません", sc);
  80. if (ret.Const)
  81. throw new CodeEE(keyword + "とCONSTキーワードは同時に指定できません", sc);
  82. if (staticDefined)
  83. if (ret.Static)
  84. throw new CodeEE("STATICとDYNAMICキーワードは同時に指定できません", sc);
  85. else
  86. throw new CodeEE(keyword + "キーワードが二重に指定されています", sc);
  87. staticDefined = true;
  88. ret.Static = false;
  89. break;
  90. case "STATIC":
  91. if (!isPrivate)
  92. throw new CodeEE("広域変数の宣言に" + keyword + "キーワードは指定できません", sc);
  93. if (ret.CharaData)
  94. throw new CodeEE(keyword + "とCHARADATAキーワードは同時に指定できません", sc);
  95. if (staticDefined)
  96. if (!ret.Static)
  97. throw new CodeEE("STATICとDYNAMICキーワードは同時に指定できません", sc);
  98. else
  99. throw new CodeEE(keyword + "キーワードが二重に指定されています", sc);
  100. if (ret.Reference)
  101. throw new CodeEE(keyword + "とREFキーワードは同時に指定できません", sc);
  102. staticDefined = true;
  103. ret.Static = true;
  104. break;
  105. case "GLOBAL":
  106. if (isPrivate)
  107. throw new CodeEE("ローカル変数の宣言に" + keyword + "キーワードは指定できません", sc);
  108. if (ret.CharaData)
  109. throw new CodeEE(keyword + "とCHARADATAキーワードは同時に指定できません", sc);
  110. if (ret.Reference)
  111. throw new CodeEE(keyword + "とREFキーワードは同時に指定できません", sc);
  112. if (ret.Const)
  113. throw new CodeEE(keyword + "とCONSTキーワードは同時に指定できません", sc);
  114. if (staticDefined)
  115. if (ret.Static)
  116. throw new CodeEE("STATICとGLOBALキーワードは同時に指定できません", sc);
  117. else
  118. throw new CodeEE("DYNAMICとGLOBALキーワードは同時に指定できません", sc);
  119. ret.Global = true;
  120. break;
  121. case "SAVEDATA":
  122. if (isPrivate)
  123. throw new CodeEE("ローカル変数の宣言に" + keyword + "キーワードは指定できません", sc);
  124. if (staticDefined)
  125. if (ret.Static)
  126. throw new CodeEE("STATICとSAVEDATAキーワードは同時に指定できません", sc);
  127. else
  128. throw new CodeEE("DYNAMICとSAVEDATAキーワードは同時に指定できません", sc);
  129. if (ret.Reference)
  130. throw new CodeEE(keyword + "とREFキーワードは同時に指定できません", sc);
  131. if (ret.Const)
  132. throw new CodeEE(keyword + "とCONSTキーワードは同時に指定できません", sc);
  133. if (ret.Save)
  134. throw new CodeEE(keyword + "キーワードが二重に指定されています", sc);
  135. ret.Save = true;
  136. break;
  137. case "CHARADATA":
  138. if (isPrivate)
  139. throw new CodeEE("ローカル変数の宣言に" + keyword + "キーワードは指定できません", sc);
  140. if (ret.Reference)
  141. throw new CodeEE(keyword + "とREFキーワードは同時に指定できません", sc);
  142. if (ret.Const)
  143. throw new CodeEE(keyword + "とCONSTキーワードは同時に指定できません", sc);
  144. if (staticDefined)
  145. if (ret.Static)
  146. throw new CodeEE(keyword + "とSTATICキーワードは同時に指定できません", sc);
  147. else
  148. throw new CodeEE(keyword + "とDYNAMICキーワードは同時に指定できません", sc);
  149. if (ret.Global)
  150. throw new CodeEE(keyword + "とGLOBALキーワードは同時に指定できません", sc);
  151. if (ret.CharaData)
  152. throw new CodeEE(keyword + "キーワードが二重に指定されています", sc);
  153. ret.CharaData = true;
  154. break;
  155. default:
  156. ret.Name = keyword;
  157. goto whilebreak;
  158. }
  159. }
  160. whilebreak:
  161. if (ret.Name == null)
  162. throw new CodeEE(keyword + "の後に有効な変数名が指定されていません", sc);
  163. string errMes = "";
  164. int errLevel = -1;
  165. if (isPrivate)
  166. GlobalStatic.IdentifierDictionary.CheckUserPrivateVarName(ref errMes, ref errLevel, ret.Name);
  167. else
  168. GlobalStatic.IdentifierDictionary.CheckUserVarName(ref errMes, ref errLevel, ret.Name);
  169. if (errLevel >= 0)
  170. {
  171. if (errLevel >= 2)
  172. throw new CodeEE(errMes, sc);
  173. ParserMediator.Warn(errMes, sc, errLevel);
  174. }
  175. List<int> sizeNum = new List<int>();
  176. if (wc.EOL)//サイズ省略
  177. {
  178. if (ret.Const)
  179. throw new CodeEE("CONSTキーワードが指定されていますが初期値が設定されていません");
  180. sizeNum.Add(1);
  181. }
  182. else if (wc.Current.Type == ',')//サイズ指定
  183. {
  184. while (!wc.EOL)
  185. {
  186. if (wc.Current.Type == '=')//サイズ指定解読完了&初期値指定
  187. break;
  188. if (wc.Current.Type != ',')
  189. throw new CodeEE("書式が間違っています", sc);
  190. wc.ShiftNext();
  191. if (ret.Reference)//参照型の場合は要素数不要
  192. {
  193. sizeNum.Add(0);
  194. if (wc.EOL)
  195. break;
  196. if (wc.Current.Type == ',')
  197. continue;
  198. }
  199. if (wc.EOL)
  200. throw new CodeEE("カンマの後に有効な定数式が指定されていません", sc);
  201. IOperandTerm arg = ExpressionParser.ReduceIntegerTerm(wc, TermEndWith.Comma_Assignment);
  202. SingleTerm sizeTerm = arg.Restructure(null) as SingleTerm;
  203. if ((sizeTerm == null) || (sizeTerm.GetOperandType() != typeof(Int64)))
  204. throw new CodeEE("カンマの後に有効な定数式が指定されていません", sc);
  205. if (ret.Reference)//参照型には要素数指定不可(0にするか書かないかどっちか
  206. {
  207. if (sizeTerm.Int != 0)
  208. throw new CodeEE("参照型変数にはサイズを指定できません(サイズを省略するか0を指定してください)", sc);
  209. continue;
  210. }
  211. if ((sizeTerm.Int <= 0) || (sizeTerm.Int > 1000000))
  212. throw new CodeEE("ユーザー定義変数のサイズは1以上1000000以下でなければなりません", sc);
  213. sizeNum.Add((int)sizeTerm.Int);
  214. }
  215. }
  216. if (wc.Current.Type != '=')//初期値指定なし
  217. {
  218. if (ret.Const)
  219. throw new CodeEE("CONSTキーワードが指定されていますが初期値が設定されていません");
  220. }
  221. else//初期値指定あり
  222. {
  223. if (((OperatorWord)wc.Current).Code != OperatorCode.Assignment)
  224. throw new CodeEE("予期しない演算子を発見しました");
  225. if (ret.Reference)
  226. throw new CodeEE("参照型変数には初期値を設定できません");
  227. if (sizeNum.Count >= 2)
  228. throw new CodeEE("多次元変数には初期値を設定できません");
  229. if (ret.CharaData)
  230. throw new CodeEE("キャラ型変数には初期値を設定できません");
  231. int size = 0;
  232. if (sizeNum.Count == 1)
  233. size = sizeNum[0];
  234. wc.ShiftNext();
  235. IOperandTerm[] terms = ExpressionParser.ReduceArguments(wc, ArgsEndWith.EoL, false);
  236. if (terms.Length == 0)
  237. throw new CodeEE("配列の初期値は省略できません");
  238. if (size > 0)
  239. {
  240. if (terms.Length > size)
  241. throw new CodeEE("初期値の数が配列のサイズを超えています");
  242. if (ret.Const && terms.Length != size)
  243. throw new CodeEE("定数の初期値の数が配列のサイズと一致しません");
  244. }
  245. if (dims)
  246. ret.DefaultStr = new string[terms.Length];
  247. else
  248. ret.DefaultInt = new Int64[terms.Length];
  249. for (int i = 0; i < terms.Length; i++)
  250. {
  251. if (terms[i] == null)
  252. throw new CodeEE("配列の初期値は省略できません");
  253. terms[i] = terms[i].Restructure(GlobalStatic.EMediator);
  254. SingleTerm sTerm = terms[i] as SingleTerm;
  255. if (sTerm == null)
  256. throw new CodeEE("配列の初期値には定数のみ指定できます");
  257. if (dims != sTerm.IsString)
  258. throw new CodeEE("変数の型と初期値の型が一致していません");
  259. if (dims)
  260. ret.DefaultStr[i] = sTerm.Str;
  261. else
  262. ret.DefaultInt[i] = sTerm.Int;
  263. }
  264. if (sizeNum.Count == 0)
  265. sizeNum.Add(terms.Length);
  266. }
  267. if (!wc.EOL)
  268. throw new CodeEE("書式が間違っています", sc);
  269. if (sizeNum.Count == 0)
  270. sizeNum.Add(1);
  271. ret.Private = isPrivate;
  272. ret.Dimension = sizeNum.Count;
  273. if (ret.Const && ret.Dimension > 1)
  274. throw new CodeEE("CONSTキーワードが指定された変数を多次元配列にはできません");
  275. if (ret.CharaData && ret.Dimension > 2)
  276. throw new CodeEE("3次元以上のキャラ型変数を宣言することはできません", sc);
  277. if (ret.Dimension > 3)
  278. throw new CodeEE("4次元以上の配列変数を宣言することはできません", sc);
  279. ret.Lengths = new int[sizeNum.Count];
  280. if (ret.Reference)
  281. return ret;
  282. Int64 totalBytes = 1;
  283. for (int i = 0; i < sizeNum.Count; i++)
  284. {
  285. ret.Lengths[i] = sizeNum[i];
  286. totalBytes *= ret.Lengths[i];
  287. }
  288. if ((totalBytes <= 0) || (totalBytes > 1000000))
  289. throw new CodeEE("ユーザー定義変数のサイズは1以上1000000以下でなければなりません", sc);
  290. if (!isPrivate && ret.Save && !Config.SystemSaveInBinary)
  291. {
  292. if (dims && ret.Dimension > 1)
  293. throw new CodeEE("文字列型の多次元配列変数にSAVEDATAフラグを付ける場合には「バイナリ型セーブ」オプションが必須です", sc);
  294. if (ret.CharaData)
  295. throw new CodeEE("キャラ型変数にSAVEDATAフラグを付ける場合には「バイナリ型セーブ」オプションが必須です", sc);
  296. }
  297. return ret;
  298. }
  299. }
  300. }