private Var Evaluate(ref string expression, bool recursive)
        {
            Stack <Var>          mOperands  = new Stack <Var>();
            Stack <OperatorInfo> mOperators = new Stack <OperatorInfo>();

            // Initialize bounds
            mOperators.Push(new OperatorInfo("", -1, ""));
            ParsingState state = ParsingState.expectingOperand;

            while (true)
            {
                Token token = GetNextToken(ref expression);

                switch (state)
                {
                case ParsingState.expectingOperand:
                    //---------------------------------
                    switch (token.tokentype)
                    {
                    case TokenType.constantNumber:
                        mOperands.Push(new DecimalVar(token.t));
                        state = ParsingState.expectingOperator;
                        continue;

                    case TokenType.constantString:
                        mOperands.Push(new StringVar(token.t));
                        state = ParsingState.expectingOperator;
                        continue;

                    case TokenType.identifier:
                        // Controleer of het een bekende constante is
                        Var r = CheckConstantValue(token.t);
                        if (r != null)
                        {
                            mOperands.Push(r);
                            state = ParsingState.expectingOperator;
                            continue;
                        }

                        // Controleer of het een standaard functie is
                        if (OperatorInfo.cvOperators.Contains(token.t))
                        {
                            OperatorInfo op = OperatorInfo.cvOperators[token.t] as OperatorInfo;
                            System.Diagnostics.Debug.Assert(op.function);
                            mOperators.Push(op.Kloon());
                            state = ParsingState.expectingParameterList;
                            continue;
                        }

                        // Controleer op een Variabele referentie
                        r = myTokenResolver.TokenEvaluator(token.t);
                        if (r != null)
                        {
                            mOperands.Push(r);
                            state = ParsingState.expectingOperator;
                            continue;
                        }

                        // Controleer op een functieaanroep
                        FunctionInfo fi = myTokenResolver.FunctionFinder(token.t);
                        if (fi != null)
                        {
                            OperatorInfo op = new OperatorInfo(fi.Name, 98, null, false, true);
                            mOperators.Push(op);
                            state = ParsingState.expectingParameterList;
                            continue;
                        }

                        // Anders kan het niks zijn.
                        throw new SyntaxErrorException(null, token.t);

                    case TokenType.openhaak:
                        mOperands.Push(Evaluate(ref expression, true));
                        token = GetNextToken(ref expression);
                        if (token.tokentype != TokenType.sluithaak)
                        {
                            throw new ParenthesisCloseExpectedException(null, token.t);
                        }

                        state = ParsingState.expectingOperator;
                        continue;

                    default:
                        throw new SyntaxErrorException(null, token.t);
                    }

                case ParsingState.expectingOperator:
                    //---------------------------------

                    switch (token.tokentype)
                    {
                    case TokenType.sluithaak:
                    case TokenType.komma:
                    case TokenType.sluitblokhaak:
                        // Dat kan als we recursief zijn aangeroepen
                        if (recursive)
                        {
                            // un-get de token in de expressie.
                            expression = token.ToString() + expression;
                            while (mOperators.Peek().name != "")
                            {
                                ProcessOperator(mOperators.Pop(), mOperands);
                            }
                            System.Diagnostics.Debug.Assert(mOperands.Count == 1);
                            System.Diagnostics.Debug.Assert(mOperators.Count == 1);

                            return(mOperands.Count > 0 ? mOperands.Pop() : null);
                        }
                        throw new UnknownTokenException(null, token.t);

                    case TokenType.none:
                        // einde van de expressie. We moeten alle operatoren van de stack
                        // uitvoeren en uiteindelijk op 1 operand uitkomen en die
                        // teruggeven.
                        while (mOperators.Peek().name != "")
                        {
                            ProcessOperator(mOperators.Pop(), mOperands);
                        }
                        System.Diagnostics.Debug.Assert(mOperands.Count <= 1);
                        System.Diagnostics.Debug.Assert(mOperators.Count == 1);

                        return(mOperands.Count > 0 ? mOperands.Pop() : null);

                    case TokenType.other:
                        // Check ff dat het echt een operator is die we kennen.
                        if (!OperatorInfo.cvOperators.Contains(token.t))
                        {
                            throw new OperatorExpectedException(null, token.t);
                        }

                        OperatorInfo op = OperatorInfo.cvOperators[token.t] as OperatorInfo;
                        System.Diagnostics.Debug.Assert(!op.function);

                        while (op.precedence <= mOperators.Peek().precedence)
                        {
                            ProcessOperator(mOperators.Pop(), mOperands);
                        }
                        mOperators.Push(op.Kloon());
                        state = ParsingState.expectingOperand;
                        continue;

                    default:
                        throw new OperatorExpectedException(null, token.t);
                    }

                case ParsingState.expectingParameterList:
                    //---------------------------------
                    switch (token.tokentype)
                    {
                    case TokenType.openhaak:
                        // Verwerk zolang operands tot er geen komma meer is.
                        token = GetNextToken(ref expression);
                        if (token.tokentype == TokenType.sluithaak)
                        {
                            // het moet een functie zonder parameters zijn
                            ProcessOperator(mOperators.Pop(), mOperands);
                            state = ParsingState.expectingOperator;
                            continue;
                        }
                        // Oeps, het was zeker het begin van een expressie die een parameter oplevert.
                        // Zet de token er weer voor.
                        expression = token.ToString() + expression;
                        do
                        {
                            mOperators.Peek().parameters.Add(Evaluate(ref expression, true));
                            token = GetNextToken(ref expression);
                        } while (token.tokentype == TokenType.komma);

                        // en check dat dat dan wel een ')' is.
                        if (token.tokentype != TokenType.sluithaak)
                        {
                            throw new ParenthesisCloseExpectedException(null, token.t);
                        }

                        ProcessOperator(mOperators.Pop(), mOperands);
                        state = ParsingState.expectingOperator;
                        continue;

                    default:
                        throw new ParenthesisOpenExpectedException(null, token.t);
                    }

                case ParsingState.expectingParameter:
                    //---------------------------------
                    System.Diagnostics.Debug.Assert(false);
                    continue;

                case ParsingState.expectingArrayList:
                    //---------------------------------
                    System.Diagnostics.Debug.Assert(false);
                    break;

                case ParsingState.expectingArrayIndex:
                    //---------------------------------
                    System.Diagnostics.Debug.Assert(false);
                    break;
                }
            }
        }
Exemple #2
0
        public Var Evaluate(string expression)
        {
            System.Globalization.NumberFormatInfo
                numberformat = new System.Globalization.NumberFormatInfo();
            numberformat.NumberDecimalSeparator = ".";

            int i;

            mOperands  = new Stack();
            mOperators = new Stack();

            // Simulate expression in brackets

            PushOperator(new OperatorInfo("(", -1, ""));
            expression = expression + ").";

            bool bLastTokenWasOperand
                = false;

            while (expression != ".")
            {
                // Allow for continue from multiple levels.
                bool bGotoNextPart
                    = false;

                // first eat all spaces
                if (Char.IsWhiteSpace(expression[0]))
                {
                    do
                    {
                        expression = expression.Remove(0, 1);
                    } while (Char.IsWhiteSpace(expression[0]));
                    continue;
                }

                // Look for an operator. If found process it...
                foreach (OperatorInfo op in OperatorInfo.cvOperators.Values)
                {
                    if (expression.StartsWith(op.name) && (!op.IsText || !Char.IsLetter(expression[op.name.Length])))
                    {
                        if (op.name == ")" || op.name == ",")
                        {
                            // Make sure any awaiting operations are processed first
                            do
                            {
                                ProcessOperator();
                            } while (mTopOperator.name != "(" && mTopOperator.name != ",");
                            // Now push the ) and process the () or function call.
                            PushOperator(op);
                            ProcessOperator();
                        }
                        //else if (!bLastTokenWasOperand && !op.function)
                        //{
                        //    throw new OperandExpectedException(0, expression.Substring(0, expression.Length - 2));
                        //}
                        else if ((op.precedence > mTopOperator.precedence) ||
                                 (mTopOperator.name == "("))
                        {
                            // Next operator is higher in precedence. Process it first.
                            PushOperator(op);
                        }
                        else
                        {
                            do
                            {
                                ProcessOperator();
                            } while (op.precedence <= mTopOperator.precedence && mTopOperator.name != "(" && mTopOperator.name != ",");
                            PushOperator(op);
                        }
                        bLastTokenWasOperand = false;
                        expression           = expression.Remove(0, op.name.Length);
                        bGotoNextPart        = true;
                        break;
                    }
                }
                if (bGotoNextPart)
                {
                    continue;
                }

                if (bLastTokenWasOperand)
                {
                    throw new Exceptions.OperatorExpectedException(null, expression.Substring(0, expression.Length - 2));
                }

                // Now check to see if first part of expression is a number
                if (Char.IsDigit(expression, 0))
                {
                    DecimalVar v = new DecimalVar();
                    i = 0;
                    // Eat the integer part of the number
                    do
                    {
                        i++;
                    } while (Char.IsDigit(expression, i));
                    if (expression[i] == '.')
                    {
                        // It is a decimal
                        do
                        {
                            i++;
                        } while (Char.IsDigit(expression, i));
                        v.v = Decimal.Parse(expression.Substring(0, i), System.Globalization.NumberStyles.Number, numberformat);
                    }
                    else
                    {
                        // It is an integer
                        v.v = Int32.Parse(expression.Substring(0, i));
                    }
                    v.empty = false;
                    mOperands.Push(v);
                    expression           = expression.Remove(0, i);
                    bLastTokenWasOperand = true;
                    continue;
                }

                // Check if first part is string constant
                if (expression[0] == '\"')
                {
                    i = 1;
                    StringVar v = new StringVar();
                    while (i < expression.Length && expression[i] != '\"')
                    {
                        if (expression[i] == '\\')
                        {
                            if ((i + 1) == expression.Length)
                            {
                                throw new StringTerminatorExpectedException(null, expression);
                            }
                            switch (expression[i + 1])
                            {
                            case '\"':
                                v.v += "\"";
                                break;

                            case '\\':
                                v.v += "\\";
                                break;

                            case 't':
                                v.v += "\t";
                                break;

                            case 'n':
                                v.v += "\n";
                                break;

                            default:
                                v.v += expression[i + 1].ToString();
                                break;
                            }
                            // Shift additional position
                            i++;
                        }
                        else
                        {
                            v.v += expression[i].ToString();
                        }
                        i++;
                        v.empty = false;
                    }
                    if (i >= expression.Length)
                    {
                        throw new StringTerminatorExpectedException(null, expression.Substring(0, expression.Length - 2));
                    }

                    mOperands.Push(v);
                    expression           = expression.Remove(0, i + 1);
                    bLastTokenWasOperand = true;
                    continue;
                }

                // Eat all identifiers, separated by '.' and make it
                // a big token. Let the delegate decide which part it
                // can process.
                bool bTokenEnded = false;
                i = 0;
                while (!bTokenEnded)
                {
                    if (!Char.IsLetter(expression, i))
                    {
                        bTokenEnded = true;
                        break;
                    }
                    i++;

                    // identifier consists of letter + 0/more letter/digit/_
                    while (Char.IsLetterOrDigit(expression, i) ||
                           expression[i] == '_')
                    {
                        i++;
                    }
                    if (expression[i] != '.')
                    {
                        bTokenEnded = true;
                        break;
                    }
                    i++; // Read over the '.' and get next identifier
                }
                if (i > 0)
                {
                    StringVar sToken = new StringVar(expression.Substring(0, i));

                    Var r = CheckConstantValue(sToken);
                    if (r == null)
                    {
                        r = myTokenResolver.TokenEvaluator(sToken);
                    }

                    if (r == null)
                    {
                        FunctionInfo fi = myTokenResolver.FunctionFinder(sToken.v);
                        if (fi != null)
                        {
                            OperatorInfo oi = new OperatorInfo(fi.Name, 98, null, false, true);
                            PushOperator(oi);
                            expression           = expression.Remove(0, i);
                            bLastTokenWasOperand = true;
                            continue;
                        }
                    }
                    else
                    {
                        // Store the result on the operand stack.
                        mOperands.Push(r);
                        // Remove the tokens we ate, and replace it with the
                        // remainders of the tokenevaluation
                        expression           = expression.Remove(0, i);
                        expression           = sToken.v + expression;
                        bGotoNextPart        = true;
                        bLastTokenWasOperand = true;
                    }
                }

                if (bGotoNextPart)
                {
                    continue;
                }

                throw new UnknownTokenException(-1, expression.Substring(0, i)); //this new StringVar(String.Format("Syntax error. '{0}' unexpected.", expression.Substring(0,i)));
                //throw new ApplicationException(String.Format("Syntax error. '{0}' unexpected.", expression.Substring(0,i)));
            }

            if (bLastTokenWasOperand)
            {
                throw new OperatorExpectedException(-1, expression.Substring(-1, expression.Length - 2));
            }

            //ProcessOperator();
            if (mOperands.Count == 0)
            {
                return(null);
            }
            else
            {
                return(mOperands.Pop() as Var);
            }
        }