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; } } }
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); } }