/// <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. }