Ejemplo n.º 1
0
        /// <summary>
        /// 执行实际的运算操作
        /// </summary>
        /// <param name="polish">要计算的逆波兰式</param>
        /// <param name="calcList">逆波兰计算项向量</param>
        /// <returns>逆波兰式折叠结果</returns>
        private static object HandleEval(string polish, List <PolishItem> calcList)
        {
            if (calcList.Count == 0)
            {
                return(null);
            }
            var calcStack = new Stack <PolishItem>();

            foreach (PolishItem poi in calcList)
            {
                // 操作数压栈
                if (poi.ItemType < PolishItemType.CAL_PLUS)
                {
                    calcStack.Push(poi);
                    continue;
                }
                // 下面开始是运算符
                if (poi.ItemType == PolishItemType.CAL_NOT && calcStack.Count >= 1)
                {
                    PolishItem peeker = calcStack.Peek();
                    switch (peeker.ItemType)
                    {
                    case PolishItemType.CONSTANT:
                    case PolishItemType.VAR_NUM:
                    {
                        calcStack.Pop();
                        double     notres = Math.Abs(peeker.Number) < 1e-15 ? 1.0 : 0.0;
                        PolishItem np     = new PolishItem()
                        {
                            Number    = notres,
                            Reference = notres
                        };
                        calcStack.Push(np);
                        continue;
                    }

                    case PolishItemType.STRING:
                    case PolishItemType.VAR_STRING:
                    {
                        calcStack.Pop();
                        double notres = peeker.Cluster == String.Empty ? 1.0 : 0.0;

                        PolishItem np = new PolishItem()
                        {
                            Number    = notres,
                            Reference = notres
                        };
                        calcStack.Push(np);
                        continue;
                    }
                    }
                }
                if (calcStack.Count >= 2)
                {
                    PolishItem operand2 = calcStack.Pop();
                    PolishItem operand1 = calcStack.Pop();
                    if (PolishItem.IsOperatable(operand1, operand2, poi))
                    {
                        PolishItem newPoi;
                        double     tempDouble;
                        switch (poi.ItemType)
                        {
                        case PolishItemType.CAL_PLUS:
                            if (operand1.Reference is string || operand2.Reference is string)
                            {
                                var tempString = Convert.ToString(operand1.Reference) + Convert.ToString(operand2.Reference);
                                newPoi = new PolishItem()
                                {
                                    Cluster   = tempString,
                                    Reference = tempString
                                };
                                calcStack.Push(newPoi);
                            }
                            else
                            {
                                tempDouble = Convert.ToDouble(operand1.Reference) + Convert.ToDouble(operand2.Reference);
                                newPoi     = new PolishItem()
                                {
                                    Number    = tempDouble,
                                    Reference = tempDouble
                                };
                                calcStack.Push(newPoi);
                            }
                            break;

                        case PolishItemType.CAL_MINUS:
                            if (operand1.Reference is ValueType)
                            {
                                tempDouble = Convert.ToDouble(operand1.Reference) - Convert.ToDouble(operand2.Reference);
                                newPoi     = new PolishItem()
                                {
                                    Number    = tempDouble,
                                    Reference = tempDouble
                                };
                                calcStack.Push(newPoi);
                            }
                            else
                            {
                                throw new Exception("字符串异常操作:减法");
                            }
                            break;

                        case PolishItemType.CAL_MULTI:
                            if (operand1.Reference is ValueType)
                            {
                                tempDouble = Convert.ToDouble(operand1.Reference) * Convert.ToDouble(operand2.Reference);
                                newPoi     = new PolishItem()
                                {
                                    Number    = tempDouble,
                                    Reference = tempDouble
                                };
                                calcStack.Push(newPoi);
                            }
                            else
                            {
                                throw new Exception("字符串异常操作:乘法");
                            }
                            break;

                        case PolishItemType.CAL_DIV:
                            if (operand1.Reference is ValueType)
                            {
                                if (Math.Abs((double)operand2.Reference) < 0)
                                {
                                    throw new Exception("除零错误");
                                }
                                tempDouble = Convert.ToDouble(operand1.Reference) / Convert.ToDouble(operand2.Reference);
                                newPoi     = new PolishItem()
                                {
                                    Number    = tempDouble,
                                    Reference = tempDouble
                                };
                                calcStack.Push(newPoi);
                            }
                            else
                            {
                                throw new Exception("字符串异常操作:除法");
                            }
                            break;

                        case PolishItemType.CAL_ANDAND:
                            if (operand1.Reference is ValueType)
                            {
                                tempDouble = (Math.Abs(Convert.ToDouble(operand1.Reference)) > 0 && Math.Abs(Convert.ToDouble(operand2.Reference)) > 0) ? 1 : 0;
                                newPoi     = new PolishItem()
                                {
                                    Number    = tempDouble,
                                    Reference = tempDouble
                                };
                                calcStack.Push(newPoi);
                            }
                            else
                            {
                                throw new Exception("字符串异常操作:&&");
                            }
                            break;

                        case PolishItemType.CAL_OROR:
                            if (operand1.Reference is ValueType)
                            {
                                tempDouble = (Math.Abs(Convert.ToDouble(operand1.Reference)) > 0 || Math.Abs(Convert.ToDouble(operand2.Reference)) > 0) ? 1 : 0;
                                newPoi     = new PolishItem()
                                {
                                    Number    = tempDouble,
                                    Reference = tempDouble
                                };
                                calcStack.Push(newPoi);
                            }
                            else
                            {
                                throw new Exception("字符串异常操作:||");
                            }
                            break;

                        case PolishItemType.CAL_EQUAL:
                            if (operand1.Reference is ValueType)
                            {
                                tempDouble = Convert.ToDouble(operand1.Reference) == Convert.ToDouble(operand2.Reference) ? 1 : 0;
                                newPoi     = new PolishItem()
                                {
                                    Number    = tempDouble,
                                    Reference = tempDouble
                                };
                                calcStack.Push(newPoi);
                            }
                            else
                            {
                                tempDouble = (string)operand1.Reference == (string)operand2.Reference ? 1 : 0;
                                newPoi     = new PolishItem()
                                {
                                    Number    = tempDouble,
                                    Reference = tempDouble
                                };
                                calcStack.Push(newPoi);
                            }
                            break;

                        case PolishItemType.CAL_NOTEQUAL:
                            if (operand1.Reference is ValueType)
                            {
                                tempDouble = Convert.ToDouble(operand1.Reference) != Convert.ToDouble(operand2.Reference) ? 1 : 0;
                                newPoi     = new PolishItem()
                                {
                                    Number    = tempDouble,
                                    Reference = tempDouble
                                };
                                calcStack.Push(newPoi);
                            }
                            else
                            {
                                tempDouble = (string)operand1.Reference != (string)operand2.Reference ? 1 : 0;
                                newPoi     = new PolishItem()
                                {
                                    Number    = tempDouble,
                                    Reference = tempDouble
                                };
                                calcStack.Push(newPoi);
                            }
                            break;

                        case PolishItemType.CAL_BIG:
                            if (operand1.Reference is ValueType)
                            {
                                tempDouble = Convert.ToDouble(operand1.Reference) > Convert.ToDouble(operand2.Reference) ? 1 : 0;
                                newPoi     = new PolishItem()
                                {
                                    Number    = tempDouble,
                                    Reference = tempDouble
                                };
                                calcStack.Push(newPoi);
                            }
                            else
                            {
                                tempDouble = String.Compare((string)operand1.Reference, (string)operand2.Reference) > 0 ? 1 : 0;
                                newPoi     = new PolishItem()
                                {
                                    Number    = tempDouble,
                                    Reference = tempDouble
                                };
                                calcStack.Push(newPoi);
                            }
                            break;

                        case PolishItemType.CAL_BIGEQUAL:
                            if (operand1.Reference is ValueType)
                            {
                                tempDouble = Convert.ToDouble(operand1.Reference) >= Convert.ToDouble(operand2.Reference) ? 1 : 0;
                                newPoi     = new PolishItem()
                                {
                                    Number    = tempDouble,
                                    Reference = tempDouble
                                };
                                calcStack.Push(newPoi);
                            }
                            else
                            {
                                tempDouble = String.Compare((string)operand1.Reference, (string)operand2.Reference) >= 0 ? 1 : 0;
                                newPoi     = new PolishItem()
                                {
                                    Number    = tempDouble,
                                    Reference = tempDouble
                                };
                                calcStack.Push(newPoi);
                            }
                            break;

                        case PolishItemType.CAL_SMALL:
                            if (operand1.Reference is ValueType)
                            {
                                tempDouble = Convert.ToDouble(operand1.Reference) < Convert.ToDouble(operand2.Reference) ? 1 : 0;
                                newPoi     = new PolishItem()
                                {
                                    Number    = tempDouble,
                                    Reference = tempDouble
                                };
                                calcStack.Push(newPoi);
                            }
                            else
                            {
                                tempDouble = String.Compare((string)operand1.Reference, (string)operand2.Reference) < 0 ? 1 : 0;
                                newPoi     = new PolishItem()
                                {
                                    Number    = tempDouble,
                                    Reference = tempDouble
                                };
                                calcStack.Push(newPoi);
                            }
                            break;

                        case PolishItemType.CAL_SMALLEQUAL:
                            if (operand1.Reference is ValueType)
                            {
                                tempDouble = Convert.ToDouble(operand1.Reference) <= Convert.ToDouble(operand2.Reference) ? 1 : 0;
                                newPoi     = new PolishItem()
                                {
                                    Number    = tempDouble,
                                    Reference = tempDouble
                                };
                                calcStack.Push(newPoi);
                            }
                            else
                            {
                                tempDouble = String.Compare((string)operand1.Reference, (string)operand2.Reference) <= 0 ? 1 : 0;
                                newPoi     = new PolishItem()
                                {
                                    Number    = tempDouble,
                                    Reference = tempDouble
                                };
                                calcStack.Push(newPoi);
                            }
                            break;

                        default:
                            break;
                        }
                    }
                }
            }
            if (calcStack.Count != 1)
            {
                Utils.LogUtils.LogLine("求值器无法计算逆波兰式:" + polish, "PolishEvaluator", Utils.LogLevel.Error);
                throw new Exception("表达式有错误");
            }
            return(calcStack.Peek().Reference);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// 将逆波兰式转化为可计算的项
        /// </summary>
        /// <param name="polish">逆波兰式字符串</param>
        /// <param name="vsm">关于哪个调用堆栈做动作</param>
        /// <returns>可计算项目向量</returns>
        private static List <PolishItem> GetPolishItemList(string polish, StackMachine vsm, EvaluatableContext ctx)
        {
            var resVec     = new List <PolishItem>();
            var polishItem = polish.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

            foreach (string item in polishItem)
            {
                PolishItem poi        = null;
                Regex      floatRegEx = new Regex(@"^(\-|\+)?\d+(\.\d+)?$");
                // 常数项
                if (floatRegEx.IsMatch(item))
                {
                    double numitem = Convert.ToDouble(item);
                    poi = new PolishItem()
                    {
                        Number    = numitem,
                        Cluster   = null,
                        ItemType  = PolishItemType.CONSTANT,
                        Reference = numitem
                    };
                }
                // 字符串
                else if (item.StartsWith("\"") && item.EndsWith("\""))
                {
                    string trimItem = item.Substring(1, item.Length - 2);
                    poi = new PolishItem()
                    {
                        Number    = 0.0f,
                        Cluster   = trimItem,
                        ItemType  = PolishItemType.STRING,
                        Reference = trimItem
                    };
                }
                // 变量时
                else if ((item.StartsWith("&") || item.StartsWith("$") || item.StartsWith("%")) && item.Length > 1)
                {
                    object varRef = ctx != null?ctx.Fetch(item.Substring(1)) : Director.RunMana.Fetch(item, vsm);

                    if (varRef is ValueType)
                    {
                        poi = new PolishItem()
                        {
                            Number    = Convert.ToDouble(varRef),
                            Cluster   = null,
                            ItemType  = PolishItemType.VAR_NUM,
                            Reference = varRef
                        };
                    }
                    else
                    {
                        poi = new PolishItem()
                        {
                            Number    = 0.0f,
                            Cluster   = Convert.ToString(varRef),
                            ItemType  = PolishItemType.VAR_STRING,
                            Reference = varRef
                        };
                    }
                }
                else
                {
                    switch (item)
                    {
                    case "+":
                        poi = new PolishItem()
                        {
                            Number    = 0.0f,
                            Cluster   = null,
                            ItemType  = PolishItemType.CAL_PLUS,
                            Reference = null
                        };
                        break;

                    case "-":
                        poi = new PolishItem()
                        {
                            Number    = 0.0f,
                            Cluster   = null,
                            ItemType  = PolishItemType.CAL_MINUS,
                            Reference = null
                        };
                        break;

                    case "*":
                        poi = new PolishItem()
                        {
                            Number    = 0.0f,
                            Cluster   = null,
                            ItemType  = PolishItemType.CAL_MULTI,
                            Reference = null
                        };
                        break;

                    case "/":
                        poi = new PolishItem()
                        {
                            Number    = 0.0f,
                            Cluster   = null,
                            ItemType  = PolishItemType.CAL_DIV,
                            Reference = null
                        };
                        break;

                    case "!":
                        poi = new PolishItem()
                        {
                            Number    = 0.0f,
                            Cluster   = null,
                            ItemType  = PolishItemType.CAL_NOT,
                            Reference = null
                        };
                        break;

                    case "&&":
                        poi = new PolishItem()
                        {
                            Number    = 0.0f,
                            Cluster   = null,
                            ItemType  = PolishItemType.CAL_ANDAND,
                            Reference = null
                        };
                        break;

                    case "||":
                        poi = new PolishItem()
                        {
                            Number    = 0.0f,
                            Cluster   = null,
                            ItemType  = PolishItemType.CAL_OROR,
                            Reference = null
                        };
                        break;

                    case "<>":
                        poi = new PolishItem()
                        {
                            Number    = 0.0f,
                            Cluster   = null,
                            ItemType  = PolishItemType.CAL_NOTEQUAL,
                            Reference = null
                        };
                        break;

                    case "==":
                        poi = new PolishItem()
                        {
                            Number    = 0.0f,
                            Cluster   = null,
                            ItemType  = PolishItemType.CAL_EQUAL,
                            Reference = null
                        };
                        break;

                    case ">":
                        poi = new PolishItem()
                        {
                            Number    = 0.0f,
                            Cluster   = null,
                            ItemType  = PolishItemType.CAL_BIG,
                            Reference = null
                        };
                        break;

                    case "<":
                        poi = new PolishItem()
                        {
                            Number    = 0.0f,
                            Cluster   = null,
                            ItemType  = PolishItemType.CAL_SMALL,
                            Reference = null
                        };
                        break;

                    case ">=":
                        poi = new PolishItem()
                        {
                            Number    = 0.0f,
                            Cluster   = null,
                            ItemType  = PolishItemType.CAL_BIGEQUAL,
                            Reference = null
                        };
                        break;

                    case "<=":
                        poi = new PolishItem()
                        {
                            Number    = 0.0f,
                            Cluster   = null,
                            ItemType  = PolishItemType.CAL_SMALLEQUAL,
                            Reference = null
                        };
                        break;
                    }
                }
                if (poi != null)
                {
                    resVec.Add(poi);
                }
            }
            return(resVec);
        }