public Token(TokenParser.Tokens name, string value) { TokenName = name; TokenValue = value; }
private static int GetPrecedence(TokenParser.Tokens token) { if (token == TokenParser.Tokens.Add || token == TokenParser.Tokens.Subtract) return 1; if (token == TokenParser.Tokens.Multiply || token == TokenParser.Tokens.Divide || token == TokenParser.Tokens.Modulus) return 2; if (token == TokenParser.Tokens.Exponent) return 3; if (token == TokenParser.Tokens.Lparen || token == TokenParser.Tokens.Rparen) return 4; return 0; }
private static bool IsOperator(TokenParser.Tokens token) { return token == TokenParser.Tokens.Add || token == TokenParser.Tokens.Divide || token == TokenParser.Tokens.Exponent || token == TokenParser.Tokens.Modulus || token == TokenParser.Tokens.Multiply || token == TokenParser.Tokens.Subtract; }
public SimplificationReturnValue Simplify(string equation) { var retval = new SimplificationReturnValue { OriginalEquation = equation }; if (equation.Trim().StartsWith("-") || equation.Trim().StartsWith("+")) equation = "0" + equation; equation = equation.Replace("(+", "(0+"); equation = equation.Replace("(-", "(0-"); equation = equation.Replace("( +", "( 0+"); equation = equation.Replace("( -", "( 0-"); equation = equation.Replace(",-", ",0-"); equation = equation.Replace(", -", ", 0-"); equation = equation.Replace(",+", ",0+"); equation = equation.Replace(", +", ", 0+"); var tp = new TokenParser(); foreach (var cf in _customFunctions) { tp.RegisterCustomFunction(cf.Key); } tp.InputString = equation; Token token = tp.GetToken(); _operatorStack.Clear(); _outputQueue.Clear(); while (token != null) { if (token.TokenName == TokenParser.Tokens.Sqrt) { string expression = token.TokenValue.Substring(4, token.TokenValue.Length - 4); SimplificationReturnValue rv = EvaluateExpression(new NumberClass { Expression = expression, NumberType = NumberClass.NumberTypes.Expression }); token.TokenName = TokenParser.Tokens.Float; switch (rv.ReturnType) { case SimplificationReturnValue.ReturnTypes.Integer: token.TokenValue = Math.Sqrt(rv.IntValue).ToString(); break; case SimplificationReturnValue.ReturnTypes.Float: token.TokenValue = Math.Sqrt(rv.DoubleValue).ToString(); break; } } if (token.TokenName == TokenParser.Tokens.Sin) { string expression = token.TokenValue.Substring(3, token.TokenValue.Length - 3); SimplificationReturnValue rv = EvaluateExpression(new NumberClass { Expression = expression, NumberType = NumberClass.NumberTypes.Expression }); token.TokenName = TokenParser.Tokens.Float; switch (rv.ReturnType) { case SimplificationReturnValue.ReturnTypes.Integer: token.TokenValue = Math.Sin(rv.IntValue).ToString(); break; case SimplificationReturnValue.ReturnTypes.Float: token.TokenValue = Math.Sin(rv.DoubleValue).ToString(); break; } } if (token.TokenName == TokenParser.Tokens.Log) { string expression = token.TokenValue.Substring(3, token.TokenValue.Length - 3); SimplificationReturnValue rv = EvaluateExpression(new NumberClass { Expression = expression, NumberType = NumberClass.NumberTypes.Expression }); token.TokenName = TokenParser.Tokens.Float; switch (rv.ReturnType) { case SimplificationReturnValue.ReturnTypes.Integer: token.TokenValue = Math.Log(rv.IntValue, 10).ToString(); break; case SimplificationReturnValue.ReturnTypes.Float: token.TokenValue = Math.Log(rv.DoubleValue, 10).ToString(); break; } } if (token.TokenName == TokenParser.Tokens.LogN) { string expression = token.TokenValue.Substring(4, token.TokenValue.Length - 4); SimplificationReturnValue rv = EvaluateExpression(new NumberClass { Expression = expression, NumberType = NumberClass.NumberTypes.Expression }); token.TokenName = TokenParser.Tokens.Float; switch (rv.ReturnType) { case SimplificationReturnValue.ReturnTypes.Integer: token.TokenValue = Math.Log(rv.IntValue).ToString(); break; case SimplificationReturnValue.ReturnTypes.Float: token.TokenValue = Math.Log(rv.DoubleValue).ToString(); break; } } if (token.TokenName == TokenParser.Tokens.Tan) { string expression = token.TokenValue.Substring(3, token.TokenValue.Length - 3); var rv = EvaluateExpression(new NumberClass { Expression = expression, NumberType = NumberClass.NumberTypes.Expression }); token.TokenName = TokenParser.Tokens.Float; switch (rv.ReturnType) { case SimplificationReturnValue.ReturnTypes.Integer: token.TokenValue = Math.Tan(rv.IntValue).ToString(); break; case SimplificationReturnValue.ReturnTypes.Float: token.TokenValue = Math.Tan(rv.DoubleValue).ToString(); break; } } if (token.TokenName == TokenParser.Tokens.Abs) { string expression = token.TokenValue.Substring(3, token.TokenValue.Length - 3); var rv = EvaluateExpression(new NumberClass { Expression = expression, NumberType = NumberClass.NumberTypes.Expression }); token.TokenName = TokenParser.Tokens.Float; switch (rv.ReturnType) { case SimplificationReturnValue.ReturnTypes.Integer: token.TokenValue = Math.Abs(rv.IntValue).ToString(); break; case SimplificationReturnValue.ReturnTypes.Float: token.TokenValue = Math.Abs(rv.DoubleValue).ToString(); break; } } if (token.TokenName == TokenParser.Tokens.Cos) { string expression = token.TokenValue.Substring(3, token.TokenValue.Length - 3); var rv = EvaluateExpression(new NumberClass { Expression = expression, NumberType = NumberClass.NumberTypes.Expression }); token.TokenName = TokenParser.Tokens.Float; switch (rv.ReturnType) { case SimplificationReturnValue.ReturnTypes.Integer: token.TokenValue = Math.Cos(rv.IntValue).ToString(); break; case SimplificationReturnValue.ReturnTypes.Float: token.TokenValue = Math.Cos(rv.DoubleValue).ToString(); break; } } if ((int)token.TokenName >= 100) { int ndx1 = token.TokenValue.IndexOf("("); string fn = token.TokenValue.Substring(0, ndx1); string origExpression = token.TokenValue.Substring(ndx1); string[] expressions = origExpression.Replace(",", "),(").Split(','); bool found = false; foreach(var _f in _customFunctions) { if(_f.Key.Equals(fn)) { found = true; break; } } if (found) { foreach (var ff in _customFunctions) { if (ff.Key.Equals(fn)) { var p = new Parser(); foreach (var cfr in _customFunctions) p.AddCustomFunction(cfr.Key, cfr.Value); foreach (var vr in _variables) p.AddVariable(vr.Key, vr.Value); foreach (var vf in _functions) p.AddFunction(vf.Name, vf.Arguments, vf.Expression); var ex = new SimplificationReturnValue[expressions.Length]; for(var i = 0; i < expressions.Length; i++) { ex[i] = p.Simplify(expressions[i]); } object funcRetval = null; if (ff.Value.Method.ReturnType == typeof(int)) { var intParams = new object[ex.Length]; int ndx = 0; foreach (var pp in ex) { if (pp.ReturnType == SimplificationReturnValue.ReturnTypes.Float) intParams[ndx] = (int)pp.DoubleValue; if (pp.ReturnType == SimplificationReturnValue.ReturnTypes.Integer) intParams[ndx] = pp.IntValue; ndx++; } funcRetval = ff.Value.DynamicInvoke(intParams); } if (ff.Value.Method.ReturnType == typeof(double)) { var floatParams = new object[ex.Length]; int ndx = 0; foreach (var pp in ex) { if (pp.ReturnType == SimplificationReturnValue.ReturnTypes.Float) floatParams[ndx] = pp.DoubleValue; if (pp.ReturnType == SimplificationReturnValue.ReturnTypes.Integer) floatParams[ndx] = pp.IntValue; ndx++; } funcRetval = ff.Value.DynamicInvoke(floatParams); } if (ff.Value.Method.ReturnType==typeof(object)) { var ex2 = new SimplificationReturnValue[expressions.Length]; for(var i = 0; i < ex2.Length; i++) ex2[i] = p.Simplify(expressions[i]); funcRetval = ff.Value.DynamicInvoke(ex2); } //object funcRetval = ff.Value.DynamicInvoke(expressions.Select(p.Simplify).ToArray()); if (funcRetval is double) { token.TokenValue = ((double)funcRetval).ToString(); token.TokenName = TokenParser.Tokens.Float; } if (funcRetval is int) { token.TokenValue = ((int)funcRetval).ToString(); token.TokenName = TokenParser.Tokens.Integer; } if (funcRetval is SimplificationReturnValue) { var srv = (SimplificationReturnValue)funcRetval; if (srv.ReturnType == SimplificationReturnValue.ReturnTypes.Integer) { token.TokenValue = srv.IntValue.ToString(); token.TokenName = TokenParser.Tokens.Integer; } if (srv.ReturnType == SimplificationReturnValue.ReturnTypes.Float) { token.TokenValue = srv.DoubleValue.ToString(); token.TokenName = TokenParser.Tokens.Float; } } break; } } } if (!found) { throw new NoSuchFunctionException(StringResources.No_such_function_defined + ": " + fn); } } if (token.TokenName == TokenParser.Tokens.Function) { int ndx1 = token.TokenValue.IndexOf("("); string fn = token.TokenValue.Substring(0, ndx1).Remove(0, 4); string origExpression = token.TokenValue.Substring(ndx1); string[] expressions = origExpression.Replace(",", "),(").Split(','); bool found = false; FunctionClass fun = null; foreach(var _f in _functions) { if(_f.Name.Equals(fn)) { found = true; break; } } if (found) { foreach (var ff in _functions) if (ff.Name.Equals(fn)) fun = ff; } if (!found) { throw new NoSuchFunctionException(StringResources.No_such_function_defined + ": " + fn); } var parser = new Parser(); foreach (var cfh in _customFunctions) parser.AddCustomFunction(cfh.Key, cfh.Value); foreach (var v in _variables) { if (v.Value.NumberType == NumberClass.NumberTypes.Float) { parser.AddVariable(v.Key, v.Value.FloatNumber); } if (v.Value.NumberType == NumberClass.NumberTypes.Integer) { parser.AddVariable(v.Key, v.Value.IntNumber); } if (v.Value.NumberType == NumberClass.NumberTypes.Expression) { parser.AddVariable(v.Key, v.Value.Expression); } } foreach (var f in _functions) { parser.AddFunction(f.Name, f.Arguments, f.Expression); } var expressionList = new List<NumberClass>(); foreach (var expression in expressions) { SimplificationReturnValue simRetval = parser.Simplify(expression); var numClass = new NumberClass(); if (simRetval.ReturnType == SimplificationReturnValue.ReturnTypes.Float) { numClass.FloatNumber = simRetval.DoubleValue; numClass.NumberType = NumberClass.NumberTypes.Float; } if (simRetval.ReturnType == SimplificationReturnValue.ReturnTypes.Integer) { numClass.IntNumber = simRetval.IntValue; numClass.NumberType = NumberClass.NumberTypes.Integer; } expressionList.Add(numClass); } if (fun != null) { var numClass = new NumberClass { NumberType = NumberClass.NumberTypes.Expression, Expression = fun.Expression }; SimplificationReturnValue sretval = parser.EvaluateFunction(numClass, fun, expressionList); if (sretval != null && sretval.ReturnType == SimplificationReturnValue.ReturnTypes.Integer) { token.TokenName = TokenParser.Tokens.Integer; token.TokenValue = sretval.IntValue.ToString(); } if (sretval != null && sretval.ReturnType == SimplificationReturnValue.ReturnTypes.Float) { token.TokenName = TokenParser.Tokens.Float; token.TokenValue = sretval.DoubleValue.ToString(); } } } if (token.TokenName == TokenParser.Tokens.Variable) { if (_variables.ContainsKey(token.TokenValue)) { var z = _variables[token.TokenValue]; if (z.NumberType == NumberClass.NumberTypes.Float) { token.TokenName = TokenParser.Tokens.Float; token.TokenValue = z.FloatNumber.ToString(); } else if (z.NumberType == NumberClass.NumberTypes.Integer) { token.TokenName = TokenParser.Tokens.Integer; token.TokenValue = z.IntNumber.ToString(); } } else { throw new NoSuchVariableException(StringResources.Undefined_Variable + ": " + token.TokenValue); } } if (token.TokenName == TokenParser.Tokens.Whitespace || token.TokenName == TokenParser.Tokens.Newline) { token = tp.GetToken(); continue; } if (token.TokenName == TokenParser.Tokens.Integer || token.TokenName == TokenParser.Tokens.Float) { var nc = new NumberClass(); switch (token.TokenName) { case TokenParser.Tokens.Float: nc.NumberType = NumberClass.NumberTypes.Float; nc.FloatNumber = double.Parse(token.TokenValue); break; case TokenParser.Tokens.Integer: nc.NumberType = NumberClass.NumberTypes.Integer; nc.IntNumber = int.Parse(token.TokenValue); break; } _outputQueue.Enqueue(nc); } if (IsOperator(token.TokenName)) { if (_operatorStack.Count > 0) { while (_operatorStack.Count > 0) { var op = _operatorStack.Peek(); //o2 if (op == "(" || op == ")") break; if ((GetPrecedence(token.TokenName) <= GetPrecedence(op) && IsLeftAssociative(token.TokenValue)) || !IsLeftAssociative(token.TokenValue) && GetPrecedence(token.TokenName) < GetPrecedence(op)) { op = _operatorStack.Pop(); var nc = new NumberClass { NumberType = NumberClass.NumberTypes.Operator, Operator = op }; _outputQueue.Enqueue(nc); } else break; } } _operatorStack.Push(token.TokenValue); } if (token.TokenName == TokenParser.Tokens.Lparen) _operatorStack.Push(token.TokenValue); if (token.TokenName == TokenParser.Tokens.Rparen) { if (_operatorStack.Count > 0) { var op = _operatorStack.Pop(); while (op != "(") { var nc = new NumberClass { Operator = op, NumberType = NumberClass.NumberTypes.Operator }; _outputQueue.Enqueue(nc); if (_operatorStack.Count > 0) op = _operatorStack.Pop(); else { throw new MismatchedParenthesisException(); } } } else { throw new MismatchedParenthesisException(); } } token = tp.GetToken(); } while (_operatorStack.Count > 0) { var op = _operatorStack.Pop(); if (op == "(" || op == ")") { throw new MismatchedParenthesisException(); } var nc = new NumberClass { NumberType = NumberClass.NumberTypes.Operator, Operator = op }; _outputQueue.Enqueue(nc); } bool floatAnswer = false; bool slashAnswer = false; foreach(var v in _outputQueue) { if(v.NumberType == NumberClass.NumberTypes.Float) { floatAnswer = true; } if(v.Operator == "/") { slashAnswer = true; } } if (floatAnswer || slashAnswer) { var dblStack = new Stack<double>(); foreach (var nc in _outputQueue) { if (nc.NumberType == NumberClass.NumberTypes.Integer) dblStack.Push(nc.IntNumber); if (nc.NumberType == NumberClass.NumberTypes.Float) dblStack.Push(nc.FloatNumber); if (nc.NumberType == NumberClass.NumberTypes.Operator) { double val = DoMath(nc.Operator, dblStack.Pop(), dblStack.Pop()); dblStack.Push(val); } } if (dblStack.Count == 0) throw new CouldNotParseExpressionException(); retval.DoubleValue = dblStack.Pop(); retval.ReturnType = SimplificationReturnValue.ReturnTypes.Float; } else { var intStack = new Stack<int>(); foreach (var nc in _outputQueue) { if (nc.NumberType == NumberClass.NumberTypes.Integer) intStack.Push(nc.IntNumber); if (nc.NumberType == NumberClass.NumberTypes.Float) intStack.Push((int)nc.FloatNumber); if (nc.NumberType == NumberClass.NumberTypes.Operator) { int val = DoMath(nc.Operator, intStack.Pop(), intStack.Pop()); intStack.Push(val); } } if (intStack.Count == 0) throw new CouldNotParseExpressionException(); retval.IntValue = intStack.Pop(); retval.ReturnType = SimplificationReturnValue.ReturnTypes.Integer; } return retval; }