/**
         * 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);
        }