📄 formulaparser.java
字号:
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(','); } 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('+'); Factor(); tokens.add(new UnaryPlusPtg()); } else if (look == '(' ) { Match('('); Expression(); Match(')'); tokens.add(new ParenthesisPtg()); } else if (IsAlpha(look) || look == '\''){ Ident(); } else if(look == '"') { StringLiteral(); } else if (look == ')' || look == ',') { tokens.add(new MissingArgPtg()); } else { String number2 = null; String exponent = null; String number1 = GetNum(); if (look == '.') { GetChar(); number2 = GetNum(); } if (look == 'E') { GetChar(); String sign = ""; if (look == '+') { GetChar(); } else if (look == '-') { GetChar(); sign = "-"; } String number = GetNum(); if (number == null) { Expected("Integer"); } exponent = sign + number; } if (number1 == null && number2 == null) { Expected("Integer"); } tokens.add(getNumberPtgFromString(number1, number2, exponent)); } } /** * Get a PTG for an integer from its string representation. * return Int or Number Ptg based on size of input */ private Ptg getNumberPtgFromString(String number1, String number2, String exponent) { StringBuffer number = new StringBuffer(); if (number2 == null) { number.append(number1); if (exponent != null) { number.append('E'); number.append(exponent); } String numberStr = number.toString(); try { return new IntPtg(numberStr); } catch (NumberFormatException e) { return new NumberPtg(numberStr); } } else { if (number1 != null) { number.append(number1); } number.append('.'); number.append(number2); if (exponent != null) { number.append('E'); number.append(exponent); } return new NumberPtg(number.toString()); } } 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(); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -