public ArgumentMismatchException(IExpressionElement element)
     : this(element, null)
 {
 }
 public ElementParsingException(IExpressionElement element)
     : this(element, null)
 {
 }
 public ElementParsingException(IExpressionElement element, Exception inner)
     : base("Parsing exception. Can't parse element - error occured while parsing element.", inner, element)
 {
 }
 public ElementEvaluationException(IExpressionElement element)
     : this(element, null)
 {
 }
 public ElementEvaluationException(IExpressionElement element, Exception inner)
     : base("Evaluation exception. Can't evaluate operation - error occured while evaluating operation.", inner, element)
 {
 }
 public IAstTreeNode CreateAstNode(IExpressionElement value, IList<IAstTreeNode> children)
 {
     var n = new AstNode(this, value);
     n.Children.AddRange(children);
     return n;
 }
 public EvaluatorException(String message, Exception exception, IExpressionElement element)
     : base(message, exception)
 {
     Element = element;
 }
 public NullArgumentsException(IExpressionElement element)
     : this(element, null)
 {
 }
 public NullArgumentsException(IExpressionElement element, Exception inner)
     : base("Evaluation exception. No arguments recieved (null).", inner, element)
 {
 }
Example #10
0
        public bool IsInEquality()
        {
            IExpressionElement e = _expression.Last();

            return((e is Less) || (e is Greater));
        }
Example #11
0
 public Expression Append(IExpressionElement element)
 {
     _expression.Add(element);
     return(this);
 }
Example #12
0
        private IList <IExpressionElement> Tokenize(string expression)
        {
            Dictionary <string, List <IExpressionElement> > dict = new Dictionary <string, List <IExpressionElement> >();

            foreach (IExpressionElement element in Constants.Cast <IExpressionElement>().
                     Concat(Variables.Cast <IExpressionElement>()).
                     Concat(Operators.Cast <IExpressionElement>()).
                     Concat(Functions.Cast <IExpressionElement>()).
                     Concat(Statements.Cast <IExpressionElement>()))
            {
                string name = element.Name;
                if (!dict.ContainsKey(name))
                {
                    dict[name] = new List <IExpressionElement>();
                }
                if (dict[name].Count > 0)
                {
                    if (!(element is IOperator || element is IFunction))
                    {
                        throw new ArgumentException("Only operators and functions can be overloaded.");
                    }
                    IExpressionElement elem = dict[name][0];
                    if ((elem is IOperator && element is IFunction) ||
                        (elem is IFunction && element is IOperator))
                    {
                        throw new ArgumentException("Function and operator cannot have the same name.");
                    }
                    if (element is IOperator)
                    {
                        foreach (IExpressionElement eelem in dict[name])
                        {
                            if ((element is IUnaryOperator && eelem is IUnaryOperator) ||
                                (element is IBinaryOperator && eelem is IBinaryOperator))
                            {
                                throw new ArgumentException("There cannot be two identical operators.");
                            }
                        }
                    }
                    if (element is IFunction)
                    {
                        IFunction felement = element as IFunction;
                        foreach (IExpressionElement eelem in dict[name])
                        {
                            IFunction felem = eelem as IFunction;
                            if (felem != null && felem.Name == felement.Name && felem.ParametersCount == felement.ParametersCount)
                            {
                                throw new ArgumentException("There cannot be two identical functions.");
                            }
                        }
                    }
                }
                dict[name].Add(element);
            }

            List <IExpressionElement> tokens = new List <IExpressionElement>();
            int i = 0;
            int l = expression.Length;

            while (i < l)
            {
                char c = expression[i];
                if (char.IsWhiteSpace(c)) /* eat */ } {
Example #13
0
        public ParsedExpression Parse(string expression)
        {
            IList <IExpressionElement> tokens = Tokenize(expression);

            if (tokens.Count == 0)
            {
                throw new ArgumentException("Empty expression.");
            }

            List <IExpressionElement>  output = new List <IExpressionElement>();
            Stack <IExpressionElement> stack  = new Stack <IExpressionElement>();

            Stack <int>  argumentsStack          = new Stack <int>();
            Stack <bool> insideFunctionStack     = new Stack <bool>();
            bool         afterFunction           = false;
            bool         afterFnParenthesis      = false;
            bool         afterNonFnParenthesis   = false;
            bool         afterClosingParenthesis = false;
            bool         afterSeparator          = false;
            bool         insideFunction          = false;
            int          arguments   = 0;
            bool         mustBeUnary = true;

            int tokenIndex = -1;

            foreach (IExpressionElement token in tokens)
            {
                tokenIndex++;
                IExpressionElement nextToken = tokenIndex + 1 < tokens.Count ? tokens[tokenIndex + 1] : null;
                // If the token is a number, then add it to the output queue.
                if (!afterFunction && !afterClosingParenthesis && (token is ILiteral || token is IConstant || token is IVariable))
                {
                    output.Add(token);
                    mustBeUnary             = false;
                    afterClosingParenthesis = afterNonFnParenthesis = afterFnParenthesis = afterSeparator = false;
                }
                // If the token is a function token, then push it onto the stack.
                else if (!afterFunction && !afterClosingParenthesis && (token is IFunction || (token is MultipleElements && (token as MultipleElements).Elements[0] is IFunction)))
                {
                    stack.Push(token);
                    afterFunction           = true;
                    afterClosingParenthesis = afterNonFnParenthesis = afterFnParenthesis = afterSeparator = false;
                }
                // If the token is a function argument separator (e.g., a comma):
                // • Until the topmost element of the stack is a left parenthesis, pop the element onto the output queue.
                //   If no left parentheses are encountered, either the separator was misplaced or parentheses were mismatched.
                else if (!afterFunction && insideFunction && token == Symbol.FunctionArgumentSeparator)
                {
                    if (afterFnParenthesis)
                    {
                        throw new ArgumentException("Missing argument.");
                    }
                    while (stack.Peek() != Symbol.LeftParenthesis)
                    {
                        output.Add(stack.Pop());
                    }
                    if (stack.Peek() != Symbol.LeftParenthesis)
                    {
                        throw new ArgumentException("Either the separator is misplaced or parentheses are mismatched.");
                    }
                    arguments++;
                    afterClosingParenthesis = afterNonFnParenthesis = afterFnParenthesis = false;
                    afterSeparator          = true;
                }
                // If the token is an operator, o1, then:
                // • while there is an operator, o2, at the top of the stack, and either
                //       o1 is associative or left-associative and its precedence is less than (lower precedence) or equal to that of o2, or
                //       o1 is right-associative and its precedence is less than (lower precedence) that of o2,
                //     pop o2 off the stack, onto the output queue;
                // • push o1 onto the stack.
                else if (!afterFunction && (token is IOperator || (token is MultipleElements && (token as MultipleElements).Elements[0] is IOperator)))
                {
                    IOperator op = null;
                    if ((mustBeUnary && token is IUnaryOperator) || (!mustBeUnary && token is IBinaryOperator))
                    {
                        op = token as IOperator;
                    }
                    else if (token is MultipleElements)
                    {
                        foreach (IExpressionElement elem in (token as MultipleElements).Elements)
                        {
                            if ((mustBeUnary && elem is IUnaryOperator) || (!mustBeUnary && elem is IBinaryOperator))
                            {
                                op = elem as IOperator;
                                break;
                            }
                        }
                    }
                    if (op == null)
                    {
                        throw new ArgumentException(string.Format("{0} is not {1} operator.", token.Name, mustBeUnary ? "an unary" : "a binary"));
                    }
                    IOperator sop = stack.Count > 0 ? stack.Peek() as IOperator : null;
                    while (sop != null && (
                               (
                                   op is IBinaryOperator &&
                                   (op as IBinaryOperator).Associativity != OperatorAssociativity.RightAssociative &&
                                   op.Precedence <= sop.Precedence
                               )
                               ||
                               (
                                   (
                                       (op is IBinaryOperator && (op as IBinaryOperator).Associativity == OperatorAssociativity.RightAssociative) ||
                                       op is IUnaryOperator
                                   )
                                   &&
                                   op.Precedence < sop.Precedence
                               )))
                    {
                        output.Add(stack.Pop());
                        sop = stack.Count > 0 ? stack.Peek() as IOperator : null;
                    }

                    stack.Push(op);
                    mustBeUnary             = true;
                    afterClosingParenthesis = afterFnParenthesis = afterNonFnParenthesis = afterSeparator = false;
                }
                // If the token is a left parenthesis, then push it onto the stack.
                else if (!afterClosingParenthesis && token == Symbol.LeftParenthesis)
                {
                    stack.Push(token);
                    argumentsStack.Push(arguments);
                    insideFunctionStack.Push(insideFunction);
                    // initial argument count
                    arguments = nextToken == Symbol.RightParenthesis ? 0 : 1;
                    if (afterFunction)
                    {
                        afterNonFnParenthesis = afterFunction = false;
                        insideFunction        = afterFnParenthesis = true;
                    }
                    else
                    {
                        afterNonFnParenthesis = true;
                        insideFunction        = afterFnParenthesis = false;
                    }
                    mustBeUnary             = true;
                    afterClosingParenthesis = afterSeparator = false;
                }
                // If the token is a right parenthesis:
                // • Until the token at the top of the stack is a left parenthesis, pop operators off the stack onto the output queue.
                // • Pop the left parenthesis from the stack, but not onto the output queue.
                // • If the token at the top of the stack is a function token, pop it and onto the output queue.
                // • If the stack runs out without finding a left parenthesis, then there are mismatched parentheses.
                else if (!afterFunction && !afterSeparator && token == Symbol.RightParenthesis)
                {
                    if (afterNonFnParenthesis)
                    {
                        throw new ArgumentException("Unexpected token: '()'.");
                    }
                    if (stack.Count == 0)
                    {
                        throw new ArgumentException("There are mismatched parentheses.");
                    }
                    while (stack.Peek() != Symbol.LeftParenthesis)
                    {
                        output.Add(stack.Pop());
                        if (stack.Count == 0)
                        {
                            throw new ArgumentException("There are mismatched parentheses.");
                        }
                    }
                    IExpressionElement parenthesis = stack.Pop(); // parenthesis
                    if (stack.Count > 0)
                    {
                        IExpressionElement elem = stack.Peek();
                        if (elem is IFunction || (elem is MultipleElements && (elem as MultipleElements).Elements[0] is IFunction))
                        {
                            elem = stack.Pop();
                            IExpressionElement func = null;
                            if (elem is IFunction)
                            {
                                if ((elem as IFunction).ParametersCount != arguments)
                                {
                                    UndefinedFunctionFoundEventArgs args = new UndefinedFunctionFoundEventArgs(elem.Name, arguments);
                                    if (UndefinedFunctionFound != null)
                                    {
                                        UndefinedFunctionFound(this, args);
                                    }
                                    if (!args.Handled)
                                    {
                                        throw new ArgumentException(string.Format("There is no function ‘{0}’ with {1} parameters defined.", elem.Name, arguments));
                                    }
                                    elem = new UnknownFunction(elem.Name);
                                    (elem as UnknownFunction).ParametersCount = arguments;
                                }
                                func = elem;
                            }
                            else
                            {
                                foreach (IFunction f in (elem as MultipleElements).Elements)
                                {
                                    if (f.ParametersCount == arguments)
                                    {
                                        func = f;
                                        break;
                                    }
                                }
                                if (func == null)
                                {
                                    UndefinedFunctionFoundEventArgs args = new UndefinedFunctionFoundEventArgs((elem as MultipleElements).Elements[0].Name, arguments);
                                    if (UndefinedFunctionFound != null)
                                    {
                                        UndefinedFunctionFound(this, args);
                                    }
                                    if (!args.Handled)
                                    {
                                        throw new ArgumentException(string.Format("There is no function ‘{0}’ with {1} parameters defined.", args.Name, arguments));
                                    }
                                    func = new UnknownFunction(args.Name);
                                    (func as UnknownFunction).ParametersCount = arguments;
                                }
                            }
                            output.Add(func);
                        }
                    }
                    arguments               = argumentsStack.Count > 0 ? argumentsStack.Pop() : 0;
                    insideFunction          = insideFunctionStack.Pop();
                    afterFnParenthesis      = afterNonFnParenthesis = mustBeUnary = afterSeparator = false;
                    afterClosingParenthesis = true;
                }
                else
                {
                    IExpressionElement elem = token;
                    if (token is MultipleElements)
                    {
                        elem = (token as MultipleElements).Elements[0];
                    }
                    throw new ArgumentException(string.Format("Unexpected token: ‘{0}’", elem.Name));
                }
            }
            // When there are no more tokens to read:
            // • While there are still operator tokens in the stack:
            //   • If the operator token on the top of the stack is a parenthesis, then there are mismatched parentheses.
            //   • Pop the operator onto the output queue.
            while (stack.Count > 0)
            {
                if (stack.Peek() == Symbol.LeftParenthesis || stack.Peek() == Symbol.RightParenthesis)
                {
                    var r = stack.Peek();
                    throw new ArgumentException("There are mismatched parentheses.");
                }
                output.Add(stack.Pop());
            }
            return(new ParsedExpression(output, ZeroOnError));
        }
Example #14
0
 public AstNode(ParsedExpression parsedExpression, IExpressionElement value)
 {
     _parsedExpression = parsedExpression;
     Value = value;
     Children = new List<IAstTreeNode>();
 }
 public ArgumentMismatchException(IExpressionElement element, Exception inner)
     : base("Evaluation exception. Operands number mismatched - two operands needed for evaluation.", inner, element)
 {
 }
 double GetDynamicValue(IExpressionElement element)
 {
     return(((IDynamicNumber)element).Value);
 }
Example #17
0
 public Expression Append( IExpressionElement element )
 {
     _expression.Add( element );
     return this;
 }
Example #18
0
        internal ParsedExpression(IList <IExpressionElement> elements, bool zeroOnError)
        {
            this.ZeroOnError = zeroOnError;
            this.Elements    = elements;
            // validate the expression and create the AST tree
            Stack <KeyValuePair <int, IExpressionElement> > stack = new Stack <KeyValuePair <int, IExpressionElement> >();
            Stack <AstNode> tree = new Stack <AstNode>();
            int             l    = elements.Count;

            for (int i = 0; i < l; i++)
            {
                IExpressionElement element = elements[i];
                if (element is AssignmentOperator)
                {
                    stack.Pop();
                    KeyValuePair <int, IExpressionElement> var = stack.Pop();
                    if (!(var.Value is IVariable))
                    {
                        throw new InvalidOperationException("The left-hand side of an assignment must be a variable.");
                    }
                    elements[var.Key] = new VariableReference((IVariable)var.Value);
                    stack.Push(new KeyValuePair <int, IExpressionElement>(-1, null));

                    AstNode node = new AstNode(this, element);
                    node.Children.Add(tree.Pop());
                    node.Children.Insert(0, tree.Pop());
                    tree.Push(node);
                }
                else if (element is ILiteral)
                {
                    tree.Push(new AstNode(this, element));
                    stack.Push(new KeyValuePair <int, IExpressionElement>(i, element));
                }
                else if (element is IConstant)
                {
                    tree.Push(new AstNode(this, element));
                    stack.Push(new KeyValuePair <int, IExpressionElement>(i, element));
                }
                else if (element is IVariable)
                {
                    tree.Push(new AstNode(this, element));
                    stack.Push(new KeyValuePair <int, IExpressionElement>(i, element));
                }
                else if (element is IUnaryOperator)
                {
                    stack.Pop();
                    stack.Push(new KeyValuePair <int, IExpressionElement>(-1, null));

                    AstNode node = new AstNode(this, element);
                    node.Children.Add(tree.Pop());
                    tree.Push(node);
                }
                else if (element is IBinaryOperator)
                {
                    stack.Pop();
                    stack.Pop();
                    stack.Push(new KeyValuePair <int, IExpressionElement>(-1, null));

                    AstNode node = new AstNode(this, element);
                    node.Children.Add(tree.Pop());
                    node.Children.Insert(0, tree.Pop());
                    tree.Push(node);
                }
                else if (element is IFunction)
                {
                    AstNode   node = new AstNode(this, element);
                    IFunction func = element as IFunction;
                    int       _l   = func.ParametersCount;
                    for (int _i = 0; _i < _l; _i++)
                    {
                        stack.Pop();
                        node.Children.Insert(0, tree.Pop());
                    }
                    stack.Push(new KeyValuePair <int, IExpressionElement>(-1, null));
                    tree.Push(node);
                }
                else
                {
                    throw new ArgumentException(string.Format("Unexpected element: ‘{0}’.", element.Name));
                }
            }
            this.ExpressionTree = tree.Pop();
            if (tree.Count > 0)
            {
                throw new ArgumentException(string.Format("Unexpected element: ‘{0}’.", tree.Pop().Value.Name));
            }
        }