/// <summary> Handles the case when parsing a string when a token is a function /// /// </summary> /// <param name="sf">the string function /// </param> /// <param name="i"> the token iterator /// </param> /// <param name="stack">the parse tree stack /// </param> /// <exception cref=""> FormulaException if an error occurs /// </exception> private void handleFunction(StringFunction sf, ArrayList pis, Stack stack) { ParseItem pi2 = parseCurrent(pis); // If the function is unknown, then throw an error if (sf.getFunction(settings) == Function.UNKNOWN) { throw new FormulaException(FormulaException.unrecognizedFunction); } // First check for possible optimized functions and possible // use of the Attribute token if (sf.getFunction(settings) == Function.SUM && arguments == null) { // this is handled by an attribute Attribute a = new Attribute(sf, settings); a.add(pi2); stack.Push(a); return; } if (sf.getFunction(settings) == Function.IF) { // this is handled by an attribute Attribute a = new Attribute(sf, settings); // Add in the if conditions as a var arg function in // the correct order VariableArgFunction vaf = new VariableArgFunction(settings); // [TODO] TEST is the order the same as in Java? object[] argumentsArray = arguments.ToArray(); for (int j = 0; j < argumentsArray.Length; j++) { vaf.add((ParseItem)argumentsArray[j]); } a.IfConditions = vaf; stack.Push(a); return; } // Function cannot be optimized. See if it is a variable argument // function or not if (sf.getFunction(settings).NumArgs == 0xff) { // If the arg stack has not been initialized, it means // that there was only one argument, which is the // returned parse item if (arguments == null) { VariableArgFunction vaf = new VariableArgFunction(sf.getFunction(settings), 1, settings); vaf.add(pi2); stack.Push(vaf); } else { // Add the args to the function in reverse order. The // VariableArgFunction will reverse these when it writes out the // byte version as they are stored in the correct order // within Excel int numargs = arguments.Count; VariableArgFunction vaf = new VariableArgFunction(sf.getFunction(settings), numargs, settings); for (int j = 0; j < numargs; j++) { ParseItem pi3 = (ParseItem)arguments.Pop(); vaf.add(pi3); } stack.Push(vaf); // [TODO] - check it // arguments.empty(); arguments.Clear(); arguments = null; } return; } // Function is a standard built in function BuiltInFunction bif = new BuiltInFunction(sf.getFunction(settings), settings); int numargs2 = sf.getFunction(settings).NumArgs; if (numargs2 == 1) { // only one item which is the returned ParseItem bif.add(pi2); } else { if ((arguments == null && numargs2 != 0) || (arguments != null && numargs2 != arguments.Count)) { throw new FormulaException(FormulaException.incorrectArguments); } // multiple arguments so go to the arguments stack. // Unlike the variable argument function, the args are // stored in reverse order // [TODO] TEST is the order the same as in Java? object[] argumentsArray = arguments.ToArray(); for (int j = 0; j < numargs2; j++) { bif.add((ParseItem)argumentsArray[j]); } } stack.Push(bif); }
/// <summary> Parses the sublist of tokens. In most cases this will equate to /// the full list /// /// </summary> /// <param name="len">the .Length of the subexpression to parse /// </param> /// <exception cref=""> FormulaException /// </exception> 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 ifStack = new Stack(); // 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.unrecognizedToken, 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.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); tokenStack.Push(n); } else if (t == Token.NAMED_RANGE) { NameRange nr = new NameRange(nameTable); pos += nr.read(tokenData, pos); 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.Sum) { 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.Function != 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.IfConditions = vaf; tokenStack.Push(ifattr); } } // Other things else if (t == Token.MEM_FUNC) { MemFunc memFunc = new MemFunc(); pos += memFunc.read(tokenData, pos); // Create new tokenStack for the sub expression Stack oldStack = tokenStack; tokenStack = new Stack(); parseSubExpression(memFunc.Length); ParseItem[] subexpr = new ParseItem[tokenStack.Count]; int i = 0; while (tokenStack.Count > 0) { subexpr[i] = (ParseItem)tokenStack.Pop(); i++; } memFunc.SubExpression = subexpr; tokenStack = oldStack; tokenStack.Push(memFunc); } } }