/// <summary> /// Returns a compiled expression for specified source string. /// </summary> public CompiledExpression Compile(PreparedExpression preparedExpression) { if (preparedExpression == null) { throw new ArgumentNullException("preparedExpression"); } // OperationsStack operationsStack = new OperationsStack(operationsRegistry); // for (int itemIndex = 0; itemIndex < preparedExpression.PreparedExpressionItems.Count; itemIndex++) { PreparedExpressionItem item = preparedExpression.PreparedExpressionItems[itemIndex]; // If constant or variable - add to result if (item.Kind == PreparedExpressionItemKind.Constant) { operationsStack.PushConstant(item.Constant); } if (item.Kind == PreparedExpressionItemKind.Variable) { operationsStack.PushVariable(item.VariableName); } // If delimiter if (item.Kind == PreparedExpressionItemKind.Delimiter) { operationsStack.PushDelimiter(item.DelimiterKind); } // Signature (operator signature / part of signature / function) if (item.Kind == PreparedExpressionItemKind.Signature) { List <Operation> operations = new List <Operation>(operationsRegistry.GetOperationsUsingSignature(item.Signature)); operations.Sort(new Comparison <Operation>(compareOperationsByOperandsCount)); // for (int i = 0; i < operations.Count; i++) { Operation operation = operations[i]; // Operator if (operation.Kind == OperationKind.Operator) { // Unary operator if (operation.OperandsCount == 1) { // If operator placed at the start of subexpression if ((itemIndex == 0) || ((itemIndex > 0) && (preparedExpression.PreparedExpressionItems[itemIndex - 1].Kind == PreparedExpressionItemKind.Delimiter) && (preparedExpression.PreparedExpressionItems[itemIndex - 1].DelimiterKind == DelimiterKind.OpeningBrace) || (preparedExpression.PreparedExpressionItems[itemIndex - 1].DelimiterKind == DelimiterKind.Comma))) { // operationsStack.PushUnaryOperator(operation); break; } } // Binary operator if (operation.OperandsCount == 2) { operationsStack.PushBinaryOperator(operation); break; } // Ternary and more if (operation.OperandsCount > 2) { int partNumber = 0; for (int k = 0; k < operation.Signature.Length; k++) { if (operation.Signature[k] == item.Signature) { partNumber = k + 1; break; } } // If it is start part in signature if (partNumber == 1) { operationsStack.PushComplexOperatorFirstSignature(operation); break; } // operationsStack.PushComplexOperatorNonFirstSignature(operation, partNumber); break; } } // Function if (operation.Kind == OperationKind.Function) { operationsStack.PushFunction(operation); break; } } } } // operationsStack.DoFinalFlush(); // CompiledExpression res = operationsStack.GetResult(); if (!isCompiledExpressionStackBalanced(res)) { throw new CompilerSyntaxException("Operands disbalance detected."); } return(res); }
/// <summary> /// Prepares source string for compilation. /// </summary> public PreparedExpression Parse(string sourceString) { if (sourceString == null) { throw new ArgumentNullException("sourceString"); } if (sourceString.Length == 0) { throw new ArgumentException("String is empty.", "sourceString"); } // Signatures lenghts int[] lens = _OperationsRegistry.SignaturesLens; List <PreparedExpressionItem> res = new List <PreparedExpressionItem>(); bool operandStarted = false; int operandStartIndex = 0; for (int i = 0; i < sourceString.Length; i++) { PreparedExpressionItem additionalItem = null; // Check for delimiters if ((sourceString[i] == '(') || (sourceString[i] == ')') || (sourceString[i] == ',')) { // Storing delimiter DelimiterKind delimiterKind = new DelimiterKind(); switch (sourceString[i]) { case '(': { delimiterKind = DelimiterKind.OpeningBrace; break; } case ')': { delimiterKind = DelimiterKind.ClosingBrace; break; } case ',': { delimiterKind = DelimiterKind.Comma; break; } } additionalItem = new PreparedExpressionItem(PreparedExpressionItemKind.Delimiter, delimiterKind); } // If not found, check for signatures, from max length to min if (additionalItem == null) { for (int j = lens.Length - 1; j >= 0; j--) { if (i + lens[j] <= sourceString.Length) { // If signature found if (_OperationsRegistry.IsSignatureDefined(sourceString.Substring(i, lens[j]))) { // Storing signature additionalItem = new PreparedExpressionItem(PreparedExpressionItemKind.Signature, sourceString.Substring(i, lens[j])); break; } } } } // If not found, working with operand if (additionalItem == null) { if (!operandStarted) { operandStarted = true; operandStartIndex = i; } } else { // NOTE: Duplicate code // Storing operand (constant or variable) if (operandStarted) { string operandString = sourceString.Substring(operandStartIndex, i - operandStartIndex); double constant; if (Double.TryParse(operandString, System.Globalization.NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out constant)) { res.Add(new PreparedExpressionItem(PreparedExpressionItemKind.Constant, constant)); } else { if (!IsValidVariableName(operandString)) { throw new CompilerSyntaxException(String.Format("{0} is not valid variable identifier.", operandString)); } res.Add(new PreparedExpressionItem(PreparedExpressionItemKind.Variable, operandString)); } operandStarted = false; } // Delayed storing a delimiter or signature res.Add(additionalItem); // If additionalItem was a signature, we should add correct i index according to signature lenght if (additionalItem.Kind == PreparedExpressionItemKind.Signature) { i += additionalItem.Signature.Length - 1; } } } // Storing operand (constant or variable) if (operandStarted) { string operandString = sourceString.Substring(operandStartIndex); double constant; if (Double.TryParse(operandString.Replace('.', ','), out constant)) { res.Add(new PreparedExpressionItem(PreparedExpressionItemKind.Constant, constant)); } else { if (!IsValidVariableName(operandString)) { throw new CompilerSyntaxException(String.Format("{0} is not valid variable identifier.", operandString)); } res.Add(new PreparedExpressionItem(PreparedExpressionItemKind.Variable, operandString)); } } return(new PreparedExpression(res)); }