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;
                }
            }
        }
        /// <summary>
        /// Process the top operator on the operator stack.
        /// Consume as many operands as needed from the operands stack.
        /// When top-operator is closing bracket, two options:
        ///   a * ( b + c )
        ///   In(a, b)
        /// </summary>
        private void ProcessOperator(OperatorInfo op, Stack <Var> operands)
        {
            ArrayList arglist = new ArrayList();

            if (op.function)
            {
                foreach (Var v in op.parameters)
                {
                    arglist.Add(v);
                }
            }
            else
            {
                // It must be an operator. It can be unary or not, so get at least one operand.
                arglist.Insert(0, operands.Pop());
                if (!op.unary)
                {
                    arglist.Insert(0, operands.Pop());
                }
            }

            if (op.methodname == null && op.function)
            {
                // Process function
                // Haal eerst de functieinformatie op.
                Var result = myTokenResolver.FunctionEvaluator(op.name, arglist);
                System.Diagnostics.Debug.Assert(result != null);
                operands.Push(result);
            }
            else
            {
                Var          o1 = (arglist[0] as Var);
                System.Type  t1 = o1.GetType();
                MemberInfo[] ts = t1.FindMembers(
                    System.Reflection.MemberTypes.Method,
                    System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public,
                    new System.Reflection.MemberFilter(FindOperator),
                    op);

                if (ts.GetLength(0) == 0)
                {
                    throw new OperationNotDefinedException(null, op.name, o1.TypeName(), arglist);
                }

                // Find the method taking the right type of parameter
                MethodInfo methodFound = null;
                foreach (MethodInfo method in ts)
                {
                    ParameterInfo[] parms = method.GetParameters();

                    if (parms.GetLength(0) == arglist.Count)
                    {
                        methodFound = method;
                        for (int pi = 0; pi < arglist.Count; pi++)
                        {
                            if (parms[pi].ParameterType != arglist[pi].GetType())
                            {
                                methodFound = null;
                                break;
                            }
                        }
                        if (methodFound != null)
                        {
                            break;
                        }
                    }
                }
                if (methodFound == null)
                {
                    throw new OperationNotDefinedException(null, op.name, o1.TypeName(), arglist);
                }

                // Method found. Apply it
                object[] args = arglist.ToArray();
                //			if (op.unary)
                //				args = new object[] {o1};
                //			else
                //				args = new object[] {o1, o2};

                if (methodFound.ReturnType == typeof(void))
                {
                    methodFound.Invoke(null, args);
                }
                else
                {
                    object result = methodFound.Invoke(null, args);
                    operands.Push(result as Var);
                }
            }
            return;
        }
Beispiel #3
0
        /// <summary>
        /// Process the top operator on the operator stack.
        /// Consume as many operands as needed from the operands stack.
        /// When top-operator is closing bracket, two options:
        ///   a * ( b + c )
        ///   In(a, b)
        /// </summary>
        private void ProcessOperator()
        {
            ArrayList arglist = new ArrayList();

            // Process closing bracket. Pop operators and process these
            // until an opening bracket is found on the stack.
            OperatorInfo op = PopOperator();

            if (op.name == ")")
            {
                op = PopOperator();
                while (op.name != "(")
                {
                    System.Diagnostics.Debug.Assert(op.name == ",", "Er zou alleen een ',' op de stack mogen staan of een '(', en niet een '" + op.name + "'");
                    arglist.Insert(0, mOperands.Pop());
                    op = PopOperator();
                }

                if (arglist.Count > 0)
                {
                    if (mTopOperator == null || !mTopOperator.function)
                    {
                        throw new ApplicationException(String.Format("Argument list found but not function call before '('"));
                    }
                }
                else
                {
                    // No arglist found.
                    // If function, pop first argument, else it was () combination. Return
                    if (mTopOperator == null || !mTopOperator.function)
                    {
                        return;
                    }
                }
                // It is a function call
                // Pop first argument
                arglist.Insert(0, mOperands.Pop());
                op = PopOperator();
            }
            else if (op.name == "," || op.name == "(")
            {
                PushOperator(op);                       // do not process yet!
                return;
            }
            else
            {
                // It must be an operator. It can be unary or not, so get at least one operand.
                arglist.Insert(0, mOperands.Pop());
                if (!op.unary)
                {
                    arglist.Insert(0, mOperands.Pop());
                }
            }

            Var o1 = (arglist[0] as Var);

            if (op.methodname == null && op.function)
            {
                // Process function
                // Haal eerst de functieinformatie op.
                Var result = myTokenResolver.FunctionEvaluator(op.name, arglist);
                mOperands.Push(result);
            }
            else
            {
                System.Type  t1 = o1.GetType();
                MemberInfo[] ts = t1.FindMembers(
                    System.Reflection.MemberTypes.Method,
                    System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public,
                    new System.Reflection.MemberFilter(FindOperator),
                    op);

                if (ts.GetLength(0) == 0)
                {
                    throw new ApplicationException(String.Format("Operation '{0}' not defined for '{1}'", op.name, o1.GetType().Name));
                }

                // Find the method taking the right type of parameter
                MethodInfo methodFound = null;
                foreach (MethodInfo method in ts)
                {
                    ParameterInfo[] parms = method.GetParameters();

                    if (parms.GetLength(0) == arglist.Count)
                    {
                        methodFound = method;
                        for (int pi = 0; pi < arglist.Count; pi++)
                        {
                            if (parms[pi].ParameterType != arglist[pi].GetType())
                            {
                                methodFound = null;
                                break;
                            }
                        }
                        if (methodFound != null)
                        {
                            break;
                        }
                    }
                }
                if (methodFound == null)
                {
                    string msg = String.Format("Operation '{0}' not defined for ", op.name);
                    foreach (Var v in arglist)
                    {
                        msg += "'" + v.GetType().Name + "',";
                    }
                    throw new ApplicationException(msg);
                    //				if (op.unary)
                    //					throw new ApplicationException(String.Format("Operation '{0}' not defined for '{1}'", op.name, o1.GetType().Name));
                    //				else
                    //					throw new ApplicationException(String.Format("Operation '{0}' not defined for '{1}' and '{2}'", op.name, o1.GetType().Name, o2.GetType().Name));
                }

                // Method found. Apply it
                object[] args = arglist.ToArray();
                //			if (op.unary)
                //				args = new object[] {o1};
                //			else
                //				args = new object[] {o1, o2};

                if (methodFound.ReturnType == typeof(void))
                {
                    methodFound.Invoke(null, args);
                }
                else
                {
                    object result = methodFound.Invoke(null, args);
                    mOperands.Push(result);
                }
            }
            return;
        }
Beispiel #4
0
 private void PushOperator(OperatorInfo op)
 {
     mOperators.Push(op);
     mTopOperator = op;
 }
Beispiel #5
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);
            }
        }