Source Code Cross Referenced for FormulaParser.java in  » Collaboration » poi-3.0.2-beta2 » org » apache » poi » hssf » model » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Collaboration » poi 3.0.2 beta2 » org.apache.poi.hssf.model 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* ====================================================================
0002:         Licensed to the Apache Software Foundation (ASF) under one or more
0003:         contributor license agreements.  See the NOTICE file distributed with
0004:         this work for additional information regarding copyright ownership.
0005:         The ASF licenses this file to You under the Apache License, Version 2.0
0006:         (the "License"); you may not use this file except in compliance with
0007:         the License.  You may obtain a copy of the License at
0008:
0009:         http://www.apache.org/licenses/LICENSE-2.0
0010:
0011:         Unless required by applicable law or agreed to in writing, software
0012:         distributed under the License is distributed on an "AS IS" BASIS,
0013:         WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         See the License for the specific language governing permissions and
0015:         limitations under the License.
0016:         ==================================================================== */
0017:
0018:        package org.apache.poi.hssf.model;
0019:
0020:        import java.util.ArrayList;
0021:        import java.util.Iterator;
0022:        import java.util.LinkedList;
0023:        import java.util.List;
0024:
0025:        //import PTG's .. since we need everything, import *
0026:        import org.apache.poi.hssf.record.formula.*;
0027:
0028:        /**
0029:         * This class parses a formula string into a List of tokens in RPN order.
0030:         * Inspired by 
0031:         *           Lets Build a Compiler, by Jack Crenshaw
0032:         * BNF for the formula expression is :
0033:         * <expression> ::= <term> [<addop> <term>]*
0034:         * <term> ::= <factor>  [ <mulop> <factor> ]*
0035:         * <factor> ::= <number> | (<expression>) | <cellRef> | <function>
0036:         * <function> ::= <functionName> ([expression [, expression]*])
0037:         *
0038:         *  @author Avik Sengupta <avik at apache dot org>
0039:         *  @author Andrew C. oliver (acoliver at apache dot org)
0040:         *  @author Eric Ladner (eladner at goldinc dot com)
0041:         *  @author Cameron Riley (criley at ekmail.com)
0042:         *  @author Peter M. Murray (pete at quantrix dot com)
0043:         *  @author Pavel Krupets (pkrupets at palmtreebusiness dot com)
0044:         */
0045:        public class FormulaParser {
0046:
0047:            public static int FORMULA_TYPE_CELL = 0;
0048:            public static int FORMULA_TYPE_SHARED = 1;
0049:            public static int FORMULA_TYPE_ARRAY = 2;
0050:            public static int FORMULA_TYPE_CONDFOMRAT = 3;
0051:            public static int FORMULA_TYPE_NAMEDRANGE = 4;
0052:
0053:            private String formulaString;
0054:            private int pointer = 0;
0055:            private int formulaLength;
0056:
0057:            private List tokens = new java.util.Stack();
0058:
0059:            /**
0060:             * Using an unsynchronized linkedlist to implement a stack since we're not multi-threaded.
0061:             */
0062:            private List functionTokens = new LinkedList();
0063:
0064:            private static char TAB = '\t';
0065:            private static char CR = '\n';
0066:
0067:            private char look; // Lookahead Character
0068:
0069:            private Workbook book;
0070:
0071:            /** 
0072:             * Create the formula parser, with the string that is to be
0073:             *  parsed against the supplied workbook.
0074:             * A later call the parse() method to return ptg list in
0075:             *  rpn order, then call the getRPNPtg() to retrive the
0076:             *  parse results.
0077:             * This class is recommended only for single threaded use.
0078:             * 
0079:             * If you only have a usermodel.HSSFWorkbook, and not a
0080:             *  model.Workbook, then use the convenience method on
0081:             *  usermodel.HSSFFormulaEvaluator 
0082:             */
0083:            public FormulaParser(String formula, Workbook book) {
0084:                formulaString = formula;
0085:                pointer = 0;
0086:                this .book = book;
0087:                formulaLength = formulaString.length();
0088:            }
0089:
0090:            /** Read New Character From Input Stream */
0091:            private void GetChar() {
0092:                // Check to see if we've walked off the end of the string.
0093:                // Just return if so and reset Look to smoething to keep 
0094:                // SkipWhitespace from spinning
0095:                if (pointer == formulaLength) {
0096:                    look = (char) 0;
0097:                    return;
0098:                }
0099:                look = formulaString.charAt(pointer++);
0100:                //System.out.println("Got char: "+ look);
0101:            }
0102:
0103:            /** Report an Error */
0104:            private void Error(String s) {
0105:                System.out.println("Error: " + s);
0106:            }
0107:
0108:            /** Report Error and Halt */
0109:            private void Abort(String s) {
0110:                Error(s);
0111:                //System.exit(1);  //throw exception??
0112:                throw new RuntimeException("Cannot Parse, sorry : " + s + " @ "
0113:                        + pointer + " [Formula String was: '" + formulaString
0114:                        + "']");
0115:            }
0116:
0117:            /** Report What Was Expected */
0118:            private void Expected(String s) {
0119:                Abort(s + " Expected");
0120:            }
0121:
0122:            /** Recognize an Alpha Character */
0123:            private boolean IsAlpha(char c) {
0124:                return Character.isLetter(c) || c == '$' || c == '_';
0125:            }
0126:
0127:            /** Recognize a Decimal Digit */
0128:            private boolean IsDigit(char c) {
0129:                //System.out.println("Checking digit for"+c);
0130:                return Character.isDigit(c);
0131:            }
0132:
0133:            /** Recognize an Alphanumeric */
0134:            private boolean IsAlNum(char c) {
0135:                return (IsAlpha(c) || IsDigit(c));
0136:            }
0137:
0138:            /** Recognize an Addop */
0139:            private boolean IsAddop(char c) {
0140:                return (c == '+' || c == '-');
0141:            }
0142:
0143:            /** Recognize White Space */
0144:            private boolean IsWhite(char c) {
0145:                return (c == ' ' || c == TAB);
0146:            }
0147:
0148:            /**
0149:             * Determines special characters;primarily in use for definition of string literals
0150:             * @param c
0151:             * @return boolean
0152:             */
0153:            private boolean IsSpecialChar(char c) {
0154:                return (c == '>' || c == '<' || c == '=' || c == '&'
0155:                        || c == '[' || c == ']');
0156:            }
0157:
0158:            /** Skip Over Leading White Space */
0159:            private void SkipWhite() {
0160:                while (IsWhite(look)) {
0161:                    GetChar();
0162:                }
0163:            }
0164:
0165:            /** Match a Specific Input Character */
0166:            private void Match(char x) {
0167:                if (look != x) {
0168:                    Expected("" + x + "");
0169:                } else {
0170:                    GetChar();
0171:                    SkipWhite();
0172:                }
0173:            }
0174:
0175:            /** Get an Identifier */
0176:            private String GetName() {
0177:                StringBuffer Token = new StringBuffer();
0178:                if (!IsAlpha(look) && look != '\'') {
0179:                    Expected("Name");
0180:                }
0181:                if (look == '\'') {
0182:                    Match('\'');
0183:                    boolean done = look == '\'';
0184:                    while (!done) {
0185:                        Token.append(Character.toUpperCase(look));
0186:                        GetChar();
0187:                        if (look == '\'') {
0188:                            Match('\'');
0189:                            done = look != '\'';
0190:                        }
0191:                    }
0192:                } else {
0193:                    while (IsAlNum(look)) {
0194:                        Token.append(Character.toUpperCase(look));
0195:                        GetChar();
0196:                    }
0197:                }
0198:                SkipWhite();
0199:                return Token.toString();
0200:            }
0201:
0202:            /**Get an Identifier AS IS, without stripping white spaces or 
0203:               converting to uppercase; used for literals */
0204:            private String GetNameAsIs() {
0205:                StringBuffer Token = new StringBuffer();
0206:
0207:                while (IsAlNum(look) || IsWhite(look) || IsSpecialChar(look)) {
0208:                    Token = Token.append(look);
0209:                    GetChar();
0210:                }
0211:                return Token.toString();
0212:            }
0213:
0214:            /** Get a Number */
0215:            private String GetNum() {
0216:                StringBuffer value = new StringBuffer();
0217:
0218:                while (IsDigit(this .look)) {
0219:                    value.append(this .look);
0220:                    GetChar();
0221:                }
0222:
0223:                SkipWhite();
0224:
0225:                return value.length() == 0 ? null : value.toString();
0226:            }
0227:
0228:            /** Output a String with Tab */
0229:            private void Emit(String s) {
0230:                System.out.print(TAB + s);
0231:            }
0232:
0233:            /** Output a String with Tab and CRLF */
0234:            private void EmitLn(String s) {
0235:                Emit(s);
0236:                System.out.println();
0237:                ;
0238:            }
0239:
0240:            /** Parse and Translate a String Identifier */
0241:            private void Ident() {
0242:                String name;
0243:                name = GetName();
0244:                if (look == '(') {
0245:                    //This is a function
0246:                    function(name);
0247:                } else if (look == ':' || look == '.') { // this is a AreaReference
0248:                    GetChar();
0249:
0250:                    while (look == '.') { // formulas can have . or .. or ... instead of :
0251:                        GetChar();
0252:                    }
0253:
0254:                    String first = name;
0255:                    String second = GetName();
0256:                    tokens.add(new AreaPtg(first + ":" + second));
0257:                } else if (look == '!') {
0258:                    Match('!');
0259:                    String sheetName = name;
0260:                    String first = GetName();
0261:                    short externIdx = book.checkExternSheet(book
0262:                            .getSheetIndex(sheetName));
0263:                    if (look == ':') {
0264:                        Match(':');
0265:                        String second = GetName();
0266:                        if (look == '!') {
0267:                            //The sheet name was included in both of the areas. Only really
0268:                            //need it once
0269:                            Match('!');
0270:                            String third = GetName();
0271:
0272:                            if (!sheetName.equals(second))
0273:                                throw new RuntimeException(
0274:                                        "Unhandled double sheet reference.");
0275:
0276:                            tokens.add(new Area3DPtg(first + ":" + third,
0277:                                    externIdx));
0278:                        } else {
0279:                            tokens.add(new Area3DPtg(first + ":" + second,
0280:                                    externIdx));
0281:                        }
0282:                    } else {
0283:                        tokens.add(new Ref3DPtg(first, externIdx));
0284:                    }
0285:                } else {
0286:                    //this can be either a cell ref or a named range !!
0287:                    boolean cellRef = true; //we should probably do it with reg exp??
0288:                    boolean boolLit = (name.equals("TRUE") || name
0289:                            .equals("FALSE"));
0290:                    if (boolLit) {
0291:                        tokens.add(new BoolPtg(name));
0292:                    } else if (cellRef) {
0293:                        tokens.add(new ReferencePtg(name));
0294:                    } else {
0295:                        //handle after named range is integrated!!
0296:                    }
0297:                }
0298:            }
0299:
0300:            /**
0301:             * Adds a pointer to the last token to the latest function argument list.
0302:             * @param obj
0303:             */
0304:            private void addArgumentPointer() {
0305:                if (this .functionTokens.size() > 0) {
0306:                    //no bounds check because this method should not be called unless a token array is setup by function()
0307:                    List arguments = (List) this .functionTokens.get(0);
0308:                    arguments.add(tokens.get(tokens.size() - 1));
0309:                }
0310:            }
0311:
0312:            private void function(String name) {
0313:                //average 2 args per function
0314:                this .functionTokens.add(0, new ArrayList(2));
0315:
0316:                Match('(');
0317:                int numArgs = Arguments();
0318:                Match(')');
0319:
0320:                AbstractFunctionPtg functionPtg = getFunction(name,
0321:                        (byte) numArgs);
0322:
0323:                tokens.add(functionPtg);
0324:
0325:                if (functionPtg.getName().equals("externalflag")) {
0326:                    tokens.add(new NamePtg(name, this .book));
0327:                }
0328:
0329:                //remove what we just put in
0330:                this .functionTokens.remove(0);
0331:            }
0332:
0333:            /**
0334:             * Adds the size of all the ptgs after the provided index (inclusive).
0335:             * <p>
0336:             * Initially used to count a goto
0337:             * @param index
0338:             * @return int
0339:             */
0340:            private int getPtgSize(int index) {
0341:                int count = 0;
0342:
0343:                Iterator ptgIterator = tokens.listIterator(index);
0344:                while (ptgIterator.hasNext()) {
0345:                    Ptg ptg = (Ptg) ptgIterator.next();
0346:                    count += ptg.getSize();
0347:                }
0348:
0349:                return count;
0350:            }
0351:
0352:            private int getPtgSize(int start, int end) {
0353:                int count = 0;
0354:                int index = start;
0355:                Iterator ptgIterator = tokens.listIterator(index);
0356:                while (ptgIterator.hasNext() && index <= end) {
0357:                    Ptg ptg = (Ptg) ptgIterator.next();
0358:                    count += ptg.getSize();
0359:                    index++;
0360:                }
0361:
0362:                return count;
0363:            }
0364:
0365:            /**
0366:             * Generates the variable function ptg for the formula.
0367:             * <p>
0368:             * For IF Formulas, additional PTGs are added to the tokens 
0369:             * @param name
0370:             * @param numArgs
0371:             * @return Ptg a null is returned if we're in an IF formula, it needs extreme manipulation and is handled in this function
0372:             */
0373:            private AbstractFunctionPtg getFunction(String name, byte numArgs) {
0374:                AbstractFunctionPtg retval = null;
0375:
0376:                if (name.equals("IF")) {
0377:                    retval = new FuncVarPtg(AbstractFunctionPtg.ATTR_NAME,
0378:                            numArgs);
0379:
0380:                    //simulated pop, no bounds checking because this list better be populated by function()
0381:                    List argumentPointers = (List) this .functionTokens.get(0);
0382:
0383:                    AttrPtg ifPtg = new AttrPtg();
0384:                    ifPtg.setData((short) 7); //mirroring excel output
0385:                    ifPtg.setOptimizedIf(true);
0386:
0387:                    if (argumentPointers.size() != 2
0388:                            && argumentPointers.size() != 3) {
0389:                        throw new IllegalArgumentException(
0390:                                "["
0391:                                        + argumentPointers.size()
0392:                                        + "] Arguments Found - An IF formula requires 2 or 3 arguments. IF(CONDITION, TRUE_VALUE, FALSE_VALUE [OPTIONAL]");
0393:                    }
0394:
0395:                    //Biffview of an IF formula record indicates the attr ptg goes after the condition ptgs and are
0396:                    //tracked in the argument pointers
0397:                    //The beginning first argument pointer is the last ptg of the condition
0398:                    int ifIndex = tokens.indexOf(argumentPointers.get(0)) + 1;
0399:                    tokens.add(ifIndex, ifPtg);
0400:
0401:                    //we now need a goto ptgAttr to skip to the end of the formula after a true condition
0402:                    //the true condition is should be inserted after the last ptg in the first argument
0403:
0404:                    int gotoIndex = tokens.indexOf(argumentPointers.get(1)) + 1;
0405:
0406:                    AttrPtg goto1Ptg = new AttrPtg();
0407:                    goto1Ptg.setGoto(true);
0408:
0409:                    tokens.add(gotoIndex, goto1Ptg);
0410:
0411:                    if (numArgs > 2) { //only add false jump if there is a false condition
0412:
0413:                        //second goto to skip past the function ptg
0414:                        AttrPtg goto2Ptg = new AttrPtg();
0415:                        goto2Ptg.setGoto(true);
0416:                        goto2Ptg.setData((short) (retval.getSize() - 1));
0417:                        //Page 472 of the Microsoft Excel Developer's kit states that:
0418:                        //The b(or w) field specifies the number byes (or words to skip, minus 1
0419:
0420:                        tokens.add(goto2Ptg); //this goes after all the arguments are defined
0421:                    }
0422:
0423:                    //data portion of the if ptg points to the false subexpression (Page 472 of MS Excel Developer's kit)
0424:                    //count the number of bytes after the ifPtg to the False Subexpression
0425:                    //doesn't specify -1 in the documentation
0426:                    ifPtg.setData((short) (getPtgSize(ifIndex + 1, gotoIndex)));
0427:
0428:                    //count all the additional (goto) ptgs but dont count itself
0429:                    int ptgCount = this .getPtgSize(gotoIndex)
0430:                            - goto1Ptg.getSize() + retval.getSize();
0431:                    if (ptgCount > (int) Short.MAX_VALUE) {
0432:                        throw new RuntimeException(
0433:                                "Ptg Size exceeds short when being specified for a goto ptg in an if");
0434:                    }
0435:
0436:                    goto1Ptg.setData((short) (ptgCount - 1));
0437:
0438:                } else {
0439:
0440:                    retval = new FuncVarPtg(name, numArgs);
0441:                }
0442:
0443:                return retval;
0444:            }
0445:
0446:            /** get arguments to a function */
0447:            private int Arguments() {
0448:                int numArgs = 0;
0449:                if (look != ')') {
0450:                    numArgs++;
0451:                    Expression();
0452:                    addArgumentPointer();
0453:                }
0454:                while (look == ',' || look == ';') { //TODO handle EmptyArgs
0455:                    if (look == ',') {
0456:                        Match(',');
0457:                    } else {
0458:                        Match(';');
0459:                    }
0460:                    Expression();
0461:                    addArgumentPointer();
0462:                    numArgs++;
0463:                }
0464:                return numArgs;
0465:            }
0466:
0467:            /** Parse and Translate a Math Factor  */
0468:            private void Factor() {
0469:                if (look == '-') {
0470:                    Match('-');
0471:                    Factor();
0472:                    tokens.add(new UnaryMinusPtg());
0473:                } else if (look == '+') {
0474:                    Match('+');
0475:                    Factor();
0476:                    tokens.add(new UnaryPlusPtg());
0477:                } else if (look == '(') {
0478:                    Match('(');
0479:                    Expression();
0480:                    Match(')');
0481:                    tokens.add(new ParenthesisPtg());
0482:                } else if (IsAlpha(look) || look == '\'') {
0483:                    Ident();
0484:                } else if (look == '"') {
0485:                    StringLiteral();
0486:                } else if (look == ')' || look == ',') {
0487:                    tokens.add(new MissingArgPtg());
0488:                } else {
0489:                    String number2 = null;
0490:                    String exponent = null;
0491:                    String number1 = GetNum();
0492:
0493:                    if (look == '.') {
0494:                        GetChar();
0495:                        number2 = GetNum();
0496:                    }
0497:
0498:                    if (look == 'E') {
0499:                        GetChar();
0500:
0501:                        String sign = "";
0502:                        if (look == '+') {
0503:                            GetChar();
0504:                        } else if (look == '-') {
0505:                            GetChar();
0506:                            sign = "-";
0507:                        }
0508:
0509:                        String number = GetNum();
0510:                        if (number == null) {
0511:                            Expected("Integer");
0512:                        }
0513:                        exponent = sign + number;
0514:                    }
0515:
0516:                    if (number1 == null && number2 == null) {
0517:                        Expected("Integer");
0518:                    }
0519:
0520:                    tokens.add(getNumberPtgFromString(number1, number2,
0521:                            exponent));
0522:                }
0523:            }
0524:
0525:            /** 
0526:             * Get a PTG for an integer from its string representation. 
0527:             * return Int or Number Ptg based on size of input
0528:             */
0529:            private Ptg getNumberPtgFromString(String number1, String number2,
0530:                    String exponent) {
0531:                StringBuffer number = new StringBuffer();
0532:
0533:                if (number2 == null) {
0534:                    number.append(number1);
0535:
0536:                    if (exponent != null) {
0537:                        number.append('E');
0538:                        number.append(exponent);
0539:                    }
0540:
0541:                    String numberStr = number.toString();
0542:
0543:                    try {
0544:                        return new IntPtg(numberStr);
0545:                    } catch (NumberFormatException e) {
0546:                        return new NumberPtg(numberStr);
0547:                    }
0548:                } else {
0549:                    if (number1 != null) {
0550:                        number.append(number1);
0551:                    }
0552:
0553:                    number.append('.');
0554:                    number.append(number2);
0555:
0556:                    if (exponent != null) {
0557:                        number.append('E');
0558:                        number.append(exponent);
0559:                    }
0560:
0561:                    return new NumberPtg(number.toString());
0562:                }
0563:            }
0564:
0565:            private void StringLiteral() {
0566:                // Can't use match here 'cuz it consumes whitespace
0567:                // which we need to preserve inside the string.
0568:                // - pete
0569:                // Match('"');
0570:                if (look != '"')
0571:                    Expected("\"");
0572:                else {
0573:                    GetChar();
0574:                    StringBuffer Token = new StringBuffer();
0575:                    for (;;) {
0576:                        if (look == '"') {
0577:                            GetChar();
0578:                            SkipWhite(); //potential white space here since it doesnt matter up to the operator
0579:                            if (look == '"')
0580:                                Token.append("\"");
0581:                            else
0582:                                break;
0583:                        } else if (look == 0) {
0584:                            break;
0585:                        } else {
0586:                            Token.append(look);
0587:                            GetChar();
0588:                        }
0589:                    }
0590:                    tokens.add(new StringPtg(Token.toString()));
0591:                }
0592:            }
0593:
0594:            /** Recognize and Translate a Multiply */
0595:            private void Multiply() {
0596:                Match('*');
0597:                Factor();
0598:                tokens.add(new MultiplyPtg());
0599:
0600:            }
0601:
0602:            /** Recognize and Translate a Divide */
0603:            private void Divide() {
0604:                Match('/');
0605:                Factor();
0606:                tokens.add(new DividePtg());
0607:
0608:            }
0609:
0610:            /** Parse and Translate a Math Term */
0611:            private void Term() {
0612:                Factor();
0613:                while (look == '*' || look == '/' || look == '^' || look == '&') {
0614:
0615:                    ///TODO do we need to do anything here??
0616:                    if (look == '*')
0617:                        Multiply();
0618:                    else if (look == '/')
0619:                        Divide();
0620:                    else if (look == '^')
0621:                        Power();
0622:                    else if (look == '&')
0623:                        Concat();
0624:                }
0625:            }
0626:
0627:            /** Recognize and Translate an Add */
0628:            private void Add() {
0629:                Match('+');
0630:                Term();
0631:                tokens.add(new AddPtg());
0632:            }
0633:
0634:            /** Recognize and Translate a Concatination */
0635:            private void Concat() {
0636:                Match('&');
0637:                Term();
0638:                tokens.add(new ConcatPtg());
0639:            }
0640:
0641:            /** Recognize and Translate a test for Equality  */
0642:            private void Equal() {
0643:                Match('=');
0644:                Expression();
0645:                tokens.add(new EqualPtg());
0646:            }
0647:
0648:            /** Recognize and Translate a Subtract */
0649:            private void Subtract() {
0650:                Match('-');
0651:                Term();
0652:                tokens.add(new SubtractPtg());
0653:            }
0654:
0655:            private void Power() {
0656:                Match('^');
0657:                Term();
0658:                tokens.add(new PowerPtg());
0659:            }
0660:
0661:            /** Parse and Translate an Expression */
0662:            private void Expression() {
0663:                Term();
0664:                while (IsAddop(look)) {
0665:                    if (look == '+')
0666:                        Add();
0667:                    else if (look == '-')
0668:                        Subtract();
0669:                }
0670:
0671:                /*
0672:                 * This isn't quite right since it would allow multiple comparison operators.
0673:                 */
0674:
0675:                if (look == '=' || look == '>' || look == '<') {
0676:                    if (look == '=')
0677:                        Equal();
0678:                    else if (look == '>')
0679:                        GreaterThan();
0680:                    else if (look == '<')
0681:                        LessThan();
0682:                    return;
0683:                }
0684:
0685:            }
0686:
0687:            /** Recognize and Translate a Greater Than  */
0688:            private void GreaterThan() {
0689:                Match('>');
0690:                if (look == '=')
0691:                    GreaterEqual();
0692:                else {
0693:                    Expression();
0694:                    tokens.add(new GreaterThanPtg());
0695:                }
0696:            }
0697:
0698:            /** Recognize and Translate a Less Than  */
0699:            private void LessThan() {
0700:                Match('<');
0701:                if (look == '=')
0702:                    LessEqual();
0703:                else if (look == '>')
0704:                    NotEqual();
0705:                else {
0706:                    Expression();
0707:                    tokens.add(new LessThanPtg());
0708:                }
0709:
0710:            }
0711:
0712:            /**
0713:             * Recognize and translate Greater than or Equal
0714:             *
0715:             */
0716:            private void GreaterEqual() {
0717:                Match('=');
0718:                Expression();
0719:                tokens.add(new GreaterEqualPtg());
0720:            }
0721:
0722:            /**
0723:             * Recognize and translate Less than or Equal
0724:             *
0725:             */
0726:
0727:            private void LessEqual() {
0728:                Match('=');
0729:                Expression();
0730:                tokens.add(new LessEqualPtg());
0731:            }
0732:
0733:            /**
0734:             * Recognize and not Equal
0735:             *
0736:             */
0737:
0738:            private void NotEqual() {
0739:                Match('>');
0740:                Expression();
0741:                tokens.add(new NotEqualPtg());
0742:            }
0743:
0744:            //{--------------------------------------------------------------}
0745:            //{ Parse and Translate an Assignment Statement }
0746:            /**
0747:            procedure Assignment;
0748:            var Name: string[8];
0749:            begin
0750:            Name := GetName;
0751:            Match('=');
0752:            Expression;
0753:
0754:            end;
0755:             **/
0756:
0757:            /** Initialize */
0758:
0759:            private void init() {
0760:                GetChar();
0761:                SkipWhite();
0762:            }
0763:
0764:            /** API call to execute the parsing of the formula
0765:             *
0766:             */
0767:            public void parse() {
0768:                synchronized (tokens) {
0769:                    init();
0770:                    Expression();
0771:                }
0772:            }
0773:
0774:            /*********************************
0775:             * PARSER IMPLEMENTATION ENDS HERE
0776:             * EXCEL SPECIFIC METHODS BELOW
0777:             *******************************/
0778:
0779:            /** API call to retrive the array of Ptgs created as 
0780:             * a result of the parsing
0781:             */
0782:            public Ptg[] getRPNPtg() {
0783:                return getRPNPtg(FORMULA_TYPE_CELL);
0784:            }
0785:
0786:            public Ptg[] getRPNPtg(int formulaType) {
0787:                Node node = createTree();
0788:                setRootLevelRVA(node, formulaType);
0789:                setParameterRVA(node, formulaType);
0790:                return (Ptg[]) tokens.toArray(new Ptg[0]);
0791:            }
0792:
0793:            private void setRootLevelRVA(Node n, int formulaType) {
0794:                //Pg 16, excelfileformat.pdf @ openoffice.org
0795:                Ptg p = (Ptg) n.getValue();
0796:                if (formulaType == FormulaParser.FORMULA_TYPE_NAMEDRANGE) {
0797:                    if (p.getDefaultOperandClass() == Ptg.CLASS_REF) {
0798:                        setClass(n, Ptg.CLASS_REF);
0799:                    } else {
0800:                        setClass(n, Ptg.CLASS_ARRAY);
0801:                    }
0802:                } else {
0803:                    setClass(n, Ptg.CLASS_VALUE);
0804:                }
0805:
0806:            }
0807:
0808:            private void setParameterRVA(Node n, int formulaType) {
0809:                Ptg p = n.getValue();
0810:                int numOperands = n.getNumChildren();
0811:                if (p instanceof  AbstractFunctionPtg) {
0812:                    for (int i = 0; i < numOperands; i++) {
0813:                        setParameterRVA(n.getChild(i),
0814:                                ((AbstractFunctionPtg) p).getParameterClass(i),
0815:                                formulaType);
0816:                        //                if (n.getChild(i).getValue() instanceof AbstractFunctionPtg) {
0817:                        //                    setParameterRVA(n.getChild(i),formulaType);
0818:                        //                }
0819:                        setParameterRVA(n.getChild(i), formulaType);
0820:                    }
0821:                } else {
0822:                    for (int i = 0; i < numOperands; i++) {
0823:                        setParameterRVA(n.getChild(i), formulaType);
0824:                    }
0825:                }
0826:            }
0827:
0828:            private void setParameterRVA(Node n, int expectedClass,
0829:                    int formulaType) {
0830:                Ptg p = (Ptg) n.getValue();
0831:                if (expectedClass == Ptg.CLASS_REF) { //pg 15, table 1 
0832:                    if (p.getDefaultOperandClass() == Ptg.CLASS_REF) {
0833:                        setClass(n, Ptg.CLASS_REF);
0834:                    }
0835:                    if (p.getDefaultOperandClass() == Ptg.CLASS_VALUE) {
0836:                        if (formulaType == FORMULA_TYPE_CELL
0837:                                || formulaType == FORMULA_TYPE_SHARED) {
0838:                            setClass(n, Ptg.CLASS_VALUE);
0839:                        } else {
0840:                            setClass(n, Ptg.CLASS_ARRAY);
0841:                        }
0842:                    }
0843:                    if (p.getDefaultOperandClass() == Ptg.CLASS_ARRAY) {
0844:                        setClass(n, Ptg.CLASS_ARRAY);
0845:                    }
0846:                } else if (expectedClass == Ptg.CLASS_VALUE) { //pg 15, table 2
0847:                    if (formulaType == FORMULA_TYPE_NAMEDRANGE) {
0848:                        setClass(n, Ptg.CLASS_ARRAY);
0849:                    } else {
0850:                        setClass(n, Ptg.CLASS_VALUE);
0851:                    }
0852:                } else { //Array class, pg 16. 
0853:                    if (p.getDefaultOperandClass() == Ptg.CLASS_VALUE
0854:                            && (formulaType == FORMULA_TYPE_CELL || formulaType == FORMULA_TYPE_SHARED)) {
0855:                        setClass(n, Ptg.CLASS_VALUE);
0856:                    } else {
0857:                        setClass(n, Ptg.CLASS_ARRAY);
0858:                    }
0859:                }
0860:            }
0861:
0862:            private void setClass(Node n, byte theClass) {
0863:                Ptg p = (Ptg) n.getValue();
0864:                if (p instanceof  AbstractFunctionPtg
0865:                        || !(p instanceof  OperationPtg)) {
0866:                    p.setClass(theClass);
0867:                } else {
0868:                    for (int i = 0; i < n.getNumChildren(); i++) {
0869:                        setClass(n.getChild(i), theClass);
0870:                    }
0871:                }
0872:            }
0873:
0874:            /**
0875:             * Convience method which takes in a list then passes it to the
0876:             *  other toFormulaString signature. 
0877:             * @param book   workbook for 3D and named references
0878:             * @param lptgs  list of Ptg, can be null or empty
0879:             * @return a human readable String
0880:             */
0881:            public static String toFormulaString(Workbook book, List lptgs) {
0882:                String retval = null;
0883:                if (lptgs == null || lptgs.size() == 0)
0884:                    return "#NAME";
0885:                Ptg[] ptgs = new Ptg[lptgs.size()];
0886:                ptgs = (Ptg[]) lptgs.toArray(ptgs);
0887:                retval = toFormulaString(book, ptgs);
0888:                return retval;
0889:            }
0890:
0891:            /**
0892:             * Convience method which takes in a list then passes it to the
0893:             *  other toFormulaString signature. Works on the current
0894:             *  workbook for 3D and named references
0895:             * @param lptgs  list of Ptg, can be null or empty
0896:             * @return a human readable String
0897:             */
0898:            public String toFormulaString(List lptgs) {
0899:                return toFormulaString(book, lptgs);
0900:            }
0901:
0902:            /**
0903:             * Static method to convert an array of Ptgs in RPN order
0904:             * to a human readable string format in infix mode.
0905:             * @param book  workbook for named and 3D references
0906:             * @param ptgs  array of Ptg, can be null or empty
0907:             * @return a human readable String
0908:             */
0909:            public static String toFormulaString(Workbook book, Ptg[] ptgs) {
0910:                if (ptgs == null || ptgs.length == 0)
0911:                    return "#NAME";
0912:                java.util.Stack stack = new java.util.Stack();
0913:                AttrPtg ifptg = null;
0914:
0915:                // Excel allows to have AttrPtg at position 0 (such as Blanks) which
0916:                // do not have any operands. Skip them.
0917:                stack.push(ptgs[0].toFormulaString(book));
0918:
0919:                for (int i = 1; i < ptgs.length; i++) {
0920:                    if (!(ptgs[i] instanceof  OperationPtg)) {
0921:                        stack.push(ptgs[i].toFormulaString(book));
0922:                        continue;
0923:                    }
0924:
0925:                    if (ptgs[i] instanceof  AttrPtg
0926:                            && ((AttrPtg) ptgs[i]).isOptimizedIf()) {
0927:                        ifptg = (AttrPtg) ptgs[i];
0928:                        continue;
0929:                    }
0930:
0931:                    final OperationPtg o = (OperationPtg) ptgs[i];
0932:                    final String[] operands = new String[o
0933:                            .getNumberOfOperands()];
0934:
0935:                    for (int j = operands.length; j > 0; j--) {
0936:                        //TODO: catch stack underflow and throw parse exception.
0937:                        operands[j - 1] = (String) stack.pop();
0938:                    }
0939:
0940:                    stack.push(o.toFormulaString(operands));
0941:                    if (!(o instanceof  AbstractFunctionPtg))
0942:                        continue;
0943:
0944:                    final AbstractFunctionPtg f = (AbstractFunctionPtg) o;
0945:                    final String fname = f.getName();
0946:                    if (fname == null)
0947:                        continue;
0948:
0949:                    if ((ifptg != null) && (fname.equals("specialflag"))) {
0950:                        // this special case will be way different.
0951:                        stack.push(ifptg
0952:                                .toFormulaString(new String[] { (String) stack
0953:                                        .pop() }));
0954:                        continue;
0955:                    }
0956:                    if (fname.equals("externalflag")) {
0957:                        final String top = (String) stack.pop();
0958:                        final int paren = top.indexOf('(');
0959:                        final int comma = top.indexOf(',');
0960:                        if (comma == -1) {
0961:                            final int rparen = top.indexOf(')');
0962:                            stack.push(top.substring(paren + 1, rparen) + "()");
0963:                        } else {
0964:                            stack.push(top.substring(paren + 1, comma) + '('
0965:                                    + top.substring(comma + 1));
0966:                        }
0967:                    }
0968:                }
0969:                // TODO: catch stack underflow and throw parse exception.
0970:                return (String) stack.pop();
0971:            }
0972:
0973:            /**
0974:             * Static method to convert an array of Ptgs in RPN order
0975:             *  to a human readable string format in infix mode. Works
0976:             *  on the current workbook for named and 3D references.
0977:             * @param ptgs  array of Ptg, can be null or empty
0978:             * @return a human readable String
0979:             */
0980:            public String toFormulaString(Ptg[] ptgs) {
0981:                return toFormulaString(book, ptgs);
0982:            }
0983:
0984:            /** Create a tree representation of the RPN token array
0985:             *used to run the class(RVA) change algo
0986:             */
0987:            private Node createTree() {
0988:                java.util.Stack stack = new java.util.Stack();
0989:                int numPtgs = tokens.size();
0990:                OperationPtg o;
0991:                int numOperands;
0992:                Node[] operands;
0993:                for (int i = 0; i < numPtgs; i++) {
0994:                    if (tokens.get(i) instanceof  OperationPtg) {
0995:
0996:                        o = (OperationPtg) tokens.get(i);
0997:                        numOperands = o.getNumberOfOperands();
0998:                        operands = new Node[numOperands];
0999:                        for (int j = 0; j < numOperands; j++) {
1000:                            operands[numOperands - j - 1] = (Node) stack.pop();
1001:                        }
1002:                        Node result = new Node(o);
1003:                        result.setChildren(operands);
1004:                        stack.push(result);
1005:                    } else {
1006:                        stack.push(new Node((Ptg) tokens.get(i)));
1007:                    }
1008:                }
1009:                return (Node) stack.pop();
1010:            }
1011:
1012:            /** toString on the parser instance returns the RPN ordered list of tokens
1013:             *   Useful for testing
1014:             */
1015:            public String toString() {
1016:                StringBuffer buf = new StringBuffer();
1017:                for (int i = 0; i < tokens.size(); i++) {
1018:                    buf.append(((Ptg) tokens.get(i)).toFormulaString(book));
1019:                    buf.append(' ');
1020:                }
1021:                return buf.toString();
1022:            }
1023:
1024:        }
1025:
1026:        /** Private helper class, used to create a tree representation of the formula*/
1027:        class Node {
1028:            private Ptg value = null;
1029:            private Node[] children = new Node[0];
1030:            private int numChild = 0;
1031:
1032:            public Node(Ptg val) {
1033:                value = val;
1034:            }
1035:
1036:            public void setChildren(Node[] child) {
1037:                children = child;
1038:                numChild = child.length;
1039:            }
1040:
1041:            public int getNumChildren() {
1042:                return numChild;
1043:            }
1044:
1045:            public Node getChild(int number) {
1046:                return children[number];
1047:            }
1048:
1049:            public Ptg getValue() {
1050:                return value;
1051:            }
1052:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.