예제 #1
0
 public void Add(IOperationRule rule)
 {
     if (rules == null)
     {
         rules = new List <IOperationRule>();
     }
     rules.Add(rule);
 }
예제 #2
0
 public void Remove(IOperationRule rule)
 {
     rules?.Remove(rule);
 }
예제 #3
0
        /// <summary>
        /// Registers the specified operation rule.
        /// </summary>
        /// <param name="rule"></param>
        public static void RegisterOperationRule(IOperationRule rule)
        {
            ObjectManager <IOperationRule> .Instance.Register(rule);

            g_operationExpressionCalculator = new OperationExpressionCalculator(ObjectManager <IOperationRule> .Instance.Objects);
        }
        /// <summary>
        /// Calculates result of <paramref name="expressionString"/>.
        /// </summary>
        /// <param name="expressionString"></param>
        /// <returns></returns>
        public object Compute(string expressionString)
        {
            if (string.IsNullOrWhiteSpace(expressionString))
            {
                throw new ArgumentException("expressionString is null or empty", "expressionString");
            }

            // check format
            string invalidPart = this.GetInvalidPart(expressionString);

            if (invalidPart.Length > 0)
            {
                throw new InvalidOperationExpressionException(string.Format("Invalid characters in operation expression: {0}", invalidPart));
            }

            // parse brackets
            expressionString = this.ParseBrackets(expressionString);

            // analyse each operand and operator
            IOperationRule rule = null;
            Element <int, IOperationOperator> element = null;
            IOperationOperator         currentOperator = null, previousOperator = null;
            OperationExpressionContext context = new OperationExpressionContext();
            List <object>  operands      = new List <object>();
            Stack <object> operandsStack = new Stack <object>();
            Stack <Element <int, IOperationOperator> > operatorsStack = new Stack <Element <int, IOperationOperator> >();

            foreach (Match match in this.m_expressionRegex.Matches(expressionString))
            {
                if (this.m_rules.ContainsKey(match.Value))
                {
                    rule            = this.m_rules[match.Value];
                    currentOperator = rule.CreateOperator(context);

                    while (operatorsStack.Count > 0)
                    {
                        previousOperator = operatorsStack.Peek().Component2;
                        if (currentOperator.Priority > previousOperator.Priority)
                        {
                            break;
                        }

                        element = operatorsStack.Pop();
                        if ((context.AvailableOperandCount += element.Component1) < previousOperator.OperandCount)
                        {
                            throw new InvalidOperationExpressionException(string.Format("{0} operator needs {1} operands.", previousOperator.OwnerRule.OperatorSymbol, previousOperator.OperandCount));
                        }

                        operands.Clear();
                        for (int i = 0; i < previousOperator.OperandCount; i++)
                        {
                            operands.Add(operandsStack.Pop());
                        }
                        operands.Reverse();
                        context.AvailableOperandCount -= previousOperator.OperandCount;

                        operandsStack.Push(previousOperator.Compute(context, operands));
                        ++context.AvailableOperandCount;
                    }

                    operatorsStack.Push(new Element <int, IOperationOperator>(Math.Min(context.AvailableOperandCount, currentOperator.OperandCount), currentOperator));
                    context.AvailableOperandCount -= operatorsStack.Peek().Component1;
                }
                else
                {
                    operandsStack.Push(match.Value);
                    ++context.AvailableOperandCount;
                }
            }

            while (operatorsStack.Count > 0)
            {
                element          = operatorsStack.Pop();
                previousOperator = element.Component2;
                if ((context.AvailableOperandCount += element.Component1) < previousOperator.OperandCount)
                {
                    throw new InvalidOperationExpressionException(string.Format("{0} operator needs {1} operands.", previousOperator.OwnerRule.OperatorSymbol, previousOperator.OperandCount));
                }

                operands.Clear();
                for (int i = 0; i < previousOperator.OperandCount; i++)
                {
                    operands.Add(operandsStack.Pop());
                }
                operands.Reverse();
                context.AvailableOperandCount -= previousOperator.OperandCount;

                operandsStack.Push(previousOperator.Compute(context, operands));
                ++context.AvailableOperandCount;
            }

            if (operandsStack.Count > 1)
            {
                throw new Exception("Logic error: more than one operand is left finally.");
            }

            object result = operandsStack.Pop();

            if (result is string)
            {
                result = this.GetSingleValue(context, (string)result);
            }

            return(result);
        }