/// <summary> /// Decode the token, is it an operand type double number? /// </summary> /// <param name="token"></param> /// <param name="result"></param> /// <param name="exprFinalOperand"></param> /// <returns></returns> private bool IsOperandDouble(ExprToken token, ParseResult result, ExprFinalOperand exprFinalOperand) { global::System.IFormatProvider culture = null; if (_exprEvalConfig.DecimalAndFunctionSeparators == DecimalAndFunctionSeparators.Standard) { // the decimal separator is a point, exp: 123.45 culture = new global::System.Globalization.CultureInfo("en-US"); } else { // the decimal separator is a comma, exp: 123,45 culture = new global::System.Globalization.CultureInfo("fr-fr"); } //NumberStyles styles = NumberStyles.AllowExponent | NumberStyles.AllowThousands | NumberStyles.AllowDecimalPoint; NumberStyles styles = NumberStyles.AllowExponent | NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign; double numberDouble; if (double.TryParse(token.Value, styles, culture, out numberDouble)) { exprFinalOperand.ContentType = OperandType.ValueDouble; exprFinalOperand.ValueDouble = numberDouble; return(true); } // its not a double operand value return(false); }
/// <summary> /// Can Group these 2 tokens ? /// (because both represents a special token). /// Manage these cases: negative numbers like: 3toks: -, -, 12 ---> 2toks: -, -12 /// a, -, -, 12 -> group it a, -, -12 /// a, -, 3 -> don't group -3 !! /// a, =, -, 3 -> group it a, =, -3 /// a and - 3 - group it, /// </summary> /// <returns></returns> private bool CanGroupTokens(ExprToken prevToken, ExprToken token, ExprToken nextToken) { // DEBUG: //ExprToken prevToken = null; if (nextToken == null) { // no more next token, so can't group return(false); } // manage negative number if (token.Value == "-") { // the next one is again a minus sign? if (nextToken.Value == "-") { // its a special case (exp: --12) return(false); } // need to check the previous token: can group only if its a calculation token: +,-, *,/, modulo // exp: a-3 don't group -3!! // ok can group, its a negative number (have to check that the next token is a number) if (prevToken == null) { // can group, exp -3 ... return(true); } // if the previous token is an operator: logical, comparison or calculation -> group it , its a negative number. // todo: manque cas spécial du modulo!! exp: 12 modulo -3 -> il faut grouper!! if (_exprEvalConfig.IsOperator(prevToken.Value)) { // ok, can group, exp: + - 3 --> + -3 return(true); } // can't group, exp: a - 3 return(false); } // the current token is the start of a special token having more than one char, exp: >= string specialToken; if (IsStartSpecialOperator(token.Value, out specialToken)) { // the next token should be the end of the special large operator if (IsEndSpecialOperator(specialToken, nextToken.Value)) { // ok, can group these two tokens return(true); } } // can't group these two tokens return(false); }
private void FinalizeToken(List <ExprToken> listExprToken, ExprToken token) { // termine le token précédent s'il y a if (token == null) { return; } listExprToken.Add(token); }
public ExprError AddError(ErrorCode errorCode, ExprToken token) { var error = new ExprError(); error.Code = errorCode; error.Token = token; ListError.Add(error); return(error); }
/// <summary> /// Decode the token, is it an operator?? /// Depending of the language, get the right operator. /// can be: /// Logical, comparison, calculation or a setValue. /// </summary> /// <param name="token"></param> private bool DecodeTokenOperator(Stack <ExpressionBase> stack, ExprToken token) { //----is it a comparison operator? if (_exprEvalConfig.DictComparisonOperators.ContainsKey(token.Value.ToLower())) { OperatorComparisonCode operComp = _exprEvalConfig.DictComparisonOperators[token.Value.ToLower()]; // empile le token opérateur ExprOperatorComparison exprOperatorComparison = new ExprOperatorComparison(); exprOperatorComparison.Operator = operComp; exprOperatorComparison.Token = token; stack.Push(exprOperatorComparison); return(true); } // is it a logical operator? if (_exprEvalConfig.DictLogicalOperators.ContainsKey(token.Value.ToLower())) { OperatorLogicalCode operLogical = _exprEvalConfig.DictLogicalOperators[token.Value.ToLower()]; // is it the NOT operator? if (operLogical == OperatorLogicalCode.Not) { // empile le token opérateur ExprOperatorLogicalNot exprOperatorLogicalNot = new ExprOperatorLogicalNot(); exprOperatorLogicalNot.Token = token; stack.Push(exprOperatorLogicalNot); return(true); } // empile le token opérateur ExprOperatorLogical exprOperatorLogical = new ExprOperatorLogical(); exprOperatorLogical.Operator = operLogical; exprOperatorLogical.Token = token; stack.Push(exprOperatorLogical); return(true); } // is it a calculation operator? if (_exprEvalConfig.DictCalculationOperators.ContainsKey(token.Value.ToLower())) { OperatorCalculationCode operCalc = _exprEvalConfig.DictCalculationOperators[token.Value.ToLower()]; // empile le token opérateur ExprOperatorCalculation exprOperatorCalc = new ExprOperatorCalculation(); exprOperatorCalc.Operator = operCalc; exprOperatorCalc.Token = token; stack.Push(exprOperatorCalc); return(true); } // the token is not an operator return(false); }
/// <summary> /// Build a new token, add it to the list (if exists). /// </summary> /// <param name="listExprToken"></param> /// <param name="currPos"></param> /// <param name="strToken"></param> /// <returns></returns> private ExprToken BuildToken(List <ExprToken> listExprToken, int currPos, string strToken) { var token = new ExprToken(); token.Position = currPos; token.Value = strToken; if (listExprToken != null) { listExprToken.Add(token); } return(token); }
private bool CheckObjectNameSyntax(ExprToken token, ParseResult result, ExprFinalOperand exprFinalOperand) { exprFinalOperand.ContentType = OperandType.ObjectName; // the first char mut be: a letter or an underscore if (!char.IsLetter(token.Value[0]) && token.Value[0] != '_') { // erreur! plus de token, token attendu: opérande gauche. ExprError error = new ExprError(); error.Code = ErrorCode.ObjectNameSyntaxWrong; result.ListError.Add(error); return(false); } // check others char of the objectName // ici(); exprFinalOperand.ContentType = OperandType.ObjectName; return(true); }
/// <summary> /// adds open and close bracket to the tokens, exp A=B -> (A=B) /// /// Only if there is no brackets, open and close. /// /// Because the process is made for expressions having always opne and close bracket. /// </summary> /// <param name="listTokens"></param> private void AddBrackets(List <ExprToken> listTokens) { // get the first token ExprToken firstToken = listTokens[0]; ExprToken lastToken = listTokens[listTokens.Count - 1]; //if (firstToken.Value == "(" && lastToken.Value == ")") // the expression has an opened and a closed bracket, so nothing to do // return; // there is no open and close bracket, so add it ExprToken tokenOpenBracket = new ExprToken(); tokenOpenBracket.Position = 0; tokenOpenBracket.Value = "("; listTokens.Insert(0, tokenOpenBracket); ExprToken tokenCloseBracket = new ExprToken(); tokenCloseBracket.Position = 0; tokenCloseBracket.Value = ")"; listTokens.Add(tokenCloseBracket); }
/// <summary> /// Split the expression string, generate tokens. /// </summary> /// <returns></returns> public List <ExprToken> SplitExpr(string expr) { List <ExprToken> listExprToken = new List <ExprToken>(); if (_listSpecial2CharOperators == null) { return(listExprToken); } if (string.IsNullOrWhiteSpace(expr)) { return(listExprToken); } // scan the string expression, char by char int currPos = 0; char currChar; ExprToken token = null; while (true) { // plus de char à traiter? if (currPos >= expr.Length) // finalise token encours, s'il y a { // termine le token précédent s'il y a FinalizeToken(listExprToken, token); token = null; break; } // recup car en cours currChar = expr[currPos]; //----Est-ce un car séparteur pur (espace, tab,...)? (ne pas garder) if (_listSeparatorPure.Contains(currChar)) { // termine le token précédent s'il y a FinalizeToken(listExprToken, token); token = null; // passe au char suivant currPos++; continue; } //----Est-ce un car séparateur spécial? (à garder) if (_exprEvalConfig.ListSeparatorSpecial.Contains(currChar)) { // termine le token précédent s'il y a FinalizeToken(listExprToken, token); // est un nouveau token BuildToken(listExprToken, currPos, currChar.ToString()); token = null; // passe au char suivant currPos++; continue; } //----Is it a string start tag? if (_exprEvalConfig.StringTagValue == currChar.ToString()) { // termine le token précédent s'il y a FinalizeToken(listExprToken, token); // save start position of the string int posStartString = currPos; char tagStartString = currChar; // find the string end tag (must find) int posEndString; if (!FindStringEndTag(expr, posStartString, tagStartString, out posEndString)) { // create a new token token = BuildToken(listExprToken, currPos, expr.Substring(currPos, posEndString + 1 - currPos)); token = null; // stop, no end tag found, so get all the end of the expr string return(listExprToken); } // create a new token token = BuildToken(listExprToken, currPos, expr.Substring(currPos, posEndString + 1 - currPos)); token = null; currPos = posEndString; // passe au char suivant currPos++; continue; } //----Is it a comment start tag? // todo: //----le car courant est un car std de token // pas de token précédent? if (token == null) { // create a new token token = BuildToken(null, currPos, currChar.ToString()); // passe au char suivant currPos++; continue; } // car de token, ajoute le char au token token.Value += currChar.ToString(); // passe au char suivant currPos++; } // return the list of token found in the string return(listExprToken); }
/// <summary> /// group tokens if necessary, like operators comparators (having 2 char length) /// Depends on specials char. /// group also negative number, exp: -, 12 becomes -12 /// /// exp: '>', '=' becomes '>=' /// /// </summary> /// <param name="expr"></param> /// <param name="listTokens"></param> /// <returns></returns> public List <ExprToken> GroupTokens(string expr, List <ExprToken> listTokens) { List <ExprToken> listTokensOut = new List <ExprToken>(); // expr is null or mepty, contains no token, so the returned list is empty if (listTokens.Count == 0) { return(listTokensOut); } if (_listSpecial2CharOperators == null) { return(listTokensOut); } // scan all tokens int i = 0; ExprToken prevToken; ExprToken token; ExprToken nextToken; while (true) { // no more token to process if (i >= listTokens.Count) { break; } if (i > 0) { prevToken = listTokens[i - 1]; } else { prevToken = null; } // get the current token token = listTokens[i]; // get the next one if exists nextToken = GetToken(listTokens, i + 1); // both current token and the next can be grouped/compacted // need the previous to manage the minus case if (CanGroupTokens(prevToken, token, nextToken)) { // build a new token based on two: current and next ExprToken groupToken = new ExprToken(); groupToken.Position = token.Position; groupToken.Value = token.Value + nextToken.Value; // save it listTokensOut.Add(groupToken); // move to next token (first step) i++; } else { listTokensOut.Add(token); } i++; } return(listTokensOut); }
/// <summary> /// Build the final operand: not a separator. /// can be a number (positive or negative), an object name (var, fct,...) or a string. /// /// The string can be well-formed or bad-formed: the end tag is missing. /// </summary> /// <param name="token"></param> /// <returns></returns> private ExprFinalOperand BuildOperand(ExprToken token, ParseResult result) { ExprFinalOperand exprFinalOperand = new ExprFinalOperand(); exprFinalOperand.Operand = token.Value; exprFinalOperand.Token = token; //----is the value a string? starts with a string tag (quote or double-quote) if (_exprEvalConfig.StringTagValue == token.Value[0].ToString()) { // is the last char a string tag? //if (_exprEvalConfig.ListStringTag.Contains(token.Value[token.Value.Length-1]) && token.Value.Length>1) if (_exprEvalConfig.StringTagValue == token.Value[token.Value.Length - 1].ToString() && token.Value.Length > 1) { exprFinalOperand.ContentType = OperandType.ValueString; return(exprFinalOperand); } exprFinalOperand.ContentType = OperandType.ValueStringBadFormed; ExprError error = new ExprError(); error.Token = token; error.Code = ErrorCode.ValueStringBadFormed; result.ListError.Add(error); return(exprFinalOperand); } //----is the value an integer? int numberInt; if (int.TryParse(token.Value, out numberInt)) { exprFinalOperand.ContentType = OperandType.ValueInt; exprFinalOperand.ValueInt = numberInt; return(exprFinalOperand); } //----is the value a double? if (IsOperandDouble(token, result, exprFinalOperand)) { return(exprFinalOperand); } // is it a bad-formed number? (seems to be number: start with minus or a digit) if (token.Value[0] == '-' || char.IsDigit(token.Value[0])) { exprFinalOperand.ContentType = OperandType.ValueNumberBadFormed; ExprError error = new ExprError(); error.Token = token; error.Code = ErrorCode.ValueNumberBadFormed; result.ListError.Add(error); return(exprFinalOperand); } //-----is it a bool value? // todo: get values from the configurator: true/false, vrai/faux BoolConst boolConst = _exprEvalConfig.ListBoolConst.Find(bc => bc.BoolStringValue.Equals(token.Value, StringComparison.InvariantCultureIgnoreCase)); if (boolConst != null) { exprFinalOperand.ContentType = OperandType.ValueBool; exprFinalOperand.ValueBool = boolConst.BoolValue; return(exprFinalOperand); } // it's an object name, (sure?) check the syntax CheckObjectNameSyntax(token, result, exprFinalOperand); return(exprFinalOperand); }
/// <summary> /// Is the token a function call paramater separator? /// a comma or a dot-comma, depending on the configuration. /// </summary> /// <param name="stack"></param> /// <param name="token"></param> /// <returns></returns> private bool DecodeTokenFunctionCallParameterSeparator(Stack <ExpressionBase> stack, ExprToken token) { // is it a function call parameter separator? if (_exprEvalConfig.DecimalAndFunctionSeparators == DecimalAndFunctionSeparators.Standard) { // is it the comma? exp: fct(a,b) if (token.Value == ",") { // yes! ExprFunctionCallParameterSeparator exprSeparator = new ExprFunctionCallParameterSeparator(); exprSeparator.Token = token; stack.Push(exprSeparator); return(true); } // no return(false); } // is it a function call parameter separator? if (_exprEvalConfig.DecimalAndFunctionSeparators == DecimalAndFunctionSeparators.ExcelLike) { // is it the dot-comma? exp: fct(a;b) if (token.Value == ";") { // yes! ExprFunctionCallParameterSeparator exprSeparator = new ExprFunctionCallParameterSeparator(); exprSeparator.Token = token; stack.Push(exprSeparator); return(true); } // no return(false); } // not the function call parameter separator return(false); }