ExpressionParser.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. using System;
  2. using System.Collections.Generic;
  3. using NTERA.EmuEra.Game.EraEmu.GameData.Variable;
  4. using NTERA.EmuEra.Game.EraEmu.Sub;
  5. namespace NTERA.EmuEra.Game.EraEmu.GameData.Expression
  6. {
  7. internal enum ArgsEndWith
  8. {
  9. None,
  10. EoL,
  11. RightParenthesis,//)終端
  12. RightBracket//]終端
  13. }
  14. internal enum TermEndWith
  15. {
  16. None = 0x0000,
  17. EoL = 0x0001,
  18. Comma = 0x0002,//','終端
  19. RightParenthesis = 0x0004,//')'終端
  20. RightBracket = 0x0008,//')'終端
  21. Assignment = 0x0010,//')'終端
  22. RightParenthesis_Comma = RightParenthesis | Comma,//',' or ')'終端
  23. RightBracket_Comma = RightBracket | Comma,//',' or ']'終端
  24. Comma_Assignment = Comma | Assignment,//',' or '='終端
  25. RightParenthesis_Comma_Assignment = RightParenthesis | Comma | Assignment,//',' or ')' or '='終端
  26. RightBracket_Comma_Assignment = RightBracket | Comma | Assignment//',' or ']' or '='終端
  27. }
  28. internal static class ExpressionParser
  29. {
  30. #region public Reduce
  31. /// <summary>
  32. /// カンマで区切られた引数を一括して取得。
  33. /// return時にはendWithの次の文字がCurrentになっているはず。終端の適切さの検証はExpressionParserがが行う。
  34. /// 呼び出し元はCodeEEを適切に処理すること
  35. /// </summary>
  36. /// <returns></returns>
  37. public static IOperandTerm[] ReduceArguments(WordCollection wc, ArgsEndWith endWith, bool isDefine)
  38. {
  39. if(wc == null)
  40. throw new ExeEE("空のストリームを渡された");
  41. List<IOperandTerm> terms = new List<IOperandTerm>();
  42. TermEndWith termEndWith = TermEndWith.EoL;
  43. switch (endWith)
  44. {
  45. case ArgsEndWith.EoL:
  46. termEndWith = TermEndWith.Comma;
  47. break;
  48. //case ArgsEndWith.RightBracket:
  49. // termEndWith = TermEndWith.RightBracket_Comma;
  50. // break;
  51. case ArgsEndWith.RightParenthesis:
  52. termEndWith = TermEndWith.RightParenthesis_Comma;
  53. break;
  54. }
  55. TermEndWith termEndWith_Assignment = termEndWith | TermEndWith.Assignment;
  56. while (true)
  57. {
  58. Word word = wc.Current;
  59. switch (word.Type)
  60. {
  61. case '\0':
  62. if (endWith == ArgsEndWith.RightBracket)
  63. throw new CodeEE("'['に対応する']'が見つかりません");
  64. if (endWith == ArgsEndWith.RightParenthesis)
  65. throw new CodeEE("'('に対応する')'が見つかりません");
  66. goto end;
  67. case ')':
  68. if (endWith == ArgsEndWith.RightParenthesis)
  69. {
  70. wc.ShiftNext();
  71. goto end;
  72. }
  73. throw new CodeEE("構文解析中に予期しない')'を発見しました");
  74. case ']':
  75. if (endWith == ArgsEndWith.RightBracket)
  76. {
  77. wc.ShiftNext();
  78. goto end;
  79. }
  80. throw new CodeEE("構文解析中に予期しない']'を発見しました");
  81. }
  82. if(!isDefine)
  83. terms.Add(ReduceExpressionTerm(wc, termEndWith));
  84. else
  85. {
  86. terms.Add(ReduceExpressionTerm(wc, termEndWith_Assignment));
  87. if (terms[terms.Count - 1] == null)
  88. throw new CodeEE("関数定義の引数は省略できません");
  89. if (wc.Current is OperatorWord)
  90. {//=がある
  91. wc.ShiftNext();
  92. IOperandTerm term = reduceTerm(wc, false, termEndWith, VariableCode.__NULL__);
  93. if (term == null)
  94. throw new CodeEE("'='の後に式がありません");
  95. if (term.GetOperandType() != terms[terms.Count - 1].GetOperandType())
  96. throw new CodeEE("'='の前後で型が一致しません");
  97. terms.Add(term);
  98. }
  99. else
  100. {
  101. if (terms[terms.Count - 1].GetOperandType() == typeof(Int64))
  102. terms.Add(new NullTerm(0));
  103. else
  104. terms.Add(new NullTerm(""));
  105. }
  106. }
  107. if (wc.Current.Type == ',')
  108. wc.ShiftNext();
  109. }
  110. end:
  111. IOperandTerm[] ret = new IOperandTerm[terms.Count];
  112. terms.CopyTo(ret);
  113. return ret;
  114. }
  115. /// <summary>
  116. /// 数式または文字列式。CALLの引数などを扱う。nullを返すことがある。
  117. /// return時にはendWithの文字がCurrentになっているはず。終端の適切さの検証は呼び出し元が行う。
  118. /// </summary>
  119. /// <param name="st"></param>
  120. /// <returns></returns>
  121. public static IOperandTerm ReduceExpressionTerm(WordCollection wc, TermEndWith endWith)
  122. {
  123. IOperandTerm term = reduceTerm(wc, false, endWith, VariableCode.__NULL__);
  124. return term;
  125. }
  126. ///// <summary>
  127. ///// 単純文字列、書式付文字列、文字列式のうち、文字列式を取り扱う。
  128. ///// 終端記号が正しいかどうかは呼び出し元で調べること
  129. ///// </summary>
  130. ///// <param name="st"></param>
  131. ///// <returns></returns>
  132. //public static IOperandTerm ReduceStringTerm(WordCollection wc, TermEndWith endWith)
  133. //{
  134. // IOperandTerm term = reduceTerm(wc, false, endWith, VariableCode.__NULL__);
  135. // if (term.GetOperandType() != typeof(string))
  136. // throw new CodeEE("式の結果が文字列ではありません");
  137. // return term;
  138. //}
  139. public static IOperandTerm ReduceIntegerTerm(WordCollection wc, TermEndWith endwith)
  140. {
  141. IOperandTerm term = reduceTerm(wc, false, endwith, VariableCode.__NULL__);
  142. if (term == null)
  143. throw new CodeEE("構文を式として解釈できません");
  144. if (term.GetOperandType() != typeof(Int64))
  145. throw new CodeEE("式の結果が数値ではありません");
  146. return term;
  147. }
  148. /// <summary>
  149. /// 結果次第ではSingleTermを返すことがある。
  150. /// </summary>
  151. /// <returns></returns>
  152. public static IOperandTerm ToStrFormTerm(StrFormWord sfw)
  153. {
  154. StrForm strf = StrForm.FromWordToken(sfw);
  155. if(strf.IsConst)
  156. return new SingleTerm(strf.GetString(null));
  157. return new StrFormTerm(strf);
  158. }
  159. /// <summary>
  160. /// カンマで区切られたCASEの引数を一括して取得。行端で終わる。
  161. /// </summary>
  162. /// <param name="st"></param>
  163. /// <returns></returns>
  164. public static CaseExpression[] ReduceCaseExpressions(WordCollection wc)
  165. {
  166. List<CaseExpression> terms = new List<CaseExpression>();
  167. while (!wc.EOL)
  168. {
  169. terms.Add(reduceCaseExpression(wc));
  170. wc.ShiftNext();
  171. }
  172. CaseExpression[] ret = new CaseExpression[terms.Count];
  173. terms.CopyTo(ret);
  174. return ret;
  175. }
  176. public static IOperandTerm ReduceVariableArgument(WordCollection wc, VariableCode varCode)
  177. {
  178. IOperandTerm ret = reduceTerm(wc, false, TermEndWith.EoL, varCode);
  179. if(ret == null)
  180. throw new CodeEE("変数の:の後に引数がありません");
  181. return ret;
  182. }
  183. public static VariableToken ReduceVariableIdentifier(WordCollection wc, string idStr)
  184. {
  185. string subId = null;
  186. if (wc.Current.Type == '@')
  187. {
  188. wc.ShiftNext();
  189. IdentifierWord subidWT = wc.Current as IdentifierWord;
  190. if (subidWT == null)
  191. throw new CodeEE("@の使い方が不正です");
  192. wc.ShiftNext();
  193. subId = subidWT.Code;
  194. }
  195. return GlobalStatic.IdentifierDictionary.GetVariableToken(idStr, subId, true);
  196. }
  197. /// <summary>
  198. /// 識別子一つを解決
  199. /// </summary>
  200. /// <param name="wc"></param>
  201. /// <param name="idStr">識別子文字列</param>
  202. /// <param name="varCode">変数の引数の場合はその変数のCode。連想配列的につかう</param>
  203. /// <returns></returns>
  204. private static IOperandTerm reduceIdentifier(WordCollection wc, string idStr, VariableCode varCode)
  205. {
  206. wc.ShiftNext();
  207. SymbolWord symbol = wc.Current as SymbolWord;
  208. if (symbol != null && symbol.Type == '.')
  209. {//名前空間
  210. throw new NotImplCodeEE();
  211. }
  212. if (symbol != null && (symbol.Type == '(' || symbol.Type == '['))
  213. {//関数
  214. wc.ShiftNext();
  215. if (symbol.Type == '[')//1810 多分永久に実装されない
  216. throw new CodeEE("[]を使った機能はまだ実装されていません");
  217. //引数を処理
  218. IOperandTerm[] args = ReduceArguments(wc, ArgsEndWith.RightParenthesis, false);
  219. IOperandTerm mToken = GlobalStatic.IdentifierDictionary.GetFunctionMethod(GlobalStatic.LabelDictionary, idStr, args, false);
  220. if (mToken == null)
  221. {
  222. if (!Program.AnalysisMode)
  223. GlobalStatic.IdentifierDictionary.ThrowException(idStr, true);
  224. else
  225. {
  226. if (GlobalStatic.tempDic.ContainsKey(idStr))
  227. GlobalStatic.tempDic[idStr]++;
  228. else
  229. GlobalStatic.tempDic.Add(idStr, 1);
  230. return new NullTerm(0);
  231. }
  232. }
  233. return mToken;
  234. }
  235. //変数 or キーワード
  236. idStr = idStr.Replace("PARAM","PALAM"); // JVN: cheatsy doodles activate! PARAM becomes PALAM internally, things now work
  237. VariableToken id = ReduceVariableIdentifier(wc, idStr);
  238. if (id != null)//idStrが変数名の場合、
  239. {
  240. if (varCode != VariableCode.__NULL__)//変数の引数が引数を持つことはない
  241. return VariableParser.ReduceVariable(id, null, null, null);
  242. return VariableParser.ReduceVariable(id, wc);
  243. }
  244. //idStrが変数名でない場合、
  245. IOperandTerm refToken = GlobalStatic.IdentifierDictionary.GetFunctionMethod(GlobalStatic.LabelDictionary, idStr, null, false);
  246. if (refToken != null)//関数参照と名前が一致したらそれを返す。実際に使うとエラー
  247. return refToken;
  248. if (varCode != VariableCode.__NULL__ && GlobalStatic.ConstantData.isDefined(varCode, idStr))//連想配列的な可能性アリ
  249. return new SingleTerm(idStr);
  250. GlobalStatic.IdentifierDictionary.ThrowException(idStr, false);
  251. throw new ExeEE("エラー投げ損ねた");//ここまででthrowかreturnのどちらかをするはず。
  252. }
  253. #endregion
  254. #region private reduce
  255. private static CaseExpression reduceCaseExpression(WordCollection wc)
  256. {
  257. CaseExpression ret = new CaseExpression();
  258. IdentifierWord id = wc.Current as IdentifierWord;
  259. if ((id != null) && (id.Code.Equals("IS", Config.Config.SCVariable)))
  260. {
  261. wc.ShiftNext();
  262. ret.CaseType = CaseExpressionType.Is;
  263. OperatorWord opWT = wc.Current as OperatorWord;
  264. if (opWT == null)
  265. throw new CodeEE("ISキーワードの後に演算子がありません");
  266. OperatorCode op = opWT.Code;
  267. if (!OperatorManager.IsBinary(op))
  268. throw new CodeEE("ISキーワードの後の演算子が2項演算子ではありません");
  269. wc.ShiftNext();
  270. ret.Operator = op;
  271. ret.LeftTerm = reduceTerm(wc, false, TermEndWith.Comma, VariableCode.__NULL__);
  272. if (ret.LeftTerm == null)
  273. throw new CodeEE("ISキーワードの後に式がありません");
  274. Type type = ret.LeftTerm.GetOperandType();
  275. return ret;
  276. }
  277. ret.LeftTerm = reduceTerm(wc, true, TermEndWith.Comma, VariableCode.__NULL__);
  278. if (ret.LeftTerm == null)
  279. throw new CodeEE("CASEの引数は省略できません");
  280. id = wc.Current as IdentifierWord;
  281. if ((id != null) && (id.Code.Equals("TO", Config.Config.SCVariable)))
  282. {
  283. ret.CaseType = CaseExpressionType.To;
  284. wc.ShiftNext();
  285. ret.RightTerm = reduceTerm(wc, true, TermEndWith.Comma, VariableCode.__NULL__);
  286. if (ret.RightTerm == null)
  287. throw new CodeEE("TOキーワードの後に式がありません");
  288. id = wc.Current as IdentifierWord;
  289. if ((id != null) && (id.Code.Equals("TO", Config.Config.SCVariable)))
  290. throw new CodeEE("TOキーワードが2度使われています");
  291. if (ret.LeftTerm.GetOperandType() != ret.RightTerm.GetOperandType())
  292. throw new CodeEE("TOキーワードの前後の型が一致していません");
  293. return ret;
  294. }
  295. ret.CaseType = CaseExpressionType.Normal;
  296. return ret;
  297. }
  298. /// <summary>
  299. /// 解析器の本体
  300. /// </summary>
  301. /// <param name="wc"></param>
  302. /// <param name="allowKeywordTo">TOキーワードが見つかっても良いか</param>
  303. /// <param name="endWith">終端記号</param>
  304. /// <returns></returns>
  305. private static IOperandTerm reduceTerm(WordCollection wc, bool allowKeywordTo, TermEndWith endWith, VariableCode varCode)
  306. {
  307. TermStack stack = new TermStack();
  308. //int termCount = 0;
  309. int ternaryCount = 0;
  310. OperatorCode formerOp = OperatorCode.NULL;
  311. bool varArg = varCode != VariableCode.__NULL__;
  312. do
  313. {
  314. Word token = wc.Current;
  315. switch (token.Type)
  316. {
  317. case '\0':
  318. goto end;
  319. case '"'://LiteralStringWT
  320. stack.Add(((LiteralStringWord)token).Str);
  321. break;
  322. case '0'://LiteralIntegerWT
  323. stack.Add(((LiteralIntegerWord)token).Int);
  324. break;
  325. case 'F'://FormattedStringWT
  326. stack.Add(ToStrFormTerm((StrFormWord)token));
  327. break;
  328. case 'A'://IdentifierWT
  329. {
  330. string idStr = (((IdentifierWord)token).Code);
  331. if (idStr.Equals("TO", Config.Config.SCVariable))
  332. {
  333. if (allowKeywordTo)
  334. goto end;
  335. throw new CodeEE("TOキーワードはここでは使用できません");
  336. }
  337. if (idStr.Equals("IS", Config.Config.SCVariable))
  338. throw new CodeEE("ISキーワードはここでは使用できません");
  339. stack.Add(reduceIdentifier(wc, idStr, varCode));
  340. continue;
  341. }
  342. case '='://OperatorWT
  343. {
  344. if (varArg)
  345. throw new CodeEE("変数の引数の読み取り中に予期しない演算子を発見しました");
  346. OperatorCode op = ((OperatorWord)token).Code;
  347. if (op == OperatorCode.Assignment)
  348. {
  349. if ((endWith & TermEndWith.Assignment) == TermEndWith.Assignment)
  350. goto end;
  351. throw new CodeEE("式中で代入演算子'='が使われています(等価比較には'=='を使用してください)");
  352. }
  353. if (formerOp == OperatorCode.Equal || formerOp == OperatorCode.Greater || formerOp == OperatorCode.Less
  354. || formerOp == OperatorCode.GreaterEqual || formerOp == OperatorCode.LessEqual || formerOp == OperatorCode.NotEqual)
  355. {
  356. if (op == OperatorCode.Equal || op == OperatorCode.Greater || op == OperatorCode.Less
  357. || op == OperatorCode.GreaterEqual || op == OperatorCode.LessEqual || op == OperatorCode.NotEqual)
  358. {
  359. ParserMediator.Warn("(構文上の注意)比較演算子が連続しています。", GlobalStatic.Process.GetScaningLine(), 0, false, false);
  360. }
  361. }
  362. stack.Add(op);
  363. formerOp = op;
  364. if (op == OperatorCode.Ternary_a)
  365. ternaryCount++;
  366. else if (op == OperatorCode.Ternary_b)
  367. {
  368. if (ternaryCount > 0)
  369. ternaryCount--;
  370. else
  371. throw new CodeEE("対応する'?'のない'#'です");
  372. }
  373. break;
  374. }
  375. case '(':
  376. wc.ShiftNext();
  377. IOperandTerm inTerm = reduceTerm(wc, false, TermEndWith.RightParenthesis, VariableCode.__NULL__);
  378. if (inTerm == null)
  379. throw new CodeEE("かっこ\"(\"~\")\"の中に式が含まれていません");
  380. stack.Add(inTerm);
  381. if (wc.Current.Type != ')')
  382. throw new CodeEE("対応する')'のない'('です");
  383. //termCount++;
  384. wc.ShiftNext();
  385. continue;
  386. case ')':
  387. if ((endWith & TermEndWith.RightParenthesis) == TermEndWith.RightParenthesis)
  388. goto end;
  389. throw new CodeEE("構文解釈中に予期しない記号'" + token.Type + "'を発見しました");
  390. case ']':
  391. if ((endWith & TermEndWith.RightBracket) == TermEndWith.RightBracket)
  392. goto end;
  393. throw new CodeEE("構文解釈中に予期しない記号'" + token.Type + "'を発見しました");
  394. case ',':
  395. if ((endWith & TermEndWith.Comma) == TermEndWith.Comma)
  396. goto end;
  397. throw new CodeEE("構文解釈中に予期しない記号'" + token.Type + "'を発見しました");
  398. case 'M':
  399. throw new ExeEE("マクロ解決失敗");
  400. default:
  401. throw new CodeEE("構文解釈中に予期しない記号'" + token.Type + "'を発見しました");
  402. }
  403. //termCount++;
  404. wc.ShiftNext();
  405. } while (!varArg);
  406. end:
  407. if (ternaryCount > 0)
  408. throw new CodeEE("'?'と'#'の数が正しく対応していません");
  409. return stack.ReduceAll();
  410. }
  411. #endregion
  412. /// <summary>
  413. /// 式解決用クラス
  414. /// </summary>
  415. private class TermStack
  416. {
  417. /// <summary>
  418. /// 次に来るべきものの種類。
  419. /// (前置)単項演算子か値待ちなら0、二項・三項演算子待ちなら1、値待ちなら2、++、--、!に対応する値待ちの場合は3。
  420. /// </summary>
  421. int state;
  422. bool hasBefore;
  423. bool hasAfter;
  424. bool waitAfter;
  425. Stack<Object> stack = new Stack<Object>();
  426. public void Add(OperatorCode op)
  427. {
  428. if (state == 2 || state == 3)
  429. throw new CodeEE("Unrecognized syntax");
  430. if (state == 0)
  431. {
  432. if (!OperatorManager.IsUnary(op))
  433. throw new CodeEE("Unrecognized syntax");
  434. stack.Push(op);
  435. if (op == OperatorCode.Plus || op == OperatorCode.Minus || op == OperatorCode.BitNot)
  436. state = 2;
  437. else
  438. state = 3;
  439. return;
  440. }
  441. if (state == 1)
  442. {
  443. //後置単項演算子の場合は特殊処理へ
  444. if (OperatorManager.IsUnaryAfter(op))
  445. {
  446. if (hasAfter)
  447. {
  448. hasAfter = false;
  449. throw new CodeEE("後置の単項演算子が複数存在しています");
  450. }
  451. if (hasBefore)
  452. {
  453. hasBefore = false;
  454. throw new CodeEE("インクリメント・デクリメントを前置・後置両方同時に使うことはできません");
  455. }
  456. stack.Push(op);
  457. reduceUnaryAfter();
  458. //前置単項演算子が処理を待っている場合はここで解決
  459. if (waitAfter)
  460. reduceUnary();
  461. hasBefore = false;
  462. hasAfter = true;
  463. waitAfter = false;
  464. return;
  465. }
  466. if (!OperatorManager.IsBinary(op) && !OperatorManager.IsTernary(op))
  467. throw new CodeEE("Unrecognized syntax");
  468. //先に未解決の前置演算子解決
  469. if (waitAfter)
  470. reduceUnary();
  471. int priority = OperatorManager.GetPriority(op);
  472. //直前の計算の優先度が同じか高いなら還元。
  473. while (lastPriority() >= priority)
  474. {
  475. reduceLastThree();
  476. }
  477. stack.Push(op);
  478. state = 0;
  479. waitAfter = false;
  480. hasBefore = false;
  481. hasAfter = false;
  482. return;
  483. }
  484. throw new CodeEE("Unrecognized syntax");
  485. }
  486. public void Add(Int64 i) { Add(new SingleTerm(i)); }
  487. public void Add(string s) { Add(new SingleTerm(s)); }
  488. public void Add(IOperandTerm term)
  489. {
  490. stack.Push(term);
  491. if (state == 1)
  492. throw new CodeEE("Unrecognized syntax");
  493. if (state == 2)
  494. waitAfter = true;
  495. if (state == 3)
  496. {
  497. reduceUnary();
  498. hasBefore = true;
  499. }
  500. state = 1;
  501. }
  502. private int lastPriority()
  503. {
  504. if (stack.Count < 3)
  505. return -1;
  506. object temp = stack.Pop();
  507. OperatorCode opCode = (OperatorCode)stack.Peek();
  508. int priority = OperatorManager.GetPriority(opCode);
  509. stack.Push(temp);
  510. return priority;
  511. }
  512. public IOperandTerm ReduceAll()
  513. {
  514. if (stack.Count == 0)
  515. return null;
  516. if (state != 1)
  517. throw new CodeEE("Unrecognized syntax");
  518. //単項演算子の待ちが未解決の時はここで解決
  519. if (waitAfter)
  520. reduceUnary();
  521. waitAfter = false;
  522. hasBefore = false;
  523. hasAfter = false;
  524. while (stack.Count > 1)
  525. {
  526. reduceLastThree();
  527. }
  528. IOperandTerm retTerm = (IOperandTerm)stack.Pop();
  529. return retTerm;
  530. }
  531. private void reduceUnary()
  532. {
  533. //if (stack.Count < 2)
  534. // throw new ExeEE("不正な時期の呼び出し");
  535. IOperandTerm operand = (IOperandTerm)stack.Pop();
  536. OperatorCode op = (OperatorCode)stack.Pop();
  537. IOperandTerm newTerm = OperatorMethodManager.ReduceUnaryTerm(op, operand);
  538. stack.Push(newTerm);
  539. }
  540. private void reduceUnaryAfter()
  541. {
  542. //if (stack.Count < 2)
  543. // throw new ExeEE("不正な時期の呼び出し");
  544. OperatorCode op = (OperatorCode)stack.Pop();
  545. IOperandTerm operand = (IOperandTerm)stack.Pop();
  546. IOperandTerm newTerm = OperatorMethodManager.ReduceUnaryAfterTerm(op, operand);
  547. stack.Push(newTerm);
  548. }
  549. private void reduceLastThree()
  550. {
  551. //if (stack.Count < 2)
  552. // throw new ExeEE("不正な時期の呼び出し");
  553. IOperandTerm right = (IOperandTerm)stack.Pop();//後から入れたほうが右側
  554. OperatorCode op = (OperatorCode)stack.Pop();
  555. IOperandTerm left = (IOperandTerm)stack.Pop();
  556. if (OperatorManager.IsTernary(op))
  557. {
  558. if (stack.Count > 1)
  559. {
  560. reduceTernary(left, right, op);
  561. return;
  562. }
  563. throw new CodeEE("式の数が不足しています");
  564. }
  565. IOperandTerm newTerm = OperatorMethodManager.ReduceBinaryTerm(op, left, right);
  566. stack.Push(newTerm);
  567. }
  568. private void reduceTernary(IOperandTerm left, IOperandTerm right, OperatorCode op)
  569. {
  570. OperatorCode newOp = (OperatorCode)stack.Pop();
  571. IOperandTerm newLeft = (IOperandTerm)stack.Pop();
  572. IOperandTerm newTerm = OperatorMethodManager.ReduceTernaryTerm(newOp, newLeft, left, right);
  573. stack.Push(newTerm);
  574. }
  575. SingleTerm GetSingle(IOperandTerm oprand)
  576. {
  577. return (SingleTerm)oprand;
  578. }
  579. }
  580. }
  581. }