Beispiel #1
0
        /// <summary>
        /// Evalua una expresion aritmetica determinada.
        /// </summary>
        /// <param name="expression">La expresion a evaluar.</param>
        /// <returns>Un string que representa el valor de la expresion evaluada.</returns>
        public string Evaluate(string expression)
        {
            if (expression == null)
            {
                throw new InvalidOperationException("Nothing to evaluate.");
            }
            if (expression == "")
            {
                return(expression);
            }

            Stack <Token>       operatorStack     = new Stack <Token>();
            string              postfixExpression = "";
            Tokenizer           tokenizer         = new Tokenizer(expression);
            IEnumerable <Token> tokens            = tokenizer.GetTokens();

            IEnumerator <Token> enumerator = tokens.GetEnumerator();

            Token prevToken = null;

            while (enumerator.MoveNext())
            {
                Token currentToken = enumerator.Current;
                bool  unaryMinusBeforeParenthesis = false;
                switch (currentToken.Type)
                {
                case TokenType.OpenedParenthesis: // Si hay un parentesis, recupera la expresion completa y la evalua recursivamente.
                    string auxExp = "";

                    int openPCount   = 1;
                    int closedPCount = 0;

                    do
                    {
                        if (!enumerator.MoveNext())
                        {
                            throw new InvalidOperationException("Unbalanced parenthesis");
                        }
                        if (enumerator.Current.Type == TokenType.OpenedParenthesis)
                        {
                            openPCount++;
                        }
                        else if (enumerator.Current.Type == TokenType.ClosedParenthesis)
                        {
                            closedPCount++;
                        }

                        if (enumerator.Current.Type != TokenType.ClosedParenthesis || closedPCount < openPCount)
                        {
                            auxExp += enumerator.Current.Value + " ";
                        }
                    } while (closedPCount != openPCount);

                    string extra = unaryMinusBeforeParenthesis ? "-1 * " : " ";

                    postfixExpression += Evaluate(auxExp) + extra;
                    break;

                case TokenType.ClosedParenthesis:
                    throw new InvalidOperationException("Unbalanced parenthesis");

                case TokenType.Name:                      // Si es un nombre, pregunta por su tipo y lo sustituye por su valor
                    string name = currentToken.Value;
                    if (Variables.ContainsVariable(name)) // Es una variable?
                    {
                        Variable v = Variables[name];
                        if (v.Type != VariableType.Empty)
                        {
                            postfixExpression += Variables[name] + " ";
                        }
                    }
                    else if (Arrays.ArrayExists(currentToken.Value)) // Es un array?
                    {
                        string array = name;

                        while (enumerator.MoveNext() && enumerator.Current.Type != TokenType.ClosedBracket)
                        {
                            array += enumerator.Current.Value;
                        }

                        array += "]";

                        postfixExpression += GetArrayValue(array) + " ";
                    }
                    else
                    {
                        throw new InvalidOperationException(string.Format("Unknown name token: \"{0}\".", name));
                    }
                    break;

                // Si es un valor, simplemente lo agrega a la expresion en postfijo
                case TokenType.True:
                case TokenType.False:
                case TokenType.Constant:
                    postfixExpression += currentToken.Value + " ";
                    break;

                case TokenType.Minus:
                    if (GetTokenPriority(prevToken) > 0)
                    {
                        enumerator.MoveNext();
                        currentToken = enumerator.Current;
                        if (currentToken.Type == TokenType.Constant)
                        {
                            postfixExpression += "-" + currentToken.Value + " ";
                        }
                        else if (currentToken.Type == TokenType.OpenedParenthesis)
                        {
                            unaryMinusBeforeParenthesis = !unaryMinusBeforeParenthesis;
                            goto case TokenType.OpenedParenthesis;
                        }
                    }
                    else
                    {
                        goto case TokenType.Plus;
                    }
                    break;

                // Si es un operador...
                case TokenType.Plus:
                case TokenType.Asterisk:
                case TokenType.Slash:
                case TokenType.Percent:
                case TokenType.Ampersand:
                case TokenType.Caret:
                case TokenType.Greater:
                case TokenType.GreaterEqual:
                case TokenType.Less:
                case TokenType.LessEqual:
                case TokenType.Equal:
                case TokenType.NotEqual:
                    if (operatorStack.Count == 0)
                    {
                        operatorStack.Push(currentToken); // ... se agrega al stack si no habian otros operadores.
                    }
                    else // Si habian otros, los agrega a la expresion en postfijo hasta que no haya ninguno de menor prioridad.
                    {
                        int topOperPriority      = GetTokenPriority(operatorStack.Peek());
                        int currentTokenPriority = GetTokenPriority(currentToken);
                        while (operatorStack.Count > 0 && topOperPriority >= currentTokenPriority)
                        {
                            postfixExpression += operatorStack.Pop().Value + " ";
                            if (operatorStack.Count > 0)
                            {
                                topOperPriority = GetTokenPriority(operatorStack.Peek());
                            }
                        }
                        operatorStack.Push(currentToken);
                    }
                    break;

                case TokenType.Invalid:
                    throw new InvalidOperationException("Invalid token in expression.");
                }
                prevToken = enumerator.Current;
            }
            // Si la expresion termino de parsearse, agrega los operadores restantes a la expresion en postfijo.
            while (operatorStack.Count > 0)
            {
                postfixExpression += operatorStack.Pop().Value + " ";
            }

            return(EvaluatePostfix(postfixExpression)); // Pasa la expresion construida al metodo que evalua en si.
        }