package jxl.biff.formula; import common.Assert; import common.Logger; import java.util.Stack; import jxl.Cell; import jxl.WorkbookSettings; import jxl.biff.WorkbookMethods; class TokenFormulaParser implements Parser { private static Logger logger = Logger.getLogger(TokenFormulaParser.class); private byte[] tokenData; private Cell relativeTo; private int pos; private ParseItem root; private Stack tokenStack; private ExternalSheet workbook; private WorkbookMethods nameTable; private WorkbookSettings settings; public TokenFormulaParser(byte[] data, Cell c, ExternalSheet es, WorkbookMethods nt, WorkbookSettings ws) { this.tokenData = data; this.pos = 0; this.relativeTo = c; this.workbook = es; this.nameTable = nt; this.tokenStack = new Stack(); this.settings = ws; } public void parse() throws FormulaException { parseSubExpression(this.tokenData.length); this.root = this.tokenStack.pop(); Assert.verify(this.tokenStack.empty()); } private void parseSubExpression(int len) throws FormulaException { int tokenVal = 0; Token t = null; Stack ifStack = new Stack(); int endpos = this.pos + len; while (this.pos < endpos) { tokenVal = this.tokenData[this.pos]; this.pos++; t = Token.getToken(tokenVal); if (t == Token.UNKNOWN) throw new FormulaException(FormulaException.unrecognizedToken, tokenVal); Assert.verify((t != Token.UNKNOWN)); if (t == Token.REF) { CellReference cr = new CellReference(this.relativeTo); this.pos += cr.read(this.tokenData, this.pos); this.tokenStack.push(cr); continue; } if (t == Token.REF) { CellReferenceError cr = new CellReferenceError(); this.pos += cr.read(this.tokenData, this.pos); this.tokenStack.push(cr); continue; } if (t == Token.REFV) { SharedFormulaCellReference cr = new SharedFormulaCellReference(this.relativeTo); this.pos += cr.read(this.tokenData, this.pos); this.tokenStack.push(cr); continue; } if (t == Token.REF3D) { CellReference3d cr = new CellReference3d(this.relativeTo, this.workbook); this.pos += cr.read(this.tokenData, this.pos); this.tokenStack.push(cr); continue; } if (t == Token.AREA) { Area a = new Area(); this.pos += a.read(this.tokenData, this.pos); this.tokenStack.push(a); continue; } if (t == Token.AREAV) { SharedFormulaArea a = new SharedFormulaArea(this.relativeTo); this.pos += a.read(this.tokenData, this.pos); this.tokenStack.push(a); continue; } if (t == Token.AREA3D) { Area3d a = new Area3d(this.workbook); this.pos += a.read(this.tokenData, this.pos); this.tokenStack.push(a); continue; } if (t == Token.NAME) { Name n = new Name(); this.pos += n.read(this.tokenData, this.pos); this.tokenStack.push(n); continue; } if (t == Token.NAMED_RANGE) { NameRange nr = new NameRange(this.nameTable); this.pos += nr.read(this.tokenData, this.pos); this.tokenStack.push(nr); continue; } if (t == Token.INTEGER) { IntegerValue i = new IntegerValue(); this.pos += i.read(this.tokenData, this.pos); this.tokenStack.push(i); continue; } if (t == Token.DOUBLE) { DoubleValue d = new DoubleValue(); this.pos += d.read(this.tokenData, this.pos); this.tokenStack.push(d); continue; } if (t == Token.BOOL) { BooleanValue bv = new BooleanValue(); this.pos += bv.read(this.tokenData, this.pos); this.tokenStack.push(bv); continue; } if (t == Token.STRING) { StringValue sv = new StringValue(this.settings); this.pos += sv.read(this.tokenData, this.pos); this.tokenStack.push(sv); continue; } if (t == Token.MISSING_ARG) { MissingArg ma = new MissingArg(); this.pos += ma.read(this.tokenData, this.pos); this.tokenStack.push(ma); continue; } if (t == Token.UNARY_PLUS) { UnaryPlus up = new UnaryPlus(); this.pos += up.read(this.tokenData, this.pos); addOperator(up); continue; } if (t == Token.UNARY_MINUS) { UnaryMinus um = new UnaryMinus(); this.pos += um.read(this.tokenData, this.pos); addOperator(um); continue; } if (t == Token.PERCENT) { Percent p = new Percent(); this.pos += p.read(this.tokenData, this.pos); addOperator(p); continue; } if (t == Token.SUBTRACT) { Subtract s = new Subtract(); this.pos += s.read(this.tokenData, this.pos); addOperator(s); continue; } if (t == Token.ADD) { Add s = new Add(); this.pos += s.read(this.tokenData, this.pos); addOperator(s); continue; } if (t == Token.MULTIPLY) { Multiply s = new Multiply(); this.pos += s.read(this.tokenData, this.pos); addOperator(s); continue; } if (t == Token.DIVIDE) { Divide s = new Divide(); this.pos += s.read(this.tokenData, this.pos); addOperator(s); continue; } if (t == Token.CONCAT) { Concatenate c = new Concatenate(); this.pos += c.read(this.tokenData, this.pos); addOperator(c); continue; } if (t == Token.POWER) { Power p = new Power(); this.pos += p.read(this.tokenData, this.pos); addOperator(p); continue; } if (t == Token.LESS_THAN) { LessThan lt = new LessThan(); this.pos += lt.read(this.tokenData, this.pos); addOperator(lt); continue; } if (t == Token.LESS_EQUAL) { LessEqual lte = new LessEqual(); this.pos += lte.read(this.tokenData, this.pos); addOperator(lte); continue; } if (t == Token.GREATER_THAN) { GreaterThan gt = new GreaterThan(); this.pos += gt.read(this.tokenData, this.pos); addOperator(gt); continue; } if (t == Token.GREATER_EQUAL) { GreaterEqual gte = new GreaterEqual(); this.pos += gte.read(this.tokenData, this.pos); addOperator(gte); continue; } if (t == Token.NOT_EQUAL) { NotEqual ne = new NotEqual(); this.pos += ne.read(this.tokenData, this.pos); addOperator(ne); continue; } if (t == Token.EQUAL) { Equal e = new Equal(); this.pos += e.read(this.tokenData, this.pos); addOperator(e); continue; } if (t == Token.PARENTHESIS) { Parenthesis p = new Parenthesis(); this.pos += p.read(this.tokenData, this.pos); addOperator(p); continue; } if (t == Token.ATTRIBUTE) { Attribute a = new Attribute(this.settings); this.pos += a.read(this.tokenData, this.pos); if (a.isSum()) { addOperator(a); continue; } if (a.isIf()) ifStack.push(a); continue; } if (t == Token.FUNCTION) { BuiltInFunction bif = new BuiltInFunction(this.settings); this.pos += bif.read(this.tokenData, this.pos); addOperator(bif); continue; } if (t == Token.FUNCTIONVARARG) { VariableArgFunction vaf = new VariableArgFunction(this.settings); this.pos += vaf.read(this.tokenData, this.pos); if (vaf.getFunction() != Function.ATTRIBUTE) { addOperator(vaf); continue; } vaf.getOperands(this.tokenStack); Attribute ifattr = null; if (ifStack.empty()) { ifattr = new Attribute(this.settings); } else { ifattr = ifStack.pop(); } ifattr.setIfConditions(vaf); this.tokenStack.push(ifattr); continue; } if (t == Token.MEM_FUNC) { MemFunc memFunc = new MemFunc(); this.pos += memFunc.read(this.tokenData, this.pos); Stack oldStack = this.tokenStack; this.tokenStack = new Stack(); parseSubExpression(memFunc.getLength()); ParseItem[] subexpr = new ParseItem[this.tokenStack.size()]; int i = 0; while (!this.tokenStack.isEmpty()) { subexpr[i] = this.tokenStack.pop(); i++; } memFunc.setSubExpression(subexpr); this.tokenStack = oldStack; this.tokenStack.push(memFunc); } } } private void addOperator(Operator o) { o.getOperands(this.tokenStack); this.tokenStack.push(o); } public String getFormula() { StringBuffer sb = new StringBuffer(); this.root.getString(sb); return sb.toString(); } public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) { this.root.adjustRelativeCellReferences(colAdjust, rowAdjust); } public byte[] getBytes() { return this.root.getBytes(); } public void columnInserted(int sheetIndex, int col, boolean currentSheet) { this.root.columnInserted(sheetIndex, col, currentSheet); } public void columnRemoved(int sheetIndex, int col, boolean currentSheet) { this.root.columnRemoved(sheetIndex, col, currentSheet); } public void rowInserted(int sheetIndex, int row, boolean currentSheet) { this.root.rowInserted(sheetIndex, row, currentSheet); } public void rowRemoved(int sheetIndex, int row, boolean currentSheet) { this.root.rowRemoved(sheetIndex, row, currentSheet); } }