📄 formulaparser.java
字号:
} else { Match(';'); } Expression(); addArgumentPointer(); numArgs++; } return numArgs; } /** Parse and Translate a Math Factor */ private void Factor() { if (look == '-') { Match('-'); Factor(); tokens.add(new UnaryMinusPtg()); } else if (look == '(' ) { Match('('); Expression(); Match(')'); tokens.add(new ParenthesisPtg()); } else if (IsAlpha(look) || look == '\''){ Ident(); } else if(look == '"') { StringLiteral(); } else { String number = GetNum(); if (look=='.') { Match('.'); String decimalPart = null; if (IsDigit(look)) number = number +"."+ GetNum(); //this also takes care of someone entering "1234." tokens.add(new NumberPtg(number)); } else { tokens.add(new IntPtg(number)); //TODO:what if the number is too big to be a short? ..add factory to return Int or Number! } } } private void StringLiteral() { // Can't use match here 'cuz it consumes whitespace // which we need to preserve inside the string. // - pete // Match('"'); if (look != '"') Expected("\""); else { GetChar(); StringBuffer Token = new StringBuffer(); for (;;) { if (look == '"') { GetChar(); SkipWhite(); //potential white space here since it doesnt matter up to the operator if (look == '"') Token.append("\""); else break; } else if (look == 0) { break; } else { Token.append(look); GetChar(); } } tokens.add(new StringPtg(Token.toString())); } } /** Recognize and Translate a Multiply */ private void Multiply(){ Match('*'); Factor(); tokens.add(new MultiplyPtg()); } /** Recognize and Translate a Divide */ private void Divide() { Match('/'); Factor(); tokens.add(new DividePtg()); } /** Parse and Translate a Math Term */ private void Term(){ Factor(); while (look == '*' || look == '/' || look == '^' || look == '&') { ///TODO do we need to do anything here?? if (look == '*') Multiply(); else if (look == '/') Divide(); else if (look == '^') Power(); else if (look == '&') Concat(); } } /** Recognize and Translate an Add */ private void Add() { Match('+'); Term(); tokens.add(new AddPtg()); } /** Recognize and Translate a Concatination */ private void Concat() { Match('&'); Term(); tokens.add(new ConcatPtg()); } /** Recognize and Translate a test for Equality */ private void Equal() { Match('='); Expression(); tokens.add(new EqualPtg()); } /** Recognize and Translate a Subtract */ private void Subtract() { Match('-'); Term(); tokens.add(new SubtractPtg()); } private void Power() { Match('^'); Term(); tokens.add(new PowerPtg()); } /** Parse and Translate an Expression */ private void Expression() { Term(); while (IsAddop(look)) { if (look == '+' ) Add(); else if (look == '-') Subtract(); } /* * This isn't quite right since it would allow multiple comparison operators. */ if(look == '=' || look == '>' || look == '<') { if (look == '=') Equal(); else if (look == '>') GreaterThan(); else if (look == '<') LessThan(); return; } } /** Recognize and Translate a Greater Than */ private void GreaterThan() { Match('>'); if(look == '=') GreaterEqual(); else { Expression(); tokens.add(new GreaterThanPtg()); } } /** Recognize and Translate a Less Than */ private void LessThan() { Match('<'); if(look == '=') LessEqual(); else if(look == '>') NotEqual(); else { Expression(); tokens.add(new LessThanPtg()); } } /** * Recognize and translate Greater than or Equal * */ private void GreaterEqual() { Match('='); Expression(); tokens.add(new GreaterEqualPtg()); } /** * Recognize and translate Less than or Equal * */ private void LessEqual() { Match('='); Expression(); tokens.add(new LessEqualPtg()); } /** * Recognize and not Equal * */ private void NotEqual() { Match('>'); Expression(); tokens.add(new NotEqualPtg()); } //{--------------------------------------------------------------} //{ Parse and Translate an Assignment Statement } /**procedure Assignment;var Name: string[8];begin Name := GetName; Match('='); Expression;end; **/ /** Initialize */ private void init() { GetChar(); SkipWhite(); } /** API call to execute the parsing of the formula * */ public void parse() { synchronized (tokens) { init(); Expression(); } } /********************************* * PARSER IMPLEMENTATION ENDS HERE * EXCEL SPECIFIC METHODS BELOW *******************************/ /** API call to retrive the array of Ptgs created as * a result of the parsing */ public Ptg[] getRPNPtg() { return getRPNPtg(FORMULA_TYPE_CELL); } public Ptg[] getRPNPtg(int formulaType) { Node node = createTree(); setRootLevelRVA(node, formulaType); setParameterRVA(node,formulaType); return (Ptg[]) tokens.toArray(new Ptg[0]); } private void setRootLevelRVA(Node n, int formulaType) { //Pg 16, excelfileformat.pdf @ openoffice.org Ptg p = (Ptg) n.getValue(); if (formulaType == FormulaParser.FORMULA_TYPE_NAMEDRANGE) { if (p.getDefaultOperandClass() == Ptg.CLASS_REF) { setClass(n,Ptg.CLASS_REF); } else { setClass(n,Ptg.CLASS_ARRAY); } } else { setClass(n,Ptg.CLASS_VALUE); } } private void setParameterRVA(Node n, int formulaType) { Ptg p = (Ptg) n.getValue(); if (p instanceof AbstractFunctionPtg) { int numOperands = n.getNumChildren(); for (int i =0;i<n.getNumChildren();i++) { setParameterRVA(n.getChild(i),((AbstractFunctionPtg)p).getParameterClass(i),formulaType); if (n.getChild(i).getValue() instanceof AbstractFunctionPtg) { setParameterRVA(n.getChild(i),formulaType); } } } else { for (int i =0;i<n.getNumChildren();i++) { setParameterRVA(n.getChild(i),formulaType); } } } private void setParameterRVA(Node n, int expectedClass,int formulaType) { Ptg p = (Ptg) n.getValue(); if (expectedClass == Ptg.CLASS_REF) { //pg 15, table 1 if (p.getDefaultOperandClass() == Ptg.CLASS_REF ) { setClass(n, Ptg.CLASS_REF); } if (p.getDefaultOperandClass() == Ptg.CLASS_VALUE) { if (formulaType==FORMULA_TYPE_CELL || formulaType == FORMULA_TYPE_SHARED) { setClass(n,Ptg.CLASS_VALUE); } else { setClass(n,Ptg.CLASS_ARRAY); } } if (p.getDefaultOperandClass() == Ptg.CLASS_ARRAY ) { setClass(n, Ptg.CLASS_ARRAY); } } else if (expectedClass == Ptg.CLASS_VALUE) { //pg 15, table 2 if (formulaType == FORMULA_TYPE_NAMEDRANGE) { setClass(n,Ptg.CLASS_ARRAY) ; } else { setClass(n,Ptg.CLASS_VALUE); } } else { //Array class, pg 16. if (p.getDefaultOperandClass() == Ptg.CLASS_VALUE && (formulaType==FORMULA_TYPE_CELL || formulaType == FORMULA_TYPE_SHARED)) { setClass(n,Ptg.CLASS_VALUE); } else { setClass(n,Ptg.CLASS_ARRAY); } } } private void setClass(Node n, byte theClass) { Ptg p = (Ptg) n.getValue(); if (p instanceof AbstractFunctionPtg || !(p instanceof OperationPtg)) { p.setClass(theClass); } else { for (int i =0;i<n.getNumChildren();i++) { setClass(n.getChild(i),theClass); } } } /** * Convience method which takes in a list then passes it to the other toFormulaString * signature. * @param book workbook for 3D and named references * @param lptgs list of Ptg, can be null or empty * @return a human readable String */ public static String toFormulaString(Workbook book, List lptgs) { String retval = null; if (lptgs == null || lptgs.size() == 0) return "#NAME"; Ptg[] ptgs = new Ptg[lptgs.size()]; ptgs = (Ptg[])lptgs.toArray(ptgs); retval = toFormulaString(book, ptgs); return retval; } /** * Static method to convert an array of Ptgs in RPN order * to a human readable string format in infix mode. * @param book workbook for named and 3D references * @param ptgs array of Ptg, can be null or empty * @return a human readable String */ public static String toFormulaString(Workbook book, Ptg[] ptgs) { if (ptgs == null || ptgs.length == 0) return "#NAME"; java.util.Stack stack = new java.util.Stack(); AttrPtg ifptg = null; // Excel allows to have AttrPtg at position 0 (such as Blanks) which // do not have any operands. Skip them. stack.push(ptgs[0].toFormulaString(book)); for (int i = 1; i < ptgs.length; i++) { if (! (ptgs[i] instanceof OperationPtg)) { stack.push(ptgs[i].toFormulaString(book)); continue; } if (ptgs[i] instanceof AttrPtg && ((AttrPtg) ptgs[i]).isOptimizedIf()) { ifptg = (AttrPtg) ptgs[i]; continue; } final OperationPtg o = (OperationPtg) ptgs[i]; final String[] operands = new String[o.getNumberOfOperands()]; for (int j = operands.length; j > 0; j--) { //TODO: catch stack underflow and throw parse exception. operands[j - 1] = (String) stack.pop(); } stack.push(o.toFormulaString(operands)); if (!(o instanceof AbstractFunctionPtg)) continue; final AbstractFunctionPtg f = (AbstractFunctionPtg) o; final String fname = f.getName(); if (fname == null) continue; if ((ifptg != null) && (fname.equals("specialflag"))) { // this special case will be way different. stack.push(ifptg.toFormulaString(new String[]{(String) stack.pop()})); continue; } if (fname.equals("externalflag")) { final String top = (String) stack.pop(); final int paren = top.indexOf('('); final int comma = top.indexOf(','); if (comma == -1) { final int rparen = top.indexOf(')'); stack.push(top.substring(paren + 1, rparen) + "()"); } else { stack.push(top.substring(paren + 1, comma) + '(' + top.substring(comma + 1)); } } } // TODO: catch stack underflow and throw parse exception. return (String) stack.pop(); } /** Create a tree representation of the RPN token array *used to run the class(RVA) change algo */ private Node createTree() { java.util.Stack stack = new java.util.Stack(); int numPtgs = tokens.size(); OperationPtg o; int numOperands; Node[] operands; for (int i=0;i<numPtgs;i++) { if (tokens.get(i) instanceof OperationPtg) { o = (OperationPtg) tokens.get(i); numOperands = o.getNumberOfOperands(); operands = new Node[numOperands]; for (int j=0;j<numOperands;j++) { operands[numOperands-j-1] = (Node) stack.pop(); } Node result = new Node(o); result.setChildren(operands); stack.push(result); } else { stack.push(new Node((Ptg)tokens.get(i))); } } return (Node) stack.pop(); } /** toString on the parser instance returns the RPN ordered list of tokens * Useful for testing */ public String toString() { StringBuffer buf = new StringBuffer(); for (int i=0;i<tokens.size();i++) { buf.append( ( (Ptg)tokens.get(i)).toFormulaString(book)); buf.append(' '); } return buf.toString(); } } /** Private helper class, used to create a tree representation of the formula*/ class Node { private Ptg value=null; private Node[] children=new Node[0]; private int numChild=0; public Node(Ptg val) { value = val; } public void setChildren(Node[] child) {children = child;numChild=child.length;} public int getNumChildren() {return numChild;} public Node getChild(int number) {return children[number];} public Ptg getValue() {return value;} }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -