⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 formulaparser.java

📁 Office格式转换代码
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2003, 2003 The Apache Software Foundation.  All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in *    the documentation and/or other materials provided with the *    distribution. * * 3. The end-user documentation included with the redistribution, *    if any, must include the following acknowledgment: *       "This product includes software developed by the *        Apache Software Foundation (http://www.apache.org/)." *    Alternately, this acknowledgment may appear in the software itself, *    if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and *    "Apache POI" must not be used to endorse or promote products *    derived from this software without prior written permission. For *    written permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", *    "Apache POI", nor may "Apache" appear in their name, without *    prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation.  For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */package org.apache.poi.hssf.model;import java.util.ArrayList;import java.util.Iterator;import java.util.LinkedList;import java.util.List;//import PTG's .. since we need everything, import *import org.apache.poi.hssf.record.formula.*;/** * This class parses a formula string into a List of tokens in RPN order. * Inspired by  *           Lets Build a Compiler, by Jack Crenshaw * BNF for the formula expression is : * <expression> ::= <term> [<addop> <term>]* * <term> ::= <factor>  [ <mulop> <factor> ]* * <factor> ::= <number> | (<expression>) | <cellRef> | <function> * <function> ::= <functionName> ([expression [, expression]*]) * *  @author Avik Sengupta <avik AT Avik Sengupta DOT com> *  @author Andrew C. oliver (acoliver at apache dot org) *  @author Eric Ladner (eladner at goldinc dot com) *  @author Cameron Riley (criley at ekmail.com) *  @author Peter M. Murray (pete at quantrix dot com) */public class FormulaParser {        public static int FORMULA_TYPE_CELL = 0;    public static int FORMULA_TYPE_SHARED = 1;    public static int FORMULA_TYPE_ARRAY =2;    public static int FORMULA_TYPE_CONDFOMRAT = 3;    public static int FORMULA_TYPE_NAMEDRANGE = 4;        private String formulaString;    private int pointer=0;    private int formulaLength;        private List tokens = new java.util.Stack();        /**     * Using an unsynchronized linkedlist to implement a stack since we're not multi-threaded.     */    private List functionTokens = new LinkedList();        //private Stack tokens = new java.util.Stack();    private List result = new ArrayList();    private int numParen;        private static char TAB = '\t';    private static char CR = '\n';       private char look;              // Lookahead Character   private boolean inFunction = false;      private Workbook book;            /** create the parser with the string that is to be parsed     *    later call the parse() method to return ptg list in rpn order     *    then call the getRPNPtg() to retrive the parse results     *  This class is recommended only for single threaded use     */    public FormulaParser(String formula, Workbook book){        formulaString = formula;        pointer=0;        this.book = book;    	formulaLength = formulaString.length();    }        /** Read New Character From Input Stream */    private void GetChar() {        // Check to see if we've walked off the end of the string.	// Just return if so and reset Look to smoething to keep 	// SkipWhitespace from spinning        if (pointer == formulaLength) {            look = (char)0;	    return;	}        look=formulaString.charAt(pointer++);        //System.out.println("Got char: "+ look);    }        /** Report an Error */    private void Error(String s) {        System.out.println("Error: "+s);    }             /** Report Error and Halt */    private void Abort(String s) {        Error(s);        //System.exit(1);  //throw exception??        throw new RuntimeException("Cannot Parse, sorry : "+s);    }            /** Report What Was Expected */    private void Expected(String s) {        Abort(s + " Expected");    }             /** Recognize an Alpha Character */    private boolean IsAlpha(char c) {        return Character.isLetter(c) || c == '$';    }             /** Recognize a Decimal Digit */    private boolean IsDigit(char c) {        //System.out.println("Checking digit for"+c);        return Character.isDigit(c);    }            /** Recognize an Alphanumeric */    private boolean  IsAlNum(char c) {        return  (IsAlpha(c) || IsDigit(c));    }            /** Recognize an Addop */    private boolean IsAddop( char c) {        return (c =='+' || c =='-');    }        /** Recognize White Space */    private boolean IsWhite( char c) {        return  (c ==' ' || c== TAB);    }        /**     * Determines special characters;primarily in use for definition of string literals     * @param c     * @return boolean     */    private boolean IsSpecialChar(char c) {    	return (c == '>' || c== '<' || c== '=' || c=='&' || c=='[' || c==']');    }        /** Skip Over Leading White Space */    private void SkipWhite() {        while (IsWhite(look)) {            GetChar();        }    }            /** Match a Specific Input Character */    private void Match(char x) {        if (look != x) {            Expected("" + x + "");        }else {            GetChar();            SkipWhite();        }    }        /** Get an Identifier */    private String GetName() {        StringBuffer Token = new StringBuffer();        if (!IsAlpha(look) && look != '\'') {            Expected("Name");        }        if(look == '\'')        {        	Match('\'');        	boolean done = look == '\'';        	while(!done)        	{        		Token.append(Character.toUpperCase(look));        		GetChar();        		if(look == '\'')        		{        			Match('\'');        			done = look != '\'';        		}        	}        }        else        {	        while (IsAlNum(look)) {	            Token.append(Character.toUpperCase(look));	            GetChar();	        }		}        SkipWhite();        return Token.toString();    }        /**Get an Identifier AS IS, without stripping white spaces or        converting to uppercase; used for literals */    private String GetNameAsIs() {        StringBuffer Token = new StringBuffer();				while (IsAlNum(look) || IsWhite(look) || IsSpecialChar(look)) {            Token = Token.append(look);            GetChar();        }        return Token.toString();    }            /** Get a Number */    private String GetNum() {        String Value ="";        if  (!IsDigit(look)) Expected("Integer");        while (IsDigit(look)){            Value = Value + look;            GetChar();        }        SkipWhite();        return Value;    }    /** Output a String with Tab */    private void  Emit(String s){        System.out.print(TAB+s);    }    /** Output a String with Tab and CRLF */    private void EmitLn(String s) {        Emit(s);        System.out.println();;    }        /** Parse and Translate a String Identifier */    private void Ident() {        String name;        name = GetName();        if (look == '('){            //This is a function            function(name);        } else if (look == ':') { // this is a AreaReference            String first = name;            Match(':');            String second = GetName();            tokens.add(new AreaPtg(first+":"+second));        } else if (look == '!') {            Match('!');            String sheetName = name;            String first = GetName();            short externIdx = book.checkExternSheet(book.getSheetIndex(sheetName));            if (look == ':') {                Match(':');                String second=GetName();                                tokens.add(new Area3DPtg(first+":"+second,externIdx));            } else {                tokens.add(new Ref3DPtg(first,externIdx));            }        } else {            //this can be either a cell ref or a named range !!            boolean cellRef = true ; //we should probably do it with reg exp??            boolean boolLit = (name.equals("TRUE") || name.equals("FALSE"));            if (boolLit) {                tokens.add(new BoolPtg(name));            } else if (cellRef) {                tokens.add(new ReferencePtg(name));            }else {                //handle after named range is integrated!!            }        }    }        /**     * Adds a pointer to the last token to the latest function argument list.     * @param obj     */    private void addArgumentPointer() {		if (this.functionTokens.size() > 0) {			//no bounds check because this method should not be called unless a token array is setup by function()			List arguments = (List)this.functionTokens.get(0);			arguments.add(tokens.get(tokens.size()-1));		}    }        private void function(String name) {    	//average 2 args per function    	this.functionTokens.add(0, new ArrayList(2));    	        Match('(');        int numArgs = Arguments();        Match(')');                        AbstractFunctionPtg functionPtg = getFunction(name,(byte)numArgs);        		tokens.add(functionPtg);         if (functionPtg.getName().equals("externalflag")) {            tokens.add(new NamePtg(name, this.book));        } 		//remove what we just put in		this.functionTokens.remove(0);    }        /**     * Adds the size of all the ptgs after the provided index (inclusive).     * <p>     * Initially used to count a goto     * @param index     * @return int     */    private int getPtgSize(int index) {    	int count = 0;    	    	Iterator ptgIterator = tokens.listIterator(index);    	while (ptgIterator.hasNext()) {    		Ptg ptg = (Ptg)ptgIterator.next();    		count+=ptg.getSize();    	}    	    	return count;    }        private int getPtgSize(int start, int end) {        int count = 0;        int index = start;        Iterator ptgIterator = tokens.listIterator(index);        while (ptgIterator.hasNext() && index <= end) {            Ptg ptg = (Ptg)ptgIterator.next();            count+=ptg.getSize();            index++;        }                return count;    }    /**     * Generates the variable function ptg for the formula.     * <p>     * For IF Formulas, additional PTGs are added to the tokens      * @param name     * @param numArgs     * @return Ptg a null is returned if we're in an IF formula, it needs extreme manipulation and is handled in this function     */    private AbstractFunctionPtg getFunction(String name, byte numArgs) {        AbstractFunctionPtg retval = null;                if (name.equals("IF")) {            retval = new FuncVarPtg(AbstractFunctionPtg.ATTR_NAME, numArgs);                        //simulated pop, no bounds checking because this list better be populated by function()            List argumentPointers = (List)this.functionTokens.get(0);                                    AttrPtg ifPtg = new AttrPtg();            ifPtg.setData((short)7); //mirroring excel output            ifPtg.setOptimizedIf(true);                        if (argumentPointers.size() != 2  && argumentPointers.size() != 3) {                throw new IllegalArgumentException("["+argumentPointers.size()+"] Arguments Found - An IF formula requires 2 or 3 arguments. IF(CONDITION, TRUE_VALUE, FALSE_VALUE [OPTIONAL]");            }                        //Biffview of an IF formula record indicates the attr ptg goes after the condition ptgs and are            //tracked in the argument pointers            //The beginning first argument pointer is the last ptg of the condition            int ifIndex = tokens.indexOf(argumentPointers.get(0))+1;            tokens.add(ifIndex, ifPtg);                        //we now need a goto ptgAttr to skip to the end of the formula after a true condition            //the true condition is should be inserted after the last ptg in the first argument                        int gotoIndex = tokens.indexOf(argumentPointers.get(1))+1;                        AttrPtg goto1Ptg = new AttrPtg();            goto1Ptg.setGoto(true);                                    tokens.add(gotoIndex, goto1Ptg);                                    if (numArgs > 2) { //only add false jump if there is a false condition                                //second goto to skip past the function ptg                AttrPtg goto2Ptg = new AttrPtg();                goto2Ptg.setGoto(true);                goto2Ptg.setData((short)(retval.getSize()-1));                //Page 472 of the Microsoft Excel Developer's kit states that:                //The b(or w) field specifies the number byes (or words to skip, minus 1                                tokens.add(goto2Ptg); //this goes after all the arguments are defined            }                        //data portion of the if ptg points to the false subexpression (Page 472 of MS Excel Developer's kit)            //count the number of bytes after the ifPtg to the False Subexpression            //doesn't specify -1 in the documentation            ifPtg.setData((short)(getPtgSize(ifIndex+1, gotoIndex)));                        //count all the additional (goto) ptgs but dont count itself            int ptgCount = this.getPtgSize(gotoIndex)-goto1Ptg.getSize()+retval.getSize();            if (ptgCount > (int)Short.MAX_VALUE) {                throw new RuntimeException("Ptg Size exceeds short when being specified for a goto ptg in an if");            }                        goto1Ptg.setData((short)(ptgCount-1));                    } else {                        retval = new FuncVarPtg(name,numArgs);        }                return retval;    }        /** get arguments to a function */    private int Arguments() {        int numArgs = 0;        if (look != ')')  {            numArgs++;             Expression();			   addArgumentPointer();        }        while (look == ','  || look == ';') { //TODO handle EmptyArgs            if(look == ',') {              Match(',');

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -