/** * Parses the sublist of tokens. In most cases this will equate to * the full list * * @param len the length of the subexpression to parse * @exception FormulaException */ private void parseSubExpression(int len) { int tokenVal = 0; Token t = null; // Indicates that we are parsing the incredibly complicated and // hacky if construct that MS saw fit to include, the gits Stack<ParseItem> ifStack = new Stack<ParseItem>(); // The end position of the sub-expression int endpos = pos + len; while (pos < endpos) { tokenVal = tokenData[pos]; pos++; t = Token.getToken(tokenVal); if (t == Token.UNKNOWN) { throw new FormulaException (FormulaException.UNRECOGNIZED_TOKEN,tokenVal); } Assert.verify(t != Token.UNKNOWN); // Operands if (t == Token.REF) { CellReference cr = new CellReference(relativeTo); pos += cr.read(tokenData,pos); tokenStack.Push(cr); } else if (t == Token.REFERR) { CellReferenceError cr = new CellReferenceError(); pos += cr.read(tokenData,pos); tokenStack.Push(cr); } else if (t == Token.ERR) { ErrorConstant ec = new ErrorConstant(); pos += ec.read(tokenData,pos); tokenStack.Push(ec); } else if (t == Token.REFV) { SharedFormulaCellReference cr = new SharedFormulaCellReference(relativeTo); pos += cr.read(tokenData,pos); tokenStack.Push(cr); } else if (t == Token.REF3D) { CellReference3d cr = new CellReference3d(relativeTo,workbook); pos += cr.read(tokenData,pos); tokenStack.Push(cr); } else if (t == Token.AREA) { Area a = new Area(); pos += a.read(tokenData,pos); tokenStack.Push(a); } else if (t == Token.AREAV) { SharedFormulaArea a = new SharedFormulaArea(relativeTo); pos += a.read(tokenData,pos); tokenStack.Push(a); } else if (t == Token.AREA3D) { Area3d a = new Area3d(workbook); pos += a.read(tokenData,pos); tokenStack.Push(a); } else if (t == Token.NAME) { Name n = new Name(); pos += n.read(tokenData,pos); n.setParseContext(parseContext); tokenStack.Push(n); } else if (t == Token.NAMED_RANGE) { NameRange nr = new NameRange(nameTable); pos += nr.read(tokenData,pos); nr.setParseContext(parseContext); tokenStack.Push(nr); } else if (t == Token.INTEGER) { IntegerValue i = new IntegerValue(); pos += i.read(tokenData,pos); tokenStack.Push(i); } else if (t == Token.DOUBLE) { DoubleValue d = new DoubleValue(); pos += d.read(tokenData,pos); tokenStack.Push(d); } else if (t == Token.BOOL) { BooleanValue bv = new BooleanValue(); pos += bv.read(tokenData,pos); tokenStack.Push(bv); } else if (t == Token.STRING) { StringValue sv = new StringValue(settings); pos += sv.read(tokenData,pos); tokenStack.Push(sv); } else if (t == Token.MISSING_ARG) { MissingArg ma = new MissingArg(); pos += ma.read(tokenData,pos); tokenStack.Push(ma); } // Unary Operators else if (t == Token.UNARY_PLUS) { UnaryPlus up = new UnaryPlus(); pos += up.read(tokenData,pos); addOperator(up); } else if (t == Token.UNARY_MINUS) { UnaryMinus um = new UnaryMinus(); pos += um.read(tokenData,pos); addOperator(um); } else if (t == Token.PERCENT) { Percent p = new Percent(); pos += p.read(tokenData,pos); addOperator(p); } // Binary Operators else if (t == Token.SUBTRACT) { Subtract s = new Subtract(); pos += s.read(tokenData,pos); addOperator(s); } else if (t == Token.ADD) { Add s = new Add(); pos += s.read(tokenData,pos); addOperator(s); } else if (t == Token.MULTIPLY) { Multiply s = new Multiply(); pos += s.read(tokenData,pos); addOperator(s); } else if (t == Token.DIVIDE) { Divide s = new Divide(); pos += s.read(tokenData,pos); addOperator(s); } else if (t == Token.CONCAT) { Concatenate c = new Concatenate(); pos += c.read(tokenData,pos); addOperator(c); } else if (t == Token.POWER) { Power p = new Power(); pos += p.read(tokenData,pos); addOperator(p); } else if (t == Token.LESS_THAN) { LessThan lt = new LessThan(); pos += lt.read(tokenData,pos); addOperator(lt); } else if (t == Token.LESS_EQUAL) { LessEqual lte = new LessEqual(); pos += lte.read(tokenData,pos); addOperator(lte); } else if (t == Token.GREATER_THAN) { GreaterThan gt = new GreaterThan(); pos += gt.read(tokenData,pos); addOperator(gt); } else if (t == Token.GREATER_EQUAL) { GreaterEqual gte = new GreaterEqual(); pos += gte.read(tokenData,pos); addOperator(gte); } else if (t == Token.NOT_EQUAL) { NotEqual ne = new NotEqual(); pos += ne.read(tokenData,pos); addOperator(ne); } else if (t == Token.EQUAL) { Equal e = new Equal(); pos += e.read(tokenData,pos); addOperator(e); } else if (t == Token.PARENTHESIS) { Parenthesis p = new Parenthesis(); pos += p.read(tokenData,pos); addOperator(p); } // Functions else if (t == Token.ATTRIBUTE) { Attribute a = new Attribute(settings); pos += a.read(tokenData,pos); if (a.isSum()) addOperator(a); else if (a.isIf()) { // Add it to a special stack for ifs ifStack.Push(a); } } else if (t == Token.FUNCTION) { BuiltInFunction bif = new BuiltInFunction(settings); pos += bif.read(tokenData,pos); addOperator(bif); } else if (t == Token.FUNCTIONVARARG) { VariableArgFunction vaf = new VariableArgFunction(settings); pos += vaf.read(tokenData,pos); if (vaf.getFunction() != Function.ATTRIBUTE) addOperator(vaf); else { // This is part of an IF function. Get the operands, but then // add it to the top of the if stack vaf.getOperands(tokenStack); Attribute ifattr = null; if (ifStack.Count == 0) ifattr = new Attribute(settings); else ifattr = (Attribute)ifStack.Pop(); ifattr.setIfConditions(vaf); tokenStack.Push(ifattr); } } // Other things else if (t == Token.MEM_FUNC) { MemFunc memFunc = new MemFunc(); handleMemoryFunction(memFunc); } else if (t == Token.MEM_AREA) { MemArea memArea = new MemArea(); handleMemoryFunction(memArea); } } }
/** * Recursively parses the token array. Recursion is used in order * to evaluate parentheses and function arguments * * @param iterator an iterator of tokens * @return the root node of the current parse stack * @exception FormulaException if an error occurs */ private ParseItem parseCurrent(IEnumerator<ParseItem> iterator) { Stack<ParseItem> stack = new Stack<ParseItem>(); Stack<Operator> operators = new Stack<Operator>(); Stack<ParseItem> args = null; // we usually don't need this bool parenthesesClosed = false; ParseItem lastParseItem = null; while (!parenthesesClosed && iterator.MoveNext()) { ParseItem pi = iterator.Current; if (pi == null) break; pi.setParseContext(parseContext); if (pi is Operand) handleOperand((Operand)pi, stack); else if (pi is StringFunction) handleFunction((StringFunction)pi, iterator, stack); else if (pi is Operator) { Operator op = (Operator)pi; // See if the operator is a binary or unary operator // It is a unary operator either if the stack is empty, or if // the last thing off the stack was another operator if (op is StringOperator) { StringOperator sop = (StringOperator)op; if (stack.Count == 0 || lastParseItem is Operator) op = sop.getUnaryOperator(); else op = sop.getBinaryOperator(); } if (operators.Count == 0) { // nothing much going on, so do nothing for the time being operators.Push(op); } else { Operator op2 = operators.Peek(); // If the last operator has a higher precedence then add this to // the operator stack and wait if (op2.getPrecedence() < op2.getPrecedence()) operators.Push(op2); else if (op2.getPrecedence() == op2.getPrecedence() && op2 is UnaryOperator) { // The operators are of equal precedence, but because it is a // unary operator the operand isn't available yet, so put it on // the stack operators.Push(op2); } else { // The operator is of a lower precedence so we can sort out // some of the items on the stack operators.Pop(); // remove the operator from the stack op2.getOperands(stack); stack.Push(op2); operators.Push(op2); } } } else if (pi is ArgumentSeparator) { // Clean up any remaining items on this stack while (operators.Count > 0) { Operator o = operators.Pop(); o.getOperands(stack); stack.Push(o); } // Add it to the argument stack. Create the argument stack // if necessary. Items will be stored on the argument stack in // reverse order if (args == null) args = new Stack<ParseItem>(); args.Push(stack.Pop()); stack.Clear(); } else if (pi is OpenParentheses) { ParseItem pi2 = parseCurrent(iterator); Parenthesis p = new Parenthesis(); pi2.setParent(p); p.add(pi2); stack.Push(p); } else if (pi is CloseParentheses) parenthesesClosed = true; lastParseItem = pi; } while (operators.Count > 0) { Operator o = operators.Pop(); o.getOperands(stack); stack.Push(o); } ParseItem rt = (stack.Count > 0) ? (ParseItem)stack.Pop() : null; // if the argument stack is not null, then add it to that stack // as well for good measure if (args != null && rt != null) args.Push(rt); arguments = args; if (stack.Count > 0 || operators.Count > 0) { //logger.warn("Formula " + formula + " has a non-empty parse stack"); } return rt; }
/** * Parses the sublist of tokens. In most cases this will equate to * the full list * * @param len the length of the subexpression to parse * @exception FormulaException */ private void parseSubExpression(int len) { int tokenVal = 0; Token t = null; // Indicates that we are parsing the incredibly complicated and // hacky if construct that MS saw fit to include, the gits Stack <ParseItem> ifStack = new Stack <ParseItem>(); // The end position of the sub-expression int endpos = pos + len; while (pos < endpos) { tokenVal = tokenData[pos]; pos++; t = Token.getToken(tokenVal); if (t == Token.UNKNOWN) { throw new FormulaException (FormulaException.UNRECOGNIZED_TOKEN, tokenVal); } Assert.verify(t != Token.UNKNOWN); // Operands if (t == Token.REF) { CellReference cr = new CellReference(relativeTo); pos += cr.read(tokenData, pos); tokenStack.Push(cr); } else if (t == Token.REFERR) { CellReferenceError cr = new CellReferenceError(); pos += cr.read(tokenData, pos); tokenStack.Push(cr); } else if (t == Token.ERR) { ErrorConstant ec = new ErrorConstant(); pos += ec.read(tokenData, pos); tokenStack.Push(ec); } else if (t == Token.REFV) { SharedFormulaCellReference cr = new SharedFormulaCellReference(relativeTo); pos += cr.read(tokenData, pos); tokenStack.Push(cr); } else if (t == Token.REF3D) { CellReference3d cr = new CellReference3d(relativeTo, workbook); pos += cr.read(tokenData, pos); tokenStack.Push(cr); } else if (t == Token.AREA) { Area a = new Area(); pos += a.read(tokenData, pos); tokenStack.Push(a); } else if (t == Token.AREAV) { SharedFormulaArea a = new SharedFormulaArea(relativeTo); pos += a.read(tokenData, pos); tokenStack.Push(a); } else if (t == Token.AREA3D) { Area3d a = new Area3d(workbook); pos += a.read(tokenData, pos); tokenStack.Push(a); } else if (t == Token.NAME) { Name n = new Name(); pos += n.read(tokenData, pos); n.setParseContext(parseContext); tokenStack.Push(n); } else if (t == Token.NAMED_RANGE) { NameRange nr = new NameRange(nameTable); pos += nr.read(tokenData, pos); nr.setParseContext(parseContext); tokenStack.Push(nr); } else if (t == Token.INTEGER) { IntegerValue i = new IntegerValue(); pos += i.read(tokenData, pos); tokenStack.Push(i); } else if (t == Token.DOUBLE) { DoubleValue d = new DoubleValue(); pos += d.read(tokenData, pos); tokenStack.Push(d); } else if (t == Token.BOOL) { BooleanValue bv = new BooleanValue(); pos += bv.read(tokenData, pos); tokenStack.Push(bv); } else if (t == Token.STRING) { StringValue sv = new StringValue(settings); pos += sv.read(tokenData, pos); tokenStack.Push(sv); } else if (t == Token.MISSING_ARG) { MissingArg ma = new MissingArg(); pos += ma.read(tokenData, pos); tokenStack.Push(ma); } // Unary Operators else if (t == Token.UNARY_PLUS) { UnaryPlus up = new UnaryPlus(); pos += up.read(tokenData, pos); addOperator(up); } else if (t == Token.UNARY_MINUS) { UnaryMinus um = new UnaryMinus(); pos += um.read(tokenData, pos); addOperator(um); } else if (t == Token.PERCENT) { Percent p = new Percent(); pos += p.read(tokenData, pos); addOperator(p); } // Binary Operators else if (t == Token.SUBTRACT) { Subtract s = new Subtract(); pos += s.read(tokenData, pos); addOperator(s); } else if (t == Token.ADD) { Add s = new Add(); pos += s.read(tokenData, pos); addOperator(s); } else if (t == Token.MULTIPLY) { Multiply s = new Multiply(); pos += s.read(tokenData, pos); addOperator(s); } else if (t == Token.DIVIDE) { Divide s = new Divide(); pos += s.read(tokenData, pos); addOperator(s); } else if (t == Token.CONCAT) { Concatenate c = new Concatenate(); pos += c.read(tokenData, pos); addOperator(c); } else if (t == Token.POWER) { Power p = new Power(); pos += p.read(tokenData, pos); addOperator(p); } else if (t == Token.LESS_THAN) { LessThan lt = new LessThan(); pos += lt.read(tokenData, pos); addOperator(lt); } else if (t == Token.LESS_EQUAL) { LessEqual lte = new LessEqual(); pos += lte.read(tokenData, pos); addOperator(lte); } else if (t == Token.GREATER_THAN) { GreaterThan gt = new GreaterThan(); pos += gt.read(tokenData, pos); addOperator(gt); } else if (t == Token.GREATER_EQUAL) { GreaterEqual gte = new GreaterEqual(); pos += gte.read(tokenData, pos); addOperator(gte); } else if (t == Token.NOT_EQUAL) { NotEqual ne = new NotEqual(); pos += ne.read(tokenData, pos); addOperator(ne); } else if (t == Token.EQUAL) { Equal e = new Equal(); pos += e.read(tokenData, pos); addOperator(e); } else if (t == Token.PARENTHESIS) { Parenthesis p = new Parenthesis(); pos += p.read(tokenData, pos); addOperator(p); } // Functions else if (t == Token.ATTRIBUTE) { Attribute a = new Attribute(settings); pos += a.read(tokenData, pos); if (a.isSum()) { addOperator(a); } else if (a.isIf()) { // Add it to a special stack for ifs ifStack.Push(a); } } else if (t == Token.FUNCTION) { BuiltInFunction bif = new BuiltInFunction(settings); pos += bif.read(tokenData, pos); addOperator(bif); } else if (t == Token.FUNCTIONVARARG) { VariableArgFunction vaf = new VariableArgFunction(settings); pos += vaf.read(tokenData, pos); if (vaf.getFunction() != Function.ATTRIBUTE) { addOperator(vaf); } else { // This is part of an IF function. Get the operands, but then // add it to the top of the if stack vaf.getOperands(tokenStack); Attribute ifattr = null; if (ifStack.Count == 0) { ifattr = new Attribute(settings); } else { ifattr = (Attribute)ifStack.Pop(); } ifattr.setIfConditions(vaf); tokenStack.Push(ifattr); } } // Other things else if (t == Token.MEM_FUNC) { MemFunc memFunc = new MemFunc(); handleMemoryFunction(memFunc); } else if (t == Token.MEM_AREA) { MemArea memArea = new MemArea(); handleMemoryFunction(memArea); } } }
/** * Recursively parses the token array. Recursion is used in order * to evaluate parentheses and function arguments * * @param iterator an iterator of tokens * @return the root node of the current parse stack * @exception FormulaException if an error occurs */ private ParseItem parseCurrent(IEnumerator <ParseItem> iterator) { Stack <ParseItem> stack = new Stack <ParseItem>(); Stack <Operator> operators = new Stack <Operator>(); Stack <ParseItem> args = null; // we usually don't need this bool parenthesesClosed = false; ParseItem lastParseItem = null; while (!parenthesesClosed && iterator.MoveNext()) { ParseItem pi = iterator.Current; if (pi == null) { break; } pi.setParseContext(parseContext); if (pi is Operand) { handleOperand((Operand)pi, stack); } else if (pi is StringFunction) { handleFunction((StringFunction)pi, iterator, stack); } else if (pi is Operator) { Operator op = (Operator)pi; // See if the operator is a binary or unary operator // It is a unary operator either if the stack is empty, or if // the last thing off the stack was another operator if (op is StringOperator) { StringOperator sop = (StringOperator)op; if (stack.Count == 0 || lastParseItem is Operator) { op = sop.getUnaryOperator(); } else { op = sop.getBinaryOperator(); } } if (operators.Count == 0) { // nothing much going on, so do nothing for the time being operators.Push(op); } else { Operator op2 = operators.Peek(); // If the last operator has a higher precedence then add this to // the operator stack and wait if (op2.getPrecedence() < op2.getPrecedence()) { operators.Push(op2); } else if (op2.getPrecedence() == op2.getPrecedence() && op2 is UnaryOperator) { // The operators are of equal precedence, but because it is a // unary operator the operand isn't available yet, so put it on // the stack operators.Push(op2); } else { // The operator is of a lower precedence so we can sort out // some of the items on the stack operators.Pop(); // remove the operator from the stack op2.getOperands(stack); stack.Push(op2); operators.Push(op2); } } } else if (pi is ArgumentSeparator) { // Clean up any remaining items on this stack while (operators.Count > 0) { Operator o = operators.Pop(); o.getOperands(stack); stack.Push(o); } // Add it to the argument stack. Create the argument stack // if necessary. Items will be stored on the argument stack in // reverse order if (args == null) { args = new Stack <ParseItem>(); } args.Push(stack.Pop()); stack.Clear(); } else if (pi is OpenParentheses) { ParseItem pi2 = parseCurrent(iterator); Parenthesis p = new Parenthesis(); pi2.setParent(p); p.add(pi2); stack.Push(p); } else if (pi is CloseParentheses) { parenthesesClosed = true; } lastParseItem = pi; } while (operators.Count > 0) { Operator o = operators.Pop(); o.getOperands(stack); stack.Push(o); } ParseItem rt = (stack.Count > 0) ? (ParseItem)stack.Pop() : null; // if the argument stack is not null, then add it to that stack // as well for good measure if (args != null && rt != null) { args.Push(rt); } arguments = args; if (stack.Count > 0 || operators.Count > 0) { //logger.warn("Formula " + formula + " has a non-empty parse stack"); } return(rt); }