/// <summary> /// Converts a non decimal number to decimal. /// </summary> /// <param name="value"></param> /// <returns></returns> private static string AsDecimal(string value) { string number = value; int length = number.Length - 1; if (NumberToken.__binNumberPattern.IsMatch(number)) { number = Convert.ToInt64(number.Substring(0, length), 2).ToString(); CalculatorContext.GetInstance()[CalculatorContext.DisplayBase] = new NumberToken("2"); } else if (NumberToken.__octNumberPattern.IsMatch(number)) { number = Convert.ToInt64(number.Substring(0, length), 8).ToString(); CalculatorContext.GetInstance()[CalculatorContext.DisplayBase] = new NumberToken("8"); } else if (NumberToken.__hexNumberPattern.IsMatch(number)) { number = Convert.ToInt64(number.Substring(0, length), 16).ToString(); CalculatorContext.GetInstance()[CalculatorContext.DisplayBase] = new NumberToken("16"); } else { CalculatorContext.GetInstance()[CalculatorContext.DisplayBase] = new NumberToken("10"); } return(number); }
/// <summary> /// Gets the next token while within ta prefix function token parse state. /// </summary> /// <param name="internalLine"></param> /// <param name="token"></param> /// <param name="state"></param> /// <returns></returns> public override bool GetNextToken(string internalLine, out Token token, out TokenParseState state) { bool result = false; Token lastToken = CalculatorContext.GetInstance()[CalculatorContext.LastToken]; if ((result = (PerenthesisToken.TryParse(internalLine, out token) && ((PerenthesisToken)token).PerenthesisType == PerenthesisTokenType.Open))) { state = new PerenthesisTokenParseState(); } else if (lastToken.ToString().Equals("!", StringComparison.InvariantCultureIgnoreCase)) { if ((result = BooleanToken.TryParse(internalLine, out token) || ConstantToken.TryParse(internalLine, out token) || NumberToken.TryParse(internalLine, out token))) { state = new ValueTokenParseState(); } else if ((result = VariableToken.TryParse(internalLine, out token))) { state = new VariableTokenParseState(); } else { state = new InvalidTokenParseState(); } } else { state = new InvalidTokenParseState(); } return(result); }
/// <summary> /// Determines whether the last result was implied in the expression and if it was, adds the last result to the token collection. /// </summary> private void CheckForLastResultImplication() { if (_context.LastResultIsImplied) { _tokens.Add(CalculatorContext.GetInstance()[CalculatorContext.LastResult]); _context[CalculatorContext.LastToken] = _tokens[0]; CalculatorContext.GetInstance().LastResultIsImplied = false; } }
/// <summary> /// Gets a reference to the singleton instance of CalculatorContext. /// </summary> /// <returns></returns> public static CalculatorContext GetInstance() { if (CalculatorContext.__instance == null) { lock (CalculatorContext.__lockObject) { CalculatorContext.__instance = new CalculatorContext(); } } return(CalculatorContext.__instance); }
/// <summary> /// Evaluates this expression. /// </summary> /// <returns></returns> public override Token Evaluate() { Token result = new NullToken(); Token left = Operands[1].Evaluate(); Token right = Operands[0].Evaluate(); if (left is VariableToken) { result = right; CalculatorContext.GetInstance()[left.ToString()] = result; } return(result); }
/// <summary> /// Negates the value of this VariableToken. /// </summary> /// <returns></returns> public new Token Negate() { if (CalculatorContext.GetInstance().ContainsKey(ToString())) { Token value = CalculatorContext.GetInstance()[ToString()]; if (value is NumberToken) { value = ((NumberToken)value).Negate(); } CalculatorContext.GetInstance()[ToString()] = value; } return(this); }
/// <summary> /// Gets the next token while in the set container token parse state. /// </summary> /// <param name="internalLine"></param> /// <param name="token"></param> /// <param name="state"></param> /// <returns></returns> public override bool GetNextToken(string internalLine, out Token token, out TokenParseState state) { bool result = false; Token lastToken = CalculatorContext.GetInstance()[CalculatorContext.LastToken]; if ((result = SetContainerToken.TryParse(internalLine, out token) && ((SetContainerToken)token).SetContainerType == ((SetContainerToken)lastToken).SetContainerType)) { state = new SetContainerTokenParseState(); } else if ((result = CommentToken.TryParse(internalLine, out token))) { state = new NullTokenParseState(); } else if (((SetContainerToken)lastToken).SetContainerType == SetContainerTokenType.Open) { if ((result = PrefixFunctionToken.TryParse(internalLine, out token))) { state = new PrefixFunctionTokenParseState(); } else if ((result = BooleanToken.TryParse(internalLine, out token) || ConstantToken.TryParse(internalLine, out token) || NumberToken.TryParse(internalLine, out token) || LastResultToken.TryParse(internalLine, out token))) { state = new ValueTokenParseState(); } else if ((result = VariableToken.TryParse(internalLine, out token))) { state = new VariableTokenParseState(); } else { state = new InvalidTokenParseState(); } } else if ((result = InfixFunctionToken.TryParse(internalLine, out token) || ArithmeticOperatorToken.TryParse(internalLine, out token) || BinaryOperatorToken.TryParse(internalLine, out token) || BooleanOperatorToken.TryParse(internalLine, out token))) { state = new InfixOperationParseState(); } else if ((result = PostfixFunctionToken.TryParse(internalLine, out token))) { state = new PostfixFunctionParseState(); } else { state = new InvalidTokenParseState(); } return(result); }
/// <summary> /// Performs an evaluation on an expression. /// </summary> /// <param name="expression"></param> /// <returns></returns> public static string PerformEvaluation(string strExpression) { CalculatorContext context = CalculatorContext.GetInstance(); string strResult = "0"; ITokenizer tokenizer = new BpcTokenizer(strExpression); ITokenizer postfixTokenizer = new PostfixTokenizer(tokenizer); Expression expression = ExpressionYard.Formulate(postfixTokenizer); Token result = expression.Evaluate(); if (result is VariableToken) { result = context[result.ToString()]; } strResult = String.Format("{0}", result); if (result is NumberToken) { if (context[CalculatorContext.DisplayBase].ToString().Equals(DisplayBase.BinaryBase, StringComparison.InvariantCultureIgnoreCase)) { strResult = ((NumberToken)result).AsBin(); DisplayBase.ResetDisplayBase(); } else if (context[CalculatorContext.DisplayBase].ToString().Equals(DisplayBase.OctalBase, StringComparison.InvariantCultureIgnoreCase)) { strResult = ((NumberToken)result).AsOct(); DisplayBase.ResetDisplayBase(); } else if (context[CalculatorContext.DisplayBase].ToString().Equals(DisplayBase.HexadecimalBase, StringComparison.InvariantCultureIgnoreCase)) { strResult = ((NumberToken)result).AsHex(); DisplayBase.ResetDisplayBase(); } } else if (!(result is BooleanToken)) { throw new Exception(String.Format("Unexpected token was returned as result. Type: {0} value: {1}", result.Type, result)); } context[CalculatorContext.LastResult] = result; return(strResult); }
/// <summary> /// Evaluates a sub-expression. /// </summary> /// <param name="operandIndex"></param> /// <returns></returns> protected Token EvaluateOperand(int operandIndex) { Token evaluation = _operands[operandIndex].Evaluate(); if (evaluation is VariableToken) { CalculatorContext context = CalculatorContext.GetInstance(); if (context.ContainsKey(evaluation.ToString())) { evaluation = context[evaluation.ToString()]; } else { throw new MalformedExpressionException(String.Format("Variable named {0} is not defined", evaluation)); } } return(evaluation); }
/// <summary> /// Creates an instance of Program. /// </summary> /// <param name="args"></param> private Program(ProgramArguments args) { bool continueExecution = true; _context = CalculatorContext.GetInstance(); if (args.Args.Count > 0) { continueExecution = HandleArguments(args.Args); } if (continueExecution) { if (String.IsNullOrEmpty(args.Expression)) { Interact(); } else { string[] expressions = GetExpressions(args.Expression); foreach (string nextExpression in expressions) { try { Console.WriteLine("{0}", Evaluator.PerformEvaluation(nextExpression)); } catch (Exception ex) { Console.WriteLine("{0}", ex.Message); Environment.ExitCode = 1; } } } } else { Console.WriteLine(); } }
/// <summary> /// Gets the next Token if the last token was a NullToken. It first tries to get a normal, /// valid first token. If that fails, then it checks for a normal secondary token, and if /// that passes then the context LastResultIsImplied is set to true. /// </summary> /// <param name="internalLine"></param> /// <param name="token"></param> /// <returns></returns> public override bool GetNextToken(string internalLine, out Token token, out TokenParseState state) { bool result = false; if ((result = PerenthesisToken.TryParse(internalLine, out token))) { state = new PerenthesisTokenParseState(); } else if ((result = PrefixFunctionToken.TryParse(internalLine, out token))) { state = new PrefixFunctionTokenParseState(); } else if ((result = BooleanToken.TryParse(internalLine, out token) || ConstantToken.TryParse(internalLine, out token) || NumberToken.TryParse(internalLine, out token) || LastResultToken.TryParse(internalLine, out token))) { state = new ValueTokenParseState(); } else if ((result = VariableToken.TryParse(internalLine, out token))) { state = new VariableTokenParseState(); } else if ((result = InfixFunctionToken.TryParse(internalLine, out token) || ArithmeticOperatorToken.TryParse(internalLine, out token) || BinaryOperatorToken.TryParse(internalLine, out token) || BooleanOperatorToken.TryParse(internalLine, out token))) { state = new InfixOperationParseState(); CalculatorContext.GetInstance().LastResultIsImplied = true; } else if ((result = PostfixFunctionToken.TryParse(internalLine, out token))) { state = new PostfixFunctionParseState(); CalculatorContext.GetInstance().LastResultIsImplied = true; } else { state = new InvalidTokenParseState(); } return(result); }
/// <summary> /// Gets a Token of type LastResultToken from the beginning of a line of text. The resulting token /// needs to be a value token, like BooleanToken or NumberToken. /// </summary> /// <param name="line"></param> /// <returns></returns> public new static Token Parse(string line) { Token token = new NullToken(); if (LastResultToken.__constantPattern.IsMatch(line)) { string matchText = LastResultToken.__constantPattern.Matches(line)[0].Value; if (matchText.Equals("$", StringComparison.InvariantCultureIgnoreCase)) { token = new LastResultToken(CalculatorContext.GetInstance().GetLastResult(), matchText); Token intermediateToken = new NullToken(); if (NumberToken.TryParse(token.ToString(), out intermediateToken, true) || BooleanToken.TryParse(token.ToString(), out intermediateToken, true)) { token = intermediateToken; } } } return(token); }
/// <summary> /// Evaluates this expression. /// </summary> /// <returns></returns> public override Token Evaluate() { Token result = new NullToken(); string op = Operation.ToString(); bool modeIsDegrees = CalculatorContext.GetInstance()[CalculatorContext.Mode].ToString().Equals("deg", StringComparison.InvariantCultureIgnoreCase); if (Operation is PrefixFunctionToken) { Token val = EvaluateOperand(0); double res = 0.0; if (double.TryParse(val.ToString(), out res)) { if (op.Equals("abs", StringComparison.InvariantCultureIgnoreCase)) { result = new NumberToken((Math.Abs(res)).ToString()); } else if (op.Equals("cosh", StringComparison.InvariantCultureIgnoreCase)) { if (modeIsDegrees) { res = ToRadians(res); } res = Math.Cosh(res); result = new NumberToken(res.ToString()); } else if (op.Equals("sinh", StringComparison.InvariantCultureIgnoreCase)) { if (modeIsDegrees) { res = ToRadians(res); } res = Math.Sinh(res); result = new NumberToken(res.ToString()); } else if (op.Equals("tanh", StringComparison.InvariantCultureIgnoreCase)) { if (modeIsDegrees) { res = ToRadians(res); } res = Math.Tanh(res); result = new NumberToken(res.ToString()); } else if (op.Equals("cos", StringComparison.InvariantCultureIgnoreCase)) { if (modeIsDegrees) { res = ToRadians(res); } res = Math.Cos(res); result = new NumberToken(res.ToString()); } else if (op.Equals("sin", StringComparison.InvariantCultureIgnoreCase)) { if (modeIsDegrees) { res = ToRadians(res); } res = Math.Sin(res); result = new NumberToken(res.ToString()); } else if (op.Equals("tan", StringComparison.InvariantCultureIgnoreCase)) { if (modeIsDegrees) { res = ToRadians(res); } res = Math.Tan(res); result = new NumberToken(res.ToString()); } else if (op.Equals("acos", StringComparison.InvariantCultureIgnoreCase)) { res = modeIsDegrees ? ToDegrees(Math.Acos(res)) : Math.Acos(res); result = new NumberToken(res.ToString()); } else if (op.Equals("asin", StringComparison.InvariantCultureIgnoreCase)) { res = modeIsDegrees ? ToDegrees(Math.Asin(res)) : Math.Acos(res); result = new NumberToken(res.ToString()); } else if (op.Equals("atan", StringComparison.InvariantCultureIgnoreCase)) { res = modeIsDegrees ? ToDegrees(Math.Atan(res)) : Math.Acos(res); result = new NumberToken(res.ToString()); } else if (op.Equals("log", StringComparison.InvariantCultureIgnoreCase)) { result = new NumberToken((Math.Log10(res)).ToString()); } else if (op.Equals("ln", StringComparison.InvariantCultureIgnoreCase)) { result = new NumberToken((Math.Log(res)).ToString()); } else if (op.Equals("lb", StringComparison.InvariantCultureIgnoreCase) || op.Equals("ld", StringComparison.InvariantCultureIgnoreCase) || op.Equals("lg", StringComparison.InvariantCultureIgnoreCase)) { result = new NumberToken((Math.Log(res) / Math.Log(2.0)).ToString()); } else if (op.Equals("deg", StringComparison.InvariantCultureIgnoreCase)) { result = new NumberToken((ToDegrees(res)).ToString()); } else if (op.Equals("rad", StringComparison.InvariantCultureIgnoreCase)) { result = new NumberToken((ToRadians(res)).ToString()); } else if (op.Equals("sqrt", StringComparison.InvariantCultureIgnoreCase)) { result = new NumberToken((Math.Sqrt(res)).ToString()); } else if (op.Equals("too", StringComparison.InvariantCultureIgnoreCase)) { CalculatorContext.GetInstance()[CalculatorContext.DisplayBase] = new NumberToken("8"); result = new NumberToken(val); } else if (op.Equals("tod", StringComparison.InvariantCultureIgnoreCase)) { CalculatorContext.GetInstance()[CalculatorContext.DisplayBase] = new NumberToken("10"); result = new NumberToken(val); } else if (op.Equals("toh", StringComparison.InvariantCultureIgnoreCase)) { CalculatorContext.GetInstance()[CalculatorContext.DisplayBase] = new NumberToken("16"); result = new NumberToken(val); } else if (op.Equals("tob", StringComparison.InvariantCultureIgnoreCase)) { CalculatorContext.GetInstance()[CalculatorContext.DisplayBase] = new NumberToken("2"); result = new NumberToken(val); } else if (op.Equals("-", StringComparison.InvariantCultureIgnoreCase)) { result = new NumberToken((res * (-1)).ToString()); } else if (op.Equals("!", StringComparison.InvariantCultureIgnoreCase)) { if (val is BooleanToken) { result = ((BooleanToken)val).Not(); } else if (val is NumberToken) { result = ((NumberToken)val).Negate(); } } } else { throw new FormatException(String.Format("Could not parse double value from {0}", val)); } } else if (Operation is InfixFunctionToken) { Token left = EvaluateOperand(1); Token right = EvaluateOperand(0); double dLeft = 0.0; double dRight = 0.0; if (double.TryParse(left.ToString(), out dLeft) && double.TryParse(right.ToString(), out dRight)) { if (op.Equals("**", StringComparison.InvariantCultureIgnoreCase)) { result = new NumberToken((Math.Pow(dLeft, dRight)).ToString()); } else if (op.Equals("%", StringComparison.InvariantCultureIgnoreCase)) { result = new NumberToken((dLeft % dRight).ToString()); } else if (op.Equals("//", StringComparison.InvariantCultureIgnoreCase)) { if ((left is NumberToken && right is NumberToken)) { long lLeft = 0; long lRight = 0; if ((long.TryParse(((NumberToken)left).WholePart(), out lLeft) && long.TryParse(((NumberToken)right).WholePart(), out lRight))) { long rem = 0; long whole = Math.DivRem(lLeft, lRight, out rem); result = new NumberToken(whole.ToString()); } } else { throw new FormatException(String.Format("Could not parse long values from {0} or {1}.", left, right)); } } } else { throw new FormatException(String.Format("Could not parse double values from {0} or {1}.", left, right)); } } else if (Operation is PostfixFunctionToken) { Token val = EvaluateOperand(0); double res = 0.0; if (double.TryParse(val.ToString(), out res)) { if (op.Equals("!", StringComparison.InvariantCultureIgnoreCase)) { if (Operation is PostfixFunctionToken) { double counter = res; double total = counter; while (counter > 1) { counter--; total *= counter; } result = new NumberToken(total.ToString()); } } } else { throw new FormatException(String.Format("Could not parse double value from {0}", val)); } } else { throw new InvalidTokenException(String.Format("Operation {0} not currently supported. Please submit a feature request.", Operation)); } return(result); }
/// <summary> /// Resets the display base to 10. /// </summary> public static void ResetDisplayBase() { CalculatorContext.GetInstance()[CalculatorContext.DisplayBase] = new NumberToken("10", "10"); }