LogicalLineParser.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Media;
  5. using NTERA.Core;
  6. using NTERA.EmuEra.Game.EraEmu.Config;
  7. using NTERA.EmuEra.Game.EraEmu.GameData;
  8. using NTERA.EmuEra.Game.EraEmu.GameData.Expression;
  9. using NTERA.EmuEra.Game.EraEmu.GameProc.Function;
  10. using NTERA.EmuEra.Game.EraEmu.Sub;
  11. namespace NTERA.EmuEra.Game.EraEmu.GameProc
  12. {
  13. internal static class LogicalLineParser
  14. {
  15. public static bool ParseSharpLine(FunctionLabelLine label, StringStream st, ScriptPosition position, List<string> OnlyLabel)
  16. {
  17. st.ShiftNext();//'#'を飛ばす
  18. string token = LexicalAnalyzer.ReadSingleIdentifier(st);//#~自体にはマクロ非適用
  19. if (Config.Config.ICFunction)
  20. token = token.ToUpper();
  21. //#行として不正な行でもAnalyzeに行って引っかかることがあるので、先に存在しない#~は弾いてしまう
  22. if (token == null || (token != "SINGLE" && token != "LATER" && token != "PRI" && token != "ONLY" && token != "FUNCTION" && token != "FUNCTIONS"
  23. && token != "LOCALSIZE" && token != "LOCALSSIZE" && token != "DIM" && token != "DIMS"))
  24. {
  25. ParserMediator.Warn("解釈できない#行です", position, 1);
  26. return false;
  27. }
  28. try
  29. {
  30. WordCollection wc = LexicalAnalyzer.Analyse(st, LexEndWith.EoL, LexAnalyzeFlag.AllowAssignment);
  31. switch (token)
  32. {
  33. case "SINGLE":
  34. if (label.IsMethod)
  35. {
  36. ParserMediator.Warn("式中関数では#SINGLEは機能しません", position, 1);
  37. break;
  38. }
  39. else if (!label.IsEvent)
  40. {
  41. ParserMediator.Warn("イベント関数以外では#SINGLEは機能しません", position, 1);
  42. break;
  43. }
  44. else if (label.IsSingle)
  45. {
  46. ParserMediator.Warn("#SINGLEが重複して使われています", position, 1);
  47. break;
  48. }
  49. else if (label.IsOnly)
  50. {
  51. ParserMediator.Warn("#ONLYが指定されたイベント関数では#SINGLEは機能しません", position, 1);
  52. break;
  53. }
  54. label.IsSingle = true;
  55. break;
  56. case "LATER":
  57. if (label.IsMethod)
  58. {
  59. ParserMediator.Warn("式中関数では#LATERは機能しません", position, 1);
  60. break;
  61. }
  62. else if (!label.IsEvent)
  63. {
  64. ParserMediator.Warn("イベント関数以外では#LATERは機能しません", position, 1);
  65. break;
  66. }
  67. else if (label.IsLater)
  68. {
  69. ParserMediator.Warn("#LATERが重複して使われています", position, 1);
  70. break;
  71. }
  72. else if (label.IsOnly)
  73. {
  74. ParserMediator.Warn("#ONLYが指定されたイベント関数では#LATERは機能しません", position, 1);
  75. break;
  76. }
  77. else if (label.IsPri)
  78. ParserMediator.Warn("#PRIと#LATERが重複して使われています(この関数は2度呼ばれます)", position, 1);
  79. label.IsLater = true;
  80. break;
  81. case "PRI":
  82. if (label.IsMethod)
  83. {
  84. ParserMediator.Warn("式中関数では#PRIは機能しません", position, 1);
  85. break;
  86. }
  87. else if (!label.IsEvent)
  88. {
  89. ParserMediator.Warn("イベント関数以外では#PRIは機能しません", position, 1);
  90. break;
  91. }
  92. else if (label.IsPri)
  93. {
  94. ParserMediator.Warn("#PRIが重複して使われています", position, 1);
  95. break;
  96. }
  97. else if (label.IsOnly)
  98. {
  99. ParserMediator.Warn("#ONLYが指定されたイベント関数では#PRIは機能しません", position, 1);
  100. break;
  101. }
  102. else if (label.IsLater)
  103. ParserMediator.Warn("#PRIと#LATERが重複して使われています(この関数は2度呼ばれます)", position, 1);
  104. label.IsPri = true;
  105. break;
  106. case "ONLY":
  107. if (label.IsMethod)
  108. {
  109. ParserMediator.Warn("式中関数では#ONLYは機能しません", position, 1);
  110. break;
  111. }
  112. else if (!label.IsEvent)
  113. {
  114. ParserMediator.Warn("イベント関数以外では#ONLYは機能しません", position, 1);
  115. break;
  116. }
  117. else if (label.IsOnly)
  118. {
  119. ParserMediator.Warn("#ONLYが重複して使われています", position, 1);
  120. break;
  121. }
  122. else if (OnlyLabel.Contains(label.LabelName))
  123. ParserMediator.Warn("このイベント関数\"@" + label.LabelName + "\"にはすでに#ONLYが宣言されています(この関数は実行されません)", position, 1);
  124. OnlyLabel.Add(label.LabelName);
  125. label.IsOnly = true;
  126. if (label.IsPri)
  127. {
  128. ParserMediator.Warn("このイベント関数には#PRIが宣言されていますが無視されます", position, 1);
  129. label.IsPri = false;
  130. }
  131. if (label.IsLater)
  132. {
  133. ParserMediator.Warn("このイベント関数には#LATERが宣言されていますが無視されます", position, 1);
  134. label.IsLater = false;
  135. }
  136. if (label.IsSingle)
  137. {
  138. ParserMediator.Warn("このイベント関数には#SINGLEが宣言されていますが無視されます", position, 1);
  139. label.IsSingle = false;
  140. }
  141. break;
  142. case "FUNCTION":
  143. case "FUNCTIONS":
  144. if (!string.IsNullOrEmpty(label.LabelName) && char.IsDigit(label.LabelName[0]))
  145. {
  146. ParserMediator.Warn("#" + token + "属性は関数名が数字で始まる関数には指定できません", position, 1);
  147. label.IsError = true;
  148. label.ErrMes = "関数名が数字で始まっています";
  149. break;
  150. }
  151. if (label.IsMethod)
  152. {
  153. if ((label.MethodType == typeof(Int64) && token == "FUNCTION") || (label.MethodType == typeof(string) && token == "FUNCTIONS"))
  154. {
  155. ParserMediator.Warn("関数" + label.LabelName + "にはすでに#" + token + "が宣言されています(この行は無視されます)", position, 1);
  156. return false;
  157. }
  158. if (label.MethodType == typeof(Int64) && token == "FUNCTIONS")
  159. ParserMediator.Warn("関数" + label.LabelName + "にはすでに#FUNCTIONが宣言されています", position, 2);
  160. else if (label.MethodType == typeof(string) && token == "FUNCTION")
  161. ParserMediator.Warn("関数" + label.LabelName + "にはすでに#FUNCTIONSが宣言されています", position, 2);
  162. return false;
  163. }
  164. if (label.Depth == 0)
  165. {
  166. ParserMediator.Warn("システム関数に#" + token + "が指定されています", position, 2);
  167. return false;
  168. }
  169. label.IsMethod = true;
  170. label.Depth = 0;
  171. if (token == "FUNCTIONS")
  172. label.MethodType = typeof(string);
  173. else
  174. label.MethodType = typeof(Int64);
  175. if (label.IsPri)
  176. {
  177. ParserMediator.Warn("式中関数では#PRIは機能しません", position, 1);
  178. label.IsPri = false;
  179. }
  180. if (label.IsLater)
  181. {
  182. ParserMediator.Warn("式中関数では#LATERは機能しません", position, 1);
  183. label.IsLater = false;
  184. }
  185. if (label.IsSingle)
  186. {
  187. ParserMediator.Warn("式中関数では#SINGLEは機能しません", position, 1);
  188. label.IsSingle = false;
  189. }
  190. if (label.IsOnly)
  191. {
  192. ParserMediator.Warn("式中関数では#ONLYは機能しません", position, 1);
  193. label.IsOnly = false;
  194. }
  195. break;
  196. case "LOCALSIZE":
  197. case "LOCALSSIZE":
  198. {
  199. if (wc.EOL)
  200. {
  201. ParserMediator.Warn("#" + token + "の後に有効な数値が指定されていません", position, 2);
  202. break;
  203. }
  204. //イベント関数では指定しても無視される
  205. if (label.IsEvent)
  206. {
  207. ParserMediator.Warn("イベント関数では#" + token + "による" + token.Substring(0, token.Length - 4)+ "のサイズ指定は無視されます", position, 1);
  208. break;
  209. }
  210. IOperandTerm arg = ExpressionParser.ReduceIntegerTerm(wc, TermEndWith.EoL);
  211. SingleTerm sizeTerm = arg.Restructure(null) as SingleTerm;
  212. if ((sizeTerm == null) || (sizeTerm.GetOperandType() != typeof(Int64)))
  213. {
  214. ParserMediator.Warn("#" + token + "の後に有効な定数式が指定されていません", position, 2);
  215. break;
  216. }
  217. if (sizeTerm.Int <= 0)
  218. {
  219. ParserMediator.Warn("#" + token + "に0以下の値(" + sizeTerm.Int + ")が与えられました。設定は無視されます", position, 1);
  220. break;
  221. }
  222. if (sizeTerm.Int >= Int32.MaxValue)
  223. {
  224. ParserMediator.Warn("#" + token + "に大きすぎる値(" + sizeTerm.Int + ")が与えられました。設定は無視されます", position, 1);
  225. break;
  226. }
  227. int size = (int)sizeTerm.Int;
  228. if (token == "LOCALSIZE")
  229. {
  230. if (GlobalStatic.IdentifierDictionary.getLocalIsForbid("LOCAL"))
  231. {
  232. ParserMediator.Warn("#" + token + "が指定されていますが変数LOCALは使用禁止されています", position, 2);
  233. break;
  234. }
  235. if (label.LocalLength > 0)
  236. ParserMediator.Warn("この関数にはすでに#LOCALSIZEが定義されています。(以前の定義は無視されます)", position, 1);
  237. label.LocalLength = size;
  238. }
  239. else
  240. {
  241. if (GlobalStatic.IdentifierDictionary.getLocalIsForbid("LOCALS"))
  242. {
  243. ParserMediator.Warn("#" + token + "が指定されていますが変数LOCALSは使用禁止されています", position, 2);
  244. break;
  245. }
  246. if (label.LocalsLength > 0)
  247. ParserMediator.Warn("この関数にはすでに#LOCALSSIZEが定義されています。(以前の定義は無視されます)", position, 1);
  248. label.LocalsLength = size;
  249. }
  250. }
  251. break;
  252. case "DIM":
  253. case "DIMS":
  254. {
  255. UserDefinedVariableData data = UserDefinedVariableData.Create(wc, token == "DIMS", true, position);
  256. if (!label.AddPrivateVariable(data))
  257. {
  258. ParserMediator.Warn("変数名" + data.Name + "は既に使用されています", position, 2);
  259. return false;
  260. }
  261. break;
  262. }
  263. default:
  264. ParserMediator.Warn("解釈できない#行です", position, 1);
  265. break;
  266. }
  267. if (!wc.EOL)
  268. ParserMediator.Warn("#の識別子の後に余分な文字があります", position, 1);
  269. }
  270. catch (Exception e)
  271. {
  272. ParserMediator.Warn(e.Message, position, 2);
  273. goto err;
  274. }
  275. return true;
  276. err:
  277. return false;
  278. }
  279. public static LogicalLine ParseLine(string str, IConsole console)
  280. {
  281. ScriptPosition position = new ScriptPosition(str);
  282. StringStream stream = new StringStream(str);
  283. return ParseLine(stream, position, console);
  284. }
  285. public static LogicalLine ParseLabelLine(StringStream stream, ScriptPosition position, IConsole console)
  286. {
  287. bool isFunction = (stream.Current == '@');
  288. int lineNo = position.LineNo;
  289. string labelName = "";
  290. string errMes = "";
  291. try
  292. {
  293. int warnLevel = -1;
  294. stream.ShiftNext();//@か$を除去
  295. WordCollection wc = LexicalAnalyzer.Analyse(stream, LexEndWith.EoL, LexAnalyzeFlag.AllowAssignment);
  296. if (wc.EOL || !(wc.Current is IdentifierWord))
  297. {
  298. errMes = "関数名が不正であるか存在しません";
  299. goto err;
  300. }
  301. labelName = ((IdentifierWord)wc.Current).Code;
  302. wc.ShiftNext();
  303. if (Config.Config.ICVariable)
  304. labelName = labelName.ToUpper();
  305. GlobalStatic.IdentifierDictionary.CheckUserLabelName(ref errMes, ref warnLevel, isFunction, labelName);
  306. if (warnLevel >= 0)
  307. {
  308. if (warnLevel >= 2)
  309. goto err;
  310. ParserMediator.Warn(errMes, position, warnLevel);
  311. }
  312. if (!isFunction)//$ならこの時点で終了
  313. {
  314. if (!wc.EOL)
  315. ParserMediator.Warn("$で始まるラベルに引数が設定されています", position, 1);
  316. return new GotoLabelLine(position, labelName);
  317. }
  318. //labelName = LexicalAnalyzer.ReadString(stream, StrEndWith.LeftParenthesis_Bracket_Comma_Semicolon);
  319. //labelName = labelName.Trim();
  320. //if (Config.ICVariable)
  321. // labelName = labelName.ToUpper();
  322. //GlobalStatic.IdentifierDictionary.CheckUserLabelName(ref errMes, ref warnLevel, isFunction, labelName);
  323. //if(warnLevel >= 0)
  324. //{
  325. // if (warnLevel >= 2)
  326. // goto err;
  327. // ParserMediator.Warn(errMes, position, warnLevel);
  328. //}
  329. //if (!isFunction)//$ならこの時点で終了
  330. //{
  331. // LexicalAnalyzer.SkipWhiteSpace(stream);
  332. // if (!stream.EOS)
  333. // ParserMediator.Warn("$で始まるラベルに引数が設定されています", position, 1);
  334. // return new GotoLabelLine(position, labelName);
  335. //}
  336. ////関数名部分に_renameを使えないように変更
  337. //if (ParserMediator.RenameDic != null && ((stream.ToString().IndexOf("[[") >= 0) && (stream.ToString().IndexOf("]]") >= 0)))
  338. //{
  339. // string line = stream.ToString();
  340. // foreach (KeyValuePair<string, string> pair in ParserMediator.RenameDic)
  341. // line = line.Replace(pair.Key, pair.Value);
  342. // stream = new StringStream(line);
  343. //}
  344. //WordCollection wc = null;
  345. //wc = LexicalAnalyzer.Analyse(stream, LexEndWith.EoL, LexAnalyzeFlag.AllowAssignment);
  346. if (Program.AnalysisMode)
  347. console.PrintC("@" + labelName, false);
  348. FunctionLabelLine funclabelLine = new FunctionLabelLine(position, labelName, wc);
  349. if (IdentifierDictionary.IsEventLabelName(labelName))
  350. {
  351. funclabelLine.IsEvent = true;
  352. funclabelLine.IsSystem = true;
  353. funclabelLine.Depth = 0;
  354. }
  355. else if (IdentifierDictionary.IsSystemLabelName(labelName))
  356. {
  357. funclabelLine.IsSystem = true;
  358. funclabelLine.Depth = 0;
  359. }
  360. return funclabelLine;
  361. }
  362. catch (CodeEE e)
  363. {
  364. errMes = e.Message;
  365. }
  366. err:
  367. SystemSounds.Hand.Play();
  368. if (isFunction)
  369. {
  370. if(labelName.Length == 0)
  371. labelName = "<Error>";
  372. return new InvalidLabelLine(position, labelName, errMes);
  373. }
  374. return new InvalidLine(position, errMes);
  375. }
  376. public static LogicalLine ParseLine(StringStream stream, ScriptPosition position, IConsole console)
  377. {
  378. int lineNo = position.LineNo;
  379. string errMes = "";
  380. LexicalAnalyzer.SkipWhiteSpace(stream);//先頭のホワイトスペースを読み飛ばす
  381. if (stream.EOS)
  382. return null;
  383. //コメント行かどうかはここに来る前に判定しておく
  384. try
  385. {
  386. #region 前置インクリメント、デクリメント行
  387. if (stream.Current == '+' || stream.Current == '-')
  388. {
  389. char op = stream.Current;
  390. WordCollection wc = LexicalAnalyzer.Analyse(stream, LexEndWith.EoL, LexAnalyzeFlag.None);
  391. OperatorWord opWT = wc.Current as OperatorWord;
  392. if ((opWT == null)|| ((opWT.Code != OperatorCode.Increment) &&(opWT.Code != OperatorCode.Decrement)) )
  393. {
  394. if (op == '+')
  395. errMes = "行が\'+\'から始まっていますが、インクリメントではありません";
  396. else
  397. errMes = "行が\'-\'から始まっていますが、デクリメントではありません";
  398. goto err;
  399. }
  400. wc.ShiftNext();
  401. //token = EpressionParser.単語一個分取得(wc)
  402. //token非変数
  403. //token文字列形
  404. //token変更不可能
  405. //if (wc != EOS)
  406. //
  407. return new InstructionLine(position, FunctionIdentifier.SETFunction, opWT.Code, wc, null);
  408. }
  409. #endregion
  410. IdentifierWord idWT = LexicalAnalyzer.ReadFirstIdentifierWord(stream);
  411. if (idWT != null)
  412. {
  413. FunctionIdentifier func = GlobalStatic.IdentifierDictionary.GetFunctionIdentifier(idWT.Code);
  414. //命令文
  415. if (func != null)//関数文
  416. {
  417. if (stream.EOS) //引数の無い関数
  418. return new InstructionLine(position, func, stream);
  419. if ((stream.Current != ';') && (stream.Current != ' ') && (stream.Current != '\t') && (!Config.Config.SystemAllowFullSpace || (stream.Current != ' ')))
  420. {
  421. if (stream.Current == ' ')
  422. errMes = "命令で行が始まっていますが、命令の直後に半角スペース・タブ以外の文字が来ています(この警告はシステムオプション「" + Config.Config.GetConfigName(ConfigCode.SystemAllowFullSpace) + "」により無視できます)";
  423. else
  424. errMes = "命令で行が始まっていますが、命令の直後に半角スペース・タブ以外の文字が来ています";
  425. goto err;
  426. }
  427. stream.ShiftNext();
  428. return new InstructionLine(position, func, stream);
  429. }
  430. }
  431. LexicalAnalyzer.SkipWhiteSpace(stream);
  432. if (stream.EOS)
  433. {
  434. errMes = "解釈できない行です";
  435. goto err;
  436. }
  437. //命令行ではない→代入行のはず
  438. stream.Seek(0, SeekOrigin.Begin);
  439. OperatorCode assignOP = OperatorCode.NULL;
  440. WordCollection wc1 = LexicalAnalyzer.Analyse(stream, LexEndWith.Operator, LexAnalyzeFlag.None);
  441. //if (idWT != null)
  442. // wc1.Collection.Insert(0, idWT);
  443. try
  444. {
  445. assignOP = LexicalAnalyzer.ReadAssignmentOperator(stream);
  446. }
  447. catch(CodeEE)
  448. {
  449. errMes = "解釈できない行です";
  450. goto err;
  451. }
  452. //eramaker互換警告
  453. //stream.Jump(-1);
  454. //if ((stream.Current != ' ') && (stream.Current != '\t'))
  455. //{
  456. // errMes = "変数で行が始まっていますが、演算子の直前に半角スペースまたはタブがありません";
  457. // goto err;
  458. //}
  459. //stream.ShiftNext();
  460. if (assignOP == OperatorCode.Equal)
  461. {
  462. if (console != null)
  463. ParserMediator.Warn("代入演算子に\"==\"が使われています", position, 0);
  464. //"=="を代入文に使うのは本当はおかしいが結構使われているので仕様にする
  465. assignOP = OperatorCode.Assignment;
  466. }
  467. return new InstructionLine(position, FunctionIdentifier.SETFunction, assignOP, wc1, stream);
  468. err:
  469. return new InvalidLine(position, errMes);
  470. }
  471. catch (CodeEE e)
  472. {
  473. SystemSounds.Hand.Play();
  474. return new InvalidLine(position, e.Message);
  475. }
  476. }
  477. }
  478. }