first commit
This commit is contained in:
249
hrmsEjb/jxl/biff/formula/StringFormulaParser.java
Normal file
249
hrmsEjb/jxl/biff/formula/StringFormulaParser.java
Normal file
@@ -0,0 +1,249 @@
|
||||
package jxl.biff.formula;
|
||||
|
||||
import common.Logger;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.Stack;
|
||||
import jxl.WorkbookSettings;
|
||||
import jxl.biff.WorkbookMethods;
|
||||
|
||||
class StringFormulaParser implements Parser {
|
||||
private static Logger logger = Logger.getLogger(StringFormulaParser.class);
|
||||
|
||||
private String formula;
|
||||
|
||||
private String parsedFormula;
|
||||
|
||||
private ParseItem root;
|
||||
|
||||
private Stack arguments;
|
||||
|
||||
private WorkbookSettings settings;
|
||||
|
||||
private ExternalSheet externalSheet;
|
||||
|
||||
private WorkbookMethods nameTable;
|
||||
|
||||
public StringFormulaParser(String f, ExternalSheet es, WorkbookMethods nt, WorkbookSettings ws) {
|
||||
this.formula = f;
|
||||
this.settings = ws;
|
||||
this.externalSheet = es;
|
||||
this.nameTable = nt;
|
||||
}
|
||||
|
||||
public void parse() throws FormulaException {
|
||||
ArrayList tokens = getTokens();
|
||||
Iterator i = tokens.iterator();
|
||||
this.root = parseCurrent(i);
|
||||
}
|
||||
|
||||
private ParseItem parseCurrent(Iterator i) throws FormulaException {
|
||||
Stack stack = new Stack();
|
||||
Stack operators = new Stack();
|
||||
Stack args = null;
|
||||
boolean parenthesesClosed = false;
|
||||
ParseItem lastParseItem = null;
|
||||
while (i.hasNext() && !parenthesesClosed) {
|
||||
ParseItem pi = i.next();
|
||||
if (pi instanceof Operand) {
|
||||
handleOperand((Operand)pi, stack);
|
||||
} else if (pi instanceof StringFunction) {
|
||||
handleFunction((StringFunction)pi, i, stack);
|
||||
} else if (pi instanceof Operator) {
|
||||
Operator op = (Operator)pi;
|
||||
if (op instanceof StringOperator) {
|
||||
StringOperator sop = (StringOperator)op;
|
||||
if (stack.isEmpty() || lastParseItem instanceof Operator) {
|
||||
op = sop.getUnaryOperator();
|
||||
} else {
|
||||
op = sop.getBinaryOperator();
|
||||
}
|
||||
}
|
||||
if (operators.empty()) {
|
||||
operators.push(op);
|
||||
} else {
|
||||
Operator operator = operators.peek();
|
||||
if (op.getPrecedence() < operator.getPrecedence()) {
|
||||
operators.push(op);
|
||||
} else {
|
||||
operators.pop();
|
||||
operator.getOperands(stack);
|
||||
stack.push(operator);
|
||||
operators.push(op);
|
||||
}
|
||||
}
|
||||
} else if (pi instanceof ArgumentSeparator) {
|
||||
while (!operators.isEmpty()) {
|
||||
Operator o = operators.pop();
|
||||
o.getOperands(stack);
|
||||
stack.push(o);
|
||||
}
|
||||
if (args == null)
|
||||
args = new Stack();
|
||||
args.push(stack.pop());
|
||||
stack.clear();
|
||||
} else if (pi instanceof OpenParentheses) {
|
||||
ParseItem pi2 = parseCurrent(i);
|
||||
Parenthesis p = new Parenthesis();
|
||||
pi2.setParent(p);
|
||||
p.add(pi2);
|
||||
stack.push(p);
|
||||
} else if (pi instanceof CloseParentheses) {
|
||||
parenthesesClosed = true;
|
||||
}
|
||||
lastParseItem = pi;
|
||||
}
|
||||
while (!operators.isEmpty()) {
|
||||
Operator o = operators.pop();
|
||||
o.getOperands(stack);
|
||||
stack.push(o);
|
||||
}
|
||||
ParseItem rt = !stack.empty() ? stack.pop() : null;
|
||||
if (args != null && rt != null)
|
||||
args.push(rt);
|
||||
this.arguments = args;
|
||||
if (!stack.empty() || !operators.empty())
|
||||
logger.warn("Formula " + this.formula + " has a non-empty parse stack");
|
||||
return rt;
|
||||
}
|
||||
|
||||
private ArrayList getTokens() throws FormulaException {
|
||||
ArrayList tokens = new ArrayList();
|
||||
StringReader sr = new StringReader(this.formula);
|
||||
Yylex lex = new Yylex(sr);
|
||||
lex.setExternalSheet(this.externalSheet);
|
||||
lex.setNameTable(this.nameTable);
|
||||
try {
|
||||
ParseItem pi = lex.yylex();
|
||||
while (pi != null) {
|
||||
tokens.add(pi);
|
||||
pi = lex.yylex();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.warn(e.toString());
|
||||
} catch (Error e) {
|
||||
throw new FormulaException(FormulaException.lexicalError, this.formula + " at char " + lex.getPos());
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
public String getFormula() {
|
||||
if (this.parsedFormula == null) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
this.root.getString(sb);
|
||||
this.parsedFormula = sb.toString();
|
||||
}
|
||||
return this.parsedFormula;
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
byte[] bytes = this.root.getBytes();
|
||||
if (this.root.isVolatile()) {
|
||||
byte[] newBytes = new byte[bytes.length + 4];
|
||||
System.arraycopy(bytes, 0, newBytes, 4, bytes.length);
|
||||
newBytes[0] = Token.ATTRIBUTE.getCode();
|
||||
newBytes[1] = 1;
|
||||
bytes = newBytes;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private void handleFunction(StringFunction sf, Iterator i, Stack stack) throws FormulaException {
|
||||
ParseItem pi2 = parseCurrent(i);
|
||||
if (sf.getFunction(this.settings) == Function.UNKNOWN)
|
||||
throw new FormulaException(FormulaException.unrecognizedFunction);
|
||||
if (sf.getFunction(this.settings) == Function.SUM && this.arguments == null) {
|
||||
Attribute a = new Attribute(sf, this.settings);
|
||||
a.add(pi2);
|
||||
stack.push(a);
|
||||
return;
|
||||
}
|
||||
if (sf.getFunction(this.settings) == Function.IF) {
|
||||
Attribute a = new Attribute(sf, this.settings);
|
||||
VariableArgFunction vaf = new VariableArgFunction(this.settings);
|
||||
int k = this.arguments.size();
|
||||
for (int j = 0; j < k; j++) {
|
||||
ParseItem pi3 = this.arguments.get(j);
|
||||
vaf.add(pi3);
|
||||
}
|
||||
a.setIfConditions(vaf);
|
||||
stack.push(a);
|
||||
return;
|
||||
}
|
||||
if (sf.getFunction(this.settings).getNumArgs() == 255) {
|
||||
if (this.arguments == null) {
|
||||
int numArgs = (pi2 != null) ? 1 : 0;
|
||||
VariableArgFunction vaf = new VariableArgFunction(sf.getFunction(this.settings), numArgs, this.settings);
|
||||
if (pi2 != null)
|
||||
vaf.add(pi2);
|
||||
stack.push(vaf);
|
||||
} else {
|
||||
int k = this.arguments.size();
|
||||
VariableArgFunction vaf = new VariableArgFunction(sf.getFunction(this.settings), k, this.settings);
|
||||
ParseItem[] args = new ParseItem[k];
|
||||
int j;
|
||||
for (j = 0; j < k; j++) {
|
||||
ParseItem pi3 = this.arguments.pop();
|
||||
args[k - j - 1] = pi3;
|
||||
}
|
||||
for (j = 0; j < args.length; j++)
|
||||
vaf.add(args[j]);
|
||||
stack.push(vaf);
|
||||
this.arguments.clear();
|
||||
this.arguments = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
BuiltInFunction bif = new BuiltInFunction(sf.getFunction(this.settings), this.settings);
|
||||
int numargs = sf.getFunction(this.settings).getNumArgs();
|
||||
if (numargs == 1) {
|
||||
bif.add(pi2);
|
||||
} else {
|
||||
if ((this.arguments == null && numargs != 0) || (this.arguments != null && numargs != this.arguments.size()))
|
||||
throw new FormulaException(FormulaException.incorrectArguments);
|
||||
for (int j = 0; j < numargs; j++) {
|
||||
ParseItem pi3 = this.arguments.get(j);
|
||||
bif.add(pi3);
|
||||
}
|
||||
}
|
||||
stack.push(bif);
|
||||
}
|
||||
|
||||
public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) {
|
||||
this.root.adjustRelativeCellReferences(colAdjust, rowAdjust);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private void handleOperand(Operand o, Stack stack) {
|
||||
if (!(o instanceof IntegerValue)) {
|
||||
stack.push(o);
|
||||
return;
|
||||
}
|
||||
if (o instanceof IntegerValue) {
|
||||
IntegerValue iv = (IntegerValue)o;
|
||||
if (!iv.isOutOfRange()) {
|
||||
stack.push(iv);
|
||||
} else {
|
||||
DoubleValue dv = new DoubleValue(iv.getValue());
|
||||
stack.push(dv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user