Exemplo n.º 1
0
        /// <summary>
        /// Метод выполняет разбор и вычисление <c>вложенной части</c> математического выражения.
        /// </summary>
        /// <remarks>
        /// Применяется для рекурсивного вызова при необходимости вычисления аргументов пользовательских функций.
        /// </remarks>
        /// <returns>
        /// Результат вычисления.
        /// </returns>
        /// <param name="expression">Математическое выражение для разбора и вычисления.</param>
        /// <param name="from">Стартовая позиция вложенного математического выражения.</param>
        /// <param name="to">Символ, указывающий на окончание вложенной части математического выражения.</param>
        /// <example>
        /// <code>
        /// public class AbsFunction : IParserFunction
        /// {
        ///     public double Evaluate(string expression, ref int from)
        ///     {
        ///         double arg = Parser.Calculate(expression, ref from, Parser.END_ARG);
        ///         return Math.Abs(arg);
        ///     }
        /// }
        /// </code>
        /// </example>
        /// <exception cref="System.ArgumentException">Возникает при неправильно заданном математическом выражении или ограничивающих вложенное выражение аргументах.</exception>
        public static double Calculate(string expression, ref int from, char to = END_LINE)
        {
            if (from >= expression.Length || expression[from] == to)
            {
                throw new ArgumentException("Loaded invalid data: " + expression);
            }

            List <Cell>   listToMerge = new List <Cell>(16);
            StringBuilder item        = new StringBuilder();

            do
            {
                char ch = expression[from++];
                if (StillCollecting(item.Length, ch, to))
                {
                    item.Append(ch);
                    if (from < expression.Length && expression[from] != to)
                    {
                        continue;
                    }
                }

                double value;

                if (item.Length == 0 && ch == Parser.START_ARG)
                {
                    value = _identityFunction.Evaluate(expression, ref from);
                }
                else if (_functions.ContainsKey(item.ToString()))
                {
                    IParserFunction func = _functions[item.ToString()];
                    value = func.Evaluate(expression, ref from);
                }
                else
                {
                    value = _strToDoubleFunction.Evaluate(item.ToString(), ref from);
                }

                char operation = ValidOperation(ch) ? ch
                                              : UpdateOperation(expression, ref from, ch, to);

                listToMerge.Add(new Cell(value, operation));
                item.Clear();
            } while (from < expression.Length && expression[from] != to);

            if (from < expression.Length &&
                (expression[from] == END_ARG || expression[from] == to))
            {
                from++;
            }

            Cell baseCell = listToMerge[0];
            int  index    = 1;

            return(Merge(baseCell, ref index, listToMerge));
        }