Source Code Cross Referenced for XPath.java in  » Web-Server » Rimfaxe-Web-Server » org » apache » xerces » validators » schema » identity » 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 » Web Server » Rimfaxe Web Server » org.apache.xerces.validators.schema.identity 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * The Apache Software License, Version 1.1
0003:         *
0004:         *
0005:         * Copyright (c) 2000,2001 The Apache Software Foundation.
0006:         * All rights reserved.
0007:         *
0008:         * Redistribution and use in source and binary forms, with or without
0009:         * modification, are permitted provided that the following conditions
0010:         * are met:
0011:         *
0012:         * 1. Redistributions of source code must retain the above copyright
0013:         *    notice, this list of conditions and the following disclaimer.
0014:         *
0015:         * 2. Redistributions in binary form must reproduce the above copyright
0016:         *    notice, this list of conditions and the following disclaimer in
0017:         *    the documentation and/or other materials provided with the
0018:         *    distribution.
0019:         *
0020:         * 3. The end-user documentation included with the redistribution,
0021:         *    if any, must include the following acknowledgment:
0022:         *       "This product includes software developed by the
0023:         *        Apache Software Foundation (http://www.apache.org/)."
0024:         *    Alternately, this acknowledgment may appear in the software itself,
0025:         *    if and wherever such third-party acknowledgments normally appear.
0026:         *
0027:         * 4. The names "Xerces" and "Apache Software Foundation" must
0028:         *    not be used to endorse or promote products derived from this
0029:         *    software without prior written permission. For written
0030:         *    permission, please contact apache@apache.org.
0031:         *
0032:         * 5. Products derived from this software may not be called "Apache",
0033:         *    nor may "Apache" appear in their name, without prior written
0034:         *    permission of the Apache Software Foundation.
0035:         *
0036:         * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0037:         * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0038:         * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0039:         * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0040:         * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0041:         * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0042:         * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0043:         * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0044:         * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0045:         * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0046:         * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0047:         * SUCH DAMAGE.
0048:         * ====================================================================
0049:         *
0050:         * This software consists of voluntary contributions made by many
0051:         * individuals on behalf of the Apache Software Foundation and was
0052:         * originally based on software copyright (c) 1999, International
0053:         * Business Machines, Inc., http://www.apache.org.  For more
0054:         * information on the Apache Software Foundation, please see
0055:         * <http://www.apache.org/>.
0056:         */
0057:
0058:        package org.apache.xerces.validators.schema.identity;
0059:
0060:        import org.apache.xerces.utils.NamespacesScope;
0061:        import org.apache.xerces.utils.QName;
0062:        import org.apache.xerces.utils.StringPool;
0063:        import org.apache.xerces.utils.XMLCharacterProperties;
0064:
0065:        /**
0066:         * Bare minimum XPath parser.
0067:         *
0068:         * @author Andy Clark, IBM
0069:         * @version $Id: XPath.java,v 1.10 2001/06/08 14:23:49 sandygao Exp $
0070:         */
0071:        public class XPath {
0072:
0073:            //
0074:            // Constants
0075:            //
0076:
0077:            private static final boolean DEBUG_ALL = false;
0078:
0079:            private static final boolean DEBUG_XPATH_PARSE = DEBUG_ALL || false;
0080:
0081:            private static final boolean DEBUG_ANY = DEBUG_XPATH_PARSE;
0082:
0083:            //
0084:            // Data
0085:            //
0086:
0087:            /** Expression. */
0088:            protected String fExpression;
0089:
0090:            // Xerces 1.x framework
0091:
0092:            /** String pool. */
0093:            protected StringPool fStringPool;
0094:
0095:            //
0096:            // Constructors
0097:            //
0098:
0099:            /** Constructs an XPath object from the specified expression. */
0100:            public XPath(String xpath, StringPool stringPool,
0101:                    NamespacesScope context) throws XPathException {
0102:                XMLCharacterProperties.initCharFlags();
0103:                fExpression = xpath;
0104:                fStringPool = stringPool;
0105:                parseExpression(context);
0106:            } // <init>(String,StringPool,NamespacesScope)
0107:
0108:            //
0109:            // Public methods
0110:            //
0111:
0112:            /** Returns a representation of the first location path for this XPath. */
0113:            public LocationPath getLocationPath() {
0114:                return (LocationPath) fLocationPaths[0].clone();
0115:            } // getLocationPath(LocationPath)
0116:
0117:            //
0118:            // Object methods
0119:            //
0120:
0121:            /** Returns a string representation of this object. */
0122:            public String toString() {
0123:                StringBuffer buf = new StringBuffer();
0124:                for (int i = 0; i < fLocationPaths.length; i++) {
0125:                    if (i > 0) {
0126:                        buf.append("|");
0127:                    }
0128:                    buf.append(fLocationPaths[i].toString());
0129:                }
0130:                return buf.toString();
0131:            } // toString():String
0132:
0133:            //
0134:            // Private methods
0135:            //
0136:
0137:            /**
0138:             * This method is implemented by using the XPathExprScanner and
0139:             * examining the list of tokens that it returns.
0140:             */
0141:            private void parseExpression(final NamespacesScope context)
0142:                    throws XPathException {
0143:
0144:                // tokens
0145:                final XPath.Tokens xtokens = new XPath.Tokens(fStringPool);
0146:
0147:                // scanner
0148:                XPath.Scanner scanner = new XPath.Scanner(fStringPool) {
0149:                    protected void addToken(XPath.Tokens tokens, int token)
0150:                            throws XPathException {
0151:                        if (token == XPath.Tokens.EXPRTOKEN_ATSIGN
0152:                                || token == XPath.Tokens.EXPRTOKEN_AXISNAME_ATTRIBUTE
0153:                                || token == XPath.Tokens.EXPRTOKEN_AXISNAME_CHILD
0154:                                ||
0155:                                //token == XPath.Tokens.EXPRTOKEN_AXISNAME_SELF ||
0156:                                token == XPath.Tokens.EXPRTOKEN_DOUBLE_COLON
0157:                                ||
0158:                                //token == XPath.Tokens.EXPRTOKEN_NAMETEST_ANY ||
0159:                                token == XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME
0160:                                ||
0161:                                //token == XPath.Tokens.EXPRTOKEN_NODETYPE_NODE ||
0162:                                token == XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH
0163:                                || token == XPath.Tokens.EXPRTOKEN_PERIOD
0164:                                ||
0165:                                //added to conform to PR Spec
0166:                                token == XPath.Tokens.EXPRTOKEN_NAMETEST_ANY
0167:                                || token == XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE
0168:                                || token == XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH
0169:                                || token == XPath.Tokens.EXPRTOKEN_OPERATOR_UNION
0170:                        //
0171:                        ) {
0172:                            super .addToken(tokens, token);
0173:                            return;
0174:                        }
0175:                        StringBuffer str = new StringBuffer();
0176:                        str.append("token not supported: ");
0177:                        String tokenName = tokens.getTokenName(token);
0178:                        if (tokenName != null) {
0179:                            str.append('"');
0180:                            str.append(tokenName);
0181:                            str.append('"');
0182:                        } else {
0183:                            str.append('(');
0184:                            str.append(token);
0185:                            str.append(')');
0186:                        }
0187:                        String message = str.toString();
0188:                        throw new XPathException(message);
0189:                    }
0190:                };
0191:
0192:                int length = fExpression.length();
0193:                /***/
0194:                boolean success = scanner.scanExpr(fStringPool, xtokens,
0195:                        fExpression, 0, length);
0196:                //fTokens.dumpTokens();
0197:                java.util.Vector stepsVector = new java.util.Vector();
0198:                java.util.Vector locationPathsVector = new java.util.Vector();
0199:                int tokenCount = xtokens.getTokenCount();
0200:                boolean firstTokenOfLocationPath = true;
0201:
0202:                for (int i = 0; i < tokenCount; i++) {
0203:                    int token = xtokens.getToken(i);
0204:                    boolean isNamespace = false;
0205:
0206:                    switch (token) {
0207:                    case XPath.Tokens.EXPRTOKEN_OPERATOR_UNION: {
0208:                        if (i == 0) {
0209:                            throw new XPathException(
0210:                                    "not allowed to have '|' at the beginning of an xpath value");
0211:                        }
0212:
0213:                        int size = stepsVector.size();
0214:                        if (size == 0) {
0215:                            throw new XPathException("not allowed to have '||'");
0216:                        }
0217:                        Step[] steps = new Step[size];
0218:                        stepsVector.copyInto(steps);
0219:                        // add location path
0220:                        locationPathsVector.addElement(new LocationPath(steps));
0221:                        //reset stepsVector
0222:                        stepsVector.removeAllElements();
0223:                        firstTokenOfLocationPath = true;
0224:                        break;
0225:                    }
0226:
0227:                    case XPath.Tokens.EXPRTOKEN_AXISNAME_ATTRIBUTE: {
0228:                        // consume "::" token and drop through
0229:                        i++;
0230:                    }
0231:                    case XPath.Tokens.EXPRTOKEN_ATSIGN: {
0232:                        // consume QName token
0233:                        if (i == tokenCount - 1) {
0234:                            throw new XPathException("missing attribute name");
0235:                        }
0236:                        token = xtokens.getToken(++i);
0237:
0238:                        if (token != XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME
0239:                                && token != XPath.Tokens.EXPRTOKEN_NAMETEST_ANY
0240:                                && token != XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE) {
0241:                            throw new XPathException(
0242:                                    "expected \""
0243:                                            + xtokens
0244:                                                    .getTokenName(XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME)
0245:                                            + "\" or \""
0246:                                            + xtokens
0247:                                                    .getTokenName(XPath.Tokens.EXPRTOKEN_NAMETEST_ANY)
0248:                                            + "\" or \""
0249:                                            + xtokens
0250:                                                    .getTokenName(XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE)
0251:                                            + "\", found "
0252:                                            + xtokens.getTokenName(token));
0253:                        }
0254:                        boolean isNamespaceAtt = false;
0255:                        switch (token) {
0256:                        case XPath.Tokens.EXPRTOKEN_NAMETEST_ANY: {
0257:                            Axis axis = new Axis(Axis.ATTRIBUTE);
0258:                            NodeTest nodeTest = new NodeTest(NodeTest.WILDCARD);
0259:                            Step step = new Step(axis, nodeTest);
0260:                            stepsVector.addElement(step);
0261:                            break;
0262:                        }
0263:                        case XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE: {
0264:                            isNamespaceAtt = true;
0265:                        }
0266:                        case XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME: {
0267:
0268:                            token = xtokens.getToken(++i);
0269:                            int prefix = xtokens.getTokenString(token);
0270:                            int uri = StringPool.EMPTY_STRING;
0271:                            if (context != null && prefix != -1) {
0272:                                uri = context.getNamespaceForPrefix(prefix);
0273:                            }
0274:                            if (prefix != -1 && context != null
0275:                                    && uri == StringPool.EMPTY_STRING) {
0276:                                throw new XPathException("prefix "
0277:                                        + fStringPool.toString(prefix)
0278:                                        + " not bound to namespace URI");
0279:                            }
0280:
0281:                            if (isNamespaceAtt) {
0282:                                // build step
0283:                                Axis axis = new Axis(Axis.ATTRIBUTE);
0284:                                NodeTest nodeTest = new NodeTest(fStringPool,
0285:                                        prefix, uri);
0286:                                Step step = new Step(axis, nodeTest);
0287:                                stepsVector.addElement(step);
0288:                                break;
0289:                            }
0290:
0291:                            token = xtokens.getToken(++i);
0292:                            int localpart = xtokens.getTokenString(token);
0293:                            int rawname = prefix != -1 ? fStringPool
0294:                                    .addSymbol(fStringPool.toString(prefix)
0295:                                            + ':'
0296:                                            + fStringPool.toString(localpart))
0297:                                    : localpart;
0298:
0299:                            // build step
0300:                            Axis axis = new Axis(Axis.ATTRIBUTE);
0301:                            NodeTest nodeTest = new NodeTest(fStringPool,
0302:                                    new QName(prefix, localpart, rawname, uri));
0303:                            Step step = new Step(axis, nodeTest);
0304:                            stepsVector.addElement(step);
0305:                            break;
0306:                        }
0307:                        }
0308:                        firstTokenOfLocationPath = false;
0309:                        break;
0310:                    }
0311:                        /***
0312:                        case XPath.Tokens.EXPRTOKEN_AXISNAME_SELF: {
0313:                            break;
0314:                        }
0315:                        /***/
0316:                    case XPath.Tokens.EXPRTOKEN_DOUBLE_COLON: {
0317:                        // should never have a bare double colon
0318:                        throw new XPathException(
0319:                                "Not allowed to have double colon here");
0320:                    }
0321:                        /***
0322:                        case XPath.Tokens.EXPRTOKEN_NAMETEST_ANY: {
0323:                            break;
0324:                        }
0325:                        /***/
0326:                    case XPath.Tokens.EXPRTOKEN_AXISNAME_CHILD: {
0327:
0328:                        // consume "::" token and drop through
0329:                        i++;
0330:                        if (i == tokenCount - 1) {
0331:                            throw new XPathException(
0332:                                    "expected step following '"
0333:                                            + xtokens
0334:                                                    .getTokenName(XPath.Tokens.EXPRTOKEN_AXISNAME_CHILD)
0335:                                            + "::'");
0336:                        }
0337:                        firstTokenOfLocationPath = false;
0338:                        break;
0339:                    }
0340:                    case XPath.Tokens.EXPRTOKEN_NAMETEST_ANY: {
0341:                        Axis axis = new Axis(Axis.CHILD);
0342:                        NodeTest nodeTest = new NodeTest(NodeTest.WILDCARD);
0343:                        Step step = new Step(axis, nodeTest);
0344:                        stepsVector.addElement(step);
0345:                        firstTokenOfLocationPath = false;
0346:                        break;
0347:                    }
0348:
0349:                    case XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE: {
0350:                        isNamespace = true;
0351:                    }
0352:                    case XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME: {
0353:                        // consume QName token
0354:                        token = xtokens.getToken(++i);
0355:                        int prefix = xtokens.getTokenString(token);
0356:                        int uri = StringPool.EMPTY_STRING;
0357:                        if (context != null && prefix != -1) {
0358:                            uri = context.getNamespaceForPrefix(prefix);
0359:                        }
0360:                        if (prefix != -1 && context != null
0361:                                && uri == StringPool.EMPTY_STRING) {
0362:                            throw new XPathException("prefix "
0363:                                    + fStringPool.toString(prefix)
0364:                                    + " not bound to namespace URI");
0365:                        }
0366:
0367:                        if (isNamespace) {
0368:                            // build step
0369:                            Axis axis = new Axis(Axis.CHILD);
0370:                            NodeTest nodeTest = new NodeTest(fStringPool,
0371:                                    prefix, uri);
0372:                            Step step = new Step(axis, nodeTest);
0373:                            stepsVector.addElement(step);
0374:                            break;
0375:                        }
0376:
0377:                        token = xtokens.getToken(++i);
0378:                        int localpart = xtokens.getTokenString(token);
0379:                        int rawname = prefix != -1 ? fStringPool
0380:                                .addSymbol(fStringPool.toString(prefix) + ':'
0381:                                        + fStringPool.toString(localpart))
0382:                                : localpart;
0383:
0384:                        // build step
0385:                        Axis axis = new Axis(Axis.CHILD);
0386:                        NodeTest nodeTest = new NodeTest(fStringPool,
0387:                                new QName(prefix, localpart, rawname, uri));
0388:                        Step step = new Step(axis, nodeTest);
0389:                        stepsVector.addElement(step);
0390:                        firstTokenOfLocationPath = false;
0391:                        break;
0392:                    }
0393:                        /***
0394:                        case XPath.Tokens.EXPRTOKEN_NODETYPE_NODE: {
0395:                            break;
0396:                        }
0397:                        /***/
0398:
0399:                    case XPath.Tokens.EXPRTOKEN_PERIOD: {
0400:                        // build step
0401:                        Axis axis = new Axis(Axis.SELF);
0402:                        NodeTest nodeTest = new NodeTest(NodeTest.NODE);
0403:                        Step step = new Step(axis, nodeTest);
0404:                        stepsVector.addElement(step);
0405:
0406:                        if (firstTokenOfLocationPath && i + 1 < tokenCount) {
0407:                            token = xtokens.getToken(i + 1);
0408:                            if (token == XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH) {
0409:                                i++;
0410:                                if (i == tokenCount - 1) {
0411:                                    throw new XPathException(
0412:                                            "expected step following '//'");
0413:                                }
0414:                                if (i + 1 < tokenCount) {
0415:                                    token = xtokens.getToken(i + 1);
0416:                                    if (token == XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH)
0417:                                        throw new XPathException(
0418:                                                "'/' not allowed after '//'");
0419:                                }
0420:                                // build step
0421:                                axis = new Axis(Axis.DESCENDANT);
0422:                                nodeTest = new NodeTest(NodeTest.NODE);
0423:                                step = new Step(axis, nodeTest);
0424:                                stepsVector.addElement(step);
0425:                            }
0426:                        }
0427:                        firstTokenOfLocationPath = false;
0428:                        break;
0429:                    }
0430:
0431:                    case XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH: {
0432:                        throw new XPathException(
0433:                                "'//' only allowed after '.' at the beginning of an xpath");
0434:                    }
0435:                    case XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH: {
0436:                        if (i == 0) {
0437:                            throw new XPathException(
0438:                                    "not allowed to have '/' at the beginning of an xpath value");
0439:                        }
0440:                        // keep on truckin'
0441:                        if (firstTokenOfLocationPath) {
0442:                            throw new XPathException(
0443:                                    "not allowed to select the root");
0444:                        }
0445:                        if (i == tokenCount - 1) {
0446:                            throw new XPathException(
0447:                                    "expected step following '/'");
0448:                        }
0449:                        firstTokenOfLocationPath = false;
0450:                        break;
0451:                    }
0452:                    default:
0453:                        firstTokenOfLocationPath = false;
0454:                    }
0455:                }
0456:
0457:                int size = stepsVector.size();
0458:                if (size == 0) {
0459:                    if (locationPathsVector.size() == 0)
0460:                        throw new XPathException("empty xpath expression");
0461:                    else
0462:                        throw new XPathException("xpath cannot end with '|'");
0463:                }
0464:                Step[] steps = new Step[size];
0465:                stepsVector.copyInto(steps);
0466:                locationPathsVector.addElement(new LocationPath(steps));
0467:
0468:                // save location path
0469:                fLocationPaths = new LocationPath[locationPathsVector.size()];
0470:                locationPathsVector.copyInto(fLocationPaths);
0471:
0472:                if (DEBUG_XPATH_PARSE) {
0473:                    System.out.println(">>> " + fLocationPaths);
0474:                }
0475:
0476:            } // parseExpression(SymbolTable,NamespaceContext)
0477:
0478:            //
0479:            // Classes
0480:            //
0481:
0482:            // location path information
0483:
0484:            /**
0485:             * A location path representation for an XPath expression.
0486:             *
0487:             * @author Andy Clark, IBM
0488:             */
0489:            public static class LocationPath implements  Cloneable {
0490:
0491:                //
0492:                // Data
0493:                //
0494:
0495:                /** List of steps. */
0496:                public Step[] steps;
0497:
0498:                //
0499:                // Constructors
0500:                //
0501:
0502:                /** Creates a location path from a series of steps. */
0503:                public LocationPath(Step[] steps) {
0504:                    this .steps = steps;
0505:                } // <init>(Step[])
0506:
0507:                /** Copy constructor. */
0508:                protected LocationPath(LocationPath path) {
0509:                    steps = new Step[path.steps.length];
0510:                    for (int i = 0; i < steps.length; i++) {
0511:                        steps[i] = (Step) path.steps[i].clone();
0512:                    }
0513:                } // <init>(LocationPath)
0514:
0515:                //
0516:                // Object methods
0517:                //
0518:
0519:                /** Returns a string representation of this object. */
0520:                public String toString() {
0521:                    StringBuffer str = new StringBuffer();
0522:                    for (int i = 0; i < steps.length; i++) {
0523:                        if (i > 0
0524:                                && (steps[i - 1].axis.type != Axis.DESCENDANT && steps[i].axis.type != Axis.DESCENDANT)) {
0525:                            str.append('/');
0526:                        }
0527:                        str.append(steps[i].toString());
0528:                    }
0529:                    // DEBUG: This code is just for debugging and should *not*
0530:                    //        be left in because it will mess up hashcodes of
0531:                    //        serialized versions of this object. -Ac
0532:                    if (false) {
0533:                        str.append('[');
0534:                        String s = super .toString();
0535:                        str.append(s.substring(s.indexOf('@')));
0536:                        str.append(']');
0537:                    }
0538:                    return str.toString();
0539:                } // toString():String
0540:
0541:                /** Returns a clone of this object. */
0542:                public Object clone() {
0543:                    return new LocationPath(this );
0544:                } // clone():Object
0545:
0546:            } // class locationPath
0547:
0548:            /**
0549:             * A location path step comprised of an axis and node test.
0550:             *
0551:             * @author Andy Clark, IBM
0552:             */
0553:            public static class Step implements  Cloneable {
0554:
0555:                //
0556:                // Data
0557:                //
0558:
0559:                /** Axis. */
0560:                public Axis axis;
0561:
0562:                /** Node test. */
0563:                public NodeTest nodeTest;
0564:
0565:                //
0566:                // Constructors
0567:                //
0568:
0569:                /** Constructs a step from an axis and node test. */
0570:                public Step(Axis axis, NodeTest nodeTest) {
0571:                    this .axis = axis;
0572:                    this .nodeTest = nodeTest;
0573:                } // <init>(Axis,NodeTest)
0574:
0575:                /** Copy constructor. */
0576:                protected Step(Step step) {
0577:                    axis = (Axis) step.axis.clone();
0578:                    nodeTest = (NodeTest) step.nodeTest.clone();
0579:                } // <init>(Step)
0580:
0581:                //
0582:                // Object methods
0583:                //
0584:
0585:                /** Returns a string representation of this object. */
0586:                public String toString() {
0587:                    /***
0588:                    return axis.toString() + "::" + nodeTest.toString();
0589:                    /***/
0590:                    if (axis.type == Axis.SELF) {
0591:                        return ".";
0592:                    }
0593:                    if (axis.type == Axis.ATTRIBUTE) {
0594:                        return "@" + nodeTest.toString();
0595:                    }
0596:                    if (axis.type == Axis.CHILD) {
0597:                        return nodeTest.toString();
0598:                    }
0599:                    if (axis.type == Axis.DESCENDANT) {
0600:                        return "//";
0601:                    }
0602:                    return "??? (" + axis.type + ')';
0603:                    /***/
0604:                } // toString():String
0605:
0606:                /** Returns a clone of this object. */
0607:                public Object clone() {
0608:                    return new Step(this );
0609:                } // clone():Object
0610:
0611:            } // class Step
0612:
0613:            /**
0614:             * Axis.
0615:             *
0616:             * @author Andy Clark, IBM
0617:             */
0618:            public static class Axis implements  Cloneable {
0619:
0620:                //
0621:                // Constants
0622:                //
0623:
0624:                /** Type: child. */
0625:                public static final short CHILD = 1;
0626:
0627:                /** Type: attribute. */
0628:                public static final short ATTRIBUTE = 2;
0629:
0630:                /** Type: self. */
0631:                public static final short SELF = 3;
0632:
0633:                /** Type: descendant. */
0634:                public static final short DESCENDANT = 4;
0635:                //
0636:                // Data
0637:                //
0638:
0639:                /** Axis type. */
0640:                public short type;
0641:
0642:                //
0643:                // Constructors
0644:                //
0645:
0646:                /** Constructs an axis with the specified type. */
0647:                public Axis(short type) {
0648:                    this .type = type;
0649:                } // <init>(short)
0650:
0651:                /** Copy constructor. */
0652:                protected Axis(Axis axis) {
0653:                    type = axis.type;
0654:                } // <init>(Axis)
0655:
0656:                //
0657:                // Object methods
0658:                //
0659:
0660:                /** Returns a string representation of this object. */
0661:                public String toString() {
0662:                    switch (type) {
0663:                    case CHILD:
0664:                        return "child";
0665:                    case ATTRIBUTE:
0666:                        return "attribute";
0667:                    case SELF:
0668:                        return "self";
0669:                    case DESCENDANT:
0670:                        return "descendant";
0671:                    }
0672:                    return "???";
0673:                } // toString():String
0674:
0675:                /** Returns a clone of this object. */
0676:                public Object clone() {
0677:                    return new Axis(this );
0678:                } // clone():Object
0679:
0680:            } // class Axis
0681:
0682:            /**
0683:             * Node test.
0684:             *
0685:             * @author Andy Clark, IBM
0686:             */
0687:            public static class NodeTest implements  Cloneable {
0688:
0689:                //
0690:                // Constants
0691:                //
0692:
0693:                /** Type: qualified name. */
0694:                public static final short QNAME = 1;
0695:
0696:                /** Type: wildcard. */
0697:                public static final short WILDCARD = 2;
0698:
0699:                /** Type: node. */
0700:                public static final short NODE = 3;
0701:
0702:                /** Type: namespace */
0703:                public static final short NAMESPACE = 4;
0704:
0705:                //
0706:                // Data
0707:                //
0708:
0709:                /** String pool. */
0710:                protected StringPool fStringPool;
0711:
0712:                /** Node test type. */
0713:                public short type;
0714:
0715:                /** Node qualified name. */
0716:                public final QName name = new QName();
0717:
0718:                //
0719:                // Constructors
0720:                //
0721:
0722:                /** Constructs a node test of type WILDCARD or NODE. */
0723:                public NodeTest(short type) {
0724:                    this .type = type;
0725:                } // <init>(int)
0726:
0727:                /** Constructs a node test of type QName. */
0728:                public NodeTest(StringPool stringPool, QName name) {
0729:                    fStringPool = stringPool;
0730:                    this .type = QNAME;
0731:                    this .name.setValues(name);
0732:                } // <init>(QName)
0733:
0734:                /** Constructs a node test of type Namespace. */
0735:                public NodeTest(StringPool stringPool, int prefix, int uri) {
0736:                    fStringPool = stringPool;
0737:                    this .type = NAMESPACE;
0738:                    this .name.setValues(prefix, -1, -1, uri);
0739:                }
0740:
0741:                /** Copy constructor. */
0742:                public NodeTest(NodeTest nodeTest) {
0743:                    fStringPool = nodeTest.fStringPool;
0744:                    type = nodeTest.type;
0745:                    name.setValues(nodeTest.name);
0746:                } // <init>(NodeTest)
0747:
0748:                //
0749:                // Object methods
0750:                //
0751:
0752:                /** Returns a string representation of this object. */
0753:                public String toString() {
0754:
0755:                    switch (type) {
0756:                    case QNAME: {
0757:                        if (name.prefix != -1) {
0758:                            if (name.uri == StringPool.EMPTY_STRING) {
0759:                                return fStringPool.toString(name.prefix) + ':'
0760:                                        + fStringPool.toString(name.localpart);
0761:                            }
0762:                            return "{" + fStringPool.toString(name.uri) + '}'
0763:                                    + fStringPool.toString(name.prefix) + ':'
0764:                                    + fStringPool.toString(name.localpart);
0765:                        }
0766:                        return fStringPool.toString(name.localpart);
0767:                    }
0768:                    case NAMESPACE: {
0769:                        if (name.prefix != -1) {
0770:                            if (name.uri == StringPool.EMPTY_STRING) {
0771:                                return fStringPool.toString(name.prefix) + ":*";
0772:                            }
0773:                            return "{" + fStringPool.toString(name.uri) + '}'
0774:                                    + fStringPool.toString(name.prefix) + ":*";
0775:                        }
0776:                        return "???:*";
0777:                    }
0778:                    case WILDCARD: {
0779:                        return "*";
0780:                    }
0781:                    case NODE: {
0782:                        return "node()";
0783:                    }
0784:                    }
0785:                    return "???";
0786:
0787:                } // toString():String
0788:
0789:                /** Returns a clone of this object. */
0790:                public Object clone() {
0791:                    return new NodeTest(this );
0792:                } // clone():Object
0793:
0794:            } // class NodeTest
0795:
0796:            // xpath implementation
0797:
0798:            // NOTE: The XPath implementation classes are kept internal because
0799:            //       this implementation is just a temporary hack until a better
0800:            //       and/or more appropriate implementation can be written.
0801:            //       keeping the code in separate source files would "muddy" the
0802:            //       CVS directory when it's not needed. -Ac
0803:
0804:            /**
0805:             * @author Glenn Marcy, IBM
0806:             * @author Andy Clark, IBM
0807:             *
0808:             * @version $Id: XPath.java,v 1.10 2001/06/08 14:23:49 sandygao Exp $
0809:             */
0810:            private static final class Tokens {
0811:
0812:                static final boolean DUMP_TOKENS = false;
0813:
0814:                /**
0815:                 * [28] ExprToken ::= '(' | ')' | '[' | ']' | '.' | '..' | '@' | ',' | '::'
0816:                 *                  | NameTest | NodeType | Operator | FunctionName
0817:                 *                  | AxisName | Literal | Number | VariableReference
0818:                 */
0819:                public static final int EXPRTOKEN_OPEN_PAREN = 0,
0820:                        EXPRTOKEN_CLOSE_PAREN = 1,
0821:                        EXPRTOKEN_OPEN_BRACKET = 2,
0822:                        EXPRTOKEN_CLOSE_BRACKET = 3,
0823:                        EXPRTOKEN_PERIOD = 4,
0824:                        EXPRTOKEN_DOUBLE_PERIOD = 5,
0825:                        EXPRTOKEN_ATSIGN = 6,
0826:                        EXPRTOKEN_COMMA = 7,
0827:                        EXPRTOKEN_DOUBLE_COLON = 8,
0828:                        //
0829:                        // [37] NameTest ::= '*' | NCName ':' '*' | QName
0830:                        //
0831:                        // followed by symbol handle of NCName or QName
0832:                        //
0833:                        EXPRTOKEN_NAMETEST_ANY = 9,
0834:                        EXPRTOKEN_NAMETEST_NAMESPACE = 10,
0835:                        EXPRTOKEN_NAMETEST_QNAME = 11,
0836:                        //
0837:                        // [38] NodeType ::= 'comment' | 'text' | 'processing-instruction' | 'node'
0838:                        //
0839:                        EXPRTOKEN_NODETYPE_COMMENT = 12,
0840:                        EXPRTOKEN_NODETYPE_TEXT = 13,
0841:                        EXPRTOKEN_NODETYPE_PI = 14,
0842:                        EXPRTOKEN_NODETYPE_NODE = 15,
0843:                        //
0844:                        // [32] Operator ::= OperatorName
0845:                        //                 | MultiplyOperator
0846:                        //                 | '/' | '//' | '|' | '+' | '-' | '=' | '!=' | '<' | '<=' | '>' | '>='
0847:                        // [33] OperatorName ::= 'and' | 'or' | 'mod' | 'div'
0848:                        // [34] MultiplyOperator ::= '*'
0849:                        //
0850:                        EXPRTOKEN_OPERATOR_AND = 16,
0851:                        EXPRTOKEN_OPERATOR_OR = 17,
0852:                        EXPRTOKEN_OPERATOR_MOD = 18,
0853:                        EXPRTOKEN_OPERATOR_DIV = 19,
0854:                        EXPRTOKEN_OPERATOR_MULT = 20,
0855:                        EXPRTOKEN_OPERATOR_SLASH = 21,
0856:                        EXPRTOKEN_OPERATOR_DOUBLE_SLASH = 22,
0857:                        EXPRTOKEN_OPERATOR_UNION = 23,
0858:                        EXPRTOKEN_OPERATOR_PLUS = 24,
0859:                        EXPRTOKEN_OPERATOR_MINUS = 25,
0860:                        EXPRTOKEN_OPERATOR_EQUAL = 26,
0861:                        EXPRTOKEN_OPERATOR_NOT_EQUAL = 27,
0862:                        EXPRTOKEN_OPERATOR_LESS = 28,
0863:                        EXPRTOKEN_OPERATOR_LESS_EQUAL = 29,
0864:                        EXPRTOKEN_OPERATOR_GREATER = 30,
0865:                        EXPRTOKEN_OPERATOR_GREATER_EQUAL = 31,
0866:
0867:                        //EXPRTOKEN_FIRST_OPERATOR                = EXPRTOKEN_OPERATOR_AND,
0868:                        //EXPRTOKEN_LAST_OPERATOR                 = EXPRTOKEN_OPERATOR_GREATER_EQUAL,
0869:
0870:                        //
0871:                        // [35] FunctionName ::= QName - NodeType
0872:                        //
0873:                        // followed by symbol handle
0874:                        //
0875:                        EXPRTOKEN_FUNCTION_NAME = 32,
0876:                        //
0877:                        // [6] AxisName ::= 'ancestor' | 'ancestor-or-self'
0878:                        //                | 'attribute'
0879:                        //                | 'child'
0880:                        //                | 'descendant' | 'descendant-or-self'
0881:                        //                | 'following' | 'following-sibling'
0882:                        //                | 'namespace'
0883:                        //                | 'parent'
0884:                        //                | 'preceding' | 'preceding-sibling'
0885:                        //                | 'self'
0886:                        //
0887:                        EXPRTOKEN_AXISNAME_ANCESTOR = 33,
0888:                        EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF = 34,
0889:                        EXPRTOKEN_AXISNAME_ATTRIBUTE = 35,
0890:                        EXPRTOKEN_AXISNAME_CHILD = 36,
0891:                        EXPRTOKEN_AXISNAME_DESCENDANT = 37,
0892:                        EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF = 38,
0893:                        EXPRTOKEN_AXISNAME_FOLLOWING = 39,
0894:                        EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING = 40,
0895:                        EXPRTOKEN_AXISNAME_NAMESPACE = 41,
0896:                        EXPRTOKEN_AXISNAME_PARENT = 42,
0897:                        EXPRTOKEN_AXISNAME_PRECEDING = 43,
0898:                        EXPRTOKEN_AXISNAME_PRECEDING_SIBLING = 44,
0899:                        EXPRTOKEN_AXISNAME_SELF = 45,
0900:                        //
0901:                        // [29] Literal ::= '"' [^"]* '"' | "'" [^']* "'"
0902:                        //
0903:                        // followed by symbol handle for literal
0904:                        //
0905:                        EXPRTOKEN_LITERAL = 46,
0906:                        //
0907:                        // [30] Number ::= Digits ('.' Digits?)? | '.' Digits
0908:                        // [31] Digits ::= [0-9]+
0909:                        //
0910:                        // followed by number handle
0911:                        //
0912:                        EXPRTOKEN_NUMBER = 47,
0913:                        //
0914:                        // [36] VariableReference ::= '$' QName
0915:                        //
0916:                        // followed by symbol handle for QName
0917:                        //
0918:                        EXPRTOKEN_VARIABLE_REFERENCE = 48;
0919:
0920:                public static final String[] fgTokenNames = {
0921:                        "EXPRTOKEN_OPEN_PAREN", "EXPRTOKEN_CLOSE_PAREN",
0922:                        "EXPRTOKEN_OPEN_BRACKET", "EXPRTOKEN_CLOSE_BRACKET",
0923:                        "EXPRTOKEN_PERIOD", "EXPRTOKEN_DOUBLE_PERIOD",
0924:                        "EXPRTOKEN_ATSIGN", "EXPRTOKEN_COMMA",
0925:                        "EXPRTOKEN_DOUBLE_COLON", "EXPRTOKEN_NAMETEST_ANY",
0926:                        "EXPRTOKEN_NAMETEST_NAMESPACE",
0927:                        "EXPRTOKEN_NAMETEST_QNAME",
0928:                        "EXPRTOKEN_NODETYPE_COMMENT",
0929:                        "EXPRTOKEN_NODETYPE_TEXT", "EXPRTOKEN_NODETYPE_PI",
0930:                        "EXPRTOKEN_NODETYPE_NODE", "EXPRTOKEN_OPERATOR_AND",
0931:                        "EXPRTOKEN_OPERATOR_OR", "EXPRTOKEN_OPERATOR_MOD",
0932:                        "EXPRTOKEN_OPERATOR_DIV", "EXPRTOKEN_OPERATOR_MULT",
0933:                        "EXPRTOKEN_OPERATOR_SLASH",
0934:                        "EXPRTOKEN_OPERATOR_DOUBLE_SLASH",
0935:                        "EXPRTOKEN_OPERATOR_UNION", "EXPRTOKEN_OPERATOR_PLUS",
0936:                        "EXPRTOKEN_OPERATOR_MINUS", "EXPRTOKEN_OPERATOR_EQUAL",
0937:                        "EXPRTOKEN_OPERATOR_NOT_EQUAL",
0938:                        "EXPRTOKEN_OPERATOR_LESS",
0939:                        "EXPRTOKEN_OPERATOR_LESS_EQUAL",
0940:                        "EXPRTOKEN_OPERATOR_GREATER",
0941:                        "EXPRTOKEN_OPERATOR_GREATER_EQUAL",
0942:                        "EXPRTOKEN_FUNCTION_NAME",
0943:                        "EXPRTOKEN_AXISNAME_ANCESTOR",
0944:                        "EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF",
0945:                        "EXPRTOKEN_AXISNAME_ATTRIBUTE",
0946:                        "EXPRTOKEN_AXISNAME_CHILD",
0947:                        "EXPRTOKEN_AXISNAME_DESCENDANT",
0948:                        "EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF",
0949:                        "EXPRTOKEN_AXISNAME_FOLLOWING",
0950:                        "EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING",
0951:                        "EXPRTOKEN_AXISNAME_NAMESPACE",
0952:                        "EXPRTOKEN_AXISNAME_PARENT",
0953:                        "EXPRTOKEN_AXISNAME_PRECEDING",
0954:                        "EXPRTOKEN_AXISNAME_PRECEDING_SIBLING",
0955:                        "EXPRTOKEN_AXISNAME_SELF", "EXPRTOKEN_LITERAL",
0956:                        "EXPRTOKEN_NUMBER", "EXPRTOKEN_VARIABLE_REFERENCE" };
0957:
0958:                /**
0959:                 *
0960:                 */
0961:                private static final int INITIAL_TOKEN_COUNT = 1 << 8;
0962:                private int[] fTokens = new int[INITIAL_TOKEN_COUNT];
0963:                private int fTokenCount = 0; // for writing
0964:
0965:                private StringPool fStringPool;
0966:
0967:                // REVISIT: Code something better here. -Ac
0968:                //private java.util.Hashtable fSymbolMapping = new java.util.Hashtable();
0969:
0970:                // REVISIT: Code something better here. -Ac
0971:                //private java.util.Hashtable fTokenNames = new java.util.Hashtable();
0972:
0973:                //
0974:                // Constructors
0975:                //
0976:
0977:                /***
0978:                public XPath.Tokens(SymbolTable symbolTable) {
0979:                    fSymbolTable = symbolTable;
0980:                }
0981:                /***/
0982:                public Tokens(StringPool stringPool) {
0983:                    fStringPool = stringPool;
0984:                    /***
0985:                    final String[] symbols = {
0986:                        "ancestor",     "ancestor-or-self",     "attribute",
0987:                        "child",        "descendant",           "descendant-or-self",
0988:                        "following",    "following-sibling",    "namespace",
0989:                        "parent",       "preceding",            "preceding-sibling",
0990:                        "self",
0991:                    };
0992:                    for (int i = 0; i < symbols.length; i++) {
0993:                        fSymbolMapping.put(fSymbolTable.addSymbol(symbols[i]), new Integer(i));
0994:                    }
0995:                    /*
0996:                    fTokenNames.put(new Integer(EXPRTOKEN_OPEN_PAREN), "EXPRTOKEN_OPEN_PAREN");
0997:                    fTokenNames.put(new Integer(EXPRTOKEN_CLOSE_PAREN), "EXPRTOKEN_CLOSE_PAREN");
0998:                    fTokenNames.put(new Integer(EXPRTOKEN_OPEN_BRACKET), "EXPRTOKEN_OPEN_BRACKET");
0999:                    fTokenNames.put(new Integer(EXPRTOKEN_CLOSE_BRACKET), "EXPRTOKEN_CLOSE_BRACKET");
1000:                    fTokenNames.put(new Integer(EXPRTOKEN_PERIOD), "EXPRTOKEN_PERIOD");
1001:                    fTokenNames.put(new Integer(EXPRTOKEN_DOUBLE_PERIOD), "EXPRTOKEN_DOUBLE_PERIOD");
1002:                    fTokenNames.put(new Integer(EXPRTOKEN_ATSIGN), "EXPRTOKEN_ATSIGN");
1003:                    fTokenNames.put(new Integer(EXPRTOKEN_COMMA), "EXPRTOKEN_COMMA");
1004:                    fTokenNames.put(new Integer(EXPRTOKEN_DOUBLE_COLON), "EXPRTOKEN_DOUBLE_COLON");
1005:                    fTokenNames.put(new Integer(EXPRTOKEN_NAMETEST_ANY), "EXPRTOKEN_NAMETEST_ANY");
1006:                    fTokenNames.put(new Integer(EXPRTOKEN_NAMETEST_NAMESPACE), "EXPRTOKEN_NAMETEST_NAMESPACE");
1007:                    fTokenNames.put(new Integer(EXPRTOKEN_NAMETEST_QNAME), "EXPRTOKEN_NAMETEST_QNAME");
1008:                    fTokenNames.put(new Integer(EXPRTOKEN_NODETYPE_COMMENT), "EXPRTOKEN_NODETYPE_COMMENT");
1009:                    fTokenNames.put(new Integer(EXPRTOKEN_NODETYPE_TEXT), "EXPRTOKEN_NODETYPE_TEXT");
1010:                    fTokenNames.put(new Integer(EXPRTOKEN_NODETYPE_PI), "EXPRTOKEN_NODETYPE_PI");
1011:                    fTokenNames.put(new Integer(EXPRTOKEN_NODETYPE_NODE), "EXPRTOKEN_NODETYPE_NODE");
1012:                    fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_AND), "EXPRTOKEN_OPERATOR_AND");
1013:                    fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_OR), "EXPRTOKEN_OPERATOR_OR");
1014:                    fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_MOD), "EXPRTOKEN_OPERATOR_MOD");
1015:                    fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_DIV), "EXPRTOKEN_OPERATOR_DIV");
1016:                    fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_MULT), "EXPRTOKEN_OPERATOR_MULT");
1017:                    fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_SLASH), "EXPRTOKEN_OPERATOR_SLASH");
1018:                    fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_DOUBLE_SLASH), "EXPRTOKEN_OPERATOR_DOUBLE_SLASH");
1019:                    fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_UNION), "EXPRTOKEN_OPERATOR_UNION");
1020:                    fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_PLUS), "EXPRTOKEN_OPERATOR_PLUS");
1021:                    fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_MINUS), "EXPRTOKEN_OPERATOR_MINUS");
1022:                    fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_EQUAL), "EXPRTOKEN_OPERATOR_EQUAL");
1023:                    fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_NOT_EQUAL), "EXPRTOKEN_OPERATOR_NOT_EQUAL");
1024:                    fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_LESS), "EXPRTOKEN_OPERATOR_LESS");
1025:                    fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_LESS_EQUAL), "EXPRTOKEN_OPERATOR_LESS_EQUAL");
1026:                    fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_GREATER), "EXPRTOKEN_OPERATOR_GREATER");
1027:                    fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_GREATER_EQUAL), "EXPRTOKEN_OPERATOR_GREATER_EQUAL");
1028:                    fTokenNames.put(new Integer(EXPRTOKEN_FUNCTION_NAME), "EXPRTOKEN_FUNCTION_NAME");
1029:                    fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_ANCESTOR), "EXPRTOKEN_AXISNAME_ANCESTOR");
1030:                    fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF), "EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF");
1031:                    fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_ATTRIBUTE), "EXPRTOKEN_AXISNAME_ATTRIBUTE");
1032:                    fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_CHILD), "EXPRTOKEN_AXISNAME_CHILD");
1033:                    fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_DESCENDANT), "EXPRTOKEN_AXISNAME_DESCENDANT");
1034:                    fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF), "EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF");
1035:                    fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_FOLLOWING), "EXPRTOKEN_AXISNAME_FOLLOWING");
1036:                    fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING), "EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING");
1037:                    fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_NAMESPACE), "EXPRTOKEN_AXISNAME_NAMESPACE");
1038:                    fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_PARENT), "EXPRTOKEN_AXISNAME_PARENT");
1039:                    fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_PRECEDING), "EXPRTOKEN_AXISNAME_PRECEDING");
1040:                    fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_PRECEDING_SIBLING), "EXPRTOKEN_AXISNAME_PRECEDING_SIBLING");
1041:                    fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_SELF), "EXPRTOKEN_AXISNAME_SELF");
1042:                    fTokenNames.put(new Integer(EXPRTOKEN_LITERAL), "EXPRTOKEN_LITERAL");
1043:                    fTokenNames.put(new Integer(EXPRTOKEN_NUMBER), "EXPRTOKEN_NUMBER");
1044:                    fTokenNames.put(new Integer(EXPRTOKEN_VARIABLE_REFERENCE), "EXPRTOKEN_VARIABLE_REFERENCE");
1045:                     */
1046:                }
1047:
1048:                /***/
1049:
1050:                //
1051:                // Public methods
1052:                //
1053:                /***
1054:                public int addSymbol(byte[] data, int offset, int length, EncodingMap encoding) {
1055:                    //return fSymbolTable.addSymbol(data, offset, length, encoding);
1056:                    return fSymbolTable.addSymbol(new String(data, offset, length));
1057:                }
1058:                /***/
1059:
1060:                public String getTokenName(int token) {
1061:                    if (token < 0 || token >= fgTokenNames.length)
1062:                        return null;
1063:                    return fgTokenNames[token];
1064:                }
1065:
1066:                public int getTokenString(int token) {
1067:                    return token;
1068:                }
1069:
1070:                public void addToken(int token) {
1071:                    try {
1072:                        fTokens[fTokenCount] = token;
1073:                    } catch (ArrayIndexOutOfBoundsException ex) {
1074:                        int[] oldList = fTokens;
1075:                        fTokens = new int[fTokenCount << 1];
1076:                        System.arraycopy(oldList, 0, fTokens, 0, fTokenCount);
1077:                        fTokens[fTokenCount] = token;
1078:                    }
1079:                    fTokenCount++;
1080:                }
1081:
1082:                public int getTokenCount() {
1083:                    return fTokenCount;
1084:                }
1085:
1086:                public int getToken(int tokenIndex) {
1087:                    return fTokens[tokenIndex];
1088:                }
1089:
1090:                public void dumpTokens() {
1091:                    //if (DUMP_TOKENS) {
1092:                    for (int i = 0; i < fTokenCount; i++) {
1093:                        switch (fTokens[i]) {
1094:                        case EXPRTOKEN_OPEN_PAREN:
1095:                            System.out.print("<OPEN_PAREN/>");
1096:                            break;
1097:                        case EXPRTOKEN_CLOSE_PAREN:
1098:                            System.out.print("<CLOSE_PAREN/>");
1099:                            break;
1100:                        case EXPRTOKEN_OPEN_BRACKET:
1101:                            System.out.print("<OPEN_BRACKET/>");
1102:                            break;
1103:                        case EXPRTOKEN_CLOSE_BRACKET:
1104:                            System.out.print("<CLOSE_BRACKET/>");
1105:                            break;
1106:                        case EXPRTOKEN_PERIOD:
1107:                            System.out.print("<PERIOD/>");
1108:                            break;
1109:                        case EXPRTOKEN_DOUBLE_PERIOD:
1110:                            System.out.print("<DOUBLE_PERIOD/>");
1111:                            break;
1112:                        case EXPRTOKEN_ATSIGN:
1113:                            System.out.print("<ATSIGN/>");
1114:                            break;
1115:                        case EXPRTOKEN_COMMA:
1116:                            System.out.print("<COMMA/>");
1117:                            break;
1118:                        case EXPRTOKEN_DOUBLE_COLON:
1119:                            System.out.print("<DOUBLE_COLON/>");
1120:                            break;
1121:                        case EXPRTOKEN_NAMETEST_ANY:
1122:                            System.out.print("<NAMETEST_ANY/>");
1123:                            break;
1124:                        case EXPRTOKEN_NAMETEST_NAMESPACE:
1125:                            System.out.print("<NAMETEST_NAMESPACE");
1126:                            /***
1127:                            System.out.print(" prefix=\"" + fSymbolTable.toString(fTokens[++i]) + "\"");
1128:                            /***/
1129:                            System.out.print(" prefix=\""
1130:                                    + getTokenString(fTokens[++i]) + "\"");
1131:                            /***/
1132:                            System.out.print("/>");
1133:                            break;
1134:                        case EXPRTOKEN_NAMETEST_QNAME:
1135:                            System.out.print("<NAMETEST_QNAME");
1136:                            if (fTokens[++i] != -1)
1137:                                /***
1138:                                System.out.print(" prefix=\"" + fSymbolTable.toString(fTokens[i]) + "\"");
1139:                                /***/
1140:                                System.out.print(" prefix=\""
1141:                                        + getTokenString(fTokens[i]) + "\"");
1142:                            /***/
1143:                            /***
1144:                            System.out.print(" localpart=\"" + fSymbolTable.toString(fTokens[++i]) + "\"");
1145:                            /***/
1146:                            System.out.print(" localpart=\""
1147:                                    + getTokenString(fTokens[++i]) + "\"");
1148:                            /***/
1149:                            System.out.print("/>");
1150:                            break;
1151:                        case EXPRTOKEN_NODETYPE_COMMENT:
1152:                            System.out.print("<NODETYPE_COMMENT/>");
1153:                            break;
1154:                        case EXPRTOKEN_NODETYPE_TEXT:
1155:                            System.out.print("<NODETYPE_TEXT/>");
1156:                            break;
1157:                        case EXPRTOKEN_NODETYPE_PI:
1158:                            System.out.print("<NODETYPE_PI/>");
1159:                            break;
1160:                        case EXPRTOKEN_NODETYPE_NODE:
1161:                            System.out.print("<NODETYPE_NODE/>");
1162:                            break;
1163:                        case EXPRTOKEN_OPERATOR_AND:
1164:                            System.out.print("<OPERATOR_AND/>");
1165:                            break;
1166:                        case EXPRTOKEN_OPERATOR_OR:
1167:                            System.out.print("<OPERATOR_OR/>");
1168:                            break;
1169:                        case EXPRTOKEN_OPERATOR_MOD:
1170:                            System.out.print("<OPERATOR_MOD/>");
1171:                            break;
1172:                        case EXPRTOKEN_OPERATOR_DIV:
1173:                            System.out.print("<OPERATOR_DIV/>");
1174:                            break;
1175:                        case EXPRTOKEN_OPERATOR_MULT:
1176:                            System.out.print("<OPERATOR_MULT/>");
1177:                            break;
1178:                        case EXPRTOKEN_OPERATOR_SLASH:
1179:                            System.out.print("<OPERATOR_SLASH/>");
1180:                            if (i + 1 < fTokenCount) {
1181:                                System.out.println();
1182:                                System.out.print("  ");
1183:                            }
1184:                            break;
1185:                        case EXPRTOKEN_OPERATOR_DOUBLE_SLASH:
1186:                            System.out.print("<OPERATOR_DOUBLE_SLASH/>");
1187:                            break;
1188:                        case EXPRTOKEN_OPERATOR_UNION:
1189:                            System.out.print("<OPERATOR_UNION/>");
1190:                            break;
1191:                        case EXPRTOKEN_OPERATOR_PLUS:
1192:                            System.out.print("<OPERATOR_PLUS/>");
1193:                            break;
1194:                        case EXPRTOKEN_OPERATOR_MINUS:
1195:                            System.out.print("<OPERATOR_MINUS/>");
1196:                            break;
1197:                        case EXPRTOKEN_OPERATOR_EQUAL:
1198:                            System.out.print("<OPERATOR_EQUAL/>");
1199:                            break;
1200:                        case EXPRTOKEN_OPERATOR_NOT_EQUAL:
1201:                            System.out.print("<OPERATOR_NOT_EQUAL/>");
1202:                            break;
1203:                        case EXPRTOKEN_OPERATOR_LESS:
1204:                            System.out.print("<OPERATOR_LESS/>");
1205:                            break;
1206:                        case EXPRTOKEN_OPERATOR_LESS_EQUAL:
1207:                            System.out.print("<OPERATOR_LESS_EQUAL/>");
1208:                            break;
1209:                        case EXPRTOKEN_OPERATOR_GREATER:
1210:                            System.out.print("<OPERATOR_GREATER/>");
1211:                            break;
1212:                        case EXPRTOKEN_OPERATOR_GREATER_EQUAL:
1213:                            System.out.print("<OPERATOR_GREATER_EQUAL/>");
1214:                            break;
1215:                        case EXPRTOKEN_FUNCTION_NAME:
1216:                            System.out.print("<FUNCTION_NAME");
1217:                            if (fTokens[++i] != -1)
1218:                                /***
1219:                                System.out.print(" prefix=\"" + fSymbolTable.toString(fTokens[i]) + "\"");
1220:                                /***/
1221:                                System.out.print(" prefix=\""
1222:                                        + getTokenString(fTokens[i]) + "\"");
1223:                            /***/
1224:                            /***
1225:                            System.out.print(" localpart=\"" + fSymbolTable.toString(fTokens[++i]) + "\"");
1226:                            /***/
1227:                            System.out.print(" localpart=\""
1228:                                    + getTokenString(fTokens[++i]) + "\"");
1229:                            /***/
1230:                            System.out.print("/>");
1231:                            break;
1232:                        case EXPRTOKEN_AXISNAME_ANCESTOR:
1233:                            System.out.print("<AXISNAME_ANCESTOR/>");
1234:                            break;
1235:                        case EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF:
1236:                            System.out.print("<AXISNAME_ANCESTOR_OR_SELF/>");
1237:                            break;
1238:                        case EXPRTOKEN_AXISNAME_ATTRIBUTE:
1239:                            System.out.print("<AXISNAME_ATTRIBUTE/>");
1240:                            break;
1241:                        case EXPRTOKEN_AXISNAME_CHILD:
1242:                            System.out.print("<AXISNAME_CHILD/>");
1243:                            break;
1244:                        case EXPRTOKEN_AXISNAME_DESCENDANT:
1245:                            System.out.print("<AXISNAME_DESCENDANT/>");
1246:                            break;
1247:                        case EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF:
1248:                            System.out.print("<AXISNAME_DESCENDANT_OR_SELF/>");
1249:                            break;
1250:                        case EXPRTOKEN_AXISNAME_FOLLOWING:
1251:                            System.out.print("<AXISNAME_FOLLOWING/>");
1252:                            break;
1253:                        case EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING:
1254:                            System.out.print("<AXISNAME_FOLLOWING_SIBLING/>");
1255:                            break;
1256:                        case EXPRTOKEN_AXISNAME_NAMESPACE:
1257:                            System.out.print("<AXISNAME_NAMESPACE/>");
1258:                            break;
1259:                        case EXPRTOKEN_AXISNAME_PARENT:
1260:                            System.out.print("<AXISNAME_PARENT/>");
1261:                            break;
1262:                        case EXPRTOKEN_AXISNAME_PRECEDING:
1263:                            System.out.print("<AXISNAME_PRECEDING/>");
1264:                            break;
1265:                        case EXPRTOKEN_AXISNAME_PRECEDING_SIBLING:
1266:                            System.out.print("<AXISNAME_PRECEDING_SIBLING/>");
1267:                            break;
1268:                        case EXPRTOKEN_AXISNAME_SELF:
1269:                            System.out.print("<AXISNAME_SELF/>");
1270:                            break;
1271:                        case EXPRTOKEN_LITERAL:
1272:                            System.out.print("<LITERAL");
1273:                            /***
1274:                            System.out.print(" value=\"" + fSymbolTable.toString(fTokens[++i]) + "\"");
1275:                            /***/
1276:                            System.out.print(" value=\""
1277:                                    + getTokenString(fTokens[++i]) + "\"");
1278:                            /***/
1279:                            System.out.print("/>");
1280:                            break;
1281:                        case EXPRTOKEN_NUMBER:
1282:                            System.out.print("<NUMBER");
1283:                            System.out.print(" whole=\""
1284:                                    + getTokenString(fTokens[++i]) + "\"");
1285:                            System.out.print(" part=\""
1286:                                    + getTokenString(fTokens[++i]) + "\"");
1287:                            System.out.print("/>");
1288:                            break;
1289:                        case EXPRTOKEN_VARIABLE_REFERENCE:
1290:                            System.out.print("<VARIABLE_REFERENCE");
1291:                            if (fTokens[++i] != -1)
1292:                                /***
1293:                                System.out.print(" prefix=\"" + fSymbolTable.toString(fTokens[i]) + "\"");
1294:                                /***/
1295:                                System.out.print(" prefix=\""
1296:                                        + getTokenString(fTokens[i]) + "\"");
1297:                            /***/
1298:                            /***
1299:                            System.out.print(" localpart=\"" + fSymbolTable.toString(fTokens[++i]) + "\"");
1300:                            /***/
1301:                            System.out.print(" localpart=\""
1302:                                    + getTokenString(fTokens[++i]) + "\"");
1303:                            /***/
1304:                            System.out.print("/>");
1305:                            break;
1306:                        default:
1307:                            System.out.println("<???/>");
1308:                        }
1309:                    }
1310:                    System.out.println();
1311:                    //}
1312:                }
1313:
1314:            } // class Tokens
1315:
1316:            /**
1317:             * @author Glenn Marcy, IBM
1318:             * @author Andy Clark, IBM
1319:             *
1320:             * @version $Id: XPath.java,v 1.10 2001/06/08 14:23:49 sandygao Exp $
1321:             */
1322:            private static class Scanner {
1323:
1324:                /**
1325:                 * 7-bit ASCII subset
1326:                 *
1327:                 *  0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
1328:                 *  0,  0,  0,  0,  0,  0,  0,  0,  0, HT, LF,  0,  0, CR,  0,  0,  // 0
1329:                 *  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 1
1330:                 * SP,  !,  ",  #,  $,  %,  &,  ',  (,  ),  *,  +,  ,,  -,  .,  /,  // 2
1331:                 *  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  :,  ;,  <,  =,  >,  ?,  // 3
1332:                 *  @,  A,  B,  C,  D,  E,  F,  G,  H,  I,  J,  K,  L,  M,  N,  O,  // 4
1333:                 *  P,  Q,  R,  S,  T,  U,  V,  W,  X,  Y,  Z,  [,  \,  ],  ^,  _,  // 5
1334:                 *  `,  a,  b,  c,  d,  e,  f,  g,  h,  i,  j,  k,  l,  m,  n,  o,  // 6
1335:                 *  p,  q,  r,  s,  t,  u,  v,  w,  x,  y,  z,  {,  |,  },  ~, DEL  // 7
1336:                 */
1337:                private static final byte CHARTYPE_INVALID = 0, // invalid XML character
1338:                        CHARTYPE_OTHER = 1, // not special - one of "#%&;?\^`{}~" or DEL
1339:                        CHARTYPE_WHITESPACE = 2, // one of "\t\n\r " (0x09, 0x0A, 0x0D, 0x20)
1340:                        CHARTYPE_EXCLAMATION = 3, // '!' (0x21)
1341:                        CHARTYPE_QUOTE = 4, // '\"' or '\'' (0x22 and 0x27)
1342:                        CHARTYPE_DOLLAR = 5, // '$' (0x24)
1343:                        CHARTYPE_OPEN_PAREN = 6, // '(' (0x28)
1344:                        CHARTYPE_CLOSE_PAREN = 7, // ')' (0x29)
1345:                        CHARTYPE_STAR = 8, // '*' (0x2A)
1346:                        CHARTYPE_PLUS = 9, // '+' (0x2B)
1347:                        CHARTYPE_COMMA = 10, // ',' (0x2C)
1348:                        CHARTYPE_MINUS = 11, // '-' (0x2D)
1349:                        CHARTYPE_PERIOD = 12, // '.' (0x2E)
1350:                        CHARTYPE_SLASH = 13, // '/' (0x2F)
1351:                        CHARTYPE_DIGIT = 14, // '0'-'9' (0x30 to 0x39)
1352:                        CHARTYPE_COLON = 15, // ':' (0x3A)
1353:                        CHARTYPE_LESS = 16, // '<' (0x3C)
1354:                        CHARTYPE_EQUAL = 17, // '=' (0x3D)
1355:                        CHARTYPE_GREATER = 18, // '>' (0x3E)
1356:                        CHARTYPE_ATSIGN = 19, // '@' (0x40)
1357:                        CHARTYPE_LETTER = 20, // 'A'-'Z' or 'a'-'z' (0x41 to 0x5A and 0x61 to 0x7A)
1358:                        CHARTYPE_OPEN_BRACKET = 21, // '[' (0x5B)
1359:                        CHARTYPE_CLOSE_BRACKET = 22, // ']' (0x5D)
1360:                        CHARTYPE_UNDERSCORE = 23, // '_' (0x5F)
1361:                        CHARTYPE_UNION = 24, // '|' (0x7C)
1362:                        CHARTYPE_NONASCII = 25; // Non-ASCII Unicode codepoint (>= 0x80)
1363:
1364:                private static byte[] fASCIICharMap = { 0, 0, 0, 0, 0, 0, 0, 0,
1365:                        0, 2, 2, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1366:                        0, 0, 0, 0, 0, 0, 2, 3, 4, 1, 5, 1, 1, 4, 6, 7, 8, 9,
1367:                        10, 11, 12, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
1368:                        15, 1, 16, 17, 18, 1, 19, 20, 20, 20, 20, 20, 20, 20,
1369:                        20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1370:                        20, 20, 20, 20, 20, 21, 1, 22, 1, 23, 1, 20, 20, 20,
1371:                        20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1372:                        20, 20, 20, 20, 20, 20, 20, 20, 20, 1, 24, 1, 1, 1 };
1373:
1374:                /**
1375:                 * Symbol literals
1376:                 */
1377:                /***
1378:                private static int fgAndSymbol = -1;                // 'and'
1379:                private static int fgOrSymbol = -1;                 // 'or'
1380:                private static int fgModSymbol = -1;                // 'mod'
1381:                private static int fgDivSymbol = -1;                // 'div'
1382:
1383:                private static int fgCommentSymbol = -1;            // 'comment'
1384:                private static int fgTextSymbol = -1;               // 'text'
1385:                private static int fgPISymbol = -1;                 // 'processing-instruction'
1386:                private static int fgNodeSymbol = -1;               // 'node'
1387:
1388:                private static int fgAncestorSymbol = -1;           // 'ancestor'
1389:                private static int fgAncestorOrSelfSymbol = -1;     // 'ancestor-or-self'
1390:                private static int fgAttributeSymbol = -1;          // 'attribute'
1391:                private static int fgChildSymbol = -1;              // 'child'
1392:                private static int fgDescendantSymbol = -1;         // 'descendant'
1393:                private static int fgDescendantOrSelfSymbol = -1;   // 'descendant-or-self'
1394:                private static int fgFollowingSymbol = -1;          // 'following'
1395:                private static int fgFollowingSiblingSymbol = -1;   // 'following-sibling'
1396:                private static int fgNamespaceSymbol = -1;          // 'namespace'
1397:                private static int fgParentSymbol = -1;             // 'parent'
1398:                private static int fgPrecedingSymbol = -1;          // 'preceding'
1399:                private static int fgPrecedingSiblingSymbol = -1;   // 'preceding-sibling'
1400:                private static int fgSelfSymbol = -1;               // 'self'
1401:
1402:                private static SymbolTable fgSymbolTable = new SymbolTable();
1403:
1404:                static {
1405:                    fgAndSymbol = fgSymbolTable.addSymbol("and");
1406:                    fgOrSymbol = fgSymbolTable.addSymbol("or");
1407:                    fgModSymbol = fgSymbolTable.addSymbol("mod");
1408:                    fgDivSymbol = fgSymbolTable.addSymbol("div");
1409:                    fgCommentSymbol = fgSymbolTable.addSymbol("comment");
1410:                    fgTextSymbol = fgSymbolTable.addSymbol("text");
1411:                    fgPISymbol = fgSymbolTable.addSymbol("processing-instruction");
1412:                    fgNodeSymbol = fgSymbolTable.addSymbol("node");
1413:                    fgAncestorSymbol = fgSymbolTable.addSymbol("ancestor");
1414:                    fgAncestorOrSelfSymbol = fgSymbolTable.addSymbol("ancestor-or-self");
1415:                    fgAttributeSymbol = fgSymbolTable.addSymbol("attribute");
1416:                    fgChildSymbol = fgSymbolTable.addSymbol("child");
1417:                    fgDescendantSymbol = fgSymbolTable.addSymbol("descendant");
1418:                    fgDescendantOrSelfSymbol = fgSymbolTable.addSymbol("descendant-or-self");
1419:                    fgFollowingSymbol = fgSymbolTable.addSymbol("following");
1420:                    fgFollowingSiblingSymbol = fgSymbolTable.addSymbol("following-sibling");
1421:                    fgNamespaceSymbol = fgSymbolTable.addSymbol("namespace");
1422:                    fgParentSymbol = fgSymbolTable.addSymbol("parent");
1423:                    fgPrecedingSymbol = fgSymbolTable.addSymbol("preceding");
1424:                    fgPrecedingSiblingSymbol = fgSymbolTable.addSymbol("preceding-sibling");
1425:                    fgSelfSymbol = fgSymbolTable.addSymbol("self");
1426:                }
1427:                /***/
1428:
1429:                //
1430:                // Data
1431:                //
1432:                /** String pool. */
1433:                private StringPool fStringPool;
1434:
1435:                // symbols
1436:
1437:                private int fAndSymbol;
1438:                private int fOrSymbol;
1439:                private int fModSymbol;
1440:                private int fDivSymbol;
1441:
1442:                private int fCommentSymbol;
1443:                private int fTextSymbol;
1444:                private int fPISymbol;
1445:                private int fNodeSymbol;
1446:
1447:                private int fAncestorSymbol;
1448:                private int fAncestorOrSelfSymbol;
1449:                private int fAttributeSymbol;
1450:                private int fChildSymbol;
1451:                private int fDescendantSymbol;
1452:                private int fDescendantOrSelfSymbol;
1453:                private int fFollowingSymbol;
1454:                private int fFollowingSiblingSymbol;
1455:                private int fNamespaceSymbol;
1456:                private int fParentSymbol;
1457:                private int fPrecedingSymbol;
1458:                private int fPrecedingSiblingSymbol;
1459:                private int fSelfSymbol;
1460:
1461:                //
1462:                // Constructors
1463:                //
1464:
1465:                /** Constructs an XPath expression scanner. */
1466:                public Scanner(StringPool stringPool) {
1467:
1468:                    // save pool and tokens
1469:                    fStringPool = stringPool;
1470:
1471:                    // create symbols
1472:                    fAndSymbol = fStringPool.addSymbol("and");
1473:                    fOrSymbol = fStringPool.addSymbol("or");
1474:                    fModSymbol = fStringPool.addSymbol("mod");
1475:                    fDivSymbol = fStringPool.addSymbol("div");
1476:                    fCommentSymbol = fStringPool.addSymbol("comment");
1477:                    fTextSymbol = fStringPool.addSymbol("text");
1478:                    fPISymbol = fStringPool.addSymbol("processing-instruction");
1479:                    fNodeSymbol = fStringPool.addSymbol("node");
1480:                    fAncestorSymbol = fStringPool.addSymbol("ancestor");
1481:                    fAncestorOrSelfSymbol = fStringPool
1482:                            .addSymbol("ancestor-or-self");
1483:                    fAttributeSymbol = fStringPool.addSymbol("attribute");
1484:                    fChildSymbol = fStringPool.addSymbol("child");
1485:                    fDescendantSymbol = fStringPool.addSymbol("descendant");
1486:                    fDescendantOrSelfSymbol = fStringPool
1487:                            .addSymbol("descendant-or-self");
1488:                    fFollowingSymbol = fStringPool.addSymbol("following");
1489:                    fFollowingSiblingSymbol = fStringPool
1490:                            .addSymbol("following-sibling");
1491:                    fNamespaceSymbol = fStringPool.addSymbol("namespace");
1492:                    fParentSymbol = fStringPool.addSymbol("parent");
1493:                    fPrecedingSymbol = fStringPool.addSymbol("preceding");
1494:                    fPrecedingSiblingSymbol = fStringPool
1495:                            .addSymbol("preceding-sibling");
1496:                    fSelfSymbol = fStringPool.addSymbol("self");
1497:
1498:                } // <init>(StringPool)
1499:
1500:                /**
1501:                 *
1502:                 */
1503:                public boolean scanExpr(StringPool stringPool,
1504:                        XPath.Tokens tokens, String data, int currentOffset,
1505:                        int endOffset) throws XPathException {
1506:
1507:                    int nameOffset;
1508:                    int nameHandle, prefixHandle;
1509:                    boolean starIsMultiplyOperator = false;
1510:                    int ch;
1511:
1512:                    /***
1513:                    if (XPath.Tokens.DUMP_TOKENS) {
1514:                        System.out.println("  <test>");
1515:                        System.out.println("    <expression>");
1516:                        System.out.println("      " + encoding.createString(data, currentOffset, endOffset - currentOffset));
1517:                        System.out.println("    </expression>");
1518:                    }
1519:                    /***/
1520:                    while (true) {
1521:                        if (currentOffset == endOffset) {
1522:                            break;
1523:                        }
1524:                        /***
1525:                        ch = (data[currentOffset] & 0xFF);
1526:                        /***/
1527:                        ch = data.charAt(currentOffset);
1528:                        /***/
1529:                        //
1530:                        // [39] ExprWhitespace ::= S
1531:                        //
1532:                        while (ch == ' ' || ch == 0x0A || ch == 0x09
1533:                                || ch == 0x0D) {
1534:                            if (++currentOffset == endOffset) {
1535:                                break;
1536:                            }
1537:                            /***
1538:                            ch = (data[currentOffset] & 0xFF);
1539:                            /***/
1540:                            ch = data.charAt(currentOffset);
1541:                            /***/
1542:                        }
1543:                        if (currentOffset == endOffset) {
1544:                            break;
1545:                        }
1546:                        //
1547:                        // [28] ExprToken ::= '(' | ')' | '[' | ']' | '.' | '..' | '@' | ',' | '::'
1548:                        //                  | NameTest | NodeType | Operator | FunctionName
1549:                        //                  | AxisName | Literal | Number | VariableReference
1550:                        //
1551:                        byte chartype = (ch >= 0x80) ? CHARTYPE_NONASCII
1552:                                : fASCIICharMap[ch];
1553:                        switch (chartype) {
1554:                        case CHARTYPE_OPEN_PAREN: // '('
1555:                            addToken(tokens, XPath.Tokens.EXPRTOKEN_OPEN_PAREN);
1556:                            starIsMultiplyOperator = false;
1557:                            if (++currentOffset == endOffset) {
1558:                                break;
1559:                            }
1560:                            break;
1561:                        case CHARTYPE_CLOSE_PAREN: // ')'
1562:                            addToken(tokens, XPath.Tokens.EXPRTOKEN_CLOSE_PAREN);
1563:                            starIsMultiplyOperator = true;
1564:                            if (++currentOffset == endOffset) {
1565:                                break;
1566:                            }
1567:                            break;
1568:                        case CHARTYPE_OPEN_BRACKET: // '['
1569:                            addToken(tokens,
1570:                                    XPath.Tokens.EXPRTOKEN_OPEN_BRACKET);
1571:                            starIsMultiplyOperator = false;
1572:                            if (++currentOffset == endOffset) {
1573:                                break;
1574:                            }
1575:                            break;
1576:                        case CHARTYPE_CLOSE_BRACKET: // ']'
1577:                            addToken(tokens,
1578:                                    XPath.Tokens.EXPRTOKEN_CLOSE_BRACKET);
1579:                            starIsMultiplyOperator = true;
1580:                            if (++currentOffset == endOffset) {
1581:                                break;
1582:                            }
1583:                            break;
1584:                        //
1585:                        // [30] Number ::= Digits ('.' Digits?)? | '.' Digits
1586:                        //                                         ^^^^^^^^^^
1587:                        //
1588:                        case CHARTYPE_PERIOD: // '.', '..' or '.' Digits
1589:                            if (currentOffset + 1 == endOffset) {
1590:                                addToken(tokens, XPath.Tokens.EXPRTOKEN_PERIOD);
1591:                                starIsMultiplyOperator = true;
1592:                                currentOffset++;
1593:                                break;
1594:                            }
1595:                            /***
1596:                            ch = (data[currentOffset + 1] & 0xFF);
1597:                            /***/
1598:                            ch = data.charAt(currentOffset + 1);
1599:                            /***/
1600:                            if (ch == '.') { // '..'
1601:                                addToken(tokens,
1602:                                        XPath.Tokens.EXPRTOKEN_DOUBLE_PERIOD);
1603:                                starIsMultiplyOperator = true;
1604:                                currentOffset += 2;
1605:                            } else if (ch >= '0' && ch <= '9') {
1606:                                addToken(tokens, XPath.Tokens.EXPRTOKEN_NUMBER);
1607:                                starIsMultiplyOperator = true;
1608:                                currentOffset = scanNumber(tokens, data,
1609:                                        endOffset, currentOffset/*, encoding*/);
1610:                            } else if (ch == '/') {
1611:                                addToken(tokens, XPath.Tokens.EXPRTOKEN_PERIOD);
1612:                                starIsMultiplyOperator = true;
1613:                                currentOffset++;
1614:                            } else { // '.'
1615:                                throw new XPathException(
1616:                                        "Invalid character following '.'");
1617:                            }
1618:                            if (currentOffset == endOffset) {
1619:                                break;
1620:                            }
1621:                            break;
1622:                        case CHARTYPE_ATSIGN: // '@'
1623:                            addToken(tokens, XPath.Tokens.EXPRTOKEN_ATSIGN);
1624:                            starIsMultiplyOperator = false;
1625:                            if (++currentOffset == endOffset) {
1626:                                break;
1627:                            }
1628:                            break;
1629:                        case CHARTYPE_COMMA: // ','
1630:                            addToken(tokens, XPath.Tokens.EXPRTOKEN_COMMA);
1631:                            starIsMultiplyOperator = false;
1632:                            if (++currentOffset == endOffset) {
1633:                                break;
1634:                            }
1635:                            break;
1636:                        case CHARTYPE_COLON: // '::'
1637:                            if (++currentOffset == endOffset) {
1638:                                // System.out.println("abort 1a");
1639:                                return false; // REVISIT
1640:                            }
1641:                            /***
1642:                            ch = (data[currentOffset] & 0xFF);
1643:                            /***/
1644:                            ch = data.charAt(currentOffset);
1645:                            /***/
1646:                            if (ch != ':') {
1647:                                // System.out.println("abort 1b");
1648:                                return false; // REVISIT
1649:                            }
1650:                            addToken(tokens,
1651:                                    XPath.Tokens.EXPRTOKEN_DOUBLE_COLON);
1652:                            starIsMultiplyOperator = false;
1653:                            if (++currentOffset == endOffset) {
1654:                                break;
1655:                            }
1656:                            break;
1657:                        case CHARTYPE_SLASH: // '/' and '//'
1658:                            if (++currentOffset == endOffset) {
1659:                                addToken(tokens,
1660:                                        XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH);
1661:                                starIsMultiplyOperator = false;
1662:                                break;
1663:                            }
1664:                            /***
1665:                            ch = (data[currentOffset] & 0xFF);
1666:                            /***/
1667:                            ch = data.charAt(currentOffset);
1668:                            /***/
1669:                            if (ch == '/') { // '//'
1670:                                addToken(
1671:                                        tokens,
1672:                                        XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH);
1673:                                starIsMultiplyOperator = false;
1674:                                if (++currentOffset == endOffset) {
1675:                                    break;
1676:                                }
1677:                            } else {
1678:                                addToken(tokens,
1679:                                        XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH);
1680:                                starIsMultiplyOperator = false;
1681:                            }
1682:                            break;
1683:                        case CHARTYPE_UNION: // '|'
1684:                            addToken(tokens,
1685:                                    XPath.Tokens.EXPRTOKEN_OPERATOR_UNION);
1686:                            starIsMultiplyOperator = false;
1687:                            if (++currentOffset == endOffset) {
1688:                                break;
1689:                            }
1690:                            break;
1691:                        case CHARTYPE_PLUS: // '+'
1692:                            addToken(tokens,
1693:                                    XPath.Tokens.EXPRTOKEN_OPERATOR_PLUS);
1694:                            starIsMultiplyOperator = false;
1695:                            if (++currentOffset == endOffset) {
1696:                                break;
1697:                            }
1698:                            break;
1699:                        case CHARTYPE_MINUS: // '-'
1700:                            addToken(tokens,
1701:                                    XPath.Tokens.EXPRTOKEN_OPERATOR_MINUS);
1702:                            starIsMultiplyOperator = false;
1703:                            if (++currentOffset == endOffset) {
1704:                                break;
1705:                            }
1706:                            break;
1707:                        case CHARTYPE_EQUAL: // '='
1708:                            addToken(tokens,
1709:                                    XPath.Tokens.EXPRTOKEN_OPERATOR_EQUAL);
1710:                            starIsMultiplyOperator = false;
1711:                            if (++currentOffset == endOffset) {
1712:                                break;
1713:                            }
1714:                            break;
1715:                        case CHARTYPE_EXCLAMATION: // '!='
1716:                            if (++currentOffset == endOffset) {
1717:                                // System.out.println("abort 2a");
1718:                                return false; // REVISIT
1719:                            }
1720:                            /***
1721:                            ch = (data[currentOffset] & 0xFF);
1722:                            /***/
1723:                            ch = data.charAt(currentOffset);
1724:                            /***/
1725:                            if (ch != '=') {
1726:                                // System.out.println("abort 2b");
1727:                                return false; // REVISIT
1728:                            }
1729:                            addToken(tokens,
1730:                                    XPath.Tokens.EXPRTOKEN_OPERATOR_NOT_EQUAL);
1731:                            starIsMultiplyOperator = false;
1732:                            if (++currentOffset == endOffset) {
1733:                                break;
1734:                            }
1735:                            break;
1736:                        case CHARTYPE_LESS: // '<' and '<='
1737:                            if (++currentOffset == endOffset) {
1738:                                addToken(tokens,
1739:                                        XPath.Tokens.EXPRTOKEN_OPERATOR_LESS);
1740:                                starIsMultiplyOperator = false;
1741:                                break;
1742:                            }
1743:                            /***
1744:                            ch = (data[currentOffset] & 0xFF);
1745:                            /***/
1746:                            ch = data.charAt(currentOffset);
1747:                            /***/
1748:                            if (ch == '=') { // '<='
1749:                                addToken(
1750:                                        tokens,
1751:                                        XPath.Tokens.EXPRTOKEN_OPERATOR_LESS_EQUAL);
1752:                                starIsMultiplyOperator = false;
1753:                                if (++currentOffset == endOffset) {
1754:                                    break;
1755:                                }
1756:                            } else {
1757:                                addToken(tokens,
1758:                                        XPath.Tokens.EXPRTOKEN_OPERATOR_LESS);
1759:                                starIsMultiplyOperator = false;
1760:                            }
1761:                            break;
1762:                        case CHARTYPE_GREATER: // '>' and '>='
1763:                            if (++currentOffset == endOffset) {
1764:                                addToken(tokens,
1765:                                        XPath.Tokens.EXPRTOKEN_OPERATOR_GREATER);
1766:                                starIsMultiplyOperator = false;
1767:                                break;
1768:                            }
1769:                            /***
1770:                            ch = (data[currentOffset] & 0xFF);
1771:                            /***/
1772:                            ch = data.charAt(currentOffset);
1773:                            /***/
1774:                            if (ch == '=') { // '>='
1775:                                addToken(
1776:                                        tokens,
1777:                                        XPath.Tokens.EXPRTOKEN_OPERATOR_GREATER_EQUAL);
1778:                                starIsMultiplyOperator = false;
1779:                                if (++currentOffset == endOffset) {
1780:                                    break;
1781:                                }
1782:                            } else {
1783:                                addToken(tokens,
1784:                                        XPath.Tokens.EXPRTOKEN_OPERATOR_GREATER);
1785:                                starIsMultiplyOperator = false;
1786:                            }
1787:                            break;
1788:                        //
1789:                        // [29] Literal ::= '"' [^"]* '"' | "'" [^']* "'"
1790:                        //
1791:                        case CHARTYPE_QUOTE: // '\"' or '\''
1792:                            int qchar = ch;
1793:                            if (++currentOffset == endOffset) {
1794:                                // System.out.println("abort 2c");
1795:                                return false; // REVISIT
1796:                            }
1797:                            /***
1798:                            ch = (data[currentOffset] & 0xFF);
1799:                            /***/
1800:                            ch = data.charAt(currentOffset);
1801:                            /***/
1802:                            int litOffset = currentOffset;
1803:                            while (ch != qchar) {
1804:                                if (++currentOffset == endOffset) {
1805:                                    // System.out.println("abort 2d");
1806:                                    return false; // REVISIT
1807:                                }
1808:                                /***
1809:                                ch = (data[currentOffset] & 0xFF);
1810:                                /***/
1811:                                ch = data.charAt(currentOffset);
1812:                                /***/
1813:                            }
1814:                            int litLength = currentOffset - litOffset;
1815:                            addToken(tokens, XPath.Tokens.EXPRTOKEN_LITERAL);
1816:                            starIsMultiplyOperator = true;
1817:                            /***
1818:                            addToken(tokens, tokens.addSymbol(data, litOffset, litLength, encoding));
1819:                            /***/
1820:                            tokens.addToken(stringPool
1821:                                    .addSymbol(data.substring(litOffset,
1822:                                            litOffset + litLength)));
1823:                            /***/
1824:                            if (++currentOffset == endOffset) {
1825:                                break;
1826:                            }
1827:                            break;
1828:                        //
1829:                        // [30] Number ::= Digits ('.' Digits?)? | '.' Digits
1830:                        // [31] Digits ::= [0-9]+
1831:                        //
1832:                        case CHARTYPE_DIGIT:
1833:                            addToken(tokens, XPath.Tokens.EXPRTOKEN_NUMBER);
1834:                            starIsMultiplyOperator = true;
1835:                            currentOffset = scanNumber(tokens, data, endOffset,
1836:                                    currentOffset/*, encoding*/);
1837:                            break;
1838:                        //
1839:                        // [36] VariableReference ::= '$' QName
1840:                        //
1841:                        case CHARTYPE_DOLLAR:
1842:                            if (++currentOffset == endOffset) {
1843:                                // System.out.println("abort 3a");
1844:                                return false; // REVISIT
1845:                            }
1846:                            nameOffset = currentOffset;
1847:                            currentOffset = scanNCName(data, endOffset,
1848:                                    currentOffset);
1849:                            if (currentOffset == nameOffset) {
1850:                                // System.out.println("abort 3b");
1851:                                return false; // REVISIT
1852:                            }
1853:                            if (currentOffset < endOffset) {
1854:                                ch = data.charAt(currentOffset);
1855:                            } else {
1856:                                ch = -1;
1857:                            }
1858:                            /***
1859:                            nameHandle = tokens.addSymbol(data, nameOffset, currentOffset - nameOffset, encoding);
1860:                            /***/
1861:                            nameHandle = stringPool.addSymbol(data.substring(
1862:                                    nameOffset, currentOffset));
1863:                            /***/
1864:                            if (ch != ':') {
1865:                                prefixHandle = -1;
1866:                            } else {
1867:                                prefixHandle = nameHandle;
1868:                                if (++currentOffset == endOffset) {
1869:                                    // System.out.println("abort 4a");
1870:                                    return false; // REVISIT
1871:                                }
1872:                                nameOffset = currentOffset;
1873:                                currentOffset = scanNCName(data, endOffset,
1874:                                        currentOffset);
1875:                                if (currentOffset == nameOffset) {
1876:                                    // System.out.println("abort 4b");
1877:                                    return false; // REVISIT
1878:                                }
1879:                                if (currentOffset < endOffset) {
1880:                                    ch = data.charAt(currentOffset);
1881:                                } else {
1882:                                    ch = -1;
1883:                                }
1884:                                /***
1885:                                nameHandle = tokens.addSymbol(data, nameOffset, currentOffset - nameOffset, encoding);
1886:                                /***/
1887:                                nameHandle = stringPool.addSymbol(data
1888:                                        .substring(nameOffset, currentOffset));
1889:                                /***/
1890:                            }
1891:                            addToken(tokens,
1892:                                    XPath.Tokens.EXPRTOKEN_VARIABLE_REFERENCE);
1893:                            starIsMultiplyOperator = true;
1894:                            tokens.addToken(prefixHandle);
1895:                            tokens.addToken(nameHandle);
1896:                            break;
1897:                        //
1898:                        // [37] NameTest ::= '*' | NCName ':' '*' | QName
1899:                        // [34] MultiplyOperator ::= '*'
1900:                        //
1901:                        case CHARTYPE_STAR: // '*'
1902:                            //
1903:                            // 3.7 Lexical Structure
1904:                            //
1905:                            //  If there is a preceding token and the preceding token is not one of @, ::, (, [, , or
1906:                            //  an Operator, then a * must be recognized as a MultiplyOperator.
1907:                            //
1908:                            // Otherwise, the token must not be recognized as a MultiplyOperator.
1909:                            //
1910:                            if (starIsMultiplyOperator) {
1911:                                addToken(tokens,
1912:                                        XPath.Tokens.EXPRTOKEN_OPERATOR_MULT);
1913:                                starIsMultiplyOperator = false;
1914:                            } else {
1915:                                addToken(tokens,
1916:                                        XPath.Tokens.EXPRTOKEN_NAMETEST_ANY);
1917:                                starIsMultiplyOperator = true;
1918:                            }
1919:                            if (++currentOffset == endOffset) {
1920:                                break;
1921:                            }
1922:                            break;
1923:                        //
1924:                        // NCName, QName and non-terminals
1925:                        //
1926:                        case CHARTYPE_NONASCII: // possibly a valid non-ascii 'Letter' (BaseChar | Ideographic)
1927:                        case CHARTYPE_LETTER:
1928:                        case CHARTYPE_UNDERSCORE:
1929:                            //
1930:                            // 3.7 Lexical Structure
1931:                            //
1932:                            //  If there is a preceding token and the preceding token is not one of @, ::, (, [, , or
1933:                            //  an Operator, then an NCName must be recognized as an OperatorName.
1934:                            //
1935:                            //  If the character following an NCName (possibly after intervening ExprWhitespace) is (,
1936:                            //  then the token must be recognized as a NodeType or a FunctionName.
1937:                            //
1938:                            //  If the two characters following an NCName (possibly after intervening ExprWhitespace)
1939:                            //  are ::, then the token must be recognized as an AxisName.
1940:                            //
1941:                            //  Otherwise, the token must not be recognized as an OperatorName, a NodeType, a
1942:                            //  FunctionName, or an AxisName.
1943:                            //
1944:                            // [33] OperatorName ::= 'and' | 'or' | 'mod' | 'div'
1945:                            // [38] NodeType ::= 'comment' | 'text' | 'processing-instruction' | 'node'
1946:                            // [35] FunctionName ::= QName - NodeType
1947:                            // [6] AxisName ::= (see above)
1948:                            //
1949:                            // [37] NameTest ::= '*' | NCName ':' '*' | QName
1950:                            // [5] NCName ::= (Letter | '_') (NCNameChar)*
1951:                            // [?] NCNameChar ::= Letter | Digit | '.' | '-' | '_'  (ascii subset of 'NCNameChar')
1952:                            // [?] QName ::= (NCName ':')? NCName
1953:                            // [?] Letter ::= [A-Za-z]                              (ascii subset of 'Letter')
1954:                            // [?] Digit ::= [0-9]                                  (ascii subset of 'Digit')
1955:                            //
1956:                            nameOffset = currentOffset;
1957:                            currentOffset = scanNCName(data, endOffset,
1958:                                    currentOffset);
1959:                            if (currentOffset == nameOffset) {
1960:                                // System.out.println("abort 4c");
1961:                                return false; // REVISIT
1962:                            }
1963:                            if (currentOffset < endOffset) {
1964:                                ch = data.charAt(currentOffset);
1965:                            } else {
1966:                                ch = -1;
1967:                            }
1968:                            /***
1969:                            nameHandle = tokens.addSymbol(data, nameOffset, currentOffset - nameOffset, encoding);
1970:                            /***/
1971:                            nameHandle = stringPool.addSymbol(data.substring(
1972:                                    nameOffset, currentOffset));
1973:                            /***/
1974:                            boolean isNameTestNCName = false;
1975:                            boolean isAxisName = false;
1976:                            prefixHandle = -1;
1977:                            if (ch == ':') {
1978:                                if (++currentOffset == endOffset) {
1979:                                    // System.out.println("abort 5");
1980:                                    return false; // REVISIT
1981:                                }
1982:                                /***
1983:                                ch = (data[currentOffset] & 0xFF);
1984:                                /***/
1985:                                ch = data.charAt(currentOffset);
1986:                                /***/
1987:                                if (ch == '*') {
1988:                                    if (++currentOffset < endOffset) {
1989:                                        /***
1990:                                        ch = (data[currentOffset] & 0xFF);
1991:                                        /***/
1992:                                        ch = data.charAt(currentOffset);
1993:                                        /***/
1994:                                    }
1995:                                    isNameTestNCName = true;
1996:                                } else if (ch == ':') {
1997:                                    if (++currentOffset < endOffset) {
1998:                                        /***
1999:                                        ch = (data[currentOffset] & 0xFF);
2000:                                        /***/
2001:                                        ch = data.charAt(currentOffset);
2002:                                        /***/
2003:                                    }
2004:                                    isAxisName = true;
2005:                                } else {
2006:                                    prefixHandle = nameHandle;
2007:                                    nameOffset = currentOffset;
2008:                                    currentOffset = scanNCName(data, endOffset,
2009:                                            currentOffset);
2010:                                    if (currentOffset == nameOffset) {
2011:                                        // System.out.println("abort 5b");
2012:                                        return false; // REVISIT
2013:                                    }
2014:                                    if (currentOffset < endOffset) {
2015:                                        ch = data.charAt(currentOffset);
2016:                                    } else {
2017:                                        ch = -1;
2018:                                    }
2019:                                    /***
2020:                                    nameHandle = tokens.addSymbol(data, nameOffset, currentOffset - nameOffset, encoding);
2021:                                    /***/
2022:                                    nameHandle = stringPool.addSymbol(data
2023:                                            .substring(nameOffset,
2024:                                                    currentOffset));
2025:                                    /***/
2026:                                }
2027:                            }
2028:                            //
2029:                            // [39] ExprWhitespace ::= S
2030:                            //
2031:                            while (ch == ' ' || ch == 0x0A || ch == 0x09
2032:                                    || ch == 0x0D) {
2033:                                if (++currentOffset == endOffset) {
2034:                                    break;
2035:                                }
2036:                                /***
2037:                                ch = (data[currentOffset] & 0xFF);
2038:                                /***/
2039:                                ch = data.charAt(currentOffset);
2040:                                /***/
2041:                            }
2042:                            //
2043:                            //  If there is a preceding token and the preceding token is not one of @, ::, (, [, , or
2044:                            //  an Operator, then an NCName must be recognized as an OperatorName.
2045:                            //
2046:                            if (starIsMultiplyOperator) {
2047:                                if (nameHandle == fAndSymbol) {
2048:                                    addToken(tokens,
2049:                                            XPath.Tokens.EXPRTOKEN_OPERATOR_AND);
2050:                                    starIsMultiplyOperator = false;
2051:                                } else if (nameHandle == fOrSymbol) {
2052:                                    addToken(tokens,
2053:                                            XPath.Tokens.EXPRTOKEN_OPERATOR_OR);
2054:                                    starIsMultiplyOperator = false;
2055:                                } else if (nameHandle == fModSymbol) {
2056:                                    addToken(tokens,
2057:                                            XPath.Tokens.EXPRTOKEN_OPERATOR_MOD);
2058:                                    starIsMultiplyOperator = false;
2059:                                } else if (nameHandle == fDivSymbol) {
2060:                                    addToken(tokens,
2061:                                            XPath.Tokens.EXPRTOKEN_OPERATOR_DIV);
2062:                                    starIsMultiplyOperator = false;
2063:                                } else {
2064:                                    // System.out.println("abort 6");
2065:                                    return false; // REVISIT
2066:                                }
2067:                                if (isNameTestNCName) {
2068:                                    // System.out.println("abort 7");
2069:                                    return false; // REVISIT - NCName:* where an OperatorName is required
2070:                                } else if (isAxisName) {
2071:                                    // System.out.println("abort 8");
2072:                                    return false; // REVISIT - AxisName:: where an OperatorName is required
2073:                                }
2074:                                break;
2075:                            }
2076:                            //
2077:                            //  If the character following an NCName (possibly after intervening ExprWhitespace) is (,
2078:                            //  then the token must be recognized as a NodeType or a FunctionName.
2079:                            //
2080:                            if (ch == '(' && !isNameTestNCName && !isAxisName) {
2081:                                if (nameHandle == fCommentSymbol) {
2082:                                    addToken(
2083:                                            tokens,
2084:                                            XPath.Tokens.EXPRTOKEN_NODETYPE_COMMENT);
2085:                                } else if (nameHandle == fTextSymbol) {
2086:                                    addToken(
2087:                                            tokens,
2088:                                            XPath.Tokens.EXPRTOKEN_NODETYPE_TEXT);
2089:                                } else if (nameHandle == fPISymbol) {
2090:                                    addToken(tokens,
2091:                                            XPath.Tokens.EXPRTOKEN_NODETYPE_PI);
2092:                                } else if (nameHandle == fNodeSymbol) {
2093:                                    addToken(
2094:                                            tokens,
2095:                                            XPath.Tokens.EXPRTOKEN_NODETYPE_NODE);
2096:                                } else {
2097:                                    addToken(
2098:                                            tokens,
2099:                                            XPath.Tokens.EXPRTOKEN_FUNCTION_NAME);
2100:                                    tokens.addToken(prefixHandle);
2101:                                    tokens.addToken(nameHandle);
2102:                                }
2103:                                addToken(tokens,
2104:                                        XPath.Tokens.EXPRTOKEN_OPEN_PAREN);
2105:                                starIsMultiplyOperator = false;
2106:                                if (++currentOffset == endOffset) {
2107:                                    break;
2108:                                }
2109:                                break;
2110:                            }
2111:                            //
2112:                            //  If the two characters following an NCName (possibly after intervening ExprWhitespace)
2113:                            //  are ::, then the token must be recognized as an AxisName.
2114:                            //
2115:                            if (isAxisName
2116:                                    || (ch == ':'
2117:                                            && currentOffset + 1 < endOffset &&
2118:                                    /***
2119:                                    (data[currentOffset + 1] & 0xFF) == ':')) {
2120:                                    /***/
2121:                                    data.charAt(currentOffset + 1) == ':')) {
2122:                                /***/
2123:                                if (nameHandle == fAncestorSymbol) {
2124:                                    addToken(
2125:                                            tokens,
2126:                                            XPath.Tokens.EXPRTOKEN_AXISNAME_ANCESTOR);
2127:                                } else if (nameHandle == fAncestorOrSelfSymbol) {
2128:                                    addToken(
2129:                                            tokens,
2130:                                            XPath.Tokens.EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF);
2131:                                } else if (nameHandle == fAttributeSymbol) {
2132:                                    addToken(
2133:                                            tokens,
2134:                                            XPath.Tokens.EXPRTOKEN_AXISNAME_ATTRIBUTE);
2135:                                } else if (nameHandle == fChildSymbol) {
2136:                                    addToken(
2137:                                            tokens,
2138:                                            XPath.Tokens.EXPRTOKEN_AXISNAME_CHILD);
2139:                                } else if (nameHandle == fDescendantSymbol) {
2140:                                    addToken(
2141:                                            tokens,
2142:                                            XPath.Tokens.EXPRTOKEN_AXISNAME_DESCENDANT);
2143:                                } else if (nameHandle == fDescendantOrSelfSymbol) {
2144:                                    addToken(
2145:                                            tokens,
2146:                                            XPath.Tokens.EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF);
2147:                                } else if (nameHandle == fFollowingSymbol) {
2148:                                    addToken(
2149:                                            tokens,
2150:                                            XPath.Tokens.EXPRTOKEN_AXISNAME_FOLLOWING);
2151:                                } else if (nameHandle == fFollowingSiblingSymbol) {
2152:                                    addToken(
2153:                                            tokens,
2154:                                            XPath.Tokens.EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING);
2155:                                } else if (nameHandle == fNamespaceSymbol) {
2156:                                    addToken(
2157:                                            tokens,
2158:                                            XPath.Tokens.EXPRTOKEN_AXISNAME_NAMESPACE);
2159:                                } else if (nameHandle == fParentSymbol) {
2160:                                    addToken(
2161:                                            tokens,
2162:                                            XPath.Tokens.EXPRTOKEN_AXISNAME_PARENT);
2163:                                } else if (nameHandle == fPrecedingSymbol) {
2164:                                    addToken(
2165:                                            tokens,
2166:                                            XPath.Tokens.EXPRTOKEN_AXISNAME_PRECEDING);
2167:                                } else if (nameHandle == fPrecedingSiblingSymbol) {
2168:                                    addToken(
2169:                                            tokens,
2170:                                            XPath.Tokens.EXPRTOKEN_AXISNAME_PRECEDING_SIBLING);
2171:                                } else if (nameHandle == fSelfSymbol) {
2172:                                    addToken(
2173:                                            tokens,
2174:                                            XPath.Tokens.EXPRTOKEN_AXISNAME_SELF);
2175:                                } else {
2176:                                    // System.out.println("abort 9");
2177:                                    return false; // REVISIT
2178:                                }
2179:                                if (isNameTestNCName) {
2180:                                    // System.out.println("abort 10");
2181:                                    return false; // REVISIT - "NCName:* ::" where "AxisName ::" is required
2182:                                }
2183:                                addToken(tokens,
2184:                                        XPath.Tokens.EXPRTOKEN_DOUBLE_COLON);
2185:                                starIsMultiplyOperator = false;
2186:                                if (!isAxisName) {
2187:                                    currentOffset++;
2188:                                    if (++currentOffset == endOffset) {
2189:                                        break;
2190:                                    }
2191:                                }
2192:                                break;
2193:                            }
2194:                            //
2195:                            //  Otherwise, the token must not be recognized as an OperatorName, a NodeType, a
2196:                            //  FunctionName, or an AxisName.
2197:                            //
2198:                            if (isNameTestNCName) {
2199:                                addToken(
2200:                                        tokens,
2201:                                        XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE);
2202:                                starIsMultiplyOperator = true;
2203:                                tokens.addToken(nameHandle);
2204:                            } else {
2205:                                addToken(tokens,
2206:                                        XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME);
2207:                                starIsMultiplyOperator = true;
2208:                                tokens.addToken(prefixHandle);
2209:                                tokens.addToken(nameHandle);
2210:                            }
2211:                            break;
2212:                        }
2213:                    }
2214:                    if (XPath.Tokens.DUMP_TOKENS) {
2215:                        tokens.dumpTokens();
2216:                    }
2217:                    return true;
2218:                }
2219:
2220:                //
2221:                // [5] NCName ::= (Letter | '_') (NCNameChar)*
2222:                // [6] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | CombiningChar | Extender
2223:                //
2224:                int scanNCName(String data, int endOffset, int currentOffset) {
2225:                    int ch = data.charAt(currentOffset);
2226:                    if (ch >= 0x80) {
2227:                        if ((XMLCharacterProperties.fgCharFlags[ch] & XMLCharacterProperties.E_InitialNameCharFlag) == 0) {
2228:                            return currentOffset;
2229:                        }
2230:                    } else {
2231:                        byte chartype = fASCIICharMap[ch];
2232:                        if (chartype != CHARTYPE_LETTER
2233:                                && chartype != CHARTYPE_UNDERSCORE) {
2234:                            return currentOffset;
2235:                        }
2236:                    }
2237:                    while (++currentOffset < endOffset) {
2238:                        ch = data.charAt(currentOffset);
2239:                        if (ch >= 0x80) {
2240:                            if ((XMLCharacterProperties.fgCharFlags[ch] & XMLCharacterProperties.E_NameCharFlag) == 0) {
2241:                                break;
2242:                            }
2243:                        } else {
2244:                            byte chartype = fASCIICharMap[ch];
2245:                            if (chartype != CHARTYPE_LETTER
2246:                                    && chartype != CHARTYPE_DIGIT
2247:                                    && chartype != CHARTYPE_PERIOD
2248:                                    && chartype != CHARTYPE_MINUS
2249:                                    && chartype != CHARTYPE_UNDERSCORE) {
2250:                                break;
2251:                            }
2252:                        }
2253:                    }
2254:                    return currentOffset;
2255:                }
2256:
2257:                /*
2258:                void allocateProducer(byte[] data, int offset, int length, EncodingSupport encoding) {
2259:                    XPathStringProducer sp = fStringProducers[fStringProducerCount];
2260:                    if (sp != null) {
2261:                        sp = sp.setState(data, offset, length, encoding);
2262:                    } else {
2263:                        sp = new XPathStringProducer(data, offset, length, encoding);
2264:                    }
2265:                    fStringProducers[fStringProducerCount++] = sp;
2266:                }
2267:                void finalizeProducer(byte[] data) {
2268:                    fStringProducerCount--;
2269:                }
2270:                class XPathStringProducer {
2271:                    byte[] fData = null;
2272:                    int fOffset = -1;
2273:                    int fLength = -1;
2274:                    String fEncoding = null;
2275:                    XPathStringProducer(byte[] data, int offset, int length, EncodingSupport encoding) {
2276:                        init(data, offset, length, encoding);
2277:                    }
2278:                    XPathStringProducer setState(byte[] bytes, int offset, int length, EncodingSupport encoding) {
2279:                        init(bytes, offset, length, encoding);
2280:                        return this;
2281:                    }
2282:                    void init(byte[] data, int offset, int length, EncodingSupport encoding) {
2283:                        fData = data;
2284:                        fOffset = offset;
2285:                        fLength = length;
2286:                        fEncoding = encoding;
2287:                    }
2288:                    String getEncoding() {
2289:                        return fEncoding;
2290:                    }
2291:                    void finalizeProducer() {
2292:                        // do nothing
2293:                    }
2294:                    int addSymbol(int offset, int length) {
2295:                        return fSymbolTable.addSymbol(fData, offset, length, fEncoding);
2296:                    }
2297:                }
2298:                private XPathStringProducer[] fStringProducers = new XPathStringProducer[8];
2299:                private int fStringProducerCount = 0;
2300:                private XPathStringProducer getStringProducer(byte[] data) {
2301:                    XPathStringProducer sp = null;
2302:                    for (int i = 0; i < fStringProducerCount; i++) {
2303:                        if (fStringProducers[i].fData == data) {
2304:                            return fStringProducers[i];
2305:                        }
2306:                    }
2307:                    throw new RuntimeException("No StringProducer");
2308:                }
2309:                 */
2310:                //
2311:                // [30] Number ::= Digits ('.' Digits?)? | '.' Digits
2312:                // [31] Digits ::= [0-9]+
2313:                //
2314:                private int scanNumber(XPath.Tokens tokens,
2315:                        String/*byte[]*/data, int endOffset, int currentOffset/*, EncodingSupport encoding*/) {
2316:                    /***
2317:                    int ch = (data[currentOffset] & 0xFF);
2318:                    /***/
2319:                    int ch = data.charAt(currentOffset);
2320:                    /***/
2321:                    int whole = 0;
2322:                    int part = 0;
2323:                    while (ch >= '0' && ch <= '9') {
2324:                        whole = (whole * 10) + (ch - '0');
2325:                        if (++currentOffset == endOffset) {
2326:                            break;
2327:                        }
2328:                        /***
2329:                        ch = (data[currentOffset] & 0xFF);
2330:                        /***/
2331:                        ch = data.charAt(currentOffset);
2332:                        /***/
2333:                    }
2334:                    if (ch == '.') {
2335:                        if (++currentOffset < endOffset) {
2336:                            int start = currentOffset;
2337:                            /***
2338:                            ch = (data[currentOffset] & 0xFF);
2339:                            /***/
2340:                            ch = data.charAt(currentOffset);
2341:                            /***/
2342:                            while (ch >= '0' && ch <= '9') {
2343:                                part = (part * 10) + (ch - '0');
2344:                                if (++currentOffset == endOffset) {
2345:                                    break;
2346:                                }
2347:                                /***
2348:                                ch = (data[currentOffset] & 0xFF);
2349:                                /***/
2350:                                ch = data.charAt(currentOffset);
2351:                                /***/
2352:                            }
2353:                            if (part != 0) {
2354:                                /***
2355:                                part = tokens.addSymbol(data, start, currentOffset - start, encoding);
2356:                                /***/
2357:                                throw new RuntimeException("find a solution!");
2358:                                //part = fStringPool.addSymbol(data.substring(start, currentOffset));
2359:                                /***/
2360:                            }
2361:                        }
2362:                    }
2363:                    tokens.addToken(whole);
2364:                    tokens.addToken(part);
2365:                    return currentOffset;
2366:                }
2367:
2368:                /***
2369:                public static SymbolTable getGlobalTokens() {
2370:                    return fgSymbolTable;
2371:                }
2372:
2373:                public static void main(String argv[]) {
2374:                    try {
2375:                        SymbolTable symbols = new SymbolTable(XPathExprScanner.getGlobalTokens());
2376:                        XPath.Tokens tokens = new XPath.Tokens(symbols);
2377:                        byte[] bytes = new byte[1 << 8]; // 256
2378:                        int i = 0;
2379:                        if (XPath.Tokens.DUMP_TOKENS) {
2380:                            System.out.println("<output>");
2381:                            System.out.println();
2382:                        }
2383:                        while (i < argv.length) {
2384:                            String uri = argv[i++];
2385:                            // System.out.println("uri: "+uri);
2386:                            FileInputStream is = new FileInputStream(uri);
2387:                            int lineOffset = 0;
2388:                            int offset = 0;
2389:                            while (true) {
2390:                                int avail = bytes.length - offset;
2391:                                if (avail == 0) {
2392:                                    avail = bytes.length;
2393:                                    byte[] newBytes = new byte[avail << 1];
2394:                                    System.arraycopy(bytes, 0, newBytes, 0, avail);
2395:                                    bytes = newBytes;
2396:                                }
2397:                                int result = is.read(bytes, offset, avail);
2398:                                if (result == -1) {
2399:                                    bytes[offset] = 0;
2400:                                    break;
2401:                                }
2402:                                result += offset;
2403:                                for (int j = offset; j < result; j++) {
2404:                                    int ch = bytes[j];
2405:                                    if (ch == 0x0A || ch == 0x0D) {
2406:                                        if (lineOffset < offset) {
2407:                                            XPathExprScanner.scanExpr(tokens, bytes, lineOffset, offset, UTF8EncodingSupport.getInstance());
2408:                                        }
2409:                                        while (ch == 0x0A || ch == 0x0D) {
2410:                                            if (++j == result) {
2411:                                                j = result;
2412:                                                break;
2413:                                            }
2414:                                            ch = bytes[j];
2415:                                        }
2416:                                        lineOffset = offset;
2417:                                        if (j == result) {
2418:                                            break;
2419:                                        }
2420:                                    }
2421:                                    bytes[offset++] = (byte)ch;
2422:                                }
2423:                            }
2424:                            is.close();
2425:                        }
2426:                        if (XPath.Tokens.DUMP_TOKENS) {
2427:                            System.out.println("</output>");
2428:                        }
2429:                    }
2430:                    catch (Exception e) {
2431:                        e.printStackTrace();
2432:                    }
2433:                }
2434:                /***/
2435:
2436:                //
2437:                // Protected methods
2438:                //
2439:                /**
2440:                 * This method adds the specified token to the token list. By
2441:                 * default, this method allows all tokens. However, subclasses
2442:                 * of the XPathExprScanner can override this method in order
2443:                 * to disallow certain tokens from being used in the scanned
2444:                 * XPath expression. This is a convenient way of allowing only
2445:                 * a subset of XPath.
2446:                 */
2447:                protected void addToken(XPath.Tokens tokens, int token)
2448:                        throws XPathException {
2449:                    tokens.addToken(token);
2450:                } // addToken(int)
2451:
2452:            } // class Scanner
2453:
2454:            /**
2455:             * @author Glenn Marcy, IBM
2456:             * @author Andy Clark, IBM
2457:             *
2458:             * @version $Id: XPath.java,v 1.10 2001/06/08 14:23:49 sandygao Exp $
2459:             */
2460:            /***
2461:            public static class XPathExprParser {
2462:
2463:                //
2464:                // Constants
2465:                //
2466:
2467:                private static final boolean DUMP_PARSE_TREE = false;
2468:
2469:                private static final boolean DEBUG_PUSH_PARSEOPS = false;
2470:
2471:                /** Parse Tree operations * /
2472:                public static final int
2473:                    PARSEOP_OR                              = -5000,
2474:                    PARSEOP_AND                             = -5001,
2475:                    PARSEOP_EQUAL                           = -5002,
2476:                    PARSEOP_NOT_EQUAL                       = -5003,
2477:                    PARSEOP_PLUS                            = -5004,
2478:                    PARSEOP_MINUS                           = -5005,
2479:                    PARSEOP_MULT                            = -5006,
2480:                    PARSEOP_DIV                             = -5007,
2481:                    PARSEOP_MOD                             = -5008,
2482:                    PARSEOP_LESS                            = -5009,
2483:                    PARSEOP_GREATER                         = -5010,
2484:                    PARSEOP_LESS_EQUAL                      = -5011,
2485:                    PARSEOP_GREATER_EQUAL                   = -5012,
2486:                    PARSEOP_NEGATE                          = -5013,
2487:                    PARSEOP_UNION                           = -5014,
2488:                    PARSEOP_SELECT_ROOT                     = -5015,
2489:                    PARSEOP_STEPS                           = -5016,
2490:                    PARSEOP_STEP                            = -5017,
2491:                    PARSEOP_AXIS_ANCESTOR                   = -5018,
2492:                    PARSEOP_AXIS_ANCESTOR_OR_SELF           = -5019,
2493:                    PARSEOP_AXIS_ATTRIBUTE                  = -5020,
2494:                    PARSEOP_AXIS_CHILD                      = -5021,
2495:                    PARSEOP_AXIS_DESCENDANT                 = -5022,
2496:                    PARSEOP_AXIS_DESCENDANT_OR_SELF         = -5023,
2497:                    PARSEOP_AXIS_FOLLOWING                  = -5024,
2498:                    PARSEOP_AXIS_FOLLOWING_SIBLING          = -5025,
2499:                    PARSEOP_AXIS_NAMESPACE                  = -5026,
2500:                    PARSEOP_AXIS_PARENT                     = -5027,
2501:                    PARSEOP_AXIS_PRECEDING                  = -5028,
2502:                    PARSEOP_AXIS_PRECEDING_SIBLING          = -5029,
2503:                    PARSEOP_AXIS_SELF                       = -5030,
2504:                    PARSEOP_NODETEST_ANY                    = -5031,
2505:                    PARSEOP_NODETEST_NAMESPACE              = -5032,
2506:                    PARSEOP_NODETEST_QNAME                  = -5033,
2507:                    PARSEOP_NODETEST_COMMENT                = -5034,
2508:                    PARSEOP_NODETEST_TEXT                   = -5035,
2509:                    PARSEOP_NODETEST_PI                     = -5036,
2510:                    PARSEOP_NODETEST_PI_TARGET              = -5037,
2511:                    PARSEOP_NODETEST_NODE                   = -5038,
2512:                    PARSEOP_FILTER                          = -5039,
2513:                    PARSEOP_PREDICATES                      = -5040,
2514:                    PARSEOP_PREDICATE                       = -5041,
2515:                    PARSEOP_VARIABLE_REFERENCE              = -5042,
2516:                    PARSEOP_GROUPING                        = -5043,
2517:                    PARSEOP_LITERAL                         = -5044,
2518:                    PARSEOP_NUMBER                          = -5045,
2519:                    PARSEOP_FUNCTION                        = -5046,
2520:                    PARSEOP_FUNCTION_NAME                   = -5047,
2521:                    PARSEOP_FUNCTION_ARGUMENTS              = -5048;
2522:
2523:                //
2524:                // Data
2525:                //
2526:
2527:                private int fTokenCount = 0;  // for reading
2528:                private int fCurrentToken = 0;  // for reading
2529:
2530:                private static final int INITIAL_PARSEOP_COUNT = 1 << 8;
2531:                private int[] fParseTree = new int[INITIAL_PARSEOP_COUNT];
2532:                private int fParseOpCount = 0;    // for writing
2533:                private int fCurrentParseOp = 0;  // for reading
2534:
2535:                /** Symbol table. * /
2536:                private SymbolTable fSymbolTable;
2537:
2538:                /** Tokens. * /
2539:                private XPath.Tokens fTokens;
2540:
2541:                /** Scanner. * /
2542:                private XPathExprScanner fScanner;
2543:
2544:                //
2545:                // Constructors
2546:                //
2547:
2548:                public XPathExprParser() {
2549:                    this(new SymbolTable());
2550:                }
2551:
2552:                public XPathExprParser(SymbolTable symbolTable) {
2553:                    this(symbolTable, new XPathExprScanner(symbolTable));
2554:                }
2555:
2556:                public XPathExprParser(SymbolTable symbolTable, XPathExprScanner scanner) {
2557:
2558:                    fSymbolTable = symbolTable;
2559:                    fScanner = scanner;
2560:
2561:                } // <init>(SymbolTable,XPathExprScanner)
2562:
2563:                //
2564:                // Public methods
2565:                //
2566:
2567:                // init
2568:
2569:                public void reset() {
2570:                    fParseOpCount = 0;
2571:                    fCurrentParseOp = 0;
2572:                }
2573:
2574:                // parsing
2575:
2576:                public int parseExpr(String data) throws XPathException {
2577:                    return parseExpr(data, 0, data.length());
2578:                }
2579:
2580:                public int parseExpr(String data, int currentOffset, int endOffset)
2581:                    throws XPathException {
2582:                    return parseExprOrPattern(data, currentOffset, endOffset, false);
2583:                }
2584:
2585:                public int parsePattern(String data, int currentOffset, int endOffset)
2586:                    throws XPathException {
2587:                    return parseExprOrPattern(data, currentOffset, endOffset, true);
2588:                }
2589:
2590:                public int parseExprOrPattern(String data, int currentOffset,
2591:                                              int endOffset, boolean isPattern)
2592:                    throws XPathException {
2593:                    fTokenCount = 0;
2594:
2595:                    if (DUMP_PARSE_TREE) {
2596:                        System.out.println("  <test>");
2597:                        System.out.println("    <expression>");
2598:                        System.out.println("      " + data.substring(currentOffset, endOffset));
2599:                        System.out.println("    </expression>");
2600:                    }
2601:                    fTokens = new XPath.Tokens(fSymbolTable);
2602:                    fScanner.scanExpr(fTokens, data, currentOffset, endOffset);
2603:                    //
2604:                    // Build parse tree
2605:                    //
2606:                    fTokenCount = fTokens.getTokenCount();
2607:                    fCurrentToken = 0;
2608:                    if (!parseExpr()) {
2609:            			// System.out.println("abort 12");
2610:                        return -1; // REVISIT
2611:                    }
2612:                    if (fCurrentToken < fTokenCount) {
2613:            			// System.out.println("abort 13");
2614:                        return -1; // REVISIT
2615:                    }
2616:                    if (DUMP_PARSE_TREE) {
2617:                        dumpParseTree(fCurrentParseOp, 4);
2618:                    }
2619:                    if (DUMP_PARSE_TREE) {
2620:                        System.out.println("  </test>");
2621:                        System.out.println();
2622:                    }
2623:                    return fCurrentParseOp;
2624:                }
2625:
2626:                // parse tree ops
2627:
2628:                public int getCurrentParseOp() {
2629:                    return fCurrentParseOp;
2630:                }
2631:
2632:                public int getParseTreeOp(int handle) {
2633:                    return fParseTree[handle];
2634:                }
2635:
2636:                public int getParseTreeSubHandle(int handle, int subHandleIndex) {
2637:                    return fParseTree[handle - 1 - subHandleIndex];
2638:                }
2639:
2640:                public String getParseTreeSymbol(int handle, int subHandleIndex) {
2641:                    int symHandle = fParseTree[handle - 1 - subHandleIndex];
2642:                    return fTokens.getTokenString(symHandle);
2643:                }
2644:
2645:                public int getParseTreeIntValue(int handle, int subHandleIndex) {
2646:                    return fParseTree[handle - 1 - subHandleIndex];
2647:                }
2648:
2649:                // debugging
2650:
2651:                public void dumpParseTree(int rootParseOp, int indent) {
2652:                        indentPrint(indent);
2653:                        System.out.println("<parse-tree>");
2654:                        dumpParseTreeNode(rootParseOp, indent + 2);
2655:                        indentPrint(indent);
2656:                        System.out.println("</parse-tree>");
2657:                }
2658:
2659:                public String getParseOpName(int parseOp) {
2660:                    switch (parseOp) {
2661:                        case PARSEOP_OR: return "PARSEOP_OR";
2662:                        case PARSEOP_AND: return "PARSEOP_AND";
2663:                        case PARSEOP_EQUAL: return "PARSEOP_EQUAL";
2664:                        case PARSEOP_NOT_EQUAL: return "PARSEOP_NOT_EQUAL";
2665:                        case PARSEOP_PLUS: return "PARSEOP_PLUS";
2666:                        case PARSEOP_MINUS: return "PARSEOP_MINUS";
2667:                        case PARSEOP_MULT: return "PARSEOP_MULT";
2668:                        case PARSEOP_DIV: return "PARSEOP_DIV";
2669:                        case PARSEOP_MOD: return "PARSEOP_MOD";
2670:                        case PARSEOP_LESS: return "PARSEOP_LESS";
2671:                        case PARSEOP_GREATER: return "PARSEOP_GREATER";
2672:                        case PARSEOP_LESS_EQUAL: return "PARSEOP_LESS_EQUAL";
2673:                        case PARSEOP_GREATER_EQUAL: return "PARSEOP_GREATER_EQUAL";
2674:                        case PARSEOP_NEGATE: return "PARSEOP_NEGATE";
2675:                        case PARSEOP_UNION: return "PARSEOP_UNION";
2676:                        case PARSEOP_SELECT_ROOT: return "PARSEOP_SELECT_ROOT";
2677:                        case PARSEOP_STEPS: return "PARSEOP_STEPS";
2678:                        case PARSEOP_STEP: return "PARSEOP_STEP";
2679:                        case PARSEOP_AXIS_ANCESTOR: return "PARSEOP_AXIS_ANCESTOR";
2680:                        case PARSEOP_AXIS_ANCESTOR_OR_SELF: return "PARSEOP_AXIS_ANCESTOR_OR_SELF";
2681:                        case PARSEOP_AXIS_ATTRIBUTE: return "PARSEOP_AXIS_ATTRIBUTE";
2682:                        case PARSEOP_AXIS_CHILD: return "PARSEOP_AXIS_CHILD";
2683:                        case PARSEOP_AXIS_DESCENDANT: return "PARSEOP_AXIS_DESCENDANT";
2684:                        case PARSEOP_AXIS_DESCENDANT_OR_SELF: return "PARSEOP_AXIS_DESCENDANT_OR_SELF";
2685:                        case PARSEOP_AXIS_FOLLOWING: return "PARSEOP_AXIS_FOLLOWING";
2686:                        case PARSEOP_AXIS_FOLLOWING_SIBLING: return "PARSEOP_AXIS_FOLLOWING_SIBLING";
2687:                        case PARSEOP_AXIS_NAMESPACE: return "PARSEOP_AXIS_NAMESPACE";
2688:                        case PARSEOP_AXIS_PARENT: return "PARSEOP_AXIS_PARENT";
2689:                        case PARSEOP_AXIS_PRECEDING: return "PARSEOP_AXIS_PRECEDING";
2690:                        case PARSEOP_AXIS_PRECEDING_SIBLING: return "PARSEOP_AXIS_PRECEDING_SIBLING";
2691:                        case PARSEOP_AXIS_SELF: return "PARSEOP_AXIS_SELF";
2692:                        case PARSEOP_NODETEST_ANY: return "PARSEOP_NODETEST_ANY";
2693:                        case PARSEOP_NODETEST_NAMESPACE: return "PARSEOP_NODETEST_NAMESPACE";
2694:                        case PARSEOP_NODETEST_QNAME: return "PARSEOP_NODETEST_QNAME";
2695:                        case PARSEOP_NODETEST_COMMENT: return "PARSEOP_NODETEST_COMMENT";
2696:                        case PARSEOP_NODETEST_TEXT: return "PARSEOP_NODETEST_TEXT";
2697:                        case PARSEOP_NODETEST_PI: return "PARSEOP_NODETEST_PI";
2698:                        case PARSEOP_NODETEST_PI_TARGET: return "PARSEOP_NODETEST_PI_TARGET";
2699:                        case PARSEOP_NODETEST_NODE: return "PARSEOP_NODETEST_NODE";
2700:                        case PARSEOP_FILTER: return "PARSEOP_FILTER";
2701:                        case PARSEOP_PREDICATES: return "PARSEOP_PREDICATES";
2702:                        case PARSEOP_PREDICATE: return "PARSEOP_PREDICATE";
2703:                        case PARSEOP_VARIABLE_REFERENCE: return "PARSEOP_VARIABLE_REFERENCE";
2704:                        case PARSEOP_GROUPING: return "PARSEOP_GROUPING";
2705:                        case PARSEOP_LITERAL: return "PARSEOP_LITERAL";
2706:                        case PARSEOP_NUMBER: return "PARSEOP_NUMBER";
2707:                        case PARSEOP_FUNCTION: return "PARSEOP_FUNCTION";
2708:                        case PARSEOP_FUNCTION_NAME: return "PARSEOP_FUNCTION_NAME";
2709:                        case PARSEOP_FUNCTION_ARGUMENTS: return "PARSEOP_FUNCTION_ARGUMENTS";
2710:                    }
2711:                    return "??? ("+parseOp+')';
2712:                }
2713:
2714:                //
2715:                // Protected methods
2716:                //
2717:
2718:                protected void checkParseOp(int parseOp) throws XPathException {
2719:                    // do nothing; all parse ops allowed in the class
2720:                }
2721:
2722:                //
2723:                // Private methods
2724:                //
2725:
2726:                private void pushParseOp(int parseOp) throws XPathException {
2727:                    if (DEBUG_PUSH_PARSEOPS) {
2728:                        System.out.println("pushParseOp: "+getParseOpName(parseOp));
2729:                    }
2730:                    checkParseOp(parseOp);
2731:                    try {
2732:                        fParseTree[fParseOpCount] = parseOp;
2733:                    } catch (ArrayIndexOutOfBoundsException ex) {
2734:                        int[] oldList = fParseTree;
2735:                        fParseTree = new int[fParseOpCount << 1];
2736:                        System.arraycopy(oldList, 0, fParseTree, 0, fParseOpCount);
2737:                        fParseTree[fParseOpCount] = parseOp;
2738:                    }
2739:                    fCurrentParseOp = fParseOpCount++;
2740:                }
2741:
2742:                private void pushParseOp2(int parseOp, int arg) throws XPathException {
2743:                    if (DEBUG_PUSH_PARSEOPS) {
2744:                        System.out.println("pushParseOp2: "+getParseOpName(parseOp)+", "+arg);
2745:                    }
2746:                    checkParseOp(parseOp);
2747:                    try {
2748:                        fParseTree[fParseOpCount + 1] = parseOp;
2749:                    } catch (ArrayIndexOutOfBoundsException ex) {
2750:                        int[] oldList = fParseTree;
2751:                        fParseTree = new int[fParseOpCount << 1];
2752:                        System.arraycopy(oldList, 0, fParseTree, 0, fParseOpCount);
2753:                        fParseTree[fParseOpCount + 1] = parseOp;
2754:                    }
2755:                    fParseTree[fParseOpCount++] = arg;
2756:                    fCurrentParseOp = fParseOpCount++;
2757:                }
2758:
2759:                private void pushParseOp3(int parseOp, int arg1, int arg2)
2760:                    throws XPathException {
2761:                    if (DEBUG_PUSH_PARSEOPS) {
2762:                        System.out.println("pushParseOp3: "+getParseOpName(parseOp)+", "+arg1+", "+arg2);
2763:                    }
2764:                    checkParseOp(parseOp);
2765:                    try {
2766:                        fParseTree[fParseOpCount + 2] = parseOp;
2767:                    } catch (ArrayIndexOutOfBoundsException ex) {
2768:                        int[] oldList = fParseTree;
2769:                        fParseTree = new int[fParseOpCount << 1];
2770:                        System.arraycopy(oldList, 0, fParseTree, 0, fParseOpCount);
2771:                        fParseTree[fParseOpCount + 2] = parseOp;
2772:                    }
2773:                    fParseTree[fParseOpCount++] = arg2;
2774:                    fParseTree[fParseOpCount++] = arg1;
2775:                    fCurrentParseOp = fParseOpCount++;
2776:                }
2777:
2778:                private void indentPrint(int indent) {
2779:                    for (int i = 0; i < indent; i++) {
2780:                        System.out.print(" ");
2781:                    }
2782:                }
2783:
2784:                private void dumpParseTreeNode(int parseOp, int indent) {
2785:                        switch (fParseTree[parseOp]) {
2786:                        case PARSEOP_OR:
2787:                            indentPrint(indent);
2788:                            System.out.println("<or>");
2789:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2790:                            dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2791:                            indentPrint(indent);
2792:                            System.out.println("</or>");
2793:                            break;
2794:                        case PARSEOP_AND:
2795:                            indentPrint(indent);
2796:                            System.out.println("<and>");
2797:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2798:                            dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2799:                            indentPrint(indent);
2800:                            System.out.println("</and>");
2801:                            break;
2802:                        case PARSEOP_EQUAL:
2803:                            indentPrint(indent);
2804:                            System.out.println("<equal>");
2805:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2806:                            dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2807:                            indentPrint(indent);
2808:                            System.out.println("</equal>");
2809:                            break;
2810:                        case PARSEOP_NOT_EQUAL:
2811:                            indentPrint(indent);
2812:                            System.out.println("<not-equal>");
2813:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2814:                            dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2815:                            indentPrint(indent);
2816:                            System.out.println("</not-equal>");
2817:                            break;
2818:                        case PARSEOP_PLUS:
2819:                            indentPrint(indent);
2820:                            System.out.println("<plus>");
2821:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2822:                            dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2823:                            indentPrint(indent);
2824:                            System.out.println("</plus>");
2825:                            break;
2826:                        case PARSEOP_MINUS:
2827:                            indentPrint(indent);
2828:                            System.out.println("<minus>");
2829:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2830:                            dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2831:                            indentPrint(indent);
2832:                            System.out.println("</minus>");
2833:                            break;
2834:                        case PARSEOP_MULT:
2835:                            indentPrint(indent);
2836:                            System.out.println("<mult>");
2837:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2838:                            dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2839:                            indentPrint(indent);
2840:                            System.out.println("</mult>");
2841:                            break;
2842:                        case PARSEOP_DIV:
2843:                            indentPrint(indent);
2844:                            System.out.println("<div>");
2845:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2846:                            dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2847:                            indentPrint(indent);
2848:                            System.out.println("</div>");
2849:                            break;
2850:                        case PARSEOP_MOD:
2851:                            indentPrint(indent);
2852:                            System.out.println("<mod>");
2853:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2854:                            dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2855:                            indentPrint(indent);
2856:                            System.out.println("</mod>");
2857:                            break;
2858:                        case PARSEOP_LESS:
2859:                            indentPrint(indent);
2860:                            System.out.println("<less>");
2861:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2862:                            dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2863:                            indentPrint(indent);
2864:                            System.out.println("</less>");
2865:                            break;
2866:                        case PARSEOP_GREATER:
2867:                            indentPrint(indent);
2868:                            System.out.println("<greater>");
2869:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2870:                            dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2871:                            indentPrint(indent);
2872:                            System.out.println("</greater>");
2873:                            break;
2874:                        case PARSEOP_LESS_EQUAL:
2875:                            indentPrint(indent);
2876:                            System.out.println("<less-equal>");
2877:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2878:                            dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2879:                            indentPrint(indent);
2880:                            System.out.println("</less-equal>");
2881:                            break;
2882:                        case PARSEOP_GREATER_EQUAL:
2883:                            indentPrint(indent);
2884:                            System.out.println("<greater-equal>");
2885:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2886:                            dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2887:                            indentPrint(indent);
2888:                            System.out.println("</greater-equal>");
2889:                            break;
2890:                        case PARSEOP_NEGATE:
2891:                            indentPrint(indent);
2892:                            System.out.println("<negate>");
2893:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2894:                            indentPrint(indent);
2895:                            System.out.println("</negate>");
2896:                            break;
2897:                        case PARSEOP_UNION:
2898:                            indentPrint(indent);
2899:                            System.out.println("<union>");
2900:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2901:                            dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2902:                            indentPrint(indent);
2903:                            System.out.println("</union>");
2904:                            break;
2905:                        case PARSEOP_SELECT_ROOT:
2906:                            indentPrint(indent);
2907:                            if (fParseTree[parseOp - 1] == -1) {
2908:                                System.out.println("<select-root/>");
2909:                            } else {
2910:                                System.out.println("<select-root>");
2911:                                dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2912:                                indentPrint(indent);
2913:                                System.out.println("</select-root>");
2914:                            }
2915:                            break;
2916:                        case PARSEOP_STEPS:
2917:                            indentPrint(indent);
2918:                            System.out.println("<relative-location-path>");
2919:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2920:                            dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2921:                            indentPrint(indent);
2922:                            System.out.println("</relative-location-path>");
2923:                            break;
2924:                        case PARSEOP_STEP:
2925:                            indentPrint(indent);
2926:                            System.out.println("<step>");
2927:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2928:                            dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2929:                            indentPrint(indent);
2930:                            System.out.println("</step>");
2931:                            break;
2932:                        case PARSEOP_AXIS_ANCESTOR:
2933:                            indentPrint(indent);
2934:                            System.out.println("<axis name=\"ancestor\"/>");
2935:                            break;
2936:                        case PARSEOP_AXIS_ANCESTOR_OR_SELF:
2937:                            indentPrint(indent);
2938:                            System.out.println("<axis name=\"ancestor-or-self\"/>");
2939:                            break;
2940:                        case PARSEOP_AXIS_ATTRIBUTE:
2941:                            indentPrint(indent);
2942:                            System.out.println("<axis name=\"attribute\"/>");
2943:                            break;
2944:                        case PARSEOP_AXIS_CHILD:
2945:                            indentPrint(indent);
2946:                            System.out.println("<axis name=\"child\"/>");
2947:                            break;
2948:                        case PARSEOP_AXIS_DESCENDANT:
2949:                            indentPrint(indent);
2950:                            System.out.println("<axis name=\"descendant\"/>");
2951:                            break;
2952:                        case PARSEOP_AXIS_DESCENDANT_OR_SELF:
2953:                            indentPrint(indent);
2954:                            System.out.println("<axis name=\"descendant-or-self\"/>");
2955:                            break;
2956:                        case PARSEOP_AXIS_FOLLOWING:
2957:                            indentPrint(indent);
2958:                            System.out.println("<axis name=\"following\"/>");
2959:                            break;
2960:                        case PARSEOP_AXIS_FOLLOWING_SIBLING:
2961:                            indentPrint(indent);
2962:                            System.out.println("<axis name=\"following-sibling\"/>");
2963:                            break;
2964:                        case PARSEOP_AXIS_NAMESPACE:
2965:                            indentPrint(indent);
2966:                            System.out.println("<axis name=\"namespace\"/>");
2967:                            break;
2968:                        case PARSEOP_AXIS_PARENT:
2969:                            indentPrint(indent);
2970:                            System.out.println("<axis name=\"parent\"/>");
2971:                            break;
2972:                        case PARSEOP_AXIS_PRECEDING:
2973:                            indentPrint(indent);
2974:                            System.out.println("<axis name=\"preceding\"/>");
2975:                            break;
2976:                        case PARSEOP_AXIS_PRECEDING_SIBLING:
2977:                            indentPrint(indent);
2978:                            System.out.println("<axis name=\"preceding-sibling\"/>");
2979:                            break;
2980:                        case PARSEOP_AXIS_SELF:
2981:                            indentPrint(indent);
2982:                            System.out.println("<axis name=\"self\"/>");
2983:                            break;
2984:                        case PARSEOP_NODETEST_ANY:
2985:                            indentPrint(indent);
2986:                            System.out.println("<nodetest type=\"any\"/>");
2987:                            break;
2988:                        case PARSEOP_NODETEST_NAMESPACE:
2989:                            indentPrint(indent);
2990:                            System.out.print("<nodetest type=\"namespace\"");
2991:                            System.out.print(" prefix=\"" + fParseTree[parseOp - 1] + "\"");
2992:                            System.out.println("/>");
2993:                            break;
2994:                        case PARSEOP_NODETEST_QNAME:
2995:                            indentPrint(indent);
2996:                            System.out.print("<nodetest type=\"qname\"");
2997:                            if (fParseTree[parseOp - 1] != -1) {
2998:                                System.out.print(" prefix=\"" + fParseTree[parseOp - 1] + "\"");
2999:                            }
3000:                            System.out.print(" localpart=\"" + fParseTree[parseOp - 2] + "\"");
3001:                            System.out.println("/>");
3002:                            break;
3003:                        case PARSEOP_NODETEST_COMMENT:
3004:                            indentPrint(indent);
3005:                            System.out.println("<nodetest type=\"comment\"/>");
3006:                            break;
3007:                        case PARSEOP_NODETEST_TEXT:
3008:                            indentPrint(indent);
3009:                            System.out.println("<nodetest type=\"text\"/>");
3010:                            break;
3011:                        case PARSEOP_NODETEST_PI:
3012:                            indentPrint(indent);
3013:                            System.out.println("<nodetest type=\"processing-instruction\"/>");
3014:                            break;
3015:                        case PARSEOP_NODETEST_PI_TARGET:
3016:                            indentPrint(indent);
3017:                            System.out.print("<nodetest type=\"processing-instruction\" target=\"");
3018:                            System.out.print(fParseTree[parseOp - 1]);
3019:                            System.out.println("\"/>");
3020:                            break;
3021:                        case PARSEOP_NODETEST_NODE:
3022:                            indentPrint(indent);
3023:                            System.out.println("<nodetest type=\"node\"/>");
3024:                            break;
3025:                        case PARSEOP_FILTER:
3026:                            indentPrint(indent);
3027:                            System.out.println("<step-with-predicate>");
3028:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
3029:                            dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
3030:                            indentPrint(indent);
3031:                            System.out.println("</step-with-predicate>");
3032:                            break;
3033:                        case PARSEOP_PREDICATES:
3034:                            indentPrint(indent);
3035:                            System.out.println("<predicates>");
3036:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
3037:                            dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
3038:                            indentPrint(indent);
3039:                            System.out.println("</predicates>");
3040:                            break;
3041:                        case PARSEOP_PREDICATE:
3042:                            indentPrint(indent);
3043:                            System.out.println("<predicate>");
3044:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
3045:                            indentPrint(indent);
3046:                            System.out.println("</predicate>");
3047:                            break;
3048:                        case PARSEOP_VARIABLE_REFERENCE:
3049:                            indentPrint(indent);
3050:                            System.out.print("<variable-reference");
3051:                            if (fParseTree[parseOp - 1] != -1) {
3052:                                System.out.print(" prefix=\"" + fParseTree[parseOp - 1] + "\"");
3053:                            }
3054:                            System.out.print(" localpart=\"" + fParseTree[parseOp - 2] + "\"");
3055:                            System.out.println("/>");
3056:                            break;
3057:                        case PARSEOP_GROUPING:
3058:                            indentPrint(indent);
3059:                            System.out.println("<grouping>");
3060:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
3061:                            indentPrint(indent);
3062:                            System.out.println("</grouping>");
3063:                            break;
3064:                        case PARSEOP_LITERAL:
3065:                            indentPrint(indent);
3066:                            System.out.print("<literal");
3067:                            System.out.print(" value=\"" + fParseTree[parseOp - 1] + "\"");
3068:                            System.out.println("/>");
3069:                            break;
3070:                        case PARSEOP_NUMBER:
3071:                            indentPrint(indent);
3072:                            System.out.print("<number");
3073:                            System.out.print(" whole=\"" + fParseTree[parseOp - 1] + "\"");
3074:                            System.out.print(" part=\"" + fParseTree[parseOp - 2] + "\"");
3075:                            System.out.println("/>");
3076:                            break;
3077:                        case PARSEOP_FUNCTION:
3078:                            indentPrint(indent);
3079:                            System.out.println("<function-call>");
3080:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
3081:                            if (fParseTree[parseOp - 2] != -1) {
3082:                                dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
3083:                            }
3084:                            indentPrint(indent);
3085:                            System.out.println("</function-call>");
3086:                            break;
3087:                        case PARSEOP_FUNCTION_NAME:
3088:                            indentPrint(indent);
3089:                            System.out.print("<function-name");
3090:                            if (fParseTree[parseOp - 1] != -1) {
3091:                                System.out.print(" prefix=\"" + fParseTree[parseOp - 1] + "\"");
3092:                            }
3093:                            System.out.print(" localpart=\"" + fParseTree[parseOp - 2] + "\"");
3094:                            System.out.println("/>");
3095:                            break;
3096:                        case PARSEOP_FUNCTION_ARGUMENTS:
3097:                            indentPrint(indent);
3098:                            System.out.println("<function-args>");
3099:                            dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
3100:                            dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
3101:                            indentPrint(indent);
3102:                            System.out.println("</function-args>");
3103:                            break;
3104:                        default:
3105:                            throw new RuntimeException("dumpParseTreeNode("+parseOp+")");
3106:                        }
3107:                }
3108:
3109:                //
3110:                // Package methods
3111:                //
3112:
3113:                /**
3114:             * [14] Expr ::= OrExpr
3115:             * /
3116:                boolean parseExpr() throws XPathException {
3117:                    return parseOrExpr();
3118:                }
3119:
3120:                /**
3121:             * [21] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
3122:             *
3123:             * also: OrExpr ::= (AndExpr 'or')* AndExpr
3124:             * /
3125:                boolean parseOrExpr() throws XPathException {
3126:                    if (!parseAndExpr()) {
3127:                        return false;
3128:                    }
3129:                    while (fCurrentToken < fTokenCount) {
3130:                        if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_OPERATOR_OR) {
3131:                            break;
3132:                        }
3133:                        int saveToken = fCurrentToken;
3134:                        int saveParseOp = fCurrentParseOp;
3135:                        int left = fCurrentParseOp;
3136:                        if (++fCurrentToken == fTokenCount) {
3137:                            fCurrentToken = saveToken;
3138:                            fCurrentParseOp = saveParseOp;
3139:                            return true;
3140:                        }
3141:                        if (!parseAndExpr()) {
3142:                            fCurrentToken = saveToken;
3143:                            fCurrentParseOp = saveParseOp;
3144:                            return true;
3145:                        }
3146:                        int right = fCurrentParseOp;
3147:                        pushParseOp3(PARSEOP_OR, left, right);
3148:                    }
3149:                    return true;
3150:                }
3151:
3152:                /**
3153:             * [22] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
3154:             * /
3155:                boolean parseAndExpr() throws XPathException {
3156:                    if (!parseEqualityExpr()) {
3157:                        return false;
3158:                    }
3159:                    while (fCurrentToken < fTokenCount) {
3160:                        if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_OPERATOR_AND) {
3161:                            break;
3162:                        }
3163:                        int saveToken = fCurrentToken;
3164:                        int saveParseOp = fCurrentParseOp;
3165:                        int left = fCurrentParseOp;
3166:                        if (++fCurrentToken == fTokenCount) {
3167:                            fCurrentToken = saveToken;
3168:                            fCurrentParseOp = saveParseOp;
3169:                            return true;
3170:                        }
3171:                        if (!parseEqualityExpr()) {
3172:                            fCurrentToken = saveToken;
3173:                            fCurrentParseOp = saveParseOp;
3174:                            return true;
3175:                        }
3176:                        int right = fCurrentParseOp;
3177:                        pushParseOp3(PARSEOP_AND, left, right);
3178:                    }
3179:                    return true;
3180:                }
3181:
3182:                /**
3183:             * [23] EqualityExpr ::= RelationalExpr
3184:             *                     | EqualityExpr '=' RelationalExpr
3185:             *                     | EqualityExpr '!=' RelationalExpr
3186:             * /
3187:                boolean parseEqualityExpr() throws XPathException {
3188:                    if (!parseRelationalExpr()) {
3189:                        return false;
3190:                    }
3191:                    while (fCurrentToken < fTokenCount) {
3192:                        int parseOp;
3193:                        if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_EQUAL) {
3194:                            parseOp = PARSEOP_EQUAL;
3195:                        } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_NOT_EQUAL) {
3196:                            parseOp = PARSEOP_NOT_EQUAL;
3197:                        } else {
3198:                            break;
3199:                        }
3200:                        int saveToken = fCurrentToken;
3201:                        int saveParseOp = fCurrentParseOp;
3202:                        int left = fCurrentParseOp;
3203:                        if (++fCurrentToken == fTokenCount) {
3204:                            fCurrentToken = saveToken;
3205:                            fCurrentParseOp = saveParseOp;
3206:                            return true;
3207:                        }
3208:                        if (!parseRelationalExpr()) {
3209:                            fCurrentToken = saveToken;
3210:                            fCurrentParseOp = saveParseOp;
3211:                            return true;
3212:                        }
3213:                        int right = fCurrentParseOp;
3214:                        pushParseOp3(parseOp, left, right);
3215:                    }
3216:                    return true;
3217:                }
3218:
3219:                /**
3220:             * [24] RelationalExpr ::= AdditiveExpr
3221:             *                       | RelationalExpr '<' AdditiveExpr
3222:             *                       | RelationalExpr '>' AdditiveExpr
3223:             *                       | RelationalExpr '<=' AdditiveExpr
3224:             *                       | RelationalExpr '>=' AdditiveExpr
3225:             * /
3226:                boolean parseRelationalExpr() throws XPathException {
3227:                    if (!parseAdditiveExpr()) {
3228:                        return false;
3229:                    }
3230:                    while (fCurrentToken < fTokenCount) {
3231:                        int parseOp;
3232:                        if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_LESS) {
3233:                            parseOp = PARSEOP_LESS;
3234:                        } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_GREATER) {
3235:                            parseOp = PARSEOP_GREATER;
3236:                        } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_LESS_EQUAL) {
3237:                            parseOp = PARSEOP_LESS_EQUAL;
3238:                        } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_GREATER_EQUAL) {
3239:                            parseOp = PARSEOP_GREATER_EQUAL;
3240:                        } else {
3241:                            break;
3242:                        }
3243:                        int saveToken = fCurrentToken;
3244:                        int saveParseOp = fCurrentParseOp;
3245:                        int left = fCurrentParseOp;
3246:                        if (++fCurrentToken == fTokenCount) {
3247:                            fCurrentToken = saveToken;
3248:                            fCurrentParseOp = saveParseOp;
3249:                            return true;
3250:                        }
3251:                        if (!parseAdditiveExpr()) {
3252:                            fCurrentToken = saveToken;
3253:                            fCurrentParseOp = saveParseOp;
3254:                            return true;
3255:                        }
3256:                        int right = fCurrentParseOp;
3257:                        pushParseOp3(parseOp, left, right);
3258:                    }
3259:                    return true;
3260:                }
3261:
3262:                /**
3263:             * [25] AdditiveExpr ::= MultiplicativeExpr
3264:             *                     | AdditiveExpr '+' MultiplicativeExpr
3265:             *                     | AdditiveExpr '-' MultiplicativeExpr
3266:             * /
3267:                boolean parseAdditiveExpr() throws XPathException {
3268:                    if (!parseMultiplicativeExpr()) {
3269:                        return false;
3270:                    }
3271:                    while (fCurrentToken < fTokenCount) {
3272:                        int parseOp;
3273:                        if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_PLUS) {
3274:                            parseOp = PARSEOP_PLUS;
3275:                        } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_MINUS) {
3276:                            parseOp = PARSEOP_MINUS;
3277:                        } else {
3278:                            break;
3279:                        }
3280:                        int saveToken = fCurrentToken;
3281:                        int saveParseOp = fCurrentParseOp;
3282:                        int left = fCurrentParseOp;
3283:                        if (++fCurrentToken == fTokenCount) {
3284:                            fCurrentToken = saveToken;
3285:                            fCurrentParseOp = saveParseOp;
3286:                            return true;
3287:                        }
3288:                        if (!parseMultiplicativeExpr()) {
3289:                            fCurrentToken = saveToken;
3290:                            fCurrentParseOp = saveParseOp;
3291:                            return true;
3292:                        }
3293:                        int right = fCurrentParseOp;
3294:                        pushParseOp3(parseOp, left, right);
3295:                    }
3296:                    return true;
3297:                }
3298:
3299:                /**
3300:             * [26] MultiplicativeExpr ::= UnaryExpr
3301:             *                           | MultiplicativeExpr MultiplyOperator UnaryExpr
3302:             *                           | MultiplicativeExpr 'div' UnaryExpr
3303:             *                           | MultiplicativeExpr 'mod' UnaryExpr
3304:             * [34] MultiplyOperator ::= '*'
3305:             * /
3306:                boolean parseMultiplicativeExpr() throws XPathException {
3307:                    if (!parseUnaryExpr()) {
3308:                        return false;
3309:                    }
3310:                    while (fCurrentToken < fTokenCount) {
3311:                        int parseOp;
3312:                        if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_MULT) {
3313:                            parseOp = PARSEOP_MULT;
3314:                        } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_DIV) {
3315:                            parseOp = PARSEOP_DIV;
3316:                        } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_MOD) {
3317:                            parseOp = PARSEOP_MOD;
3318:                        } else {
3319:                            break;
3320:                        }
3321:                        int saveToken = fCurrentToken;
3322:                        int saveParseOp = fCurrentParseOp;
3323:                        int left = fCurrentParseOp;
3324:                        if (++fCurrentToken == fTokenCount) {
3325:                            fCurrentToken = saveToken;
3326:                            fCurrentParseOp = saveParseOp;
3327:                            return true;
3328:                        }
3329:                        if (!parseUnaryExpr()) {
3330:                            fCurrentToken = saveToken;
3331:                            fCurrentParseOp = saveParseOp;
3332:                            return true;
3333:                        }
3334:                        int right = fCurrentParseOp;
3335:                        pushParseOp3(parseOp, left, right);
3336:                    }
3337:                    return true;
3338:                }
3339:
3340:                /**
3341:             * [27] UnaryExpr ::= UnionExpr | '-' UnaryExpr
3342:             *
3343:             * Note: "--UnionExpr" == "-(-UnionExpr)"
3344:             * /
3345:                boolean parseUnaryExpr() throws XPathException {
3346:                    if (parseUnionExpr()) {
3347:                        return true;
3348:                    }
3349:                    int saveToken = fCurrentToken;
3350:                    boolean negate = false;
3351:                    while (fCurrentToken < fTokenCount) {
3352:                        if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_OPERATOR_MINUS) {
3353:                            break;
3354:                        }
3355:                        fCurrentToken++;
3356:                        negate = !negate;
3357:                    }
3358:                    if (fCurrentToken == fTokenCount) {
3359:                        fCurrentToken = saveToken;
3360:                        return false;
3361:                    }
3362:                    if (!parseUnionExpr()) {
3363:                        fCurrentToken = saveToken;
3364:                        return false;
3365:                    }
3366:                    if (negate) {
3367:                        pushParseOp2(PARSEOP_NEGATE, fCurrentParseOp);
3368:                    }
3369:                    return true;
3370:                }
3371:
3372:                /**
3373:             * [18] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
3374:             * /
3375:                boolean parseUnionExpr() throws XPathException {
3376:                    if (!parsePathExpr()) {
3377:                        return false;
3378:                    }
3379:                    while (fCurrentToken < fTokenCount) {
3380:                        if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_OPERATOR_UNION) {
3381:                            break;
3382:                        }
3383:                        int saveToken = fCurrentToken;
3384:                        int saveParseOp = fCurrentParseOp;
3385:                        int left = fCurrentParseOp;
3386:                        if (++fCurrentToken == fTokenCount) {
3387:                            fCurrentToken = saveToken;
3388:                            fCurrentParseOp = saveParseOp;
3389:                            return true;
3390:                        }
3391:                        if (!parsePathExpr()) {
3392:                            fCurrentToken = saveToken;
3393:                            fCurrentParseOp = saveParseOp;
3394:                            return true;
3395:                        }
3396:                        int right = fCurrentParseOp;
3397:                        pushParseOp3(PARSEOP_UNION, left, right);
3398:                    }
3399:                    return true;
3400:                }
3401:
3402:                /**
3403:             * [19] PathExpr ::= RelativeLocationPath
3404:             *                 | '/' RelativeLocationPath?
3405:             *                 | '//' RelativeLocationPath
3406:             *                 | PrimaryExpr Predicate*
3407:             *                 | PrimaryExpr Predicate* '/' RelativeLocationPath
3408:             *                 | PrimaryExpr Predicate* '//' RelativeLocationPath
3409:             * /
3410:                boolean parsePathExpr() throws XPathException {
3411:                    if (parseRelativeLocationPath()) {
3412:                        return true;
3413:                    } else {
3414:                        if (fCurrentToken == fTokenCount) {
3415:                            return false;
3416:                        }
3417:                        if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH) {
3418:                            if (++fCurrentToken < fTokenCount && parseRelativeLocationPath()) {
3419:                                pushParseOp2(PARSEOP_SELECT_ROOT, fCurrentParseOp);
3420:                            } else {
3421:                                pushParseOp2(PARSEOP_SELECT_ROOT, -1);
3422:                            }
3423:                            return true;
3424:                        } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH) {
3425:                            if (++fCurrentToken == fTokenCount) {
3426:                                return false; // REVISIT - backup index
3427:                            }
3428:                            if (!parseRelativeLocationPath()) {
3429:                                return false;
3430:                            }
3431:                            int left = fCurrentParseOp;
3432:                            pushParseOp(PARSEOP_AXIS_DESCENDANT_OR_SELF);
3433:                            int left2 = fCurrentParseOp;
3434:                            pushParseOp(PARSEOP_NODETEST_NODE);
3435:                            pushParseOp3(PARSEOP_STEP, left2, fCurrentParseOp);
3436:                            pushParseOp3(PARSEOP_STEPS, fCurrentParseOp, left);
3437:                            pushParseOp2(PARSEOP_SELECT_ROOT, fCurrentParseOp);
3438:                            return true;
3439:                        }
3440:                    }
3441:                    if (!parsePrimaryExpr()) {
3442:                        return false;
3443:                    }
3444:                    int left = fCurrentParseOp;
3445:                    if (parsePredicates()) {
3446:                        pushParseOp3(PARSEOP_FILTER, left, fCurrentParseOp);
3447:                    }
3448:                    if (fCurrentToken == fTokenCount) {
3449:                        return true;
3450:                    }
3451:                    left = fCurrentParseOp;
3452:                    if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH) {
3453:                        if (++fCurrentToken == fTokenCount) {
3454:                            return false; // REVISIT
3455:                        }
3456:                        if (!parseRelativeLocationPath()) {
3457:                            return false; // REVISIT
3458:                        }
3459:                        pushParseOp3(PARSEOP_STEPS, left, fCurrentParseOp);
3460:                    } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH) {
3461:                        if (++fCurrentToken == fTokenCount) {
3462:                            return false;
3463:                        }
3464:                        if (!parseRelativeLocationPath()) {
3465:                            return false;
3466:                        }
3467:                        int left2 = fCurrentParseOp;
3468:                        pushParseOp(PARSEOP_AXIS_DESCENDANT_OR_SELF);
3469:                        int left3 = fCurrentParseOp;
3470:                        pushParseOp(PARSEOP_NODETEST_NODE);
3471:                        pushParseOp3(PARSEOP_STEP, left3, fCurrentParseOp);
3472:                        pushParseOp3(PARSEOP_STEPS, fCurrentParseOp, left2);
3473:                        pushParseOp3(PARSEOP_STEPS, left, fCurrentParseOp);
3474:                    }
3475:                    return true;
3476:                }
3477:
3478:                /**
3479:             * [3] RelativeLocationPath ::= Step
3480:             *                            | RelativeLocationPath '/' Step
3481:             *                            | RelativeLocationPath '//' Step
3482:             * /
3483:                boolean parseRelativeLocationPath() throws XPathException {
3484:                    if (!parseStep()) {
3485:                        return false;
3486:                    }
3487:                    while (fCurrentToken < fTokenCount) {
3488:                        boolean descendantOrSelf;
3489:                        if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH) {
3490:                            descendantOrSelf = false;
3491:                        } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH) {
3492:                            descendantOrSelf = true;
3493:                        } else {
3494:                            break;
3495:                        }
3496:                        int saveToken = fCurrentToken;
3497:                        int saveParseOp = fCurrentParseOp;
3498:                        int left = fCurrentParseOp;
3499:                        if (++fCurrentToken == fTokenCount) {
3500:                            fCurrentToken = saveToken;
3501:                            fCurrentParseOp = saveParseOp;
3502:                            return true;
3503:                        }
3504:                        if (!parseStep()) {
3505:                            fCurrentToken = saveToken;
3506:                            fCurrentParseOp = saveParseOp;
3507:                            return true;
3508:                        }
3509:                        if (descendantOrSelf) {
3510:                            int left2 = fCurrentParseOp;
3511:                            pushParseOp(PARSEOP_AXIS_DESCENDANT_OR_SELF);
3512:                            int left3 = fCurrentParseOp;
3513:                            pushParseOp(PARSEOP_NODETEST_NODE);
3514:                            pushParseOp3(PARSEOP_STEP, left3, fCurrentParseOp);
3515:                            pushParseOp3(PARSEOP_STEPS, left, fCurrentParseOp);
3516:                            pushParseOp3(PARSEOP_STEPS, fCurrentParseOp, left2);
3517:                        } else {
3518:                            pushParseOp3(PARSEOP_STEPS, left, fCurrentParseOp);
3519:                        }
3520:                    }
3521:                    return true;
3522:                }
3523:
3524:                /**
3525:             * [4] Step ::=  (AxisName '::' | '@'?) NodeTest Predicate* | '.' | '..'
3526:             * [6] AxisName ::= 'ancestor' | 'ancestor-or-self'
3527:             *                | 'attribute'
3528:             *                | 'child'
3529:             *                | 'descendant' | 'descendant-or-self'
3530:             *                | 'following' | 'following-sibling'
3531:             *                | 'namespace'
3532:             *                | 'parent'
3533:             *                | 'preceding' | 'preceding-sibling'
3534:             *                | 'self'
3535:             * /
3536:                boolean parseStep() throws XPathException {
3537:                    int parseOp;
3538:                    int left;
3539:                    boolean checkDoubleColon = true;
3540:                    int saveToken = fCurrentToken;
3541:                    int saveParseOp = fCurrentParseOp;
3542:                    if (fCurrentToken == fTokenCount) {
3543:                        return false;
3544:                    }
3545:                    switch (fTokens.getToken(fCurrentToken)) {
3546:                    case XPath.Tokens.EXPRTOKEN_PERIOD:
3547:                        fCurrentToken++;
3548:                        pushParseOp(PARSEOP_AXIS_SELF);
3549:                        left = fCurrentParseOp;
3550:                        pushParseOp(PARSEOP_NODETEST_NODE);
3551:                        pushParseOp3(PARSEOP_STEP, left, fCurrentParseOp);
3552:                        return true;
3553:                    case XPath.Tokens.EXPRTOKEN_DOUBLE_PERIOD:
3554:                        fCurrentToken++;
3555:                        pushParseOp(PARSEOP_AXIS_PARENT);
3556:                        left = fCurrentParseOp;
3557:                        pushParseOp(PARSEOP_NODETEST_NODE);
3558:                        pushParseOp3(PARSEOP_STEP, left, fCurrentParseOp);
3559:                        return true;
3560:                    case XPath.Tokens.EXPRTOKEN_AXISNAME_ANCESTOR:
3561:                        fCurrentToken++;
3562:                        parseOp = PARSEOP_AXIS_ANCESTOR;
3563:                        break;
3564:                    case XPath.Tokens.EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF:
3565:                        fCurrentToken++;
3566:                        parseOp = PARSEOP_AXIS_ANCESTOR_OR_SELF;
3567:                        break;
3568:                    case XPath.Tokens.EXPRTOKEN_ATSIGN:
3569:                        checkDoubleColon = false;
3570:                        // fall through
3571:                    case XPath.Tokens.EXPRTOKEN_AXISNAME_ATTRIBUTE:
3572:                        fCurrentToken++;
3573:                        parseOp = PARSEOP_AXIS_ATTRIBUTE;
3574:                        break;
3575:                    case XPath.Tokens.EXPRTOKEN_AXISNAME_DESCENDANT:
3576:                        fCurrentToken++;
3577:                        parseOp = PARSEOP_AXIS_DESCENDANT;
3578:                        break;
3579:                    case XPath.Tokens.EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF:
3580:                        fCurrentToken++;
3581:                        parseOp = PARSEOP_AXIS_DESCENDANT_OR_SELF;
3582:                        break;
3583:                    case XPath.Tokens.EXPRTOKEN_AXISNAME_FOLLOWING:
3584:                        fCurrentToken++;
3585:                        parseOp = PARSEOP_AXIS_FOLLOWING;
3586:                        break;
3587:                    case XPath.Tokens.EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING:
3588:                        fCurrentToken++;
3589:                        parseOp = PARSEOP_AXIS_FOLLOWING_SIBLING;
3590:                        break;
3591:                    case XPath.Tokens.EXPRTOKEN_AXISNAME_NAMESPACE:
3592:                        fCurrentToken++;
3593:                        parseOp = PARSEOP_AXIS_NAMESPACE;
3594:                        break;
3595:                    case XPath.Tokens.EXPRTOKEN_AXISNAME_PARENT:
3596:                        fCurrentToken++;
3597:                        parseOp = PARSEOP_AXIS_PARENT;
3598:                        break;
3599:                    case XPath.Tokens.EXPRTOKEN_AXISNAME_PRECEDING:
3600:                        fCurrentToken++;
3601:                        parseOp = PARSEOP_AXIS_PRECEDING;
3602:                        break;
3603:                    case XPath.Tokens.EXPRTOKEN_AXISNAME_PRECEDING_SIBLING:
3604:                        fCurrentToken++;
3605:                        parseOp = PARSEOP_AXIS_PRECEDING_SIBLING;
3606:                        break;
3607:                    case XPath.Tokens.EXPRTOKEN_AXISNAME_SELF:
3608:                        fCurrentToken++;
3609:                        parseOp = PARSEOP_AXIS_SELF;
3610:                        break;
3611:                    case XPath.Tokens.EXPRTOKEN_AXISNAME_CHILD:
3612:                        fCurrentToken++;
3613:                        parseOp = PARSEOP_AXIS_CHILD;
3614:                        break;
3615:                    default:
3616:                        checkDoubleColon = false;
3617:                        parseOp = PARSEOP_AXIS_CHILD;
3618:                        break;
3619:                    }
3620:                    pushParseOp(parseOp);
3621:                    left = fCurrentParseOp;
3622:                    if (checkDoubleColon) {
3623:                        if (fCurrentToken == fTokenCount) {
3624:                            fCurrentToken = saveToken;
3625:                            fCurrentParseOp = saveParseOp;
3626:                            return false;
3627:                        }
3628:                        if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_DOUBLE_COLON) {
3629:                            fCurrentToken = saveToken;
3630:                            fCurrentParseOp = saveParseOp;
3631:                            return false;
3632:                        }
3633:                        fCurrentToken++;
3634:                    }
3635:                    if (fCurrentToken == fTokenCount) {
3636:                        fCurrentToken = saveToken;
3637:                        fCurrentParseOp = saveParseOp;
3638:                        return false;
3639:                    }
3640:                    if (!parseNodeTest()) {
3641:                        fCurrentToken = saveToken;
3642:                        fCurrentParseOp = saveParseOp;
3643:                        return false;
3644:                    }
3645:                    pushParseOp3(PARSEOP_STEP, left, fCurrentParseOp);
3646:                    left = fCurrentParseOp;
3647:                    if (parsePredicates()) {
3648:                        pushParseOp3(PARSEOP_FILTER, left, fCurrentParseOp);
3649:                    }
3650:                    return true;
3651:                }
3652:
3653:                /**
3654:             * [7] NodeTest ::= '*'
3655:             *                | NCName ':' '*'
3656:             *                | QName
3657:             *                | 'comment' '(' ')'
3658:             *                | 'text' '(' ')'
3659:             *                | 'processing-instruction' '(' Literal? ')'
3660:             *                | 'node' '(' ')'
3661:             * [29] Literal ::= '"' [^"]* '"' | "'" [^']* "'"
3662:             * /
3663:                boolean parseNodeTest() throws XPathException {
3664:                    int parseOp;
3665:                    int prefix;
3666:                    int name;
3667:                    if (fCurrentToken == fTokenCount) {
3668:                        return false;
3669:                    }
3670:                    switch (fTokens.getToken(fCurrentToken)) {
3671:                    case XPath.Tokens.EXPRTOKEN_NAMETEST_ANY:
3672:                        fCurrentToken++;
3673:                        pushParseOp(PARSEOP_NODETEST_ANY);
3674:                        return true;
3675:                    case XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE:
3676:                        prefix = fTokens.getToken(++fCurrentToken);
3677:                        fCurrentToken++;
3678:                        pushParseOp2(PARSEOP_NODETEST_NAMESPACE, prefix);
3679:                        return true;
3680:                    case XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME:
3681:                        prefix = fTokens.getToken(++fCurrentToken);
3682:                        name = fTokens.getToken(++fCurrentToken);
3683:                        fCurrentToken++;
3684:                        pushParseOp3(PARSEOP_NODETEST_QNAME, prefix, name);
3685:                        return true;
3686:                    case XPath.Tokens.EXPRTOKEN_NODETYPE_COMMENT:
3687:                        parseOp = PARSEOP_NODETEST_COMMENT;
3688:                        break;
3689:                    case XPath.Tokens.EXPRTOKEN_NODETYPE_TEXT:
3690:                        parseOp = PARSEOP_NODETEST_TEXT;
3691:                        break;
3692:                    case XPath.Tokens.EXPRTOKEN_NODETYPE_PI:
3693:                        parseOp = PARSEOP_NODETEST_PI;
3694:                        break;
3695:                    case XPath.Tokens.EXPRTOKEN_NODETYPE_NODE:
3696:                        parseOp = PARSEOP_NODETEST_NODE;
3697:                        break;
3698:                    default:
3699:                        return false;
3700:                    }
3701:                    int saveToken = fCurrentToken;
3702:                    int saveParseOp = fCurrentParseOp;
3703:                    int left = fCurrentParseOp;
3704:                    if (++fCurrentToken == fTokenCount) {
3705:                        fCurrentToken = saveToken;
3706:                        fCurrentParseOp = saveParseOp;
3707:                        return false;
3708:                    }
3709:                    if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_OPEN_PAREN) {
3710:                        fCurrentToken = saveToken;
3711:                        fCurrentParseOp = saveParseOp;
3712:                        return false;
3713:                    }
3714:                    if (++fCurrentToken == fTokenCount) {
3715:                        fCurrentToken = saveToken;
3716:                        fCurrentParseOp = saveParseOp;
3717:                        return false;
3718:                    }
3719:                    if (parseOp == PARSEOP_NODETEST_PI && fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_LITERAL) {
3720:                        int target = fTokens.getToken(++fCurrentToken);
3721:                        if (++fCurrentToken == fTokenCount) {
3722:                            fCurrentToken = saveToken;
3723:                            fCurrentParseOp = saveParseOp;
3724:                            return false;
3725:                        }
3726:                        if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_CLOSE_PAREN) {
3727:                            fCurrentToken = saveToken;
3728:                            fCurrentParseOp = saveParseOp;
3729:                            return false;
3730:                        }
3731:                        fCurrentToken++;
3732:                        pushParseOp2(PARSEOP_NODETEST_PI_TARGET, target);
3733:                    } else {
3734:                        if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_CLOSE_PAREN) {
3735:                            fCurrentToken = saveToken;
3736:                            fCurrentParseOp = saveParseOp;
3737:                            return false;
3738:                        }
3739:                        fCurrentToken++;
3740:                        pushParseOp(parseOp);
3741:                    }
3742:                    return true;
3743:                }
3744:
3745:                /**
3746:             * [8] Predicate ::= '[' PredicateExpr ']'
3747:             * [9] PredicateExpr ::= Expr
3748:             * [4] Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep
3749:             * [20] FilterExpr ::= PrimaryExpr Predicate*
3750:             * /
3751:                boolean parsePredicates() throws XPathException {
3752:                    int left = -1;
3753:                    boolean found = false;
3754:                    while (true) {
3755:                        if (fCurrentToken == fTokenCount || fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_OPEN_BRACKET) {
3756:                            return found;
3757:                        }
3758:                        int saveToken = fCurrentToken;
3759:                        int saveParseOp = fCurrentParseOp;
3760:                        if (++fCurrentToken == fTokenCount || !parseExpr() ||
3761:                            fCurrentToken == fTokenCount || fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_CLOSE_BRACKET) {
3762:                            fCurrentToken = saveToken;
3763:                            fCurrentParseOp = saveParseOp;
3764:                            return found;
3765:                        }
3766:                        fCurrentToken++;
3767:                        found = true;
3768:                        pushParseOp2(PARSEOP_PREDICATE, fCurrentParseOp);
3769:                        if (left != -1) {
3770:                            pushParseOp3(PARSEOP_PREDICATES, left, fCurrentParseOp);
3771:                        }
3772:                        left = fCurrentParseOp;
3773:                    }
3774:                }
3775:
3776:                /**
3777:             * [15] PrimaryExpr ::= '$' QName
3778:             *                    | '(' Expr ')'
3779:             *                    | '"' [^"]* '"' | "'" [^']* "'"
3780:             *                    | ([0-9]+) ('.' ([0-9]+)?)? | '.' Digits
3781:             *                    | (QName - NodeType) '(' ( Expr ( ',' Expr )* )? ')'
3782:             * /
3783:                boolean parsePrimaryExpr() throws XPathException {
3784:                    int prefix;
3785:                    int handle;
3786:                    int saveToken;
3787:                    int saveParseOp;
3788:                    if (fCurrentToken == fTokenCount) {
3789:                        return false;
3790:                    }
3791:                    switch (fTokens.getToken(fCurrentToken)) {
3792:                    case XPath.Tokens.EXPRTOKEN_VARIABLE_REFERENCE:
3793:                        prefix = fTokens.getToken(++fCurrentToken);
3794:                        handle = fTokens.getToken(++fCurrentToken); // localpart
3795:                        fCurrentToken++;
3796:                        pushParseOp3(PARSEOP_VARIABLE_REFERENCE, prefix, handle);
3797:                        break;
3798:                    case XPath.Tokens.EXPRTOKEN_OPEN_PAREN:
3799:                        saveToken = fCurrentToken;
3800:                        saveParseOp = fCurrentParseOp;
3801:                        if (++fCurrentToken == fTokenCount) {
3802:                            fCurrentToken = saveToken;
3803:                            fCurrentParseOp = saveParseOp;
3804:                            return false;
3805:                        }
3806:                        if (!parseExpr()) {
3807:                            fCurrentToken = saveToken;
3808:                            fCurrentParseOp = saveParseOp;
3809:                            return false;
3810:                        }
3811:                        if (fCurrentToken == fTokenCount) {
3812:                            fCurrentToken = saveToken;
3813:                            fCurrentParseOp = saveParseOp;
3814:                            return false;
3815:                        }
3816:                        if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_CLOSE_PAREN) {
3817:                            fCurrentToken = saveToken;
3818:                            fCurrentParseOp = saveParseOp;
3819:                            return false;
3820:                        }
3821:                        fCurrentToken++;
3822:                        pushParseOp2(PARSEOP_GROUPING, fCurrentParseOp);
3823:                        break;
3824:                    case XPath.Tokens.EXPRTOKEN_LITERAL:
3825:                        handle = fTokens.getToken(++fCurrentToken);
3826:                        fCurrentToken++;
3827:                        pushParseOp2(PARSEOP_LITERAL, handle);
3828:                        break;
3829:                    case XPath.Tokens.EXPRTOKEN_NUMBER:
3830:                        int whole = fTokens.getToken(++fCurrentToken);
3831:                        int part = fTokens.getToken(++fCurrentToken);
3832:                        fCurrentToken++;
3833:                        pushParseOp3(PARSEOP_NUMBER, whole, part);
3834:                        break;
3835:                    case XPath.Tokens.EXPRTOKEN_FUNCTION_NAME:
3836:                        saveToken = fCurrentToken;
3837:                        saveParseOp = fCurrentParseOp;
3838:                        prefix = fTokens.getToken(++fCurrentToken);
3839:                        handle = fTokens.getToken(++fCurrentToken); // localpart
3840:                        fCurrentToken++;
3841:                        pushParseOp3(PARSEOP_FUNCTION_NAME, prefix, handle);
3842:                        if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_OPEN_PAREN) {
3843:                            fCurrentToken = saveToken;
3844:                            fCurrentParseOp = saveParseOp;
3845:                            return false;
3846:                        }
3847:                        fCurrentToken++;
3848:                        int funcName = fCurrentParseOp;
3849:                        int nextArg = -1;
3850:                        if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_CLOSE_PAREN) {
3851:                            fCurrentToken++;
3852:                        } else {
3853:                            while (true) {
3854:                                if (!parseExpr()) {
3855:                                    fCurrentToken = saveToken;
3856:                                    fCurrentParseOp = saveParseOp;
3857:                                    return false;
3858:                                }
3859:                                if (nextArg != -1) {
3860:                                    pushParseOp3(PARSEOP_FUNCTION_ARGUMENTS, nextArg, fCurrentParseOp);
3861:                                }
3862:                                nextArg = fCurrentParseOp;
3863:                                if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_CLOSE_PAREN) {
3864:                                    fCurrentToken++;
3865:                                    break;
3866:                                }
3867:                                if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_COMMA) {
3868:                                    fCurrentToken = saveToken;
3869:                                    fCurrentParseOp = saveParseOp;
3870:                                    return false;
3871:                                }
3872:                                fCurrentToken++;
3873:                            }
3874:                        }
3875:                        pushParseOp3(PARSEOP_FUNCTION, funcName, nextArg);
3876:                        break;
3877:                    default:
3878:                        return false;
3879:                    }
3880:                    return true;
3881:                }
3882:
3883:                //
3884:                // MAIN
3885:                //
3886:
3887:                public static void main(String argv[]) {
3888:                    for (int i = 0; i < argv.length; i++) {
3889:                        String expression = argv[i];
3890:                        System.out.println("# XPath expression: "+expression);
3891:                        XPathExprParser parser = new XPathExprParser();
3892:                        try {
3893:                            parser.parseExpr(expression);
3894:                        }
3895:                        catch (Exception e) {
3896:                            e.printStackTrace();
3897:                        }
3898:                    }
3899:                }
3900:
3901:            } // class XPathExprParser
3902:            /***/
3903:
3904:            //
3905:            // MAIN
3906:            //
3907:            /** Main program entry. */
3908:            public static void main(String[] argv) throws Exception {
3909:
3910:                for (int i = 0; i < argv.length; i++) {
3911:                    final String expression = argv[i];
3912:                    System.out.println("# XPath expression: \"" + expression
3913:                            + '"');
3914:                    try {
3915:                        StringPool stringPool = new StringPool();
3916:                        XPath xpath = new XPath(expression, stringPool, null);
3917:                        System.out.println("expanded xpath: \""
3918:                                + xpath.toString() + '"');
3919:                    } catch (XPathException e) {
3920:                        System.out.println("error: " + e.getMessage());
3921:                    }
3922:                }
3923:
3924:            } // main(String[])
3925:
3926:            /** Location paths. */
3927:            protected LocationPath[] fLocationPaths; //
3928:
3929:            // Public methods
3930:            //
3931:
3932:            /** Returns a representation of all location paths for this XPath.
3933:            	XPath = locationPath ( '|' locationPath)*
3934:             */
3935:            public LocationPath[] getLocationPaths() {
3936:                LocationPath[] ret = new LocationPath[fLocationPaths.length];
3937:                for (int i = 0; i < fLocationPaths.length; i++) {
3938:                    ret[i] = (LocationPath) fLocationPaths[i].clone();
3939:                }
3940:                return ret;
3941:            } // getLocationPath(LocationPath)
3942:        } // class XPath
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.