Example #1
0
        /// <summary>
        /// Returns a string representing the input converted to RPN.
        /// Only call this function if ParseInput() was successfull.
        /// </summary>
        /// <returns>String representing input converted into RPN.</returns>
        public String GetRPNOutputAsString()
        {
            Debug.Assert(curr_state != ParserState.ParserState_Error);
            String rpn_output = "";
            Stack <CalculatorToken> tmpstk = new Stack <CalculatorToken>(output_queue);

            while (tmpstk.Any())
            {
                CalculatorToken token = tmpstk.Pop();
                switch (token.ct_type)
                {
                case CalculatorToken.TOKEN_Type.TOKEN_Type_Function:
                case CalculatorToken.TOKEN_Type.TOKEN_Type_Operator:
                    rpn_output = rpn_output + token.ct_func + " ";
                    break;

                case CalculatorToken.TOKEN_Type.TOKEN_Type_Number:
                    rpn_output = rpn_output + token.ct_fval.ToString() + " ";
                    break;

                default:
                    break;
                }
            }

            return(rpn_output);
        }
Example #2
0
        /// <summary>
        /// Called when the parser reaches a left parenthesis.
        /// </summary>
        private void Handle_LeftParen()
        {
            //
            // Left parentheses simply get pushed into the operator stack.
            CalculatorToken new_token = new CalculatorToken {
                ct_type = CalculatorToken.TOKEN_Type.TOKEN_Type_LeftParen,
                ct_fval = 0.0f,
                ct_func = null
            };

            op_stack.Push(new_token);
            AdvanceToNextAtomEx();
        }
Example #3
0
        /// <summary>
        /// Called when the parser reaches a function.
        /// </summary>
        private void Handle_Function()
        {
            String func_name   = null;
            int    fname_start = input_iter;

            //
            // Build function name.
            for (; ;)
            {
                if (IsEndOfInput())
                {
                    break;
                }

                Char curr_atom = GetCurrentAtomFromInput();
                if (Char.IsLetterOrDigit(curr_atom))
                {
                    AdvanceToNextAtomEx();
                }
                else
                {
                    break;
                }
            }

            Debug.Assert(fname_start < input_iter);
            func_name = input_string.Substring(fname_start, input_iter - fname_start);
            //
            // Check if the calculator implements this function, and if so push it into
            // the operator stack.
            if (!ValidateFunction(func_name))
            {
                curr_state = ParserState.ParserState_Error;
                return;
            }

            CalculatorToken new_token = new CalculatorToken {
                ct_type = CalculatorToken.TOKEN_Type.TOKEN_Type_Function,
                ct_fval = 0.0f,
                ct_func = func_name
            };

            op_stack.Push(new_token);
        }
Example #4
0
        /// <summary>
        /// Called when the parser reaches an operator.
        /// </summary>
        private void Handle_Operator()
        {
            Char op1 = GetCurrentAtomFromInput();

            //
            // While there is a seconds operator (op2) at the top of the operators stack
            // and either op1 is left assoc and has a lower or equal precedence to op2
            // or op1 is right assoc and has a lower precedence that op2, pop op2
            // off the operator stack and into the output queue.
            while (op_stack.Any() &&
                   op_stack.Peek().ct_type ==
                   CalculatorToken.TOKEN_Type.TOKEN_Type_Operator)
            {
                Char op2 = op_stack.Peek().ct_func[0];

                if ((IsOperatorLeftAssociative(op1) &&
                     (GetOperatorPrecedenceLevel(op1) <= GetOperatorPrecedenceLevel(op2))) ||
                    (!IsOperatorLeftAssociative(op1) &&
                     (GetOperatorPrecedenceLevel(op1) < GetOperatorPrecedenceLevel(op2))))
                {
                    output_queue.Push(op_stack.Pop());
                }
                else
                {
                    break;
                }
            }

            //
            // Push op1 into the operator stack.
            CalculatorToken new_token = new CalculatorToken {
                ct_type = CalculatorToken.TOKEN_Type.TOKEN_Type_Operator,
                ct_fval = 0.0f,
                ct_func = new String(op1, 1)
            };

            op_stack.Push(new_token);
            AdvanceToNextAtomEx();
        }
        /// <summary>
        /// Reads the next token from the input stream and sets the parser's state
        /// based on that token's type.
        /// </summary>
        private void ReadNextTokenFromInput()
        {
            //
            // Eat any whitespaces.
            while (!IsEndOfInput() && Char.IsWhiteSpace(GetCurrentAtomFromInput())) {
              AdvanceToNextAtomEx();
            }

            if (IsEndOfInput()) {
              return;
            }

            //
            // Analyze current token and set parser's state.
            Char curr_atom = GetCurrentAtomFromInput();
            if (curr_atom == '-' && CanPeekNextAtomAndIsDigit()) {
              if (!op_stack.Any() ||
              op_stack.Peek().ct_type == CalculatorToken.TOKEN_Type.TOKEN_Type_RightParen) {
            CalculatorToken fake_plus = new CalculatorToken {
              ct_func = "+",
              ct_type = CalculatorToken.TOKEN_Type.TOKEN_Type_Operator,
              ct_fval = 0.0f
            };
            op_stack.Push(fake_plus);
              }
              curr_state = ParserState.ParserState_Digit;
              return;
            }

            if (Char.IsDigit(curr_atom)) {
              curr_state = ParserState.ParserState_Digit;
              return;
            }

            if (TokenIsAnOperator(curr_atom)) {
              curr_state = ParserState.ParserState_Operator;
              return;
            }

            if (Char.IsLetter(curr_atom)) {
              curr_state = ParserState.ParserState_Func;
              return;
            }

            if (curr_atom == '(') {
              curr_state = ParserState.ParserState_LeftParen;
              return;
            }

            if (curr_atom == ')') {
              curr_state = ParserState.ParserState_RightParen;
              return;
            }

            if (curr_atom == ',') {
              curr_state = ParserState.ParserState_Comma;
              return;
            }

            curr_state = ParserState.ParserState_Error;
        }
        /// <summary>
        /// Called when the parser reaches an operator.
        /// </summary>
        private void Handle_Operator()
        {
            Char op1 = GetCurrentAtomFromInput();

            //
            // While there is a seconds operator (op2) at the top of the operators stack
            // and either op1 is left assoc and has a lower or equal precedence to op2
            // or op1 is right assoc and has a lower precedence that op2, pop op2
            // off the operator stack and into the output queue.
            while (op_stack.Any() &&
               op_stack.Peek().ct_type ==
               CalculatorToken.TOKEN_Type.TOKEN_Type_Operator) {

              Char op2 = op_stack.Peek().ct_func[0];

              if ((IsOperatorLeftAssociative(op1) &&
              (GetOperatorPrecedenceLevel(op1) <= GetOperatorPrecedenceLevel(op2))) ||
              (!IsOperatorLeftAssociative(op1) &&
              (GetOperatorPrecedenceLevel(op1) < GetOperatorPrecedenceLevel(op2)))) {
            output_queue.Push(op_stack.Pop());
              } else {
            break;
              }
            }

            //
            // Push op1 into the operator stack.
            CalculatorToken new_token = new CalculatorToken {
              ct_type = CalculatorToken.TOKEN_Type.TOKEN_Type_Operator,
              ct_fval = 0.0f,
              ct_func = new String(op1, 1)
            };

            op_stack.Push(new_token);
            AdvanceToNextAtomEx();
        }
 /// <summary>
 /// Called when the parser reaches a left parenthesis.
 /// </summary>
 private void Handle_LeftParen()
 {
     //
     // Left parentheses simply get pushed into the operator stack.
     CalculatorToken new_token = new CalculatorToken {
       ct_type = CalculatorToken.TOKEN_Type.TOKEN_Type_LeftParen,
       ct_fval = 0.0f,
       ct_func = null
     };
     op_stack.Push(new_token);
     AdvanceToNextAtomEx();
 }
        /// <summary>
        /// Called when the parser reaches a function.
        /// </summary>
        private void Handle_Function()
        {
            String func_name = null;
            int fname_start = input_iter;

            //
            // Build function name.
            for (; ; ) {
              if (IsEndOfInput())
            break;

              Char curr_atom = GetCurrentAtomFromInput();
              if (Char.IsLetterOrDigit(curr_atom)) {
            AdvanceToNextAtomEx();
              } else {
            break;
              }
            }

            Debug.Assert(fname_start < input_iter);
            func_name = input_string.Substring(fname_start, input_iter - fname_start);
            //
            // Check if the calculator implements this function, and if so push it into
            // the operator stack.
            if (!ValidateFunction(func_name)) {
              curr_state = ParserState.ParserState_Error;
              return;
            }

            CalculatorToken new_token = new CalculatorToken {
              ct_type = CalculatorToken.TOKEN_Type.TOKEN_Type_Function,
              ct_fval = 0.0f,
              ct_func = func_name
            };
            op_stack.Push(new_token);
        }
        /// <summary>
        /// Called when the parser reaches a digit.
        /// </summary>
        private void Handle_Digit()
        {
            bool is_float = false;
            String curr_num = "";

            //
            // Check for minus sign and skip it if present.
            Char curr_atom = GetCurrentAtomFromInput();
            if (curr_atom == '-') {
              curr_num = curr_num + curr_atom;
              AdvanceToNextAtomEx();
            }

            //
            // Get the rest of the number's digits.
            for (; ; ) {
              if (IsEndOfInput())
            break;

              curr_atom = GetCurrentAtomFromInput();
              if (Char.IsDigit(curr_atom)) {
            curr_num = curr_num + curr_atom;
            AdvanceToNextAtomEx();
              } else if (curr_atom == '.') {
            if (is_float) {
              //
              // Misplaced dot, halt processing.
              curr_state = ParserState.ParserState_Error;
              return;
            }

            //
            // Floating point number.
            is_float = true;
            curr_num = curr_num + curr_atom;
            AdvanceToNextAtomEx();
              } else {
            break;
              }
            }

            //
            // Numbers get pushed into the output queue.
            Debug.Assert(curr_num.Length > 0);
            CalculatorToken new_token = new CalculatorToken {
              ct_type = CalculatorToken.TOKEN_Type.TOKEN_Type_Number,
              ct_fval = float.Parse(curr_num),
              ct_func = null
            };

            output_queue.Push(new_token);
        }
        /// <summary>
        /// Splits up the input string and returns all of the digits between the delimiters
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private List <CalculatorToken> Tokenize(string input)
        {
            var delimiters = new List <string> {
                ",", _secondaryDelimiter
            };

            var regexBracketDelimiters = new Regex("//\\[.*?\\]\\n");

            var regexSingleCharDelimiter = new Regex("\\/\\/.*?\\n");

            var bracketDelimiterMatches = regexBracketDelimiters.Matches(input);

            var singleCharMatches = regexSingleCharDelimiter.Matches(input);

            var numbersStart = input.IndexOf("\n") + 1;

            //If there are any matches where the custom delimiters fall inside brackets
            if (bracketDelimiterMatches.Any())
            {
                var match = bracketDelimiterMatches.First().Value;

                var innerString = match.Substring(2, match.Length - 3);

                var innerRegex = new Regex("\\[.*?\\]");

                var matches = innerRegex.Matches(innerString).ToList();

                //If there is only one, it will not be inside nested brackets
                if (matches.Count == 1)
                {
                    var m = matches.Single().Value;

                    var withoutBrackets = m.Substring(1, m.Length - 2);

                    delimiters.Add(withoutBrackets);
                }
                //If there are multiples, they will each be inside their own brackets
                else if (matches.Count > 1)
                {
                    foreach (var m in matches)
                    {
                        var matchInner = m.Value;

                        var withoutBrackets = matchInner.Substring(1, matchInner.Length - 2);

                        delimiters.Add(withoutBrackets);
                    }
                }
            }
            //Single character without brackets
            else if (singleCharMatches.Any())
            {
                var match = singleCharMatches.First().Value;

                var innerString = match.Substring(2, match.Length - 3);

                delimiters.Add(innerString);
            }
            else
            {
                //No Custom Delimiters
                numbersStart = 0;
            }

            var inputNumbers = input.Substring(numbersStart, input.Length - numbersStart);

            var rawTokens = inputNumbers.Split(delimiters.ToArray(), StringSplitOptions.None);

            var tokens = new List <CalculatorToken>();

            foreach (var raw in rawTokens)
            {
                var token = new CalculatorToken
                {
                    Token = raw
                };

                decimal value;

                if (Decimal.TryParse(raw, out value))
                {
                    token.Value = value;

                    //Check lower bound (error)
                    if (value < 0 && _rejectNegatives)
                    {
                        token.Errored = true;
                    }

                    //Check upper bound (act as 0)
                    if (value > _upperBound)
                    {
                        token.Value = 0;
                    }
                }

                tokens.Add(token);
            }

            return(tokens);
        }
Example #11
0
        /// <summary>
        /// Called when the parser reaches a digit.
        /// </summary>
        private void Handle_Digit()
        {
            bool   is_float = false;
            String curr_num = "";

            //
            // Check for minus sign and skip it if present.
            Char curr_atom = GetCurrentAtomFromInput();

            if (curr_atom == '-')
            {
                curr_num = curr_num + curr_atom;
                AdvanceToNextAtomEx();
            }

            //
            // Get the rest of the number's digits.
            for (; ;)
            {
                if (IsEndOfInput())
                {
                    break;
                }

                curr_atom = GetCurrentAtomFromInput();
                if (Char.IsDigit(curr_atom))
                {
                    curr_num = curr_num + curr_atom;
                    AdvanceToNextAtomEx();
                }
                else if (curr_atom == '.')
                {
                    if (is_float)
                    {
                        //
                        // Misplaced dot, halt processing.
                        curr_state = ParserState.ParserState_Error;
                        return;
                    }

                    //
                    // Floating point number.
                    is_float = true;
                    curr_num = curr_num + curr_atom;
                    AdvanceToNextAtomEx();
                }
                else
                {
                    break;
                }
            }

            //
            // Numbers get pushed into the output queue.
            Debug.Assert(curr_num.Length > 0);
            CalculatorToken new_token = new CalculatorToken {
                ct_type = CalculatorToken.TOKEN_Type.TOKEN_Type_Number,
                ct_fval = float.Parse(curr_num),
                ct_func = null
            };

            output_queue.Push(new_token);
        }
Example #12
0
        /// <summary>
        /// Reads the next token from the input stream and sets the parser's state
        /// based on that token's type.
        /// </summary>
        private void ReadNextTokenFromInput()
        {
            //
            // Eat any whitespaces.
            while (!IsEndOfInput() && Char.IsWhiteSpace(GetCurrentAtomFromInput()))
            {
                AdvanceToNextAtomEx();
            }

            if (IsEndOfInput())
            {
                return;
            }

            //
            // Analyze current token and set parser's state.
            Char curr_atom = GetCurrentAtomFromInput();

            if (curr_atom == '-' && CanPeekNextAtomAndIsDigit())
            {
                if (!op_stack.Any() ||
                    op_stack.Peek().ct_type == CalculatorToken.TOKEN_Type.TOKEN_Type_RightParen)
                {
                    CalculatorToken fake_plus = new CalculatorToken {
                        ct_func = "+",
                        ct_type = CalculatorToken.TOKEN_Type.TOKEN_Type_Operator,
                        ct_fval = 0.0f
                    };
                    op_stack.Push(fake_plus);
                }
                curr_state = ParserState.ParserState_Digit;
                return;
            }

            if (Char.IsDigit(curr_atom))
            {
                curr_state = ParserState.ParserState_Digit;
                return;
            }

            if (TokenIsAnOperator(curr_atom))
            {
                curr_state = ParserState.ParserState_Operator;
                return;
            }

            if (Char.IsLetter(curr_atom))
            {
                curr_state = ParserState.ParserState_Func;
                return;
            }

            if (curr_atom == '(')
            {
                curr_state = ParserState.ParserState_LeftParen;
                return;
            }

            if (curr_atom == ')')
            {
                curr_state = ParserState.ParserState_RightParen;
                return;
            }

            if (curr_atom == ',')
            {
                curr_state = ParserState.ParserState_Comma;
                return;
            }

            curr_state = ParserState.ParserState_Error;
        }