/// <summary>
        /// This gets the static instance of Calculator for use as an interactive shell.
        /// </summary>
        public static void Run()
        {
            try
            {
                using (Calculator calculator = new Calculator())
                {
                    while (true)
                    {
                        Console.Write("\n> ");
                        string userInput = Console.ReadLine();
                        userInput = userInput.Trim();
                        userInput = userInput.Replace(" ", "");

                        if (!String.IsNullOrEmpty(userInput))
                        {
                            try
                            {
                                switch (userInput)
                                {
                                default:
                                    Equation equation = Equation.Parse(userInput);
                                    string   result   = Calculate(equation);
                                    Console.WriteLine("{0}", result);
                                    break;

                                case "h":
                                    DisplayHelp();
                                    break;

                                case "help":
                                    DisplayHelp();
                                    break;

                                case "?":
                                    DisplayHelp();
                                    break;

                                case "q":
                                    throw new UserQuitException();

                                case "quit":
                                    throw new UserQuitException();
                                }
                            }
                            catch (TokenUnrecognizedException ex0)
                            {
                                Console.WriteLine("An internal error occurred: TokenUnrecognizedException was caught. {0}", ex0.Message);
                            }
                            catch (FormatException ex0)
                            {
                                Console.WriteLine("An internal error occurred: Probably you attempted unary operations on a binary value. {0}", ex0.Message);
                            }
                            catch (InvalidOperationException ex0)
                            {
                                Console.WriteLine("An internal error occurred: Probably the stack was empty for some reason. {0}", ex0.Message);
                            }
                        }
                    }
                }
            }
            catch (UserQuitException)
            {
                Console.WriteLine("Thanks for using PC.NET.");
            }
        }
示例#2
0
        /// <summary>
        /// Parses a string equation.
        /// </summary>
        /// <param name="equation"></param>
        /// <returns></returns>
        public static Equation Parse(string userInput)
        {
            Equation equation  = new Equation();
            Token    lastToken = Token.CreateNullToken();

            char[] parts      = userInput.ToCharArray();
            int    numParts   = parts.Length;
            string tokenValue = String.Empty;

            for (int index = 0; index < numParts; index++)
            {
                tokenValue = String.Format("{0}", parts[index]);

                if (ConditionalOperatorToken.Matches(tokenValue) || AssignmentOperatorToken.Matches(tokenValue))
                {
                    if (tokenValue.Equals("=")) // Could be either an assignment operator or a conditional
                    {
                        if (String.Format("{0}", parts[index + 1]).Equals("="))
                        {
                            lastToken = new ConditionalOperatorToken(String.Format("{0}=", tokenValue));
                            index++;
                        }
                        else
                        {
                            lastToken = new AssignmentOperatorToken();
                        }
                    }
                    else if (tokenValue.Equals("!")) // Could either be a conditional or factorial
                    {
                        if (String.Format("{0}", parts[index + 1]).Equals("="))
                        {
                            lastToken = new ConditionalOperatorToken(String.Format("{0}=", tokenValue));
                            index++;
                        }
                        else
                        {
                            lastToken = new FactorialToken();
                        }
                    }
                    else // It is a conditional that is either one or two characters long, i.e. <, >, <=, >=
                    {
                        if (String.Format("{0}", parts[index + 1]).Equals("="))
                        {
                            lastToken = new ConditionalOperatorToken(String.Format("{0}=", tokenValue));
                            index++;
                        }
                        else
                        {
                            lastToken = new ConditionalOperatorToken(tokenValue);
                        }
                    }
                }
                else if (SpecialNumberToken.Matches(tokenValue))
                {
                    int    tokenIndex = index;
                    string strPart    = String.Empty;

                    do
                    {
                        tokenValue = String.Format("{0}{1}", tokenValue, strPart);
                        tokenIndex++;

                        if (tokenIndex < numParts)
                        {
                            strPart = String.Format("{0}", parts[tokenIndex]);
                        }
                        else
                        {
                            strPart = String.Empty;
                        }
                    }while (FunctionToken.Matches(strPart));

                    lastToken = new SpecialNumberToken(tokenValue);
                    index     = tokenIndex - 1;
                }
                else if (NumberToken.Matches(tokenValue)) // Common case, where the token is a number
                {
                    int    tokenIndex = index;
                    string strPart    = String.Empty;

                    do
                    {
                        tokenValue = String.Format("{0}{1}", tokenValue, strPart);
                        tokenIndex++;

                        if (tokenIndex < numParts)
                        {
                            strPart = String.Format("{0}", parts[tokenIndex]);
                        }
                        else
                        {
                            strPart = String.Empty;
                        }
                    }while (NumberToken.Matches(strPart));

                    lastToken = new NumberToken(tokenValue);
                    index     = tokenIndex - 1;
                }
                else if (AdditionToken.Matches(tokenValue))
                {
                    lastToken = new AdditionToken();
                }
                else if (SubtractionToken.Matches(tokenValue) || NegationToken.Matches(tokenValue))
                {
                    if (lastToken.Type == TokenType.Number || lastToken.Type == TokenType.RightPerenthesis)
                    {
                        lastToken = new SubtractionToken();
                    }
                    else
                    {
                        lastToken = new NegationToken();
                    }
                }
                else if (MultiplicationToken.Matches(tokenValue))
                {
                    lastToken = new MultiplicationToken();
                }
                else if (DivisionToken.Matches(tokenValue))
                {
                    lastToken = new DivisionToken();
                }
                else if (ModulusToken.Matches(tokenValue))
                {
                    lastToken = new ModulusToken();
                }
                else if (LeftPerenthesisToken.Matches(tokenValue))
                {
                    lastToken = new LeftPerenthesisToken();
                }
                else if (RightPerenthesisToken.Matches(tokenValue))
                {
                    lastToken = new RightPerenthesisToken();
                }
                else if (FunctionToken.Matches(tokenValue))
                {
                    int    tokenIndex = index;
                    string strPart    = String.Empty;

                    do
                    {
                        tokenValue = String.Format("{0}{1}", tokenValue, strPart);
                        tokenIndex++;

                        if (tokenIndex < numParts)
                        {
                            strPart = String.Format("{0}", parts[tokenIndex]);
                        }
                        else
                        {
                            strPart = String.Empty;
                        }
                    }while (FunctionToken.Matches(strPart));

                    lastToken = new FunctionToken(tokenValue);
                    index     = tokenIndex - 1;
                }
                else if (BooleanToken.Matches(tokenValue))
                {
                    int    tokenIndex = index;
                    string strPart    = String.Empty;

                    do
                    {
                        tokenValue = String.Format("{0}{1}", tokenValue, strPart);
                        tokenIndex++;

                        if (tokenIndex < numParts)
                        {
                            strPart = String.Format("{0}", parts[tokenIndex]);
                        }
                        else
                        {
                            strPart = String.Empty;
                        }
                    }while (BooleanToken.Matches(strPart));

                    switch (tokenValue)
                    {
                    case "True":
                        lastToken = new BooleanToken("True");
                        break;

                    case "False":
                        lastToken = new BooleanToken("False");
                        break;
                    }

                    index = tokenIndex - 1;
                }
                else if (FactorialToken.Matches(tokenValue))
                {
                    lastToken = new FactorialToken();
                }
                else if (PowerToken.Matches(tokenValue))
                {
                    lastToken = new PowerToken();
                }
                else if (BitwiseOperationToken.Matches(tokenValue))
                {
                    lastToken = new BitwiseOperationToken(tokenValue);
                }
                else // This case is that we are probably dealing with a variable, but for now I'm going to throw an exception.
                {
                    // TODO: fix this to handle variables.
                    throw new TokenUnrecognizedException(tokenValue);
                }

                if (!lastToken.Equals(Token.CreateNullToken()))
                {
                    AddComponent(lastToken);
                }
            }

            // Need to transform the equation into a postfix equation so that I can evaluate it more easily.
            _tokens = ReverseTokens(_tokens);
            _tokens = PostfixateEquation(_tokens);

            return(equation);
        }
        private static string Calculate(Equation equation)
        {
            string calculationResult = String.Empty;

            Stack <Token> unusedTokens = new Stack <Token>();

            while (equation.Length > 0)
            {
                switch (equation.Peek().Type)
                {
                case TokenType.BooleanToken:
                    switch (equation.Peek().Value)
                    {
                    case "True":
                        calculationResult = "1";
                        break;

                    case "False":
                        calculationResult = "0";
                        break;
                    }

                    equation.Pop();
                    unusedTokens.Push(new NumberToken(calculationResult));
                    break;

                case TokenType.ConditionalOperator:
                    try
                    {
                        string condRight = unusedTokens.Pop().Value;
                        string condLeft  = unusedTokens.Pop().Value;
                        switch (equation.Peek().Value)
                        {
                        case "<":
                            calculationResult = Evaluator.LessThan(condLeft, condRight);
                            break;

                        case ">":
                            calculationResult = Evaluator.GreaterThan(condLeft, condRight);
                            break;

                        case "!=":
                            calculationResult = Evaluator.NotEqual(condLeft, condRight);
                            break;

                        case "<=":
                            calculationResult = Evaluator.LesThanOrEqual(condLeft, condRight);
                            break;

                        case ">=":
                            calculationResult = Evaluator.GreaterThanOrEqual(condLeft, condRight);
                            break;

                        case "==":
                            calculationResult = Evaluator.AreEqual(condLeft, condRight);
                            break;

                        default:
                            Console.WriteLine("Somehow the conditional {0} got through your filters. This is an internal error.", equation.Peek().Value);
                            throw new TokenUnrecognizedException(equation.Peek().Value);
                        }
                    }
                    catch (InvalidOperationException ex)
                    {
                        Console.WriteLine("Could not evaluate conditional because not enough operands were present. This may be an internal error. {0}", ex.Message);
                    }

                    equation.Pop();
                    unusedTokens.Push(new BooleanToken(calculationResult));
                    break;

                case TokenType.SpecialNumber:
                    switch (equation.Peek().Value.ToLower())
                    {
                    case "e":
                        calculationResult = Evaluator.GetE();
                        break;

                    case "pi":
                        calculationResult = Evaluator.GetPi();
                        break;

                    case "$":
                        calculationResult = PCState.Instance["$"] as String;

                        if (calculationResult.Equals("True"))
                        {
                            calculationResult = "1";
                        }
                        else if (calculationResult.Equals("False"))
                        {
                            calculationResult = "0";
                        }

                        break;
                    }

                    equation.Pop();
                    unusedTokens.Push(new NumberToken(calculationResult));
                    break;

                case TokenType.Number:
                    unusedTokens.Push(equation.Pop());
                    break;

                case TokenType.Negation:
                    equation.Pop();
                    try
                    {
                        string right  = unusedTokens.Pop().Value;
                        string result = Evaluator.Negate(right);

                        unusedTokens.Push(new NumberToken(result));
                    }
                    catch (InvalidOperationException ex)
                    {
                        Console.WriteLine("Could not evaluate negation because not enough operands were present. This may be an internal error. {0}", ex.Message);
                    }
                    break;

                case TokenType.Subtraction:
                    equation.Pop();
                    try
                    {
                        string subtrahend = unusedTokens.Pop().Value;
                        string minuend    = unusedTokens.Pop().Value;
                        string result     = Evaluator.Subtract(minuend, subtrahend);

                        unusedTokens.Push(new NumberToken(result));
                    }
                    catch (InvalidOperationException ex)
                    {
                        Console.WriteLine("Could not evaluate subtraction because not enough operands were present. This may be an internal error. {0}", ex.Message);
                    }
                    break;

                case TokenType.Addition:
                    equation.Pop();
                    try
                    {
                        string leftAddend  = unusedTokens.Pop().Value;
                        string rightAddend = unusedTokens.Pop().Value;
                        string result      = Evaluator.Add(leftAddend, rightAddend);

                        unusedTokens.Push(new NumberToken(result));
                    }
                    catch (InvalidOperationException ex)
                    {
                        Console.WriteLine("Could not evaluate addition because not enough operands were present. This may be an internal error. {0}", ex.Message);
                    }
                    break;

                case TokenType.Division:
                    equation.Pop();
                    try
                    {
                        string divisor  = unusedTokens.Pop().Value;
                        string dividend = unusedTokens.Pop().Value;
                        string result   = Evaluator.Divide(dividend, divisor);

                        unusedTokens.Push(new NumberToken(result));
                    }
                    catch (InvalidOperationException ex)
                    {
                        Console.WriteLine("Could not evaluate division because not enough operands were present. This may be an internal error. {0}", ex.Message);
                    }
                    break;

                case TokenType.Modulus:
                    equation.Pop();
                    try
                    {
                        string right  = unusedTokens.Pop().Value;
                        string left   = unusedTokens.Pop().Value;
                        string result = Evaluator.Modulus(left, right);

                        unusedTokens.Push(new NumberToken(result));
                    }
                    catch (InvalidOperationException ex)
                    {
                        Console.WriteLine("Could not evaluate modulus because not enough operands were present. This may be an internal error. {0}", ex.Message);
                    }
                    break;

                case TokenType.Multiplication:
                    equation.Pop();
                    try
                    {
                        string multiplicand = unusedTokens.Pop().Value;
                        string multiplier   = unusedTokens.Pop().Value;
                        string result       = Evaluator.Multiply(multiplicand, multiplier);

                        unusedTokens.Push(new NumberToken(result));
                    }
                    catch (InvalidOperationException ex)
                    {
                        Console.WriteLine("Could not evaluate multiplication because not enough operands were present. This may be an internal error. {0}", ex.Message);
                    }
                    break;

                case TokenType.Function:
                    Token function = equation.Pop();
                    try
                    {
                        string localResult = String.Empty;
                        string right       = String.Empty;
                        string left        = String.Empty;

                        switch (function.Value.ToLower())
                        {
                        case "sin":
                            right       = unusedTokens.Pop().Value;
                            localResult = Evaluator.Sine(right);
                            break;

                        case "cos":
                            right       = unusedTokens.Pop().Value;
                            localResult = Evaluator.Cosine(right);
                            break;

                        case "tan":
                            right       = unusedTokens.Pop().Value;
                            localResult = Evaluator.Tangent(right);
                            break;

                        case "arcsin":
                            right       = unusedTokens.Pop().Value;
                            localResult = Evaluator.InverseSine(right);
                            break;

                        case "arccos":
                            right       = unusedTokens.Pop().Value;
                            localResult = Evaluator.InverseCosine(right);
                            break;

                        case "arctan":
                            right       = unusedTokens.Pop().Value;
                            localResult = Evaluator.InverseTangent(right);
                            break;

                        case "log":
                            right       = unusedTokens.Pop().Value;
                            localResult = Evaluator.Logarithm(String.Format("{0}", 10), right);
                            break;

                        case "ln":
                            right       = unusedTokens.Pop().Value;
                            localResult = Evaluator.Logarithm(String.Format("{0}", System.Math.E), right);
                            break;

                        case "bin":
                            right       = unusedTokens.Pop().Value;
                            localResult = Evaluator.ToBinary(right);
                            break;

                        case "hex":
                            right       = unusedTokens.Pop().Value;
                            localResult = Evaluator.ToHexadecimal(right);
                            break;

                        case "oct":
                            right       = unusedTokens.Pop().Value;
                            localResult = Evaluator.ToOctal(right);
                            break;

                        case "mod":
                            right       = unusedTokens.Pop().Value;
                            left        = unusedTokens.Pop().Value;
                            localResult = Evaluator.Modulus(left, right);
                            break;

                        case "round":
                            right       = unusedTokens.Pop().Value;
                            localResult = Evaluator.Round(right);
                            break;

                        case "ceil":
                            right       = unusedTokens.Pop().Value;
                            localResult = Evaluator.Ceiling(right);
                            break;

                        case "floor":
                            right       = unusedTokens.Pop().Value;
                            localResult = Evaluator.Floor(right);
                            break;

                        case "tanh":
                            right       = unusedTokens.Pop().Value;
                            localResult = Evaluator.HyperbolicTangent(right);
                            break;

                        case "sinh":
                            right       = unusedTokens.Pop().Value;
                            localResult = Evaluator.HyperbolicSine(right);
                            break;

                        case "cosh":
                            right       = unusedTokens.Pop().Value;
                            localResult = Evaluator.HyperbolicCosine(right);
                            break;

                        case "rad":
                            right       = unusedTokens.Pop().Value;
                            localResult = Evaluator.ToRadians(right);
                            break;

                        case "deg":
                            right       = unusedTokens.Pop().Value;
                            localResult = Evaluator.ToDegrees(right);
                            break;

                        default:
                            throw new InvalidOperationException(function.Value.ToLower());
                        }

                        unusedTokens.Push(new NumberToken(localResult));
                    }
                    catch (InvalidOperationException ex)
                    {
                        Console.WriteLine("Could not evaluate function because function is not implemented. This may be an internal error. {0}", ex.Message);
                    }
                    break;

                case TokenType.Factorial:
                    equation.Pop();
                    try
                    {
                        string left        = unusedTokens.Pop().Value;
                        string localResult = Evaluator.Factorial(left);

                        unusedTokens.Push(new NumberToken(localResult));
                    }
                    catch (InvalidOperationException ex)
                    {
                        Console.WriteLine("Could not evaluate factorial because not enough operands were present. This may be an internal error. {0}", ex.Message);
                    }
                    break;

                case TokenType.Power:
                    equation.Pop();
                    try
                    {
                        string pow         = unusedTokens.Pop().Value;
                        string bas         = unusedTokens.Pop().Value;
                        string localResult = Evaluator.Power(bas, pow);

                        unusedTokens.Push(new NumberToken(localResult));
                    }
                    catch (InvalidOperationException ex)
                    {
                        Console.WriteLine("Could not evaluate power function because not enough operands were present. This may be an internal error. {0}", ex.Message);
                    }
                    break;

                case TokenType.BitwiseOperation:
                    string bitwiseOperator = equation.Pop().Value;
                    try
                    {
                        string right       = unusedTokens.Pop().Value;
                        string left        = unusedTokens.Pop().Value;
                        string localResult = String.Empty;

                        switch (bitwiseOperator)
                        {
                        case "&":
                            localResult = Evaluator.BitwiseAnd(left, right);
                            break;

                        case "|":
                            localResult = Evaluator.BitwiseOr(left, right);
                            break;

                        case "%":
                            localResult = Evaluator.BitwiseXor(left, right);
                            break;
                        }

                        unusedTokens.Push(new NumberToken(localResult));
                    }
                    catch (InvalidOperationException ex)
                    {
                        Console.WriteLine("Could not evaluate bitwise operation because not enough operands were present. This may be an internal error. {0}", ex.Message);
                    }
                    break;

                default:
                    throw new TokenUnrecognizedException(String.Format("{0}", equation.Peek()));
                }
            }

            calculationResult = unusedTokens.Pop().Value;

            PCState.Instance["$"] = calculationResult;

            return(calculationResult);
        }