StringFormulaParser.java 源代码


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;
import jxl.biff.formula.FormulaException;

public class StringFormulaParser implements Parser {
    static Class class$jxl$biff$formula$StringFormulaParser;
    private static Logger logger;
    private Stack arguments;
    private ExternalSheet externalSheet;
    private String formula;
    private WorkbookMethods nameTable;
    private String parsedFormula;
    private ParseItem root;
    private WorkbookSettings settings;

    static {
        Class cls = class$jxl$biff$formula$StringFormulaParser;
        if (cls == null) {
            cls = class$("jxl.biff.formula.StringFormulaParser");
            class$jxl$biff$formula$StringFormulaParser = cls;
        }
        logger = Logger.getLogger(cls);
    }

    static Class class$(String str) {
        try {
            return Class.forName(str);
        } catch (ClassNotFoundException e) {
            throw new NoClassDefFoundError(e.getMessage());
        }
    }

    public StringFormulaParser(String str, ExternalSheet externalSheet, WorkbookMethods workbookMethods, WorkbookSettings workbookSettings) {
        this.formula = str;
        this.settings = workbookSettings;
        this.externalSheet = externalSheet;
        this.nameTable = workbookMethods;
    }

    @Override
    public void parse() throws FormulaException {
        this.root = parseCurrent(getTokens().iterator());
    }

    private ParseItem parseCurrent(Iterator it) throws FormulaException {
        Stack stack = new Stack();
        Stack stack2 = new Stack();
        boolean z = false;
        Stack stack3 = null;
        ParseItem parseItem = null;
        while (it.hasNext() && !z) {
            ParseItem parseItem2 = (ParseItem) it.next();
            if (parseItem2 instanceof Operand) {
                handleOperand((Operand) parseItem2, stack);
            } else if (parseItem2 instanceof StringFunction) {
                handleFunction((StringFunction) parseItem2, it, stack);
            } else if (parseItem2 instanceof Operator) {
                Operator operator = (Operator) parseItem2;
                if (operator instanceof StringOperator) {
                    StringOperator stringOperator = (StringOperator) operator;
                    if (stack.isEmpty() || (parseItem instanceof Operator)) {
                        operator = stringOperator.getUnaryOperator();
                    } else {
                        operator = stringOperator.getBinaryOperator();
                    }
                }
                if (stack2.empty()) {
                    stack2.push(operator);
                } else {
                    Operator operator2 = (Operator) stack2.peek();
                    if (operator.getPrecedence() <= operator2.getPrecedence()) {
                        stack2.push(operator);
                    } else {
                        stack2.pop();
                        operator2.getOperands(stack);
                        stack.push(operator2);
                        stack2.push(operator);
                    }
                }
            } else if (parseItem2 instanceof ArgumentSeparator) {
                while (!stack2.isEmpty()) {
                    Operator operator3 = (Operator) stack2.pop();
                    operator3.getOperands(stack);
                    stack.push(operator3);
                }
                if (stack3 == null) {
                    stack3 = new Stack();
                }
                stack3.push(stack.pop());
                stack.clear();
            } else if (parseItem2 instanceof OpenParentheses) {
                ParseItem parseCurrent = parseCurrent(it);
                Parenthesis parenthesis = new Parenthesis();
                parseCurrent.setParent(parenthesis);
                parenthesis.add(parseCurrent);
                stack.push(parenthesis);
            } else if (parseItem2 instanceof CloseParentheses) {
                z = true;
            }
            parseItem = parseItem2;
        }
        while (!stack2.isEmpty()) {
            Operator operator4 = (Operator) stack2.pop();
            operator4.getOperands(stack);
            stack.push(operator4);
        }
        ParseItem parseItem3 = stack.empty() ? null : (ParseItem) stack.pop();
        if (stack3 != null && parseItem3 != null) {
            stack3.push(parseItem3);
        }
        this.arguments = stack3;
        if (!stack.empty() || !stack2.empty()) {
            Logger logger2 = logger;
            StringBuffer stringBuffer = new StringBuffer();
            stringBuffer.append("Formula ");
            stringBuffer.append(this.formula);
            stringBuffer.append(" has a non-empty parse stack");
            logger2.warn(stringBuffer.toString());
        }
        return parseItem3;
    }

    private ArrayList getTokens() throws FormulaException {
        ArrayList arrayList = new ArrayList();
        Yylex yylex = new Yylex(new StringReader(this.formula));
        yylex.setExternalSheet(this.externalSheet);
        yylex.setNameTable(this.nameTable);
        try {
            for (ParseItem yylex2 = yylex.yylex(); yylex2 != null; yylex2 = yylex.yylex()) {
                arrayList.add(yylex2);
            }
        } catch (IOException e) {
            logger.warn(e.toString());
        } catch (Error unused) {
            FormulaException.FormulaMessage formulaMessage = FormulaException.LEXICAL_ERROR;
            StringBuffer stringBuffer = new StringBuffer();
            stringBuffer.append(this.formula);
            stringBuffer.append(" at char  ");
            stringBuffer.append(yylex.getPos());
            throw new FormulaException(formulaMessage, stringBuffer.toString());
        }
        return arrayList;
    }

    @Override
    public String getFormula() {
        if (this.parsedFormula == null) {
            StringBuffer stringBuffer = new StringBuffer();
            this.root.getString(stringBuffer);
            this.parsedFormula = stringBuffer.toString();
        }
        return this.parsedFormula;
    }

    @Override
    public byte[] getBytes() {
        byte[] bytes = this.root.getBytes();
        if (!this.root.isVolatile()) {
            return bytes;
        }
        byte[] bArr = new byte[bytes.length + 4];
        System.arraycopy(bytes, 0, bArr, 4, bytes.length);
        bArr[0] = Token.ATTRIBUTE.getCode();
        bArr[1] = 1;
        return bArr;
    }

    private void handleFunction(StringFunction stringFunction, Iterator it, Stack stack) throws FormulaException {
        ParseItem parseCurrent = parseCurrent(it);
        if (stringFunction.getFunction(this.settings) == Function.UNKNOWN) {
            throw new FormulaException(FormulaException.UNRECOGNIZED_FUNCTION);
        }
        if (stringFunction.getFunction(this.settings) == Function.SUM && this.arguments == null) {
            Attribute attribute = new Attribute(stringFunction, this.settings);
            attribute.add(parseCurrent);
            stack.push(attribute);
            return;
        }
        if (stringFunction.getFunction(this.settings) == Function.IF) {
            Attribute attribute2 = new Attribute(stringFunction, this.settings);
            VariableArgFunction variableArgFunction = new VariableArgFunction(this.settings);
            int size = this.arguments.size();
            while (r2 < size) {
                variableArgFunction.add((ParseItem) this.arguments.get(r2));
                r2++;
            }
            attribute2.setIfConditions(variableArgFunction);
            stack.push(attribute2);
            return;
        }
        if (stringFunction.getFunction(this.settings).getNumArgs() == 255) {
            Stack stack2 = this.arguments;
            if (stack2 == null) {
                VariableArgFunction variableArgFunction2 = new VariableArgFunction(stringFunction.getFunction(this.settings), parseCurrent != null ? 1 : 0, this.settings);
                if (parseCurrent != null) {
                    variableArgFunction2.add(parseCurrent);
                }
                stack.push(variableArgFunction2);
                return;
            }
            int size2 = stack2.size();
            VariableArgFunction variableArgFunction3 = new VariableArgFunction(stringFunction.getFunction(this.settings), size2, this.settings);
            ParseItem[] parseItemArr = new ParseItem[size2];
            for (int i = 0; i < size2; i++) {
                parseItemArr[(size2 - i) - 1] = (ParseItem) this.arguments.pop();
            }
            while (r2 < size2) {
                variableArgFunction3.add(parseItemArr[r2]);
                r2++;
            }
            stack.push(variableArgFunction3);
            this.arguments.clear();
            this.arguments = null;
            return;
        }
        BuiltInFunction builtInFunction = new BuiltInFunction(stringFunction.getFunction(this.settings), this.settings);
        int numArgs = stringFunction.getFunction(this.settings).getNumArgs();
        if (numArgs == 1) {
            builtInFunction.add(parseCurrent);
        } else {
            Stack stack3 = this.arguments;
            if ((stack3 == null && numArgs != 0) || (stack3 != null && numArgs != stack3.size())) {
                throw new FormulaException(FormulaException.INCORRECT_ARGUMENTS);
            }
            while (r2 < numArgs) {
                builtInFunction.add((ParseItem) this.arguments.get(r2));
                r2++;
            }
        }
        stack.push(builtInFunction);
    }

    @Override
    public void adjustRelativeCellReferences(int i, int i2) {
        this.root.adjustRelativeCellReferences(i, i2);
    }

    @Override
    public void columnInserted(int i, int i2, boolean z) {
        this.root.columnInserted(i, i2, z);
    }

    @Override
    public void columnRemoved(int i, int i2, boolean z) {
        this.root.columnRemoved(i, i2, z);
    }

    @Override
    public void rowInserted(int i, int i2, boolean z) {
        this.root.rowInserted(i, i2, z);
    }

    @Override
    public void rowRemoved(int i, int i2, boolean z) {
        this.root.rowRemoved(i, i2, z);
    }

    private void handleOperand(Operand operand, Stack stack) {
        boolean z = operand instanceof IntegerValue;
        if (!z) {
            stack.push(operand);
            return;
        }
        if (z) {
            IntegerValue integerValue = (IntegerValue) operand;
            if (!integerValue.isOutOfRange()) {
                stack.push(integerValue);
            } else {
                stack.push(new DoubleValue(integerValue.getValue()));
            }
        }
    }

    @Override
    public boolean handleImportedCellReferences() {
        this.root.handleImportedCellReferences();
        return this.root.isValid();
    }
}