326 lines
9.7 KiB
Java
326 lines
9.7 KiB
Java
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);
|
|
}
|
|
}
|