示例#1
0
        void AddOperatorToExpr(char token, int index)
        {
            // An operator can follow a number or a symbol, thus:
            AddOperandToExpr();

            exprList.Add(CalcToken.Operator(token, index));
        }
示例#2
0
        void AddSepToExpr(int index)
        {
            // An argument seperator can follow a number or a symbol, thus:
            AddOperandToExpr();

            exprList.Add(CalcToken.ArgSeperator(index));
        }
示例#3
0
        public static bool VerifySymbol(string symbol)
        {
            // Cannot contain certain reserverd characters. Or whitespace.
            foreach (char c in symbol)
            {
                if (CalcToken.IsOperatorChar(c) ||
                    char.IsWhiteSpace(c))
                {
                    return(false);
                }

                switch (c)
                {
                case '(':
                case ')':
                case '.':
                case ',':
                    return(false);
                }
            }
            // It also can't be empty or start with a digit.
            if (symbol.Length > 0 && !char.IsDigit(symbol[0]))
            {
                return(true);
            }

            return(false);
        }
示例#4
0
        // -----------------------------------------
        // --- Methods for multicharacter tokens ---
        // -----------------------------------------


        void UpdateLastOperator(char c)
        {
            int    lastIdx = exprList.Count - 1;
            var    last    = exprList[lastIdx];
            string newOp   = last.Value + c;

            exprList[lastIdx] = CalcToken.Operator(newOp, last.OriginIndex);
        }
示例#5
0
        void AddRParenToExpr(int index)
        {
            // A right parenthesis can follow a number or a symbol, thus:
            AddOperandToExpr();

            exprList.Add(CalcToken.ParenClose(index));
            // Record the closing of a subexpression to the parentheses balance.
            depthMeter.Pop();
        }
示例#6
0
        // -------------------------------------------
        // --- Methods for single character tokens ---
        // -------------------------------------------

        void AddLParenToExpr(int index)
        {
            // A left parenthesis can follow a function, thus:
            bool funcSubexpr = AddFuncToExpr();

            exprList.Add(CalcToken.ParenOpen(index));
            // Record the opening of a subexpression to the parentheses balance.
            // Also record whether the subexpression we entered is associated with a function.
            depthMeter.Push(funcSubexpr);
        }
示例#7
0
        void AddNumToExpr()
        {
            if (numberStart >= 0 && tmpToken.Count > 0)
            {
                var num = new string( tmpToken.ToArray());
                exprList.Add(CalcToken.Number(num, numberStart));

                tmpToken.Clear();
            }

            decimalPoint = false;
            numberStart  = -1;
        }
示例#8
0
        bool AddSymToExpr(bool isFunction)
        {
            bool added = false;

            if (symbolStart >= 0 && tmpToken.Count > 0)
            {
                var sym = new string( tmpToken.ToArray());
                if (isFunction)
                {
                    exprList.Add(CalcToken.Function(sym, symbolStart));
                }
                else
                {
                    exprList.Add(CalcToken.Symbol(sym, symbolStart));
                }

                added = true;
                tmpToken.Clear();
            }

            symbolStart = -1;
            return(added);
        }
示例#9
0
 public void Push(CalcToken t)
 {
     opStack.Push(t);
 }
示例#10
0
        public TokenExpression Tokenize(string expr)
        {
            exprList = new List <CalcToken>();
            tmpToken = new List <char>();

            // Set initial values of control and housekeeping variables.
            TokenTypes allowedTokens = TokenTypes.ExprBegin;

            decimalPoint = false;
            numberStart  = -1;
            symbolStart  = -1;
            depthMeter   = new Stack <bool>();
            // Look-behind 1 character for double char ops.
            char prevc = '\0';

            for (int i = 0; i < expr.Length; i++)
            {
                char c = expr[i];

                // ----------------------
                // ----- [1] Number -----
                // ----------------------
                if (char.IsDigit(c))
                {
                    if (allowedTokens.HasFlag(TokenTypes.Number))
                    {
                        AddDigitToNum(c, i);
                        // Set the allowed tokens for the next character.
                        allowedTokens = TokenTypes.Number | TokenTypes.ExprEnd;
                    }
                    else
                    {
                        return(new TokenExpression("Unexpected number: " + c, i));
                    }
                }
                else if (c == '.')
                {
                    if (allowedTokens.HasFlag(TokenTypes.Number))
                    {
                        if (decimalPoint)
                        {
                            return(new TokenExpression("More than one decimal point detected", i));
                        }

                        AddDotToNum(i);
                        // Set the allowed tokens for the next character.
                        allowedTokens = TokenTypes.Number;
                    }
                    else
                    {
                        return(new TokenExpression("Unexpected decimal point", i));
                    }
                }

                // ---------------------------
                // ----- [2] Unary Minus -----
                // ---------------------------
                else if (c == '-' && allowedTokens.HasFlag(TokenTypes.UnaryMinus))
                {
                    exprList.Add(CalcToken.UnaryMinus(i));
                }

                // --------------------------------
                // ----- [3] Left Parenthesis -----
                // --------------------------------
                else if (c == '(')
                {
                    if (allowedTokens.HasFlag(TokenTypes.L_Paren))
                    {
                        AddLParenToExpr(i);
                        // Set the allowed tokens for the next character.
                        allowedTokens = TokenTypes.ExprBegin;
                    }
                    else
                    {
                        return(new TokenExpression("Unexpected left parenthesis", i));
                    }
                }

                // ---------------------------------
                // ----- [4] Right Parenthesis -----
                // ---------------------------------
                else if (c == ')')
                {
                    if (allowedTokens.HasFlag(TokenTypes.R_Paren))
                    {
                        if (depthMeter.Count == 0)
                        {
                            return(new TokenExpression("Tried to close a subexpression before it was opened", i));
                        }

                        AddRParenToExpr(i);
                        // Set the allowed tokens for the next character.
                        allowedTokens = TokenTypes.ExprEnd;
                    }
                    else
                    {
                        return(new TokenExpression("Unexpected right parenthesis", i));
                    }
                }

                // ------------------------
                // ----- [5] Operator -----
                // ------------------------
                else if (CalcToken.IsOperatorChar(c))
                {
                    if (allowedTokens.HasFlag(TokenTypes.Operator))
                    {
                        AddOperatorToExpr(c, i);
                        // Set the allowed tokens for the next character.
                        allowedTokens = TokenTypes.ExprBegin;
                    }
                    else if (CalcToken.IsDoubleOperator(prevc, c))
                    {
                        UpdateLastOperator(c);
                        // Monkey with the `c` variable, and thus the next `prevc` character.
                        // This is to prevent operators longer than 2 chars to pass inspection.
                        c = '\0';
                    }
                    else
                    {
                        return(new TokenExpression("Unexpected operator: " + c, i));
                    }
                }

                // ----- [6] Whitespace -----
                // Ignore whitespace.
                else if (char.IsWhiteSpace(c))
                {
                    continue;
                }

                // ----------------------------------
                // ----- [7] Argument Seperator -----
                // ----------------------------------
                else if (c == ',')
                {
                    if (allowedTokens.HasFlag(TokenTypes.R_Paren))
                    {
                        if (depthMeter.Count == 0 || depthMeter.Peek() == false)
                        {
                            return(new TokenExpression("Illegal argument seperator", i));
                        }

                        AddSepToExpr(i);
                        // Set the allowed tokens for the next character.
                        allowedTokens = TokenTypes.ExprBegin;
                    }
                    else
                    {
                        return(new TokenExpression("Unexpected argument seperator", i));
                    }
                }

                // ----------------------
                // ----- [8] Symbol -----
                // ----------------------
                else if (allowedTokens.HasFlag(TokenTypes.Symbol))
                {
                    AddCharToSym(c, i);
                    // Set the allowed tokens for the next character.
                    allowedTokens = TokenTypes.Symbol | TokenTypes.L_Paren | TokenTypes.ExprEnd;
                }

                // ----- [9] Unexpected Character -----
                else
                {
                    return(new TokenExpression("Unexpected character: " + c, i));
                }

                prevc = c;
            }

            // Abort on unclosed subexpression(s) / too many left parentheses.
            if (depthMeter.Count > 0)
            {
                return(new TokenExpression("Unclosed subexpression(s) detected, amount: " + depthMeter.Count));
            }
            // Final check. The expression should have ended in either an operand or a right parenthesis. Both of these
            // set the allowedTokens to include TokenType.Operator, which would not be set by the others. So check for
            // that to determine whether the expression has ended correctly.
            if (!allowedTokens.HasFlag(TokenTypes.Operator))
            {
                return(new TokenExpression("Expression did not end with an operand or closing parenthesis"));
            }

            AddOperandToExpr();
            return(new TokenExpression(exprList));
        }