public OperandOperation(OperationBase value) { try { Type = OperandType.Operation; _Value = value; } catch (Exception ex) { Log.Write(ex, MethodBase.GetCurrentMethod(), EventLogEntryType.Error); throw; } }
/// <summary> /// Parse the string token to get an operand of type Literal, Reference, or Operation. /// 1) Literal operands return the value that they contain. /// 2) Reference operands use their own category item criteria /// to narrow down the list of cells to which the formula applies. Then the specific cell's criteria /// is used to identify categories not in the criteria, and use those to narrow down to a single source cell. /// 3) Operation operands perform their operation and trigger the evaulation of their child operands. /// </summary> /// <param name="token"></param> /// <param name="operand"></param> /// <param name="errorMessage"></param> /// <returns></returns> private Boolean ParseToken(String token, ref OperandBase operand, ref String errorMessage) { Boolean returnValue = default(Boolean); String[] tokens = default(String[]); String leftToken = default(String); String rightToken = default(String); Boolean isFoundOperator = default(Boolean); OperatorBase foundOperator = default(OperatorBase); OperandBase leftOperand = default(OperandBase); OperandBase rightOperand = default(OperandBase); OperationBase operation = default(OperationBase); try { //look for operators, if any, in reverse precedence order foreach (OperatorBase op in arithmeticOperators) { if (token.Contains(op.Name)) { isFoundOperator = true; foundOperator = op; break; } } //create an array of one or two sub-tokens if (isFoundOperator) { //split into 2 parts only tokens = token.Split(new Char[] { foundOperator.Name[0] }, 2); } else { //create list with single item String[] newList = { token }; tokens = newList; } //process sub-tokens if (tokens.Length == 0) { throw new ArgumentException(String.Format("Incorrectly formatted formula; there does not appear to be an operand: '{0}'", token)); } else if (tokens.Length == 1) { //no operator; process single operand leftToken = tokens[0].Trim(); if (!ParseOperand(leftToken, ref leftOperand, ref errorMessage)) { throw new ApplicationException(errorMessage); } operand = leftOperand; returnValue = true; } else if (tokens.Length == 2) { //operator found; process dual operands with recursive call leftToken = tokens[0].Trim(); if (!ParseToken(leftToken, ref leftOperand, ref errorMessage)) { throw new ApplicationException(errorMessage); } rightToken = tokens[1].Trim(); if (!ParseToken(rightToken, ref rightOperand, ref errorMessage)) { throw new ApplicationException(errorMessage); } //create operation from left/right operands and operator, and create OperandOperation //create OperationBinary which configures 2 OperandBase dictionary entries called Left, Right. operation = new OperationBinary(); operation.Operands["Left"] = leftOperand; operation.Operands["Right"] = rightOperand; operation.Operator = foundOperator; operand = new OperandOperation(operation); returnValue = true; } else if (tokens.Length > 2) { throw new ArgumentException(String.Format("Unexpected formula format: '{0}'", token)); } } catch (Exception ex) { errorMessage = ex.Message; Log.Write(ex, MethodBase.GetCurrentMethod(), EventLogEntryType.Error); //throw; } return(returnValue); }