// 二項演算 static public ExpressionToken OperateBinary(ExpressionToken value1, ExpressionToken token, ExpressionToken value2) { return new ExpressionToken("", false, ExpressionToken.TokenType.Number, 0, CalcBinary(value1.variable, token, value2.variable)); }
// 二項演算の計算 static object CalcBinary(object value1, ExpressionToken token, object value2) { switch (token.name) { case Prod: // * case Div: // / case Mod: // % case Plus: // + case Minus: // - case Greater: // > case Less: // < case GreaterEq: // >= case LessEq: // <= return CalcBinaryNumber(value1, token, value2); case EqEq: // == case NotEq: // != return CalcBinaryEq(value1, token, value2); case And: // && case Or: // || return CalcBinaryAndOr(value1, token, value2); default: throw new Exception(LanguageErrorMsg.LocalizeTextFormat(Utage.ErrorMsg.ExpressionOperator, token.name)); } }
//逆ポーランド記法に変換 List <ExpressionToken> ToReversePolishNotationSub(List <ExpressionToken> tokens) { List <ExpressionToken> expList = new List <ExpressionToken>(); //返還後のリスト //式を逆ポーランド記法に変換 Stack <ExpressionToken> tmpStack = new Stack <ExpressionToken>(); //演算子用のスタック foreach (ExpressionToken token in tokens) { try { switch (token.Type) { case ExpressionToken.TokenType.Lpa: //左括弧 tmpStack.Push(token); break; case ExpressionToken.TokenType.Rpa: //右括弧 { while (tmpStack.Count != 0) { ExpressionToken last = tmpStack.Peek(); if (ExpressionToken.TokenType.Lpa == last.Type) { tmpStack.Pop(); break; } expList.Add(tmpStack.Pop()); } } break; case ExpressionToken.TokenType.Binary: //演算子 case ExpressionToken.TokenType.Unary: case ExpressionToken.TokenType.Substitution: case ExpressionToken.TokenType.Function: { ExpressionToken last = tmpStack.Peek(); while (tmpStack.Count != 0 && (token.Priority > last.Priority)) { if (ExpressionToken.TokenType.Lpa == last.Type) { break; } expList.Add(last); tmpStack.Pop(); last = tmpStack.Peek(); } tmpStack.Push(token); } break; case ExpressionToken.TokenType.Number: //変数 case ExpressionToken.TokenType.Value: //値 expList.Add(token); break; case ExpressionToken.TokenType.Comma: //カンマ // スタックのトップのトークンが左括弧になるまで // スタック上の演算子を出力キューにポップし続ける while (true) { ExpressionToken last = tmpStack.Peek(); if (ExpressionToken.TokenType.Lpa == last.Type) { break; } expList.Add(tmpStack.Pop()); } break; default: AddErrorMsg(LanguageErrorMsg.LocalizeTextFormat(Utage.ErrorMsg.UnknownType, token.Type.ToString())); break; } } catch (System.Exception e) { AddErrorMsg(e.ToString()); } } return(expList); }
// 単項演算の計算 static object CalcUnary(object value, ExpressionToken token) { switch (token.name) { case Not: // ! if (value is bool) return !(bool)value; else { throw new Exception(LanguageErrorMsg.LocalizeTextFormat(Utage.ErrorMsg.ExpressionOperator, token.name)); } case Plus: // + if (value is float) return value; else if (value is int) return value; else { throw new Exception(LanguageErrorMsg.LocalizeTextFormat(Utage.ErrorMsg.ExpressionOperator, token.name)); } case Minus: // - if (value is float) return -(float)value; else if (value is int) return -(int)value; else { throw new Exception(LanguageErrorMsg.LocalizeTextFormat(Utage.ErrorMsg.ExpressionOperator, token.name)); } default: throw new Exception(LanguageErrorMsg.LocalizeTextFormat(Utage.ErrorMsg.ExpressionOperator, token.name)); } }
// 二項演算の計算(&&や||などの論理式) static object CalcBinaryAndOr(object value1, ExpressionToken token, object value2) { if (value1 is bool) { if (value2 is bool) return CalcBinaryAndOrSub((bool)value1, token, (bool)value2); } throw new Exception(LanguageErrorMsg.LocalizeTextFormat(Utage.ErrorMsg.ExpressionOperator, token.name)); }
//関数名であればトークン作成 static bool TryParseFunction(string name, out ExpressionToken token) { switch (name) { case FuncRandom: token = new ExpressionToken(name, false, ExpressionToken.TokenType.Function, 0); token.numFunctionArg = 2; return true; case FuncRandomF: token = new ExpressionToken(name, false, ExpressionToken.TokenType.Function, 0); token.numFunctionArg = 2; return true; default: token = null; return false; } }
// 演算式の結果を計算 object Calc(System.Func<string, object, bool> callbackSetValue ) { try { ///逆ポーランド式の演算 Stack<ExpressionToken> values = new Stack<ExpressionToken>(); ExpressionToken value1; ExpressionToken value2; foreach (ExpressionToken token in tokens) { switch (token.Type) { case ExpressionToken.TokenType.Substitution: //代入演算 value2 = values.Pop(); value1 = values.Pop(); values.Push(ExpressionToken.OperateSubstition(value1, token, value2, callbackSetValue)); break; case ExpressionToken.TokenType.Unary: //単項演算 values.Push(ExpressionToken.OperateUnary(values.Pop(), token)); break; case ExpressionToken.TokenType.Binary: //二項演算 value2 = values.Pop(); value1 = values.Pop(); values.Push(ExpressionToken.OperateBinary(value1, token, value2)); break; case ExpressionToken.TokenType.Number: case ExpressionToken.TokenType.Value: values.Push(token); break; case ExpressionToken.TokenType.Function: //関数 { int num = token.NumFunctionArg; ExpressionToken[] args = new ExpressionToken[num]; for (int i = 0; i < num; ++i) { args[num-i-1] = values.Pop(); } values.Push(ExpressionToken.OperateFunction(token, args)); } break; default: break; } } if (values.Count != 1) { throw new Exception(LanguageErrorMsg.LocalizeTextFormat(Utage.ErrorMsg.ExpIllegal)); } return values.Peek().Variable; } catch(Exception e) { Debug.LogError(e.Message + e.StackTrace ); AddErrorMsg(e.Message); return null; } }
// 二項演算の計算(==や!=などの比較演算) static object CalcBinaryEq(object value1, ExpressionToken token, object value2) { if (value1 is int) { if (value2 is int) return CalcBinaryEqSub((int)value1, token, (int)value2); else if (value2 is float) return CalcBinaryEqSub((int)value1, token, (float)value2); } else if (value1 is float) { if (value2 is int) return CalcBinaryEqSub((float)value1, token, (int)value2); else if (value2 is float) return CalcBinaryEqSub((float)value1, token, (float)value2); } else if (value1 is bool) { if (value2 is bool) return CalcBinaryEqSub((bool)value1, token, (bool)value2); } else if (value1 is string) { if (value2 is string) return CalcBinaryEqSub((string)value1, token, (string)value2); } throw new Exception(LanguageErrorMsg.LocalizeTextFormat(Utage.ErrorMsg.ExpressionOperator, token.name)); }
// 演算式の結果を計算 object Calc(System.Func <string, object, bool> callbackSetValue) { try { ///逆ポーランド式の演算 Stack <ExpressionToken> values = new Stack <ExpressionToken>(); ExpressionToken value1; ExpressionToken value2; foreach (ExpressionToken token in tokens) { switch (token.Type) { case ExpressionToken.TokenType.Substitution: //代入演算 value2 = values.Pop(); value1 = values.Pop(); values.Push(ExpressionToken.OperateSubstition(value1, token, value2, callbackSetValue)); break; case ExpressionToken.TokenType.Unary: //単項演算 values.Push(ExpressionToken.OperateUnary(values.Pop(), token)); break; case ExpressionToken.TokenType.Binary: //二項演算 value2 = values.Pop(); value1 = values.Pop(); values.Push(ExpressionToken.OperateBinary(value1, token, value2)); break; case ExpressionToken.TokenType.Number: case ExpressionToken.TokenType.Value: values.Push(token); break; case ExpressionToken.TokenType.Function: //関数 { int num = token.NumFunctionArg; ExpressionToken[] args = new ExpressionToken[num]; for (int i = 0; i < num; ++i) { args[num - i - 1] = values.Pop(); } values.Push(ExpressionToken.OperateFunction(token, args)); } break; default: break; } } if (values.Count != 1) { throw new Exception(LanguageErrorMsg.LocalizeTextFormat(Utage.ErrorMsg.ExpIllegal)); } return(values.Peek().Variable); } catch (Exception e) { Debug.LogError(e.Message + e.StackTrace); AddErrorMsg(e.Message); return(null); } }
// 式を演算要素別に分解 static List <ExpressionToken> SplitToken(string exp) { List <ExpressionToken> tokens = new List <ExpressionToken>(); //演算式 tokens.Add(ExpressionToken.LpaToken); int index = 0; string strToken = ""; //直前の文字列 bool isValueMode = false; //直前のトークンが数値(変数)か、演算子か while (index < exp.Length) { char c = exp[index]; if (char.IsWhiteSpace(c) || c == ',') { //空白・区切り文字なので、直前の文字列をトークンとして分割 if (!string.IsNullOrEmpty(strToken)) { tokens.Add(ExpressionToken.CreateToken(strToken)); isValueMode = true; } strToken = ""; index++; continue; } //演算子が来たかチェック ExpressionToken operatior = ExpressionToken.FindOperator(exp, index); if (operatior == null) { //演算子はなかった。一文字シフト strToken += c; index++; } else { //演算子発見・直前の文字列をトークンとして分割 if (!string.IsNullOrEmpty(strToken)) { tokens.Add(ExpressionToken.CreateToken(strToken)); isValueMode = true; } //演算子をトークンとして追加 if (!isValueMode && operatior.Name == ExpressionToken.Minus) { //単項演算子のマイナスとして登録(二項演算子ではなく) tokens.Add(ExpressionToken.UniMinus); isValueMode = true; } else if (!isValueMode && operatior.Name == ExpressionToken.Plus) { //単項演算子のプラスとして登録(二項演算子ではなく) tokens.Add(ExpressionToken.UniPlus); isValueMode = true; } else { //見つかった演算子を追加 tokens.Add(operatior); if (operatior.Type != ExpressionToken.TokenType.Lpa && operatior.Type != ExpressionToken.TokenType.Rpa) { isValueMode = false; } } strToken = ""; index += operatior.Name.Length; } } if (!string.IsNullOrEmpty(strToken)) { tokens.Add(ExpressionToken.CreateToken(strToken)); } tokens.Add(ExpressionToken.RpaToken); return(tokens); }
// 二項演算 static public ExpressionToken OperateBinary(ExpressionToken value1, ExpressionToken token, ExpressionToken value2) { return(new ExpressionToken("", false, ExpressionToken.TokenType.Number, 0, CalcBinary(value1.variable, token, value2.variable))); }
// 単項演算 static public ExpressionToken OperateUnary(ExpressionToken value, ExpressionToken token) { return(new ExpressionToken("", false, ExpressionToken.TokenType.Number, 0, CalcUnary(value.variable, token))); }
// 代入演算 static public ExpressionToken OperateSubstition(ExpressionToken value1, ExpressionToken token, ExpressionToken value2, System.Func <string, object, bool> callbackSetValue) { value1.variable = CalcSubstition(value1.variable, token, value2.variable); //変数なので外部の代入処理 if (value1.type == ExpressionToken.TokenType.Value) { if (!callbackSetValue(value1.name, value1.variable)) { throw new Exception(LanguageErrorMsg.LocalizeTextFormat(Utage.ErrorMsg.ExpressionOperateSubstition, token.name, value1.variable)); } } return(value1); }
static object CalcBinaryNumberSub(float value1, ExpressionToken token, float value2) { switch (token.name) { case Prod: return (value1 * value2); case Div: return (value1 / value2); case Mod: return (value1 % value2); case Plus: return (value1 + value2); case Minus: return (value1 - value2); case Greater: return (value1 > value2); case Less: return (value1 < value2); case GreaterEq: return (value1 >= value2); case LessEq: return (value1 <= value2); default: throw new Exception(LanguageErrorMsg.LocalizeTextFormat(Utage.ErrorMsg.ExpressionOperator, token.name)); } }
// 代入演算 static public ExpressionToken OperateSubstition(ExpressionToken value1, ExpressionToken token, ExpressionToken value2, System.Func<string, object, bool> callbackSetValue) { value1.variable = CalcSubstition(value1.variable, token, value2.variable); //変数なので外部の代入処理 if (value1.type == ExpressionToken.TokenType.Value ) { if (!callbackSetValue(value1.name, value1.variable)) { throw new Exception(LanguageErrorMsg.LocalizeTextFormat(Utage.ErrorMsg.ExpressionOperateSubstition, token.name,value1.variable)); } } return value1; }
static object CalcBinaryNumberSub(bool value1, ExpressionToken token, string value2) { switch (token.name) { case Plus: return (value1 + value2); default: throw new Exception(LanguageErrorMsg.LocalizeTextFormat(Utage.ErrorMsg.ExpressionOperator, token.name)); } }
static object CalcSubstitionSub(float value1, ExpressionToken token, int value2) { switch (token.name) { case PlusEq: return (value1 + value2); case MinusEq: return (value1 - value2); case ProdEq: return (value1 * value2); case DivEq: return (value1 / value2); case ModEq: return (value1 % value2); default: throw new Exception(LanguageErrorMsg.LocalizeTextFormat(Utage.ErrorMsg.ExpressionOperator, token.name)); } }
static object CalcBinaryEqSub(string value1, ExpressionToken token, string value2) { switch (token.name) { case EqEq: return (value1 == value2); case NotEq: return (value1 != value2); default: throw new Exception(LanguageErrorMsg.LocalizeTextFormat(Utage.ErrorMsg.ExpressionOperator, token.name)); } }
static object CalcSubstitionSub(string value1, ExpressionToken token, float value2) { switch (token.name) { case PlusEq: return (value1 + value2); default: throw new Exception(LanguageErrorMsg.LocalizeTextFormat(Utage.ErrorMsg.ExpressionOperator, token.name)); } }
// 二項演算の計算(&&や||などの論理式) static object CalcBinaryAndOrSub(bool value1, ExpressionToken token, bool value2) { switch (token.name) { case And: return (value1 && value2); case Or: return (value1 || value2); default: throw new Exception(LanguageErrorMsg.LocalizeTextFormat(Utage.ErrorMsg.ExpressionOperator, token.name)); } }
// 単項演算 static public ExpressionToken OperateUnary(ExpressionToken value, ExpressionToken token) { return new ExpressionToken("", false, ExpressionToken.TokenType.Number, 0, CalcUnary(value.variable, token)); }
// 関数演算 static public ExpressionToken OperateFunction(ExpressionToken token, ExpressionToken[] args) { switch (token.name) { case FuncRandom: { int random = UnityEngine.Random.Range(ExpressionCast.ToInt(args[0].variable), ExpressionCast.ToInt(args[1].variable)+1); return new ExpressionToken("", false, ExpressionToken.TokenType.Number, 0, random); } case FuncRandomF: { float random = UnityEngine.Random.Range(ExpressionCast.ToFloat(args[0].variable), ExpressionCast.ToFloat(args[1].variable)); return new ExpressionToken("", false, ExpressionToken.TokenType.Number, 0, random); } default: throw new Exception("Unkonw Function :" + token.name); } }
// 式を演算要素別に分解 static List <ExpressionToken> SplitToken(string exp) { List <ExpressionToken> tokens = new List <ExpressionToken>(); //演算式 tokens.Add(ExpressionToken.LpaToken); int index = 0; string strToken = ""; //直前の文字列 while (index < exp.Length) { char c = exp[index]; bool isSkipped = false; const char StringSeparator = '\"'; const char ArraySeparator0 = '['; const char ArraySeparator1 = ']'; switch (c) { case StringSeparator: SkipGroup(StringSeparator, StringSeparator, ref strToken, exp, ref index); isSkipped = true; tokens.Add(ExpressionToken.CreateToken(strToken)); strToken = ""; break; case ArraySeparator0: SkipGroup(ArraySeparator0, ArraySeparator1, ref strToken, exp, ref index); isSkipped = true; break; default: break; } if (isSkipped) { continue; } if (char.IsWhiteSpace(c)) { //空白・区切り文字なので、直前の文字列をトークンとして分割 if (!string.IsNullOrEmpty(strToken)) { tokens.Add(ExpressionToken.CreateToken(strToken)); } strToken = ""; index++; continue; } //演算子が来たかチェック ExpressionToken operatior = ExpressionToken.FindOperator(exp, index); if (operatior == null) { //演算子はなかった。一文字シフト strToken += c; index++; } else { //演算子発見・直前の文字列をトークンとして分割 if (!string.IsNullOrEmpty(strToken)) { var token = ExpressionToken.CreateToken(strToken); tokens.Add(token); } bool isValueLastToken = tokens.Count > 0 && tokens[tokens.Count - 1].IsValueType; //演算子をトークンとして追加 if (!isValueLastToken && operatior.Name == ExpressionToken.Minus) { //単項演算子のマイナスとして登録(二項演算子ではなく) tokens.Add(ExpressionToken.UniMinus); } else if (!isValueLastToken && operatior.Name == ExpressionToken.Plus) { //単項演算子のプラスとして登録(二項演算子ではなく) tokens.Add(ExpressionToken.UniPlus); } else { //見つかった演算子を追加 tokens.Add(operatior); } strToken = ""; index += operatior.Name.Length; } } if (!string.IsNullOrEmpty(strToken)) { tokens.Add(ExpressionToken.CreateToken(strToken)); } tokens.Add(ExpressionToken.RpaToken); return(tokens); }