KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > apache > xerces > validators > schema > identity > XPath


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 2000,2001 The Apache Software Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Xerces" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation and was
52  * originally based on software copyright (c) 1999, International
53  * Business Machines, Inc., http://www.apache.org. For more
54  * information on the Apache Software Foundation, please see
55  * <http://www.apache.org/>.
56  */

57
58 package org.enhydra.apache.xerces.validators.schema.identity;
59
60 import org.enhydra.apache.xerces.utils.NamespacesScope;
61 import org.enhydra.apache.xerces.utils.QName;
62 import org.enhydra.apache.xerces.utils.StringPool;
63 import org.enhydra.apache.xerces.utils.XMLCharacterProperties;
64
65 /**
66  * Bare minimum XPath parser.
67  *
68  * @author Andy Clark, IBM
69  * @version $Id: XPath.java,v 1.1.1.1 2003/03/10 16:34:52 taweili Exp $
70  */

71 public class XPath {
72
73     //
74
// Constants
75
//
76

77     private static final boolean DEBUG_ALL = false;
78
79     private static final boolean DEBUG_XPATH_PARSE = DEBUG_ALL || false;
80
81     private static final boolean DEBUG_ANY = DEBUG_XPATH_PARSE;
82
83     //
84
// Data
85
//
86

87     /** Expression. */
88     protected String JavaDoc fExpression;
89
90
91
92     // Xerces 1.x framework
93

94     /** String pool. */
95     protected StringPool fStringPool;
96
97     //
98
// Constructors
99
//
100

101     /** Constructs an XPath object from the specified expression. */
102     public XPath(String JavaDoc xpath, StringPool stringPool,
103                  NamespacesScope context)
104         throws XPathException {
105         XMLCharacterProperties.initCharFlags();
106         fExpression = xpath;
107         fStringPool = stringPool;
108         parseExpression(context);
109     } // <init>(String,StringPool,NamespacesScope)
110

111     //
112
// Public methods
113
//
114

115     /** Returns a representation of the first location path for this XPath. */
116     public LocationPath getLocationPath() {
117         return (LocationPath)fLocationPaths[0].clone();
118     } // getLocationPath(LocationPath)
119

120     //
121
// Object methods
122
//
123

124     /** Returns a string representation of this object. */
125     public String JavaDoc toString() {
126         StringBuffer JavaDoc buf=new StringBuffer JavaDoc();
127         for (int i=0;i<fLocationPaths.length;i++){
128             if (i>0){
129                 buf.append("|");
130             }
131             buf.append(fLocationPaths[i].toString());
132         }
133         return buf.toString();
134     } // toString():String
135

136     //
137
// Private methods
138
//
139

140     /**
141      * This method is implemented by using the XPathExprScanner and
142      * examining the list of tokens that it returns.
143      */

144     private void parseExpression(final NamespacesScope context)
145         throws XPathException {
146
147         // tokens
148
final XPath.Tokens xtokens = new XPath.Tokens(fStringPool);
149
150         // scanner
151
XPath.Scanner scanner = new XPath.Scanner(fStringPool) {
152             protected void addToken(XPath.Tokens tokens, int token)
153                 throws XPathException {
154                 if (
155                     token == XPath.Tokens.EXPRTOKEN_ATSIGN ||
156                     token == XPath.Tokens.EXPRTOKEN_AXISNAME_ATTRIBUTE ||
157                     token == XPath.Tokens.EXPRTOKEN_AXISNAME_CHILD ||
158                     //token == XPath.Tokens.EXPRTOKEN_AXISNAME_SELF ||
159
token == XPath.Tokens.EXPRTOKEN_DOUBLE_COLON ||
160                     //token == XPath.Tokens.EXPRTOKEN_NAMETEST_ANY ||
161
token == XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME ||
162                     //token == XPath.Tokens.EXPRTOKEN_NODETYPE_NODE ||
163
token == XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH ||
164                     token == XPath.Tokens.EXPRTOKEN_PERIOD ||
165                     //added to conform to PR Spec
166
token == XPath.Tokens.EXPRTOKEN_NAMETEST_ANY ||
167                     token == XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE ||
168                     token == XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH ||
169                     token == XPath.Tokens.EXPRTOKEN_OPERATOR_UNION
170                     //
171
) {
172                     super.addToken(tokens, token);
173                     return;
174                 }
175                 StringBuffer JavaDoc str = new StringBuffer JavaDoc();
176                 str.append("token not supported: ");
177                 String JavaDoc tokenName = tokens.getTokenName(token);
178                 if (tokenName != null) {
179                     str.append('"');
180                     str.append(tokenName);
181                     str.append('"');
182                 }
183                 else {
184                     str.append('(');
185                     str.append(token);
186                     str.append(')');
187                 }
188                 String JavaDoc message = str.toString();
189                 throw new XPathException(message);
190             }
191         };
192
193         int length = fExpression.length();
194         /***/
195         boolean success = scanner.scanExpr(fStringPool,
196                                            xtokens, fExpression, 0, length);
197         //fTokens.dumpTokens();
198
java.util.Vector JavaDoc stepsVector = new java.util.Vector JavaDoc();
199         java.util.Vector JavaDoc locationPathsVector= new java.util.Vector JavaDoc();
200         int tokenCount = xtokens.getTokenCount();
201         boolean firstTokenOfLocationPath=true;
202
203         for (int i = 0; i < tokenCount; i++) {
204             int token = xtokens.getToken(i);
205             boolean isNamespace=false;
206
207             switch (token) {
208                 case XPath.Tokens.EXPRTOKEN_OPERATOR_UNION :{
209                     if (i == 0) {
210                         throw new XPathException("not allowed to have '|' at the beginning of an xpath value");
211                     }
212
213                     int size = stepsVector.size();
214                     if (size == 0) {
215                         throw new XPathException("not allowed to have '||'");
216                     }
217                     Step[] steps = new Step[size];
218                     stepsVector.copyInto(steps);
219                     // add location path
220
locationPathsVector.addElement(new LocationPath(steps));
221                     //reset stepsVector
222
stepsVector.removeAllElements();
223                     firstTokenOfLocationPath=true;
224                     break;
225                 }
226
227                 case XPath.Tokens.EXPRTOKEN_AXISNAME_ATTRIBUTE: {
228                     // consume "::" token and drop through
229
i++;
230                 }
231                 case XPath.Tokens.EXPRTOKEN_ATSIGN: {
232                     // consume QName token
233
if (i == tokenCount - 1) {
234                         throw new XPathException("missing attribute name");
235                     }
236                     token = xtokens.getToken(++i);
237
238                     if (token != XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME
239                         && token!= XPath.Tokens.EXPRTOKEN_NAMETEST_ANY
240                         && token!= XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE) {
241                         throw new XPathException("expected \""+xtokens.getTokenName(XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME)+
242                                                  "\" or \""+xtokens.getTokenName( XPath.Tokens.EXPRTOKEN_NAMETEST_ANY)+
243                                                  "\" or \""+xtokens.getTokenName( XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE)+
244                                                  "\", found "+xtokens.getTokenName(token));
245                     }
246                     boolean isNamespaceAtt=false;
247                     switch (token)
248                     {
249                         case XPath.Tokens.EXPRTOKEN_NAMETEST_ANY:{
250                             Axis axis = new Axis(Axis.ATTRIBUTE);
251                             NodeTest nodeTest = new NodeTest(NodeTest.WILDCARD);
252                             Step step = new Step(axis, nodeTest);
253                             stepsVector.addElement(step);
254                             break;
255                         }
256                         case XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE:{
257                             isNamespaceAtt=true;
258                     }
259                         case XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME:{
260
261                     token = xtokens.getToken(++i);
262                     int prefix = xtokens.getTokenString(token);
263                     int uri = StringPool.EMPTY_STRING;
264                     if (context != null && prefix != -1) {
265                         uri = context.getNamespaceForPrefix(prefix);
266                     }
267                     if (prefix != -1 && context != null && uri == StringPool.EMPTY_STRING) {
268                         throw new XPathException("prefix "+fStringPool.toString(prefix)+" not bound to namespace URI");
269                     }
270
271                             if (isNamespaceAtt)
272                             {
273                                 // build step
274
Axis axis = new Axis(Axis.ATTRIBUTE);
275                                 NodeTest nodeTest=new NodeTest(fStringPool,prefix,uri);
276                                 Step step = new Step(axis, nodeTest);
277                                 stepsVector.addElement(step);
278                                 break;
279                             }
280
281                     token = xtokens.getToken(++i);
282                     int localpart = xtokens.getTokenString(token);
283                     int rawname = prefix != -1
284                                 ? fStringPool.addSymbol(fStringPool.toString(prefix) + ':' + fStringPool.toString(localpart))
285                                 : localpart;
286
287                     // build step
288
Axis axis = new Axis(Axis.ATTRIBUTE);
289                     NodeTest nodeTest = new NodeTest(fStringPool, new QName(prefix, localpart, rawname, uri));
290                     Step step = new Step(axis, nodeTest);
291                     stepsVector.addElement(step);
292                     break;
293                 }
294                     }
295                     firstTokenOfLocationPath=false;
296                     break;
297                 }
298                 /***
299                 case XPath.Tokens.EXPRTOKEN_AXISNAME_SELF: {
300                     break;
301                 }
302                 /***/

303                 case XPath.Tokens.EXPRTOKEN_DOUBLE_COLON: {
304                     // should never have a bare double colon
305
throw new XPathException("Not allowed to have double colon here");
306                 }
307                 /***
308                 case XPath.Tokens.EXPRTOKEN_NAMETEST_ANY: {
309                     break;
310                 }
311                 /***/

312                 case XPath.Tokens.EXPRTOKEN_AXISNAME_CHILD: {
313
314                     // consume "::" token and drop through
315
i++;
316                     if (i == tokenCount - 1) {
317                         throw new XPathException("expected step following '"
318                             +xtokens.getTokenName(XPath.Tokens.EXPRTOKEN_AXISNAME_CHILD)+"::'");
319                     }
320                     firstTokenOfLocationPath=false;
321                     break;
322                 }
323                 case XPath.Tokens.EXPRTOKEN_NAMETEST_ANY:{
324                     Axis axis = new Axis(Axis.CHILD);
325                     NodeTest nodeTest = new NodeTest(NodeTest.WILDCARD);
326                     Step step = new Step(axis, nodeTest);
327                     stepsVector.addElement(step);
328                     firstTokenOfLocationPath=false;
329                     break;
330                 }
331
332                 case XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE:{
333                     isNamespace=true;
334                 }
335                 case XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME: {
336                     // consume QName token
337
token = xtokens.getToken(++i);
338                     int prefix = xtokens.getTokenString(token);
339                     int uri = StringPool.EMPTY_STRING;
340                     if (context != null && prefix != -1) {
341                         uri = context.getNamespaceForPrefix(prefix);
342                     }
343                     if (prefix != -1 && context != null &&
344                         uri == StringPool.EMPTY_STRING) {
345                         throw new XPathException("prefix "+fStringPool.toString(prefix)+" not bound to namespace URI");
346                     }
347
348                     if (isNamespace)
349                     {
350                         // build step
351
Axis axis = new Axis(Axis.CHILD);
352                         NodeTest nodeTest=new NodeTest(fStringPool,prefix,uri);
353                         Step step = new Step(axis, nodeTest);
354                         stepsVector.addElement(step);
355                         break;
356                     }
357
358                     token = xtokens.getToken(++i);
359                     int localpart = xtokens.getTokenString(token);
360                     int rawname = prefix != -1
361                                 ? fStringPool.addSymbol(fStringPool.toString(prefix) + ':' + fStringPool.toString(localpart))
362                                 : localpart;
363
364                     // build step
365
Axis axis = new Axis(Axis.CHILD);
366                     NodeTest nodeTest = new NodeTest(fStringPool, new QName(prefix, localpart, rawname, uri));
367                     Step step = new Step(axis, nodeTest);
368                     stepsVector.addElement(step);
369                     firstTokenOfLocationPath=false;
370                     break;
371                 }
372                 /***
373                 case XPath.Tokens.EXPRTOKEN_NODETYPE_NODE: {
374                     break;
375                 }
376                 /***/

377
378
379                 case XPath.Tokens.EXPRTOKEN_PERIOD: {
380                     // build step
381
Axis axis = new Axis(Axis.SELF);
382                     NodeTest nodeTest = new NodeTest(NodeTest.NODE);
383                     Step step = new Step(axis, nodeTest);
384                     stepsVector.addElement(step);
385
386                     if (firstTokenOfLocationPath && i+1<tokenCount){
387                         token=xtokens.getToken(i+1);
388                         if (token == XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH){
389                             i++;
390                             if (i == tokenCount - 1) {
391                                 throw new XPathException("expected step following '//'");
392                             }
393                             if (i+1<tokenCount) {
394                                 token=xtokens.getToken(i+1);
395                                 if (token==XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH)
396                                     throw new XPathException("'/' not allowed after '//'");
397                             }
398                             // build step
399
axis = new Axis(Axis.DESCENDANT);
400                             nodeTest = new NodeTest(NodeTest.NODE);
401                             step = new Step(axis, nodeTest);
402                             stepsVector.addElement(step);
403                         }
404                     }
405                     firstTokenOfLocationPath=false;
406                     break;
407                 }
408
409                 case XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH:{
410                     throw new XPathException("'//' only allowed after '.' at the beginning of an xpath");
411                 }
412                 case XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH: {
413                     if (i == 0) {
414                         throw new XPathException("not allowed to have '/' at the beginning of an xpath value");
415                     }
416                     // keep on truckin'
417
if (firstTokenOfLocationPath) {
418                         throw new XPathException("not allowed to select the root");
419                     }
420                     if (i == tokenCount - 1) {
421                         throw new XPathException("expected step following '/'");
422                     }
423                     firstTokenOfLocationPath=false;
424                     break;
425                 }
426                 default:
427                     firstTokenOfLocationPath=false;
428             }
429         }
430
431         int size = stepsVector.size();
432         if (size == 0) {
433             if (locationPathsVector.size()==0)
434             throw new XPathException("empty xpath expression");
435             else
436                 throw new XPathException("xpath cannot end with '|'");
437         }
438         Step[] steps = new Step[size];
439         stepsVector.copyInto(steps);
440         locationPathsVector.addElement(new LocationPath(steps));
441
442         // save location path
443
fLocationPaths=new LocationPath[locationPathsVector.size()];
444         locationPathsVector.copyInto(fLocationPaths);
445
446
447         if (DEBUG_XPATH_PARSE) {
448             System.out.println(">>> "+fLocationPaths);
449         }
450
451     } // parseExpression(SymbolTable,NamespaceContext)
452

453     //
454
// Classes
455
//
456

457     // location path information
458

459     /**
460      * A location path representation for an XPath expression.
461      *
462      * @author Andy Clark, IBM
463      */

464     public static class LocationPath
465         implements Cloneable JavaDoc {
466
467         //
468
// Data
469
//
470

471         /** List of steps. */
472         public Step[] steps;
473
474         //
475
// Constructors
476
//
477

478         /** Creates a location path from a series of steps. */
479         public LocationPath(Step[] steps) {
480             this.steps = steps;
481         } // <init>(Step[])
482

483         /** Copy constructor. */
484         protected LocationPath(LocationPath path) {
485             steps = new Step[path.steps.length];
486             for (int i = 0; i < steps.length; i++) {
487                 steps[i] = (Step)path.steps[i].clone();
488             }
489         } // <init>(LocationPath)
490

491         //
492
// Object methods
493
//
494

495         /** Returns a string representation of this object. */
496         public String JavaDoc toString() {
497             StringBuffer JavaDoc str = new StringBuffer JavaDoc();
498             for (int i = 0; i < steps.length; i++) {
499                 if (i > 0 && (steps[i-1].axis.type!=Axis.DESCENDANT
500                     && steps[i].axis.type!=Axis.DESCENDANT) ){
501                     str.append('/');
502                 }
503                 str.append(steps[i].toString());
504             }
505             // DEBUG: This code is just for debugging and should *not*
506
// be left in because it will mess up hashcodes of
507
// serialized versions of this object. -Ac
508
if (false) {
509                 str.append('[');
510                 String JavaDoc s = super.toString();
511                 str.append(s.substring(s.indexOf('@')));
512                 str.append(']');
513             }
514             return str.toString();
515         } // toString():String
516

517         /** Returns a clone of this object. */
518         public Object JavaDoc clone() {
519             return new LocationPath(this);
520         } // clone():Object
521

522     } // class locationPath
523

524     /**
525      * A location path step comprised of an axis and node test.
526      *
527      * @author Andy Clark, IBM
528      */

529     public static class Step
530         implements Cloneable JavaDoc {
531
532         //
533
// Data
534
//
535

536         /** Axis. */
537         public Axis axis;
538
539         /** Node test. */
540         public NodeTest nodeTest;
541
542         //
543
// Constructors
544
//
545

546         /** Constructs a step from an axis and node test. */
547         public Step(Axis axis, NodeTest nodeTest) {
548             this.axis = axis;
549             this.nodeTest = nodeTest;
550         } // <init>(Axis,NodeTest)
551

552         /** Copy constructor. */
553         protected Step(Step step) {
554             axis = (Axis)step.axis.clone();
555             nodeTest = (NodeTest)step.nodeTest.clone();
556         } // <init>(Step)
557

558         //
559
// Object methods
560
//
561

562         /** Returns a string representation of this object. */
563         public String JavaDoc toString() {
564             /***
565             return axis.toString() + "::" + nodeTest.toString();
566             /***/

567             if (axis.type == Axis.SELF) {
568                 return ".";
569             }
570             if (axis.type == Axis.ATTRIBUTE) {
571                 return "@" + nodeTest.toString();
572             }
573             if (axis.type == Axis.CHILD) {
574                 return nodeTest.toString();
575             }
576             if (axis.type == Axis.DESCENDANT) {
577                 return "//";
578             }
579             return "??? ("+axis.type+')';
580             /***/
581         } // toString():String
582

583         /** Returns a clone of this object. */
584         public Object JavaDoc clone() {
585             return new Step(this);
586         } // clone():Object
587

588     } // class Step
589

590     /**
591      * Axis.
592      *
593      * @author Andy Clark, IBM
594      */

595     public static class Axis
596         implements Cloneable JavaDoc {
597
598         //
599
// Constants
600
//
601

602         /** Type: child. */
603         public static final short CHILD = 1;
604
605         /** Type: attribute. */
606         public static final short ATTRIBUTE = 2;
607
608         /** Type: self. */
609         public static final short SELF = 3;
610
611
612         /** Type: descendant. */
613         public static final short DESCENDANT = 4;
614         //
615
// Data
616
//
617

618         /** Axis type. */
619         public short type;
620
621         //
622
// Constructors
623
//
624

625         /** Constructs an axis with the specified type. */
626         public Axis(short type) {
627             this.type = type;
628         } // <init>(short)
629

630         /** Copy constructor. */
631         protected Axis(Axis axis) {
632             type = axis.type;
633         } // <init>(Axis)
634

635         //
636
// Object methods
637
//
638

639         /** Returns a string representation of this object. */
640         public String JavaDoc toString() {
641             switch (type) {
642                 case CHILD: return "child";
643                 case ATTRIBUTE: return "attribute";
644                 case SELF: return "self";
645                 case DESCENDANT: return "descendant";
646             }
647             return "???";
648         } // toString():String
649

650         /** Returns a clone of this object. */
651         public Object JavaDoc clone() {
652             return new Axis(this);
653         } // clone():Object
654

655     } // class Axis
656

657     /**
658      * Node test.
659      *
660      * @author Andy Clark, IBM
661      */

662     public static class NodeTest
663         implements Cloneable JavaDoc {
664
665         //
666
// Constants
667
//
668

669         /** Type: qualified name. */
670         public static final short QNAME = 1;
671
672         /** Type: wildcard. */
673         public static final short WILDCARD = 2;
674
675         /** Type: node. */
676         public static final short NODE = 3;
677
678         /** Type: namespace */
679         public static final short NAMESPACE= 4;
680
681         //
682
// Data
683
//
684

685         /** String pool. */
686         protected StringPool fStringPool;
687
688         /** Node test type. */
689         public short type;
690
691         /** Node qualified name. */
692         public final QName name = new QName();
693
694         //
695
// Constructors
696
//
697

698         /** Constructs a node test of type WILDCARD or NODE. */
699         public NodeTest(short type) {
700             this.type = type;
701         } // <init>(int)
702

703         /** Constructs a node test of type QName. */
704         public NodeTest(StringPool stringPool, QName name) {
705             fStringPool = stringPool;
706             this.type = QNAME;
707             this.name.setValues(name);
708         } // <init>(QName)
709
/** Constructs a node test of type Namespace. */
710         public NodeTest(StringPool stringPool, int prefix, int uri) {
711             fStringPool = stringPool;
712             this.type = NAMESPACE;
713             this.name.setValues(prefix,-1,-1,uri);
714         }
715
716         /** Copy constructor. */
717         public NodeTest(NodeTest nodeTest) {
718             fStringPool = nodeTest.fStringPool;
719             type = nodeTest.type;
720             name.setValues(nodeTest.name);
721         } // <init>(NodeTest)
722

723         //
724
// Object methods
725
//
726

727         /** Returns a string representation of this object. */
728         public String JavaDoc toString() {
729
730             switch (type) {
731                 case QNAME: {
732                     if (name.prefix != -1) {
733                         if (name.uri == StringPool.EMPTY_STRING) {
734                             return fStringPool.toString(name.prefix) + ':' + fStringPool.toString(name.localpart);
735                         }
736                         return "{" + fStringPool.toString(name.uri) + '}' + fStringPool.toString(name.prefix) + ':' + fStringPool.toString(name.localpart);
737                     }
738                     return fStringPool.toString(name.localpart);
739                 }
740                 case NAMESPACE: {
741                     if (name.prefix!=-1) {
742                         if (name.uri == StringPool.EMPTY_STRING) {
743                             return fStringPool.toString(name.prefix) + ":*";
744                         }
745                         return "{" + fStringPool.toString(name.uri) + '}' + fStringPool.toString(name.prefix) + ":*";
746                     }
747                     return "???:*";
748                 }
749                 case WILDCARD: {
750                     return "*";
751                 }
752                 case NODE: {
753                     return "node()";
754                 }
755             }
756             return "???";
757
758         } // toString():String
759

760         /** Returns a clone of this object. */
761         public Object JavaDoc clone() {
762             return new NodeTest(this);
763         } // clone():Object
764

765     } // class NodeTest
766

767     // xpath implementation
768

769     // NOTE: The XPath implementation classes are kept internal because
770
// this implementation is just a temporary hack until a better
771
// and/or more appropriate implementation can be written.
772
// keeping the code in separate source files would "muddy" the
773
// CVS directory when it's not needed. -Ac
774

775     /**
776      * @author Glenn Marcy, IBM
777      * @author Andy Clark, IBM
778      *
779      * @version $Id: XPath.java,v 1.1.1.1 2003/03/10 16:34:52 taweili Exp $
780      */

781     private static final class Tokens {
782
783         static final boolean DUMP_TOKENS = false;
784
785         /**
786          * [28] ExprToken ::= '(' | ')' | '[' | ']' | '.' | '..' | '@' | ',' | '::'
787          * | NameTest | NodeType | Operator | FunctionName
788          * | AxisName | Literal | Number | VariableReference
789          */

790         public static final int
791             EXPRTOKEN_OPEN_PAREN = 0,
792             EXPRTOKEN_CLOSE_PAREN = 1,
793             EXPRTOKEN_OPEN_BRACKET = 2,
794             EXPRTOKEN_CLOSE_BRACKET = 3,
795             EXPRTOKEN_PERIOD = 4,
796             EXPRTOKEN_DOUBLE_PERIOD = 5,
797             EXPRTOKEN_ATSIGN = 6,
798             EXPRTOKEN_COMMA = 7,
799             EXPRTOKEN_DOUBLE_COLON = 8,
800             //
801
// [37] NameTest ::= '*' | NCName ':' '*' | QName
802
//
803
// followed by symbol handle of NCName or QName
804
//
805
EXPRTOKEN_NAMETEST_ANY = 9,
806             EXPRTOKEN_NAMETEST_NAMESPACE = 10,
807             EXPRTOKEN_NAMETEST_QNAME = 11,
808             //
809
// [38] NodeType ::= 'comment' | 'text' | 'processing-instruction' | 'node'
810
//
811
EXPRTOKEN_NODETYPE_COMMENT = 12,
812             EXPRTOKEN_NODETYPE_TEXT = 13,
813             EXPRTOKEN_NODETYPE_PI = 14,
814             EXPRTOKEN_NODETYPE_NODE = 15,
815             //
816
// [32] Operator ::= OperatorName
817
// | MultiplyOperator
818
// | '/' | '//' | '|' | '+' | '-' | '=' | '!=' | '<' | '<=' | '>' | '>='
819
// [33] OperatorName ::= 'and' | 'or' | 'mod' | 'div'
820
// [34] MultiplyOperator ::= '*'
821
//
822
EXPRTOKEN_OPERATOR_AND = 16,
823             EXPRTOKEN_OPERATOR_OR = 17,
824             EXPRTOKEN_OPERATOR_MOD = 18,
825             EXPRTOKEN_OPERATOR_DIV = 19,
826             EXPRTOKEN_OPERATOR_MULT = 20,
827             EXPRTOKEN_OPERATOR_SLASH = 21,
828             EXPRTOKEN_OPERATOR_DOUBLE_SLASH = 22,
829             EXPRTOKEN_OPERATOR_UNION = 23,
830             EXPRTOKEN_OPERATOR_PLUS = 24,
831             EXPRTOKEN_OPERATOR_MINUS = 25,
832             EXPRTOKEN_OPERATOR_EQUAL = 26,
833             EXPRTOKEN_OPERATOR_NOT_EQUAL = 27,
834             EXPRTOKEN_OPERATOR_LESS = 28,
835             EXPRTOKEN_OPERATOR_LESS_EQUAL = 29,
836             EXPRTOKEN_OPERATOR_GREATER = 30,
837             EXPRTOKEN_OPERATOR_GREATER_EQUAL = 31,
838
839             //EXPRTOKEN_FIRST_OPERATOR = EXPRTOKEN_OPERATOR_AND,
840
//EXPRTOKEN_LAST_OPERATOR = EXPRTOKEN_OPERATOR_GREATER_EQUAL,
841

842             //
843
// [35] FunctionName ::= QName - NodeType
844
//
845
// followed by symbol handle
846
//
847
EXPRTOKEN_FUNCTION_NAME = 32,
848             //
849
// [6] AxisName ::= 'ancestor' | 'ancestor-or-self'
850
// | 'attribute'
851
// | 'child'
852
// | 'descendant' | 'descendant-or-self'
853
// | 'following' | 'following-sibling'
854
// | 'namespace'
855
// | 'parent'
856
// | 'preceding' | 'preceding-sibling'
857
// | 'self'
858
//
859
EXPRTOKEN_AXISNAME_ANCESTOR = 33,
860             EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF = 34,
861             EXPRTOKEN_AXISNAME_ATTRIBUTE = 35,
862             EXPRTOKEN_AXISNAME_CHILD = 36,
863             EXPRTOKEN_AXISNAME_DESCENDANT = 37,
864             EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF = 38,
865             EXPRTOKEN_AXISNAME_FOLLOWING = 39,
866             EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING = 40,
867             EXPRTOKEN_AXISNAME_NAMESPACE = 41,
868             EXPRTOKEN_AXISNAME_PARENT = 42,
869             EXPRTOKEN_AXISNAME_PRECEDING = 43,
870             EXPRTOKEN_AXISNAME_PRECEDING_SIBLING = 44,
871             EXPRTOKEN_AXISNAME_SELF = 45,
872             //
873
// [29] Literal ::= '"' [^"]* '"' | "'" [^']* "'"
874
//
875
// followed by symbol handle for literal
876
//
877
EXPRTOKEN_LITERAL = 46,
878             //
879
// [30] Number ::= Digits ('.' Digits?)? | '.' Digits
880
// [31] Digits ::= [0-9]+
881
//
882
// followed by number handle
883
//
884
EXPRTOKEN_NUMBER = 47,
885             //
886
// [36] VariableReference ::= '$' QName
887
//
888
// followed by symbol handle for QName
889
//
890
EXPRTOKEN_VARIABLE_REFERENCE = 48;
891
892         public static final String JavaDoc[] fgTokenNames = {
893             "EXPRTOKEN_OPEN_PAREN",
894             "EXPRTOKEN_CLOSE_PAREN",
895             "EXPRTOKEN_OPEN_BRACKET",
896             "EXPRTOKEN_CLOSE_BRACKET",
897             "EXPRTOKEN_PERIOD",
898             "EXPRTOKEN_DOUBLE_PERIOD",
899             "EXPRTOKEN_ATSIGN",
900             "EXPRTOKEN_COMMA",
901             "EXPRTOKEN_DOUBLE_COLON",
902             "EXPRTOKEN_NAMETEST_ANY",
903             "EXPRTOKEN_NAMETEST_NAMESPACE",
904             "EXPRTOKEN_NAMETEST_QNAME",
905             "EXPRTOKEN_NODETYPE_COMMENT",
906             "EXPRTOKEN_NODETYPE_TEXT",
907             "EXPRTOKEN_NODETYPE_PI",
908             "EXPRTOKEN_NODETYPE_NODE",
909             "EXPRTOKEN_OPERATOR_AND",
910             "EXPRTOKEN_OPERATOR_OR",
911             "EXPRTOKEN_OPERATOR_MOD",
912             "EXPRTOKEN_OPERATOR_DIV",
913             "EXPRTOKEN_OPERATOR_MULT",
914             "EXPRTOKEN_OPERATOR_SLASH",
915             "EXPRTOKEN_OPERATOR_DOUBLE_SLASH",
916             "EXPRTOKEN_OPERATOR_UNION",
917             "EXPRTOKEN_OPERATOR_PLUS",
918             "EXPRTOKEN_OPERATOR_MINUS",
919             "EXPRTOKEN_OPERATOR_EQUAL",
920             "EXPRTOKEN_OPERATOR_NOT_EQUAL",
921             "EXPRTOKEN_OPERATOR_LESS",
922             "EXPRTOKEN_OPERATOR_LESS_EQUAL",
923             "EXPRTOKEN_OPERATOR_GREATER",
924             "EXPRTOKEN_OPERATOR_GREATER_EQUAL",
925             "EXPRTOKEN_FUNCTION_NAME",
926             "EXPRTOKEN_AXISNAME_ANCESTOR",
927             "EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF",
928             "EXPRTOKEN_AXISNAME_ATTRIBUTE",
929             "EXPRTOKEN_AXISNAME_CHILD",
930             "EXPRTOKEN_AXISNAME_DESCENDANT",
931             "EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF",
932             "EXPRTOKEN_AXISNAME_FOLLOWING",
933             "EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING",
934             "EXPRTOKEN_AXISNAME_NAMESPACE",
935             "EXPRTOKEN_AXISNAME_PARENT",
936             "EXPRTOKEN_AXISNAME_PRECEDING",
937             "EXPRTOKEN_AXISNAME_PRECEDING_SIBLING",
938             "EXPRTOKEN_AXISNAME_SELF",
939             "EXPRTOKEN_LITERAL",
940             "EXPRTOKEN_NUMBER",
941             "EXPRTOKEN_VARIABLE_REFERENCE"
942         };
943
944         /**
945          *
946          */

947         private static final int INITIAL_TOKEN_COUNT = 1 << 8;
948         private int[] fTokens = new int[INITIAL_TOKEN_COUNT];
949         private int fTokenCount = 0; // for writing
950

951         private StringPool fStringPool;
952
953         // REVISIT: Code something better here. -Ac
954
//private java.util.Hashtable fSymbolMapping = new java.util.Hashtable();
955

956         // REVISIT: Code something better here. -Ac
957
//private java.util.Hashtable fTokenNames = new java.util.Hashtable();
958

959         //
960
// Constructors
961
//
962

963         /***
964         public XPath.Tokens(SymbolTable symbolTable) {
965             fSymbolTable = symbolTable;
966         }
967         /***/

968         public Tokens(StringPool stringPool) {
969             fStringPool = stringPool;
970             /***
971             final String[] symbols = {
972                 "ancestor", "ancestor-or-self", "attribute",
973                 "child", "descendant", "descendant-or-self",
974                 "following", "following-sibling", "namespace",
975                 "parent", "preceding", "preceding-sibling",
976                 "self",
977             };
978             for (int i = 0; i < symbols.length; i++) {
979                 fSymbolMapping.put(fSymbolTable.addSymbol(symbols[i]), new Integer(i));
980             }
981             /*
982             fTokenNames.put(new Integer(EXPRTOKEN_OPEN_PAREN), "EXPRTOKEN_OPEN_PAREN");
983             fTokenNames.put(new Integer(EXPRTOKEN_CLOSE_PAREN), "EXPRTOKEN_CLOSE_PAREN");
984             fTokenNames.put(new Integer(EXPRTOKEN_OPEN_BRACKET), "EXPRTOKEN_OPEN_BRACKET");
985             fTokenNames.put(new Integer(EXPRTOKEN_CLOSE_BRACKET), "EXPRTOKEN_CLOSE_BRACKET");
986             fTokenNames.put(new Integer(EXPRTOKEN_PERIOD), "EXPRTOKEN_PERIOD");
987             fTokenNames.put(new Integer(EXPRTOKEN_DOUBLE_PERIOD), "EXPRTOKEN_DOUBLE_PERIOD");
988             fTokenNames.put(new Integer(EXPRTOKEN_ATSIGN), "EXPRTOKEN_ATSIGN");
989             fTokenNames.put(new Integer(EXPRTOKEN_COMMA), "EXPRTOKEN_COMMA");
990             fTokenNames.put(new Integer(EXPRTOKEN_DOUBLE_COLON), "EXPRTOKEN_DOUBLE_COLON");
991             fTokenNames.put(new Integer(EXPRTOKEN_NAMETEST_ANY), "EXPRTOKEN_NAMETEST_ANY");
992             fTokenNames.put(new Integer(EXPRTOKEN_NAMETEST_NAMESPACE), "EXPRTOKEN_NAMETEST_NAMESPACE");
993             fTokenNames.put(new Integer(EXPRTOKEN_NAMETEST_QNAME), "EXPRTOKEN_NAMETEST_QNAME");
994             fTokenNames.put(new Integer(EXPRTOKEN_NODETYPE_COMMENT), "EXPRTOKEN_NODETYPE_COMMENT");
995             fTokenNames.put(new Integer(EXPRTOKEN_NODETYPE_TEXT), "EXPRTOKEN_NODETYPE_TEXT");
996             fTokenNames.put(new Integer(EXPRTOKEN_NODETYPE_PI), "EXPRTOKEN_NODETYPE_PI");
997             fTokenNames.put(new Integer(EXPRTOKEN_NODETYPE_NODE), "EXPRTOKEN_NODETYPE_NODE");
998             fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_AND), "EXPRTOKEN_OPERATOR_AND");
999             fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_OR), "EXPRTOKEN_OPERATOR_OR");
1000            fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_MOD), "EXPRTOKEN_OPERATOR_MOD");
1001            fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_DIV), "EXPRTOKEN_OPERATOR_DIV");
1002            fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_MULT), "EXPRTOKEN_OPERATOR_MULT");
1003            fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_SLASH), "EXPRTOKEN_OPERATOR_SLASH");
1004            fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_DOUBLE_SLASH), "EXPRTOKEN_OPERATOR_DOUBLE_SLASH");
1005            fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_UNION), "EXPRTOKEN_OPERATOR_UNION");
1006            fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_PLUS), "EXPRTOKEN_OPERATOR_PLUS");
1007            fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_MINUS), "EXPRTOKEN_OPERATOR_MINUS");
1008            fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_EQUAL), "EXPRTOKEN_OPERATOR_EQUAL");
1009            fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_NOT_EQUAL), "EXPRTOKEN_OPERATOR_NOT_EQUAL");
1010            fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_LESS), "EXPRTOKEN_OPERATOR_LESS");
1011            fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_LESS_EQUAL), "EXPRTOKEN_OPERATOR_LESS_EQUAL");
1012            fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_GREATER), "EXPRTOKEN_OPERATOR_GREATER");
1013            fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_GREATER_EQUAL), "EXPRTOKEN_OPERATOR_GREATER_EQUAL");
1014            fTokenNames.put(new Integer(EXPRTOKEN_FUNCTION_NAME), "EXPRTOKEN_FUNCTION_NAME");
1015            fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_ANCESTOR), "EXPRTOKEN_AXISNAME_ANCESTOR");
1016            fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF), "EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF");
1017            fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_ATTRIBUTE), "EXPRTOKEN_AXISNAME_ATTRIBUTE");
1018            fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_CHILD), "EXPRTOKEN_AXISNAME_CHILD");
1019            fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_DESCENDANT), "EXPRTOKEN_AXISNAME_DESCENDANT");
1020            fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF), "EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF");
1021            fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_FOLLOWING), "EXPRTOKEN_AXISNAME_FOLLOWING");
1022            fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING), "EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING");
1023            fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_NAMESPACE), "EXPRTOKEN_AXISNAME_NAMESPACE");
1024            fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_PARENT), "EXPRTOKEN_AXISNAME_PARENT");
1025            fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_PRECEDING), "EXPRTOKEN_AXISNAME_PRECEDING");
1026            fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_PRECEDING_SIBLING), "EXPRTOKEN_AXISNAME_PRECEDING_SIBLING");
1027            fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_SELF), "EXPRTOKEN_AXISNAME_SELF");
1028            fTokenNames.put(new Integer(EXPRTOKEN_LITERAL), "EXPRTOKEN_LITERAL");
1029            fTokenNames.put(new Integer(EXPRTOKEN_NUMBER), "EXPRTOKEN_NUMBER");
1030            fTokenNames.put(new Integer(EXPRTOKEN_VARIABLE_REFERENCE), "EXPRTOKEN_VARIABLE_REFERENCE");
1031            */

1032        }
1033        /***/
1034
1035        //
1036
// Public methods
1037
//
1038

1039        /***
1040        public int addSymbol(byte[] data, int offset, int length, EncodingMap encoding) {
1041            //return fSymbolTable.addSymbol(data, offset, length, encoding);
1042            return fSymbolTable.addSymbol(new String(data, offset, length));
1043        }
1044        /***/

1045
1046        public String JavaDoc getTokenName(int token) {
1047            if (token < 0 || token >= fgTokenNames.length)
1048                return null;
1049            return fgTokenNames[token];
1050        }
1051
1052        public int getTokenString(int token) {
1053            return token;
1054        }
1055
1056        public void addToken(int token) {
1057            try {
1058                fTokens[fTokenCount] = token;
1059            } catch (ArrayIndexOutOfBoundsException JavaDoc ex) {
1060                int[] oldList = fTokens;
1061                fTokens = new int[fTokenCount << 1];
1062                System.arraycopy(oldList, 0, fTokens, 0, fTokenCount);
1063                fTokens[fTokenCount] = token;
1064            }
1065            fTokenCount++;
1066        }
1067        public int getTokenCount() {
1068            return fTokenCount;
1069        }
1070        public int getToken(int tokenIndex) {
1071            return fTokens[tokenIndex];
1072        }
1073        public void dumpTokens() {
1074            //if (DUMP_TOKENS) {
1075
for (int i = 0; i < fTokenCount; i++) {
1076                    switch (fTokens[i]) {
1077                    case EXPRTOKEN_OPEN_PAREN:
1078                        System.out.print("<OPEN_PAREN/>");
1079                        break;
1080                    case EXPRTOKEN_CLOSE_PAREN:
1081                        System.out.print("<CLOSE_PAREN/>");
1082                        break;
1083                    case EXPRTOKEN_OPEN_BRACKET:
1084                        System.out.print("<OPEN_BRACKET/>");
1085                        break;
1086                    case EXPRTOKEN_CLOSE_BRACKET:
1087                        System.out.print("<CLOSE_BRACKET/>");
1088                        break;
1089                    case EXPRTOKEN_PERIOD:
1090                        System.out.print("<PERIOD/>");
1091                        break;
1092                    case EXPRTOKEN_DOUBLE_PERIOD:
1093                        System.out.print("<DOUBLE_PERIOD/>");
1094                        break;
1095                    case EXPRTOKEN_ATSIGN:
1096                        System.out.print("<ATSIGN/>");
1097                        break;
1098                    case EXPRTOKEN_COMMA:
1099                        System.out.print("<COMMA/>");
1100                        break;
1101                    case EXPRTOKEN_DOUBLE_COLON:
1102                        System.out.print("<DOUBLE_COLON/>");
1103                        break;
1104                    case EXPRTOKEN_NAMETEST_ANY:
1105                        System.out.print("<NAMETEST_ANY/>");
1106                        break;
1107                    case EXPRTOKEN_NAMETEST_NAMESPACE:
1108                        System.out.print("<NAMETEST_NAMESPACE");
1109                        /***
1110                        System.out.print(" prefix=\"" + fSymbolTable.toString(fTokens[++i]) + "\"");
1111                        /***/

1112                        System.out.print(" prefix=\"" + getTokenString(fTokens[++i]) + "\"");
1113                        /***/
1114                        System.out.print("/>");
1115                        break;
1116                    case EXPRTOKEN_NAMETEST_QNAME:
1117                        System.out.print("<NAMETEST_QNAME");
1118                        if (fTokens[++i] != -1)
1119                            /***
1120                            System.out.print(" prefix=\"" + fSymbolTable.toString(fTokens[i]) + "\"");
1121                            /***/

1122                            System.out.print(" prefix=\"" + getTokenString(fTokens[i]) + "\"");
1123                            /***/
1124                        /***
1125                        System.out.print(" localpart=\"" + fSymbolTable.toString(fTokens[++i]) + "\"");
1126                        /***/

1127                        System.out.print(" localpart=\"" + getTokenString(fTokens[++i]) + "\"");
1128                        /***/
1129                        System.out.print("/>");
1130                        break;
1131                    case EXPRTOKEN_NODETYPE_COMMENT:
1132                        System.out.print("<NODETYPE_COMMENT/>");
1133                        break;
1134                    case EXPRTOKEN_NODETYPE_TEXT:
1135                        System.out.print("<NODETYPE_TEXT/>");
1136                        break;
1137                    case EXPRTOKEN_NODETYPE_PI:
1138                        System.out.print("<NODETYPE_PI/>");
1139                        break;
1140                    case EXPRTOKEN_NODETYPE_NODE:
1141                        System.out.print("<NODETYPE_NODE/>");
1142                        break;
1143                    case EXPRTOKEN_OPERATOR_AND:
1144                        System.out.print("<OPERATOR_AND/>");
1145                        break;
1146                    case EXPRTOKEN_OPERATOR_OR:
1147                        System.out.print("<OPERATOR_OR/>");
1148                        break;
1149                    case EXPRTOKEN_OPERATOR_MOD:
1150                        System.out.print("<OPERATOR_MOD/>");
1151                        break;
1152                    case EXPRTOKEN_OPERATOR_DIV:
1153                        System.out.print("<OPERATOR_DIV/>");
1154                        break;
1155                    case EXPRTOKEN_OPERATOR_MULT:
1156                        System.out.print("<OPERATOR_MULT/>");
1157                        break;
1158                    case EXPRTOKEN_OPERATOR_SLASH:
1159                        System.out.print("<OPERATOR_SLASH/>");
1160                        if (i + 1 < fTokenCount) {
1161                            System.out.println();
1162                            System.out.print(" ");
1163                        }
1164                        break;
1165                    case EXPRTOKEN_OPERATOR_DOUBLE_SLASH:
1166                        System.out.print("<OPERATOR_DOUBLE_SLASH/>");
1167                        break;
1168                    case EXPRTOKEN_OPERATOR_UNION:
1169                        System.out.print("<OPERATOR_UNION/>");
1170                        break;
1171                    case EXPRTOKEN_OPERATOR_PLUS:
1172                        System.out.print("<OPERATOR_PLUS/>");
1173                        break;
1174                    case EXPRTOKEN_OPERATOR_MINUS:
1175                        System.out.print("<OPERATOR_MINUS/>");
1176                        break;
1177                    case EXPRTOKEN_OPERATOR_EQUAL:
1178                        System.out.print("<OPERATOR_EQUAL/>");
1179                        break;
1180                    case EXPRTOKEN_OPERATOR_NOT_EQUAL:
1181                        System.out.print("<OPERATOR_NOT_EQUAL/>");
1182                        break;
1183                    case EXPRTOKEN_OPERATOR_LESS:
1184                        System.out.print("<OPERATOR_LESS/>");
1185                        break;
1186                    case EXPRTOKEN_OPERATOR_LESS_EQUAL:
1187                        System.out.print("<OPERATOR_LESS_EQUAL/>");
1188                        break;
1189                    case EXPRTOKEN_OPERATOR_GREATER:
1190                        System.out.print("<OPERATOR_GREATER/>");
1191                        break;
1192                    case EXPRTOKEN_OPERATOR_GREATER_EQUAL:
1193                        System.out.print("<OPERATOR_GREATER_EQUAL/>");
1194                        break;
1195                    case EXPRTOKEN_FUNCTION_NAME:
1196                        System.out.print("<FUNCTION_NAME");
1197                        if (fTokens[++i] != -1)
1198                            /***
1199                            System.out.print(" prefix=\"" + fSymbolTable.toString(fTokens[i]) + "\"");
1200                            /***/

1201                            System.out.print(" prefix=\"" + getTokenString(fTokens[i]) + "\"");
1202                            /***/
1203                        /***
1204                        System.out.print(" localpart=\"" + fSymbolTable.toString(fTokens[++i]) + "\"");
1205                        /***/

1206                        System.out.print(" localpart=\"" + getTokenString(fTokens[++i]) + "\"");
1207                        /***/
1208                        System.out.print("/>");
1209                        break;
1210                    case EXPRTOKEN_AXISNAME_ANCESTOR:
1211                        System.out.print("<AXISNAME_ANCESTOR/>");
1212                        break;
1213                    case EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF:
1214                        System.out.print("<AXISNAME_ANCESTOR_OR_SELF/>");
1215                        break;
1216                    case EXPRTOKEN_AXISNAME_ATTRIBUTE:
1217                        System.out.print("<AXISNAME_ATTRIBUTE/>");
1218                        break;
1219                    case EXPRTOKEN_AXISNAME_CHILD:
1220                        System.out.print("<AXISNAME_CHILD/>");
1221                        break;
1222                    case EXPRTOKEN_AXISNAME_DESCENDANT:
1223                        System.out.print("<AXISNAME_DESCENDANT/>");
1224                        break;
1225                    case EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF:
1226                        System.out.print("<AXISNAME_DESCENDANT_OR_SELF/>");
1227                        break;
1228                    case EXPRTOKEN_AXISNAME_FOLLOWING:
1229                        System.out.print("<AXISNAME_FOLLOWING/>");
1230                        break;
1231                    case EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING:
1232                        System.out.print("<AXISNAME_FOLLOWING_SIBLING/>");
1233                        break;
1234                    case EXPRTOKEN_AXISNAME_NAMESPACE:
1235                        System.out.print("<AXISNAME_NAMESPACE/>");
1236                        break;
1237                    case EXPRTOKEN_AXISNAME_PARENT:
1238                        System.out.print("<AXISNAME_PARENT/>");
1239                        break;
1240                    case EXPRTOKEN_AXISNAME_PRECEDING:
1241                        System.out.print("<AXISNAME_PRECEDING/>");
1242                        break;
1243                    case EXPRTOKEN_AXISNAME_PRECEDING_SIBLING:
1244                        System.out.print("<AXISNAME_PRECEDING_SIBLING/>");
1245                        break;
1246                    case EXPRTOKEN_AXISNAME_SELF:
1247                        System.out.print("<AXISNAME_SELF/>");
1248                        break;
1249                    case EXPRTOKEN_LITERAL:
1250                        System.out.print("<LITERAL");
1251                        /***
1252                        System.out.print(" value=\"" + fSymbolTable.toString(fTokens[++i]) + "\"");
1253                        /***/

1254                        System.out.print(" value=\"" + getTokenString(fTokens[++i]) + "\"");
1255                        /***/
1256                        System.out.print("/>");
1257                        break;
1258                    case EXPRTOKEN_NUMBER:
1259                        System.out.print("<NUMBER");
1260                        System.out.print(" whole=\"" + getTokenString(fTokens[++i]) + "\"");
1261                        System.out.print(" part=\"" + getTokenString(fTokens[++i]) + "\"");
1262                        System.out.print("/>");
1263                        break;
1264                    case EXPRTOKEN_VARIABLE_REFERENCE:
1265                        System.out.print("<VARIABLE_REFERENCE");
1266                        if (fTokens[++i] != -1)
1267                            /***
1268                            System.out.print(" prefix=\"" + fSymbolTable.toString(fTokens[i]) + "\"");
1269                            /***/

1270                            System.out.print(" prefix=\"" + getTokenString(fTokens[i]) + "\"");
1271                            /***/
1272                        /***
1273                        System.out.print(" localpart=\"" + fSymbolTable.toString(fTokens[++i]) + "\"");
1274                        /***/

1275                        System.out.print(" localpart=\"" + getTokenString(fTokens[++i]) + "\"");
1276                        /***/
1277                        System.out.print("/>");
1278                        break;
1279                    default:
1280                        System.out.println("<???/>");
1281                    }
1282                }
1283                System.out.println();
1284            //}
1285
}
1286
1287    } // class Tokens
1288

1289    /**
1290     * @author Glenn Marcy, IBM
1291     * @author Andy Clark, IBM
1292     *
1293     * @version $Id: XPath.java,v 1.1.1.1 2003/03/10 16:34:52 taweili Exp $
1294     */

1295    private static class Scanner {
1296
1297        /**
1298         * 7-bit ASCII subset
1299         *
1300         * 0 1 2 3 4 5 6 7 8 9 A B C D E F
1301         * 0, 0, 0, 0, 0, 0, 0, 0, 0, HT, LF, 0, 0, CR, 0, 0, // 0
1302         * 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
1303         * SP, !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, // 2
1304         * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, :, ;, <, =, >, ?, // 3
1305         * @, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, // 4
1306         * P, Q, R, S, T, U, V, W, X, Y, Z, [, \, ], ^, _, // 5
1307         * `, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, // 6
1308         * p, q, r, s, t, u, v, w, x, y, z, {, |, }, ~, DEL // 7
1309         */

1310        private static final byte
1311            CHARTYPE_INVALID = 0, // invalid XML character
1312
CHARTYPE_OTHER = 1, // not special - one of "#%&;?\^`{}~" or DEL
1313
CHARTYPE_WHITESPACE = 2, // one of "\t\n\r " (0x09, 0x0A, 0x0D, 0x20)
1314
CHARTYPE_EXCLAMATION = 3, // '!' (0x21)
1315
CHARTYPE_QUOTE = 4, // '\"' or '\'' (0x22 and 0x27)
1316
CHARTYPE_DOLLAR = 5, // '$' (0x24)
1317
CHARTYPE_OPEN_PAREN = 6, // '(' (0x28)
1318
CHARTYPE_CLOSE_PAREN = 7, // ')' (0x29)
1319
CHARTYPE_STAR = 8, // '*' (0x2A)
1320
CHARTYPE_PLUS = 9, // '+' (0x2B)
1321
CHARTYPE_COMMA = 10, // ',' (0x2C)
1322
CHARTYPE_MINUS = 11, // '-' (0x2D)
1323
CHARTYPE_PERIOD = 12, // '.' (0x2E)
1324
CHARTYPE_SLASH = 13, // '/' (0x2F)
1325
CHARTYPE_DIGIT = 14, // '0'-'9' (0x30 to 0x39)
1326
CHARTYPE_COLON = 15, // ':' (0x3A)
1327
CHARTYPE_LESS = 16, // '<' (0x3C)
1328
CHARTYPE_EQUAL = 17, // '=' (0x3D)
1329
CHARTYPE_GREATER = 18, // '>' (0x3E)
1330
CHARTYPE_ATSIGN = 19, // '@' (0x40)
1331
CHARTYPE_LETTER = 20, // 'A'-'Z' or 'a'-'z' (0x41 to 0x5A and 0x61 to 0x7A)
1332
CHARTYPE_OPEN_BRACKET = 21, // '[' (0x5B)
1333
CHARTYPE_CLOSE_BRACKET = 22, // ']' (0x5D)
1334
CHARTYPE_UNDERSCORE = 23, // '_' (0x5F)
1335
CHARTYPE_UNION = 24, // '|' (0x7C)
1336
CHARTYPE_NONASCII = 25; // Non-ASCII Unicode codepoint (>= 0x80)
1337

1338        private static byte[] fASCIICharMap = {
1339            0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 2, 0, 0,
1340            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1341            2, 3, 4, 1, 5, 1, 1, 4, 6, 7, 8, 9, 10, 11, 12, 13,
1342           14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 1, 16, 17, 18, 1,
1343           19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1344           20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 1, 22, 1, 23,
1345            1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1346           20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 1, 24, 1, 1, 1
1347        };
1348
1349        /**
1350         * Symbol literals
1351         */

1352        /***
1353        private static int fgAndSymbol = -1; // 'and'
1354        private static int fgOrSymbol = -1; // 'or'
1355        private static int fgModSymbol = -1; // 'mod'
1356        private static int fgDivSymbol = -1; // 'div'
1357
1358        private static int fgCommentSymbol = -1; // 'comment'
1359        private static int fgTextSymbol = -1; // 'text'
1360        private static int fgPISymbol = -1; // 'processing-instruction'
1361        private static int fgNodeSymbol = -1; // 'node'
1362
1363        private static int fgAncestorSymbol = -1; // 'ancestor'
1364        private static int fgAncestorOrSelfSymbol = -1; // 'ancestor-or-self'
1365        private static int fgAttributeSymbol = -1; // 'attribute'
1366        private static int fgChildSymbol = -1; // 'child'
1367        private static int fgDescendantSymbol = -1; // 'descendant'
1368        private static int fgDescendantOrSelfSymbol = -1; // 'descendant-or-self'
1369        private static int fgFollowingSymbol = -1; // 'following'
1370        private static int fgFollowingSiblingSymbol = -1; // 'following-sibling'
1371        private static int fgNamespaceSymbol = -1; // 'namespace'
1372        private static int fgParentSymbol = -1; // 'parent'
1373        private static int fgPrecedingSymbol = -1; // 'preceding'
1374        private static int fgPrecedingSiblingSymbol = -1; // 'preceding-sibling'
1375        private static int fgSelfSymbol = -1; // 'self'
1376
1377        private static SymbolTable fgSymbolTable = new SymbolTable();
1378
1379        static {
1380            fgAndSymbol = fgSymbolTable.addSymbol("and");
1381            fgOrSymbol = fgSymbolTable.addSymbol("or");
1382            fgModSymbol = fgSymbolTable.addSymbol("mod");
1383            fgDivSymbol = fgSymbolTable.addSymbol("div");
1384            fgCommentSymbol = fgSymbolTable.addSymbol("comment");
1385            fgTextSymbol = fgSymbolTable.addSymbol("text");
1386            fgPISymbol = fgSymbolTable.addSymbol("processing-instruction");
1387            fgNodeSymbol = fgSymbolTable.addSymbol("node");
1388            fgAncestorSymbol = fgSymbolTable.addSymbol("ancestor");
1389            fgAncestorOrSelfSymbol = fgSymbolTable.addSymbol("ancestor-or-self");
1390            fgAttributeSymbol = fgSymbolTable.addSymbol("attribute");
1391            fgChildSymbol = fgSymbolTable.addSymbol("child");
1392            fgDescendantSymbol = fgSymbolTable.addSymbol("descendant");
1393            fgDescendantOrSelfSymbol = fgSymbolTable.addSymbol("descendant-or-self");
1394            fgFollowingSymbol = fgSymbolTable.addSymbol("following");
1395            fgFollowingSiblingSymbol = fgSymbolTable.addSymbol("following-sibling");
1396            fgNamespaceSymbol = fgSymbolTable.addSymbol("namespace");
1397            fgParentSymbol = fgSymbolTable.addSymbol("parent");
1398            fgPrecedingSymbol = fgSymbolTable.addSymbol("preceding");
1399            fgPrecedingSiblingSymbol = fgSymbolTable.addSymbol("preceding-sibling");
1400            fgSelfSymbol = fgSymbolTable.addSymbol("self");
1401        }
1402        /***/

1403
1404        //
1405
// Data
1406
//
1407

1408        /** String pool. */
1409        private StringPool fStringPool;
1410
1411        // symbols
1412

1413        private int fAndSymbol;
1414        private int fOrSymbol;
1415        private int fModSymbol;
1416        private int fDivSymbol;
1417
1418        private int fCommentSymbol;
1419        private int fTextSymbol;
1420        private int fPISymbol;
1421        private int fNodeSymbol;
1422
1423        private int fAncestorSymbol;
1424        private int fAncestorOrSelfSymbol;
1425        private int fAttributeSymbol;
1426        private int fChildSymbol;
1427        private int fDescendantSymbol;
1428        private int fDescendantOrSelfSymbol;
1429        private int fFollowingSymbol;
1430        private int fFollowingSiblingSymbol;
1431        private int fNamespaceSymbol;
1432        private int fParentSymbol;
1433        private int fPrecedingSymbol;
1434        private int fPrecedingSiblingSymbol;
1435        private int fSelfSymbol;
1436
1437        //
1438
// Constructors
1439
//
1440

1441        /** Constructs an XPath expression scanner. */
1442        public Scanner(StringPool stringPool) {
1443
1444            // save pool and tokens
1445
fStringPool = stringPool;
1446
1447            // create symbols
1448
fAndSymbol = fStringPool.addSymbol("and");
1449            fOrSymbol = fStringPool.addSymbol("or");
1450            fModSymbol = fStringPool.addSymbol("mod");
1451            fDivSymbol = fStringPool.addSymbol("div");
1452            fCommentSymbol = fStringPool.addSymbol("comment");
1453            fTextSymbol = fStringPool.addSymbol("text");
1454            fPISymbol = fStringPool.addSymbol("processing-instruction");
1455            fNodeSymbol = fStringPool.addSymbol("node");
1456            fAncestorSymbol = fStringPool.addSymbol("ancestor");
1457            fAncestorOrSelfSymbol = fStringPool.addSymbol("ancestor-or-self");
1458            fAttributeSymbol = fStringPool.addSymbol("attribute");
1459            fChildSymbol = fStringPool.addSymbol("child");
1460            fDescendantSymbol = fStringPool.addSymbol("descendant");
1461            fDescendantOrSelfSymbol = fStringPool.addSymbol("descendant-or-self");
1462            fFollowingSymbol = fStringPool.addSymbol("following");
1463            fFollowingSiblingSymbol = fStringPool.addSymbol("following-sibling");
1464            fNamespaceSymbol = fStringPool.addSymbol("namespace");
1465            fParentSymbol = fStringPool.addSymbol("parent");
1466            fPrecedingSymbol = fStringPool.addSymbol("preceding");
1467            fPrecedingSiblingSymbol = fStringPool.addSymbol("preceding-sibling");
1468            fSelfSymbol = fStringPool.addSymbol("self");
1469
1470        } // <init>(StringPool)
1471

1472        /**
1473         *
1474         */

1475        public boolean scanExpr(StringPool stringPool,
1476                                XPath.Tokens tokens, String JavaDoc data,
1477                                int currentOffset, int endOffset)
1478            throws XPathException {
1479
1480            int nameOffset;
1481            int nameHandle, prefixHandle;
1482            boolean starIsMultiplyOperator = false;
1483            int ch;
1484
1485            /***
1486            if (XPath.Tokens.DUMP_TOKENS) {
1487                System.out.println(" <test>");
1488                System.out.println(" <expression>");
1489                System.out.println(" " + encoding.createString(data, currentOffset, endOffset - currentOffset));
1490                System.out.println(" </expression>");
1491            }
1492            /***/

1493            while (true) {
1494                if (currentOffset == endOffset) {
1495                    break;
1496                }
1497                /***
1498                ch = (data[currentOffset] & 0xFF);
1499                /***/

1500                ch = data.charAt(currentOffset);
1501                /***/
1502                //
1503
// [39] ExprWhitespace ::= S
1504
//
1505
while (ch == ' ' || ch == 0x0A || ch == 0x09 || ch == 0x0D) {
1506                    if (++currentOffset == endOffset) {
1507                        break;
1508                    }
1509                    /***
1510                    ch = (data[currentOffset] & 0xFF);
1511                    /***/

1512                    ch = data.charAt(currentOffset);
1513                    /***/
1514                }
1515                if (currentOffset == endOffset) {
1516                    break;
1517                }
1518                //
1519
// [28] ExprToken ::= '(' | ')' | '[' | ']' | '.' | '..' | '@' | ',' | '::'
1520
// | NameTest | NodeType | Operator | FunctionName
1521
// | AxisName | Literal | Number | VariableReference
1522
//
1523
byte chartype = (ch >= 0x80) ? CHARTYPE_NONASCII : fASCIICharMap[ch];
1524                switch (chartype) {
1525                case CHARTYPE_OPEN_PAREN: // '('
1526
addToken(tokens, XPath.Tokens.EXPRTOKEN_OPEN_PAREN);
1527                    starIsMultiplyOperator = false;
1528                    if (++currentOffset == endOffset) {
1529                        break;
1530                    }
1531                    break;
1532                case CHARTYPE_CLOSE_PAREN: // ')'
1533
addToken(tokens, XPath.Tokens.EXPRTOKEN_CLOSE_PAREN);
1534                    starIsMultiplyOperator = true;
1535                    if (++currentOffset == endOffset) {
1536                        break;
1537                    }
1538                    break;
1539                case CHARTYPE_OPEN_BRACKET: // '['
1540
addToken(tokens, XPath.Tokens.EXPRTOKEN_OPEN_BRACKET);
1541                    starIsMultiplyOperator = false;
1542                    if (++currentOffset == endOffset) {
1543                        break;
1544                    }
1545                    break;
1546                case CHARTYPE_CLOSE_BRACKET: // ']'
1547
addToken(tokens, XPath.Tokens.EXPRTOKEN_CLOSE_BRACKET);
1548                    starIsMultiplyOperator = true;
1549                    if (++currentOffset == endOffset) {
1550                        break;
1551                    }
1552                    break;
1553                //
1554
// [30] Number ::= Digits ('.' Digits?)? | '.' Digits
1555
// ^^^^^^^^^^
1556
//
1557
case CHARTYPE_PERIOD: // '.', '..' or '.' Digits
1558
if (currentOffset + 1 == endOffset) {
1559                        addToken(tokens, XPath.Tokens.EXPRTOKEN_PERIOD);
1560                        starIsMultiplyOperator = true;
1561                        currentOffset++;
1562                        break;
1563                    }
1564                    /***
1565                    ch = (data[currentOffset + 1] & 0xFF);
1566                    /***/

1567                    ch = data.charAt(currentOffset + 1);
1568                    /***/
1569                    if (ch == '.') { // '..'
1570
addToken(tokens, XPath.Tokens.EXPRTOKEN_DOUBLE_PERIOD);
1571                        starIsMultiplyOperator = true;
1572                        currentOffset += 2;
1573                    } else if (ch >= '0' && ch <= '9') {
1574                        addToken(tokens, XPath.Tokens.EXPRTOKEN_NUMBER);
1575                        starIsMultiplyOperator = true;
1576                        currentOffset = scanNumber(tokens, data, endOffset, currentOffset/*, encoding*/);
1577                    } else if (ch == '/') {
1578                        addToken(tokens, XPath.Tokens.EXPRTOKEN_PERIOD);
1579                        starIsMultiplyOperator = true;
1580                        currentOffset++;
1581                    } else { // '.'
1582
throw new XPathException ("Invalid character following '.'");
1583                    }
1584                    if (currentOffset == endOffset) {
1585                        break;
1586                    }
1587                    break;
1588                case CHARTYPE_ATSIGN: // '@'
1589
addToken(tokens, XPath.Tokens.EXPRTOKEN_ATSIGN);
1590                    starIsMultiplyOperator = false;
1591                    if (++currentOffset == endOffset) {
1592                        break;
1593                    }
1594                    break;
1595                case CHARTYPE_COMMA: // ','
1596
addToken(tokens, XPath.Tokens.EXPRTOKEN_COMMA);
1597                    starIsMultiplyOperator = false;
1598                    if (++currentOffset == endOffset) {
1599                        break;
1600                    }
1601                    break;
1602                case CHARTYPE_COLON: // '::'
1603
if (++currentOffset == endOffset) {
1604                // System.out.println("abort 1a");
1605
return false; // REVISIT
1606
}
1607                    /***
1608                    ch = (data[currentOffset] & 0xFF);
1609                    /***/

1610                    ch = data.charAt(currentOffset);
1611                    /***/
1612                    if (ch != ':') {
1613                // System.out.println("abort 1b");
1614
return false; // REVISIT
1615
}
1616                    addToken(tokens, XPath.Tokens.EXPRTOKEN_DOUBLE_COLON);
1617                    starIsMultiplyOperator = false;
1618                    if (++currentOffset == endOffset) {
1619                        break;
1620                    }
1621                    break;
1622                case CHARTYPE_SLASH: // '/' and '//'
1623
if (++currentOffset == endOffset) {
1624                        addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH);
1625                        starIsMultiplyOperator = false;
1626                        break;
1627                    }
1628                    /***
1629                    ch = (data[currentOffset] & 0xFF);
1630                    /***/

1631                    ch = data.charAt(currentOffset);
1632                    /***/
1633                    if (ch == '/') { // '//'
1634
addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH);
1635                        starIsMultiplyOperator = false;
1636                        if (++currentOffset == endOffset) {
1637                            break;
1638                        }
1639                    } else {
1640                        addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH);
1641                        starIsMultiplyOperator = false;
1642                    }
1643                    break;
1644                case CHARTYPE_UNION: // '|'
1645
addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_UNION);
1646                    starIsMultiplyOperator = false;
1647                    if (++currentOffset == endOffset) {
1648                        break;
1649                    }
1650                    break;
1651                case CHARTYPE_PLUS: // '+'
1652
addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_PLUS);
1653                    starIsMultiplyOperator = false;
1654                    if (++currentOffset == endOffset) {
1655                        break;
1656                    }
1657                    break;
1658                case CHARTYPE_MINUS: // '-'
1659
addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_MINUS);
1660                    starIsMultiplyOperator = false;
1661                    if (++currentOffset == endOffset) {
1662                        break;
1663                    }
1664                    break;
1665                case CHARTYPE_EQUAL: // '='
1666
addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_EQUAL);
1667                    starIsMultiplyOperator = false;
1668                    if (++currentOffset == endOffset) {
1669                        break;
1670                    }
1671                    break;
1672                case CHARTYPE_EXCLAMATION: // '!='
1673
if (++currentOffset == endOffset) {
1674                // System.out.println("abort 2a");
1675
return false; // REVISIT
1676
}
1677                    /***
1678                    ch = (data[currentOffset] & 0xFF);
1679                    /***/

1680                    ch = data.charAt(currentOffset);
1681                    /***/
1682                    if (ch != '=') {
1683                // System.out.println("abort 2b");
1684
return false; // REVISIT
1685
}
1686                    addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_NOT_EQUAL);
1687                    starIsMultiplyOperator = false;
1688                    if (++currentOffset == endOffset) {
1689                        break;
1690                    }
1691                    break;
1692                case CHARTYPE_LESS: // '<' and '<='
1693
if (++currentOffset == endOffset) {
1694                        addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_LESS);
1695                        starIsMultiplyOperator = false;
1696                        break;
1697                    }
1698                    /***
1699                    ch = (data[currentOffset] & 0xFF);
1700                    /***/

1701                    ch = data.charAt(currentOffset);
1702                    /***/
1703                    if (ch == '=') { // '<='
1704
addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_LESS_EQUAL);
1705                        starIsMultiplyOperator = false;
1706                        if (++currentOffset == endOffset) {
1707                            break;
1708                        }
1709                    } else {
1710                        addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_LESS);
1711                        starIsMultiplyOperator = false;
1712                    }
1713                    break;
1714                case CHARTYPE_GREATER: // '>' and '>='
1715
if (++currentOffset == endOffset) {
1716                        addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_GREATER);
1717                        starIsMultiplyOperator = false;
1718                        break;
1719                    }
1720                    /***
1721                    ch = (data[currentOffset] & 0xFF);
1722                    /***/

1723                    ch = data.charAt(currentOffset);
1724                    /***/
1725                    if (ch == '=') { // '>='
1726
addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_GREATER_EQUAL);
1727                        starIsMultiplyOperator = false;
1728                        if (++currentOffset == endOffset) {
1729                            break;
1730                        }
1731                    } else {
1732                        addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_GREATER);
1733                        starIsMultiplyOperator = false;
1734                    }
1735                    break;
1736                //
1737
// [29] Literal ::= '"' [^"]* '"' | "'" [^']* "'"
1738
//
1739
case CHARTYPE_QUOTE: // '\"' or '\''
1740
int qchar = ch;
1741                    if (++currentOffset == endOffset) {
1742                // System.out.println("abort 2c");
1743
return false; // REVISIT
1744
}
1745                    /***
1746                    ch = (data[currentOffset] & 0xFF);
1747                    /***/

1748                    ch = data.charAt(currentOffset);
1749                    /***/
1750                    int litOffset = currentOffset;
1751                    while (ch != qchar) {
1752                        if (++currentOffset == endOffset) {
1753                // System.out.println("abort 2d");
1754
return false; // REVISIT
1755
}
1756                        /***
1757                        ch = (data[currentOffset] & 0xFF);
1758                        /***/

1759                        ch = data.charAt(currentOffset);
1760                        /***/
1761                    }
1762                    int litLength = currentOffset - litOffset;
1763                    addToken(tokens, XPath.Tokens.EXPRTOKEN_LITERAL);
1764                    starIsMultiplyOperator = true;
1765                    /***
1766                    addToken(tokens, tokens.addSymbol(data, litOffset, litLength, encoding));
1767                    /***/

1768                    tokens.addToken(stringPool.addSymbol(data.substring(litOffset, litOffset + litLength)));
1769                    /***/
1770                    if (++currentOffset == endOffset) {
1771                        break;
1772                    }
1773                    break;
1774                //
1775
// [30] Number ::= Digits ('.' Digits?)? | '.' Digits
1776
// [31] Digits ::= [0-9]+
1777
//
1778
case CHARTYPE_DIGIT:
1779                    addToken(tokens, XPath.Tokens.EXPRTOKEN_NUMBER);
1780                    starIsMultiplyOperator = true;
1781                    currentOffset = scanNumber(tokens, data, endOffset, currentOffset/*, encoding*/);
1782                    break;
1783                //
1784
// [36] VariableReference ::= '$' QName
1785
//
1786
case CHARTYPE_DOLLAR:
1787                    if (++currentOffset == endOffset) {
1788                // System.out.println("abort 3a");
1789
return false; // REVISIT
1790
}
1791                    nameOffset = currentOffset;
1792                    currentOffset = scanNCName(data, endOffset, currentOffset);
1793                    if (currentOffset == nameOffset) {
1794                // System.out.println("abort 3b");
1795
return false; // REVISIT
1796
}
1797                    if (currentOffset < endOffset) {
1798                        ch = data.charAt(currentOffset);
1799                    }
1800                    else {
1801                        ch = -1;
1802                    }
1803                    /***
1804                    nameHandle = tokens.addSymbol(data, nameOffset, currentOffset - nameOffset, encoding);
1805                    /***/

1806                    nameHandle = stringPool.addSymbol(data.substring(nameOffset, currentOffset));
1807                    /***/
1808                    if (ch != ':') {
1809                        prefixHandle = -1;
1810                    } else {
1811                        prefixHandle = nameHandle;
1812                        if (++currentOffset == endOffset) {
1813                // System.out.println("abort 4a");
1814
return false; // REVISIT
1815
}
1816                        nameOffset = currentOffset;
1817                        currentOffset = scanNCName(data, endOffset, currentOffset);
1818                        if (currentOffset == nameOffset) {
1819                // System.out.println("abort 4b");
1820
return false; // REVISIT
1821
}
1822                        if (currentOffset < endOffset) {
1823                            ch = data.charAt(currentOffset);
1824                        }
1825                        else {
1826                            ch = -1;
1827                        }
1828                        /***
1829                        nameHandle = tokens.addSymbol(data, nameOffset, currentOffset - nameOffset, encoding);
1830                        /***/

1831                        nameHandle = stringPool.addSymbol(data.substring(nameOffset, currentOffset));
1832                        /***/
1833                    }
1834                    addToken(tokens, XPath.Tokens.EXPRTOKEN_VARIABLE_REFERENCE);
1835                    starIsMultiplyOperator = true;
1836                    tokens.addToken(prefixHandle);
1837                    tokens.addToken(nameHandle);
1838                    break;
1839                //
1840
// [37] NameTest ::= '*' | NCName ':' '*' | QName
1841
// [34] MultiplyOperator ::= '*'
1842
//
1843
case CHARTYPE_STAR: // '*'
1844
//
1845
// 3.7 Lexical Structure
1846
//
1847
// If there is a preceding token and the preceding token is not one of @, ::, (, [, , or
1848
// an Operator, then a * must be recognized as a MultiplyOperator.
1849
//
1850
// Otherwise, the token must not be recognized as a MultiplyOperator.
1851
//
1852
if (starIsMultiplyOperator) {
1853                        addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_MULT);
1854                        starIsMultiplyOperator = false;
1855                    } else {
1856                        addToken(tokens, XPath.Tokens.EXPRTOKEN_NAMETEST_ANY);
1857                        starIsMultiplyOperator = true;
1858                    }
1859                    if (++currentOffset == endOffset) {
1860                        break;
1861                    }
1862                    break;
1863                //
1864
// NCName, QName and non-terminals
1865
//
1866
case CHARTYPE_NONASCII: // possibly a valid non-ascii 'Letter' (BaseChar | Ideographic)
1867
case CHARTYPE_LETTER:
1868                case CHARTYPE_UNDERSCORE:
1869                    //
1870
// 3.7 Lexical Structure
1871
//
1872
// If there is a preceding token and the preceding token is not one of @, ::, (, [, , or
1873
// an Operator, then an NCName must be recognized as an OperatorName.
1874
//
1875
// If the character following an NCName (possibly after intervening ExprWhitespace) is (,
1876
// then the token must be recognized as a NodeType or a FunctionName.
1877
//
1878
// If the two characters following an NCName (possibly after intervening ExprWhitespace)
1879
// are ::, then the token must be recognized as an AxisName.
1880
//
1881
// Otherwise, the token must not be recognized as an OperatorName, a NodeType, a
1882
// FunctionName, or an AxisName.
1883
//
1884
// [33] OperatorName ::= 'and' | 'or' | 'mod' | 'div'
1885
// [38] NodeType ::= 'comment' | 'text' | 'processing-instruction' | 'node'
1886
// [35] FunctionName ::= QName - NodeType
1887
// [6] AxisName ::= (see above)
1888
//
1889
// [37] NameTest ::= '*' | NCName ':' '*' | QName
1890
// [5] NCName ::= (Letter | '_') (NCNameChar)*
1891
// [?] NCNameChar ::= Letter | Digit | '.' | '-' | '_' (ascii subset of 'NCNameChar')
1892
// [?] QName ::= (NCName ':')? NCName
1893
// [?] Letter ::= [A-Za-z] (ascii subset of 'Letter')
1894
// [?] Digit ::= [0-9] (ascii subset of 'Digit')
1895
//
1896
nameOffset = currentOffset;
1897                    currentOffset = scanNCName(data, endOffset, currentOffset);
1898                    if (currentOffset == nameOffset) {
1899                // System.out.println("abort 4c");
1900
return false; // REVISIT
1901
}
1902                    if (currentOffset < endOffset) {
1903                        ch = data.charAt(currentOffset);
1904                    }
1905                    else {
1906                        ch = -1;
1907                    }
1908                    /***
1909                    nameHandle = tokens.addSymbol(data, nameOffset, currentOffset - nameOffset, encoding);
1910                    /***/

1911                    nameHandle = stringPool.addSymbol(data.substring(nameOffset, currentOffset));
1912                    /***/
1913                    boolean isNameTestNCName = false;
1914                    boolean isAxisName = false;
1915                    prefixHandle = -1;
1916                    if (ch == ':') {
1917                        if (++currentOffset == endOffset) {
1918                // System.out.println("abort 5");
1919
return false; // REVISIT
1920
}
1921                        /***
1922                        ch = (data[currentOffset] & 0xFF);
1923                        /***/

1924                        ch = data.charAt(currentOffset);
1925                        /***/
1926                        if (ch == '*') {
1927                            if (++currentOffset < endOffset) {
1928                                /***
1929                                ch = (data[currentOffset] & 0xFF);
1930                                /***/

1931                                ch = data.charAt(currentOffset);
1932                                /***/
1933                            }
1934                            isNameTestNCName = true;
1935                        } else if (ch == ':') {
1936                            if (++currentOffset < endOffset) {
1937                                /***
1938                                ch = (data[currentOffset] & 0xFF);
1939                                /***/

1940                                ch = data.charAt(currentOffset);
1941                                /***/
1942                            }
1943                            isAxisName = true;
1944                        } else {
1945                            prefixHandle = nameHandle;
1946                            nameOffset = currentOffset;
1947                            currentOffset = scanNCName(data, endOffset, currentOffset);
1948                            if (currentOffset == nameOffset) {
1949                // System.out.println("abort 5b");
1950
return false; // REVISIT
1951
}
1952                            if (currentOffset < endOffset) {
1953                                ch = data.charAt(currentOffset);
1954                            }
1955                            else {
1956                                ch = -1;
1957                            }
1958                            /***
1959                            nameHandle = tokens.addSymbol(data, nameOffset, currentOffset - nameOffset, encoding);
1960                            /***/

1961                            nameHandle = stringPool.addSymbol(data.substring(nameOffset, currentOffset));
1962                            /***/
1963                        }
1964                    }
1965                    //
1966
// [39] ExprWhitespace ::= S
1967
//
1968
while (ch == ' ' || ch == 0x0A || ch == 0x09 || ch == 0x0D) {
1969                        if (++currentOffset == endOffset) {
1970                            break;
1971                        }
1972                        /***
1973                        ch = (data[currentOffset] & 0xFF);
1974                        /***/

1975                        ch = data.charAt(currentOffset);
1976                        /***/
1977                    }
1978                    //
1979
// If there is a preceding token and the preceding token is not one of @, ::, (, [, , or
1980
// an Operator, then an NCName must be recognized as an OperatorName.
1981
//
1982
if (starIsMultiplyOperator) {
1983                        if (nameHandle == fAndSymbol) {
1984                            addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_AND);
1985                            starIsMultiplyOperator = false;
1986                        } else if (nameHandle == fOrSymbol) {
1987                            addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_OR);
1988                            starIsMultiplyOperator = false;
1989                        } else if (nameHandle == fModSymbol) {
1990                            addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_MOD);
1991                            starIsMultiplyOperator = false;
1992                        } else if (nameHandle == fDivSymbol) {
1993                            addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_DIV);
1994                            starIsMultiplyOperator = false;
1995                        } else {
1996                // System.out.println("abort 6");
1997
return false; // REVISIT
1998
}
1999                        if (isNameTestNCName) {
2000                // System.out.println("abort 7");
2001
return false; // REVISIT - NCName:* where an OperatorName is required
2002
} else if (isAxisName) {
2003                // System.out.println("abort 8");
2004
return false; // REVISIT - AxisName:: where an OperatorName is required
2005
}
2006                        break;
2007                    }
2008                    //
2009
// If the character following an NCName (possibly after intervening ExprWhitespace) is (,
2010
// then the token must be recognized as a NodeType or a FunctionName.
2011
//
2012
if (ch == '(' && !isNameTestNCName && !isAxisName) {
2013                        if (nameHandle == fCommentSymbol) {
2014                            addToken(tokens, XPath.Tokens.EXPRTOKEN_NODETYPE_COMMENT);
2015                        } else if (nameHandle == fTextSymbol) {
2016                            addToken(tokens, XPath.Tokens.EXPRTOKEN_NODETYPE_TEXT);
2017                        } else if (nameHandle == fPISymbol) {
2018                            addToken(tokens, XPath.Tokens.EXPRTOKEN_NODETYPE_PI);
2019                        } else if (nameHandle == fNodeSymbol) {
2020                            addToken(tokens, XPath.Tokens.EXPRTOKEN_NODETYPE_NODE);
2021                        } else {
2022                            addToken(tokens, XPath.Tokens.EXPRTOKEN_FUNCTION_NAME);
2023                            tokens.addToken(prefixHandle);
2024                            tokens.addToken(nameHandle);
2025                        }
2026                        addToken(tokens, XPath.Tokens.EXPRTOKEN_OPEN_PAREN);
2027                        starIsMultiplyOperator = false;
2028                        if (++currentOffset == endOffset) {
2029                            break;
2030                        }
2031                        break;
2032                    }
2033                    //
2034
// If the two characters following an NCName (possibly after intervening ExprWhitespace)
2035
// are ::, then the token must be recognized as an AxisName.
2036
//
2037
if (isAxisName ||
2038                        (ch == ':' && currentOffset + 1 < endOffset &&
2039                         /***
2040                         (data[currentOffset + 1] & 0xFF) == ':')) {
2041                         /***/

2042                         data.charAt(currentOffset + 1) == ':')) {
2043                         /***/
2044                        if (nameHandle == fAncestorSymbol) {
2045                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_ANCESTOR);
2046                        } else if (nameHandle == fAncestorOrSelfSymbol) {
2047                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF);
2048                        } else if (nameHandle == fAttributeSymbol) {
2049                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_ATTRIBUTE);
2050                        } else if (nameHandle == fChildSymbol) {
2051                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_CHILD);
2052                        } else if (nameHandle == fDescendantSymbol) {
2053                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_DESCENDANT);
2054                        } else if (nameHandle == fDescendantOrSelfSymbol) {
2055                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF);
2056                        } else if (nameHandle == fFollowingSymbol) {
2057                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_FOLLOWING);
2058                        } else if (nameHandle == fFollowingSiblingSymbol) {
2059                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING);
2060                        } else if (nameHandle == fNamespaceSymbol) {
2061                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_NAMESPACE);
2062                        } else if (nameHandle == fParentSymbol) {
2063                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_PARENT);
2064                        } else if (nameHandle == fPrecedingSymbol) {
2065                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_PRECEDING);
2066                        } else if (nameHandle == fPrecedingSiblingSymbol) {
2067                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_PRECEDING_SIBLING);
2068                        } else if (nameHandle == fSelfSymbol) {
2069                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_SELF);
2070                        } else {
2071                // System.out.println("abort 9");
2072
return false; // REVISIT
2073
}
2074                        if (isNameTestNCName) {
2075                // System.out.println("abort 10");
2076
return false; // REVISIT - "NCName:* ::" where "AxisName ::" is required
2077
}
2078                        addToken(tokens, XPath.Tokens.EXPRTOKEN_DOUBLE_COLON);
2079                        starIsMultiplyOperator = false;
2080                        if (!isAxisName) {
2081                            currentOffset++;
2082                            if (++currentOffset == endOffset) {
2083                                break;
2084                            }
2085                        }
2086                        break;
2087                    }
2088                    //
2089
// Otherwise, the token must not be recognized as an OperatorName, a NodeType, a
2090
// FunctionName, or an AxisName.
2091
//
2092
if (isNameTestNCName) {
2093                        addToken(tokens, XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE);
2094                        starIsMultiplyOperator = true;
2095                        tokens.addToken(nameHandle);
2096                    } else {
2097                        addToken(tokens, XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME);
2098                        starIsMultiplyOperator = true;
2099                        tokens.addToken(prefixHandle);
2100                        tokens.addToken(nameHandle);
2101                    }
2102                    break;
2103                }
2104            }
2105            if (XPath.Tokens.DUMP_TOKENS) {
2106                tokens.dumpTokens();
2107            }
2108            return true;
2109        }
2110        //
2111
// [5] NCName ::= (Letter | '_') (NCNameChar)*
2112
// [6] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | CombiningChar | Extender
2113
//
2114
int scanNCName(String JavaDoc data, int endOffset, int currentOffset) {
2115            int ch = data.charAt(currentOffset);
2116            if (ch >= 0x80) {
2117                if ((XMLCharacterProperties.fgCharFlags[ch] &
2118                     XMLCharacterProperties.E_InitialNameCharFlag) == 0)
2119                {
2120                    return currentOffset;
2121                }
2122            }
2123            else {
2124                byte chartype = fASCIICharMap[ch];
2125                if (chartype != CHARTYPE_LETTER && chartype != CHARTYPE_UNDERSCORE) {
2126                    return currentOffset;
2127                }
2128            }
2129            while (++currentOffset < endOffset) {
2130                ch = data.charAt(currentOffset);
2131                if (ch >= 0x80) {
2132                    if ((XMLCharacterProperties.fgCharFlags[ch] &
2133                         XMLCharacterProperties.E_NameCharFlag) == 0)
2134                    {
2135                        break;
2136                    }
2137                }
2138                else {
2139                    byte chartype = fASCIICharMap[ch];
2140                    if (chartype != CHARTYPE_LETTER && chartype != CHARTYPE_DIGIT &&
2141                        chartype != CHARTYPE_PERIOD && chartype != CHARTYPE_MINUS &&
2142                        chartype != CHARTYPE_UNDERSCORE)
2143                    {
2144                        break;
2145                    }
2146                }
2147            }
2148            return currentOffset;
2149        }
2150        /*
2151        void allocateProducer(byte[] data, int offset, int length, EncodingSupport encoding) {
2152            XPathStringProducer sp = fStringProducers[fStringProducerCount];
2153            if (sp != null) {
2154                sp = sp.setState(data, offset, length, encoding);
2155            } else {
2156                sp = new XPathStringProducer(data, offset, length, encoding);
2157            }
2158            fStringProducers[fStringProducerCount++] = sp;
2159        }
2160        void finalizeProducer(byte[] data) {
2161            fStringProducerCount--;
2162        }
2163        class XPathStringProducer {
2164            byte[] fData = null;
2165            int fOffset = -1;
2166            int fLength = -1;
2167            String fEncoding = null;
2168            XPathStringProducer(byte[] data, int offset, int length, EncodingSupport encoding) {
2169                init(data, offset, length, encoding);
2170            }
2171            XPathStringProducer setState(byte[] bytes, int offset, int length, EncodingSupport encoding) {
2172                init(bytes, offset, length, encoding);
2173                return this;
2174            }
2175            void init(byte[] data, int offset, int length, EncodingSupport encoding) {
2176                fData = data;
2177                fOffset = offset;
2178                fLength = length;
2179                fEncoding = encoding;
2180            }
2181            String getEncoding() {
2182                return fEncoding;
2183            }
2184            void finalizeProducer() {
2185                // do nothing
2186            }
2187            int addSymbol(int offset, int length) {
2188                return fSymbolTable.addSymbol(fData, offset, length, fEncoding);
2189            }
2190        }
2191        private XPathStringProducer[] fStringProducers = new XPathStringProducer[8];
2192        private int fStringProducerCount = 0;
2193        private XPathStringProducer getStringProducer(byte[] data) {
2194            XPathStringProducer sp = null;
2195            for (int i = 0; i < fStringProducerCount; i++) {
2196                if (fStringProducers[i].fData == data) {
2197                    return fStringProducers[i];
2198                }
2199            }
2200            throw new RuntimeException("No StringProducer");
2201        }
2202        */

2203        //
2204
// [30] Number ::= Digits ('.' Digits?)? | '.' Digits
2205
// [31] Digits ::= [0-9]+
2206
//
2207
private int scanNumber(XPath.Tokens tokens, String JavaDoc/*byte[]*/ data, int endOffset, int currentOffset/*, EncodingSupport encoding*/) {
2208            /***
2209            int ch = (data[currentOffset] & 0xFF);
2210            /***/

2211            int ch = data.charAt(currentOffset);
2212            /***/
2213            int whole = 0;
2214            int part = 0;
2215            while (ch >= '0' && ch <= '9') {
2216                whole = (whole * 10) + (ch - '0');
2217                if (++currentOffset == endOffset) {
2218                    break;
2219                }
2220                /***
2221                ch = (data[currentOffset] & 0xFF);
2222                /***/

2223                ch = data.charAt(currentOffset);
2224                /***/
2225            }
2226            if (ch == '.') {
2227                if (++currentOffset < endOffset) {
2228                    int start = currentOffset;
2229                    /***
2230                    ch = (data[currentOffset] & 0xFF);
2231                    /***/

2232                    ch = data.charAt(currentOffset);
2233                    /***/
2234                    while (ch >= '0' && ch <= '9') {
2235                        part = (part * 10) + (ch - '0');
2236                        if (++currentOffset == endOffset) {
2237                            break;
2238                        }
2239                        /***
2240                        ch = (data[currentOffset] & 0xFF);
2241                        /***/

2242                        ch = data.charAt(currentOffset);
2243                        /***/
2244                    }
2245                    if (part != 0) {
2246                        /***
2247                        part = tokens.addSymbol(data, start, currentOffset - start, encoding);
2248                        /***/

2249                        throw new RuntimeException JavaDoc("find a solution!");
2250                        //part = fStringPool.addSymbol(data.substring(start, currentOffset));
2251
/***/
2252                    }
2253                }
2254            }
2255            tokens.addToken(whole);
2256            tokens.addToken(part);
2257            return currentOffset;
2258        }
2259
2260        /***
2261        public static SymbolTable getGlobalTokens() {
2262            return fgSymbolTable;
2263        }
2264
2265        public static void main(String argv[]) {
2266            try {
2267                SymbolTable symbols = new SymbolTable(XPathExprScanner.getGlobalTokens());
2268                XPath.Tokens tokens = new XPath.Tokens(symbols);
2269                byte[] bytes = new byte[1 << 8]; // 256
2270                int i = 0;
2271                if (XPath.Tokens.DUMP_TOKENS) {
2272                    System.out.println("<output>");
2273                    System.out.println();
2274                }
2275                while (i < argv.length) {
2276                    String uri = argv[i++];
2277                    // System.out.println("uri: "+uri);
2278                    FileInputStream is = new FileInputStream(uri);
2279                    int lineOffset = 0;
2280                    int offset = 0;
2281                    while (true) {
2282                        int avail = bytes.length - offset;
2283                        if (avail == 0) {
2284                            avail = bytes.length;
2285                            byte[] newBytes = new byte[avail << 1];
2286                            System.arraycopy(bytes, 0, newBytes, 0, avail);
2287                            bytes = newBytes;
2288                        }
2289                        int result = is.read(bytes, offset, avail);
2290                        if (result == -1) {
2291                            bytes[offset] = 0;
2292                            break;
2293                        }
2294                        result += offset;
2295                        for (int j = offset; j < result; j++) {
2296                            int ch = bytes[j];
2297                            if (ch == 0x0A || ch == 0x0D) {
2298                                if (lineOffset < offset) {
2299                                    XPathExprScanner.scanExpr(tokens, bytes, lineOffset, offset, UTF8EncodingSupport.getInstance());
2300                                }
2301                                while (ch == 0x0A || ch == 0x0D) {
2302                                    if (++j == result) {
2303                                        j = result;
2304                                        break;
2305                                    }
2306                                    ch = bytes[j];
2307                                }
2308                                lineOffset = offset;
2309                                if (j == result) {
2310                                    break;
2311                                }
2312                            }
2313                            bytes[offset++] = (byte)ch;
2314                        }
2315                    }
2316                    is.close();
2317                }
2318                if (XPath.Tokens.DUMP_TOKENS) {
2319                    System.out.println("</output>");
2320                }
2321            }
2322            catch (Exception e) {
2323                e.printStackTrace();
2324            }
2325        }
2326        /***/

2327
2328        //
2329
// Protected methods
2330
//
2331

2332        /**
2333         * This method adds the specified token to the token list. By
2334         * default, this method allows all tokens. However, subclasses
2335         * of the XPathExprScanner can override this method in order
2336         * to disallow certain tokens from being used in the scanned
2337         * XPath expression. This is a convenient way of allowing only
2338         * a subset of XPath.
2339         */

2340        protected void addToken(XPath.Tokens tokens, int token)
2341            throws XPathException {
2342            tokens.addToken(token);
2343        } // addToken(int)
2344

2345    } // class Scanner
2346

2347    /**
2348     * @author Glenn Marcy, IBM
2349     * @author Andy Clark, IBM
2350     *
2351     * @version $Id: XPath.java,v 1.1.1.1 2003/03/10 16:34:52 taweili Exp $
2352     */

2353    /***
2354    public static class XPathExprParser {
2355
2356        //
2357        // Constants
2358        //
2359
2360        private static final boolean DUMP_PARSE_TREE = false;
2361
2362        private static final boolean DEBUG_PUSH_PARSEOPS = false;
2363
2364        /** Parse Tree operations * /
2365        public static final int
2366            PARSEOP_OR = -5000,
2367            PARSEOP_AND = -5001,
2368            PARSEOP_EQUAL = -5002,
2369            PARSEOP_NOT_EQUAL = -5003,
2370            PARSEOP_PLUS = -5004,
2371            PARSEOP_MINUS = -5005,
2372            PARSEOP_MULT = -5006,
2373            PARSEOP_DIV = -5007,
2374            PARSEOP_MOD = -5008,
2375            PARSEOP_LESS = -5009,
2376            PARSEOP_GREATER = -5010,
2377            PARSEOP_LESS_EQUAL = -5011,
2378            PARSEOP_GREATER_EQUAL = -5012,
2379            PARSEOP_NEGATE = -5013,
2380            PARSEOP_UNION = -5014,
2381            PARSEOP_SELECT_ROOT = -5015,
2382            PARSEOP_STEPS = -5016,
2383            PARSEOP_STEP = -5017,
2384            PARSEOP_AXIS_ANCESTOR = -5018,
2385            PARSEOP_AXIS_ANCESTOR_OR_SELF = -5019,
2386            PARSEOP_AXIS_ATTRIBUTE = -5020,
2387            PARSEOP_AXIS_CHILD = -5021,
2388            PARSEOP_AXIS_DESCENDANT = -5022,
2389            PARSEOP_AXIS_DESCENDANT_OR_SELF = -5023,
2390            PARSEOP_AXIS_FOLLOWING = -5024,
2391            PARSEOP_AXIS_FOLLOWING_SIBLING = -5025,
2392            PARSEOP_AXIS_NAMESPACE = -5026,
2393            PARSEOP_AXIS_PARENT = -5027,
2394            PARSEOP_AXIS_PRECEDING = -5028,
2395            PARSEOP_AXIS_PRECEDING_SIBLING = -5029,
2396            PARSEOP_AXIS_SELF = -5030,
2397            PARSEOP_NODETEST_ANY = -5031,
2398            PARSEOP_NODETEST_NAMESPACE = -5032,
2399            PARSEOP_NODETEST_QNAME = -5033,
2400            PARSEOP_NODETEST_COMMENT = -5034,
2401            PARSEOP_NODETEST_TEXT = -5035,
2402            PARSEOP_NODETEST_PI = -5036,
2403            PARSEOP_NODETEST_PI_TARGET = -5037,
2404            PARSEOP_NODETEST_NODE = -5038,
2405            PARSEOP_FILTER = -5039,
2406            PARSEOP_PREDICATES = -5040,
2407            PARSEOP_PREDICATE = -5041,
2408            PARSEOP_VARIABLE_REFERENCE = -5042,
2409            PARSEOP_GROUPING = -5043,
2410            PARSEOP_LITERAL = -5044,
2411            PARSEOP_NUMBER = -5045,
2412            PARSEOP_FUNCTION = -5046,
2413            PARSEOP_FUNCTION_NAME = -5047,
2414            PARSEOP_FUNCTION_ARGUMENTS = -5048;
2415
2416        //
2417        // Data
2418        //
2419
2420        private int fTokenCount = 0; // for reading
2421        private int fCurrentToken = 0; // for reading
2422
2423        private static final int INITIAL_PARSEOP_COUNT = 1 << 8;
2424        private int[] fParseTree = new int[INITIAL_PARSEOP_COUNT];
2425        private int fParseOpCount = 0; // for writing
2426        private int fCurrentParseOp = 0; // for reading
2427
2428        /** Symbol table. * /
2429        private SymbolTable fSymbolTable;
2430
2431        /** Tokens. * /
2432        private XPath.Tokens fTokens;
2433
2434        /** Scanner. * /
2435        private XPathExprScanner fScanner;
2436
2437        //
2438        // Constructors
2439        //
2440
2441        public XPathExprParser() {
2442            this(new SymbolTable());
2443        }
2444
2445        public XPathExprParser(SymbolTable symbolTable) {
2446            this(symbolTable, new XPathExprScanner(symbolTable));
2447        }
2448
2449        public XPathExprParser(SymbolTable symbolTable, XPathExprScanner scanner) {
2450
2451            fSymbolTable = symbolTable;
2452            fScanner = scanner;
2453
2454        } // <init>(SymbolTable,XPathExprScanner)
2455
2456        //
2457        // Public methods
2458        //
2459
2460        // init
2461
2462        public void reset() {
2463            fParseOpCount = 0;
2464            fCurrentParseOp = 0;
2465        }
2466
2467        // parsing
2468
2469        public int parseExpr(String data) throws XPathException {
2470            return parseExpr(data, 0, data.length());
2471        }
2472
2473        public int parseExpr(String data, int currentOffset, int endOffset)
2474            throws XPathException {
2475            return parseExprOrPattern(data, currentOffset, endOffset, false);
2476        }
2477
2478        public int parsePattern(String data, int currentOffset, int endOffset)
2479            throws XPathException {
2480            return parseExprOrPattern(data, currentOffset, endOffset, true);
2481        }
2482
2483        public int parseExprOrPattern(String data, int currentOffset,
2484                                      int endOffset, boolean isPattern)
2485            throws XPathException {
2486            fTokenCount = 0;
2487
2488            if (DUMP_PARSE_TREE) {
2489                System.out.println(" <test>");
2490                System.out.println(" <expression>");
2491                System.out.println(" " + data.substring(currentOffset, endOffset));
2492                System.out.println(" </expression>");
2493            }
2494            fTokens = new XPath.Tokens(fSymbolTable);
2495            fScanner.scanExpr(fTokens, data, currentOffset, endOffset);
2496            //
2497            // Build parse tree
2498            //
2499            fTokenCount = fTokens.getTokenCount();
2500            fCurrentToken = 0;
2501            if (!parseExpr()) {
2502                // System.out.println("abort 12");
2503                return -1; // REVISIT
2504            }
2505            if (fCurrentToken < fTokenCount) {
2506                // System.out.println("abort 13");
2507                return -1; // REVISIT
2508            }
2509            if (DUMP_PARSE_TREE) {
2510                dumpParseTree(fCurrentParseOp, 4);
2511            }
2512            if (DUMP_PARSE_TREE) {
2513                System.out.println(" </test>");
2514                System.out.println();
2515            }
2516            return fCurrentParseOp;
2517        }
2518
2519        // parse tree ops
2520
2521        public int getCurrentParseOp() {
2522            return fCurrentParseOp;
2523        }
2524
2525        public int getParseTreeOp(int handle) {
2526            return fParseTree[handle];
2527        }
2528
2529        public int getParseTreeSubHandle(int handle, int subHandleIndex) {
2530            return fParseTree[handle - 1 - subHandleIndex];
2531        }
2532
2533        public String getParseTreeSymbol(int handle, int subHandleIndex) {
2534            int symHandle = fParseTree[handle - 1 - subHandleIndex];
2535            return fTokens.getTokenString(symHandle);
2536        }
2537
2538        public int getParseTreeIntValue(int handle, int subHandleIndex) {
2539            return fParseTree[handle - 1 - subHandleIndex];
2540        }
2541
2542        // debugging
2543
2544        public void dumpParseTree(int rootParseOp, int indent) {
2545                indentPrint(indent);
2546                System.out.println("<parse-tree>");
2547                dumpParseTreeNode(rootParseOp, indent + 2);
2548                indentPrint(indent);
2549                System.out.println("</parse-tree>");
2550        }
2551
2552        public String getParseOpName(int parseOp) {
2553            switch (parseOp) {
2554                case PARSEOP_OR: return "PARSEOP_OR";
2555                case PARSEOP_AND: return "PARSEOP_AND";
2556                case PARSEOP_EQUAL: return "PARSEOP_EQUAL";
2557                case PARSEOP_NOT_EQUAL: return "PARSEOP_NOT_EQUAL";
2558                case PARSEOP_PLUS: return "PARSEOP_PLUS";
2559                case PARSEOP_MINUS: return "PARSEOP_MINUS";
2560                case PARSEOP_MULT: return "PARSEOP_MULT";
2561                case PARSEOP_DIV: return "PARSEOP_DIV";
2562                case PARSEOP_MOD: return "PARSEOP_MOD";
2563                case PARSEOP_LESS: return "PARSEOP_LESS";
2564                case PARSEOP_GREATER: return "PARSEOP_GREATER";
2565                case PARSEOP_LESS_EQUAL: return "PARSEOP_LESS_EQUAL";
2566                case PARSEOP_GREATER_EQUAL: return "PARSEOP_GREATER_EQUAL";
2567                case PARSEOP_NEGATE: return "PARSEOP_NEGATE";
2568                case PARSEOP_UNION: return "PARSEOP_UNION";
2569                case PARSEOP_SELECT_ROOT: return "PARSEOP_SELECT_ROOT";
2570                case PARSEOP_STEPS: return "PARSEOP_STEPS";
2571                case PARSEOP_STEP: return "PARSEOP_STEP";
2572                case PARSEOP_AXIS_ANCESTOR: return "PARSEOP_AXIS_ANCESTOR";
2573                case PARSEOP_AXIS_ANCESTOR_OR_SELF: return "PARSEOP_AXIS_ANCESTOR_OR_SELF";
2574                case PARSEOP_AXIS_ATTRIBUTE: return "PARSEOP_AXIS_ATTRIBUTE";
2575                case PARSEOP_AXIS_CHILD: return "PARSEOP_AXIS_CHILD";
2576                case PARSEOP_AXIS_DESCENDANT: return "PARSEOP_AXIS_DESCENDANT";
2577                case PARSEOP_AXIS_DESCENDANT_OR_SELF: return "PARSEOP_AXIS_DESCENDANT_OR_SELF";
2578                case PARSEOP_AXIS_FOLLOWING: return "PARSEOP_AXIS_FOLLOWING";
2579                case PARSEOP_AXIS_FOLLOWING_SIBLING: return "PARSEOP_AXIS_FOLLOWING_SIBLING";
2580                case PARSEOP_AXIS_NAMESPACE: return "PARSEOP_AXIS_NAMESPACE";
2581                case PARSEOP_AXIS_PARENT: return "PARSEOP_AXIS_PARENT";
2582                case PARSEOP_AXIS_PRECEDING: return "PARSEOP_AXIS_PRECEDING";
2583                case PARSEOP_AXIS_PRECEDING_SIBLING: return "PARSEOP_AXIS_PRECEDING_SIBLING";
2584                case PARSEOP_AXIS_SELF: return "PARSEOP_AXIS_SELF";
2585                case PARSEOP_NODETEST_ANY: return "PARSEOP_NODETEST_ANY";
2586                case PARSEOP_NODETEST_NAMESPACE: return "PARSEOP_NODETEST_NAMESPACE";
2587                case PARSEOP_NODETEST_QNAME: return "PARSEOP_NODETEST_QNAME";
2588                case PARSEOP_NODETEST_COMMENT: return "PARSEOP_NODETEST_COMMENT";
2589                case PARSEOP_NODETEST_TEXT: return "PARSEOP_NODETEST_TEXT";
2590                case PARSEOP_NODETEST_PI: return "PARSEOP_NODETEST_PI";
2591                case PARSEOP_NODETEST_PI_TARGET: return "PARSEOP_NODETEST_PI_TARGET";
2592                case PARSEOP_NODETEST_NODE: return "PARSEOP_NODETEST_NODE";
2593                case PARSEOP_FILTER: return "PARSEOP_FILTER";
2594                case PARSEOP_PREDICATES: return "PARSEOP_PREDICATES";
2595                case PARSEOP_PREDICATE: return "PARSEOP_PREDICATE";
2596                case PARSEOP_VARIABLE_REFERENCE: return "PARSEOP_VARIABLE_REFERENCE";
2597                case PARSEOP_GROUPING: return "PARSEOP_GROUPING";
2598                case PARSEOP_LITERAL: return "PARSEOP_LITERAL";
2599                case PARSEOP_NUMBER: return "PARSEOP_NUMBER";
2600                case PARSEOP_FUNCTION: return "PARSEOP_FUNCTION";
2601                case PARSEOP_FUNCTION_NAME: return "PARSEOP_FUNCTION_NAME";
2602                case PARSEOP_FUNCTION_ARGUMENTS: return "PARSEOP_FUNCTION_ARGUMENTS";
2603            }
2604            return "??? ("+parseOp+')';
2605        }
2606
2607        //
2608        // Protected methods
2609        //
2610
2611        protected void checkParseOp(int parseOp) throws XPathException {
2612            // do nothing; all parse ops allowed in the class
2613        }
2614
2615        //
2616        // Private methods
2617        //
2618
2619        private void pushParseOp(int parseOp) throws XPathException {
2620            if (DEBUG_PUSH_PARSEOPS) {
2621                System.out.println("pushParseOp: "+getParseOpName(parseOp));
2622            }
2623            checkParseOp(parseOp);
2624            try {
2625                fParseTree[fParseOpCount] = parseOp;
2626            } catch (ArrayIndexOutOfBoundsException ex) {
2627                int[] oldList = fParseTree;
2628                fParseTree = new int[fParseOpCount << 1];
2629                System.arraycopy(oldList, 0, fParseTree, 0, fParseOpCount);
2630                fParseTree[fParseOpCount] = parseOp;
2631            }
2632            fCurrentParseOp = fParseOpCount++;
2633        }
2634
2635        private void pushParseOp2(int parseOp, int arg) throws XPathException {
2636            if (DEBUG_PUSH_PARSEOPS) {
2637                System.out.println("pushParseOp2: "+getParseOpName(parseOp)+", "+arg);
2638            }
2639            checkParseOp(parseOp);
2640            try {
2641                fParseTree[fParseOpCount + 1] = parseOp;
2642            } catch (ArrayIndexOutOfBoundsException ex) {
2643                int[] oldList = fParseTree;
2644                fParseTree = new int[fParseOpCount << 1];
2645                System.arraycopy(oldList, 0, fParseTree, 0, fParseOpCount);
2646                fParseTree[fParseOpCount + 1] = parseOp;
2647            }
2648            fParseTree[fParseOpCount++] = arg;
2649            fCurrentParseOp = fParseOpCount++;
2650        }
2651
2652        private void pushParseOp3(int parseOp, int arg1, int arg2)
2653            throws XPathException {
2654            if (DEBUG_PUSH_PARSEOPS) {
2655                System.out.println("pushParseOp3: "+getParseOpName(parseOp)+", "+arg1+", "+arg2);
2656            }
2657            checkParseOp(parseOp);
2658            try {
2659                fParseTree[fParseOpCount + 2] = parseOp;
2660            } catch (ArrayIndexOutOfBoundsException ex) {
2661                int[] oldList = fParseTree;
2662                fParseTree = new int[fParseOpCount << 1];
2663                System.arraycopy(oldList, 0, fParseTree, 0, fParseOpCount);
2664                fParseTree[fParseOpCount + 2] = parseOp;
2665            }
2666            fParseTree[fParseOpCount++] = arg2;
2667            fParseTree[fParseOpCount++] = arg1;
2668            fCurrentParseOp = fParseOpCount++;
2669        }
2670
2671        private void indentPrint(int indent) {
2672            for (int i = 0; i < indent; i++) {
2673                System.out.print(" ");
2674            }
2675        }
2676
2677        private void dumpParseTreeNode(int parseOp, int indent) {
2678                switch (fParseTree[parseOp]) {
2679                case PARSEOP_OR:
2680                    indentPrint(indent);
2681                    System.out.println("<or>");
2682                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2683                    dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2684                    indentPrint(indent);
2685                    System.out.println("</or>");
2686                    break;
2687                case PARSEOP_AND:
2688                    indentPrint(indent);
2689                    System.out.println("<and>");
2690                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2691                    dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2692                    indentPrint(indent);
2693                    System.out.println("</and>");
2694                    break;
2695                case PARSEOP_EQUAL:
2696                    indentPrint(indent);
2697                    System.out.println("<equal>");
2698                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2699                    dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2700                    indentPrint(indent);
2701                    System.out.println("</equal>");
2702                    break;
2703                case PARSEOP_NOT_EQUAL:
2704                    indentPrint(indent);
2705                    System.out.println("<not-equal>");
2706                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2707                    dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2708                    indentPrint(indent);
2709                    System.out.println("</not-equal>");
2710                    break;
2711                case PARSEOP_PLUS:
2712                    indentPrint(indent);
2713                    System.out.println("<plus>");
2714                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2715                    dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2716                    indentPrint(indent);
2717                    System.out.println("</plus>");
2718                    break;
2719                case PARSEOP_MINUS:
2720                    indentPrint(indent);
2721                    System.out.println("<minus>");
2722                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2723                    dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2724                    indentPrint(indent);
2725                    System.out.println("</minus>");
2726                    break;
2727                case PARSEOP_MULT:
2728                    indentPrint(indent);
2729                    System.out.println("<mult>");
2730                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2731                    dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2732                    indentPrint(indent);
2733                    System.out.println("</mult>");
2734                    break;
2735                case PARSEOP_DIV:
2736                    indentPrint(indent);
2737                    System.out.println("<div>");
2738                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2739                    dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2740                    indentPrint(indent);
2741                    System.out.println("</div>");
2742                    break;
2743                case PARSEOP_MOD:
2744                    indentPrint(indent);
2745                    System.out.println("<mod>");
2746                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2747                    dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2748                    indentPrint(indent);
2749                    System.out.println("</mod>");
2750                    break;
2751                case PARSEOP_LESS:
2752                    indentPrint(indent);
2753                    System.out.println("<less>");
2754                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2755                    dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2756                    indentPrint(indent);
2757                    System.out.println("</less>");
2758                    break;
2759                case PARSEOP_GREATER:
2760                    indentPrint(indent);
2761                    System.out.println("<greater>");
2762                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2763                    dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2764                    indentPrint(indent);
2765                    System.out.println("</greater>");
2766                    break;
2767                case PARSEOP_LESS_EQUAL:
2768                    indentPrint(indent);
2769                    System.out.println("<less-equal>");
2770                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2771                    dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2772                    indentPrint(indent);
2773                    System.out.println("</less-equal>");
2774                    break;
2775                case PARSEOP_GREATER_EQUAL:
2776                    indentPrint(indent);
2777                    System.out.println("<greater-equal>");
2778                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2779                    dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2780                    indentPrint(indent);
2781                    System.out.println("</greater-equal>");
2782                    break;
2783                case PARSEOP_NEGATE:
2784                    indentPrint(indent);
2785                    System.out.println("<negate>");
2786                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2787                    indentPrint(indent);
2788                    System.out.println("</negate>");
2789                    break;
2790                case PARSEOP_UNION:
2791                    indentPrint(indent);
2792                    System.out.println("<union>");
2793                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2794                    dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2795                    indentPrint(indent);
2796                    System.out.println("</union>");
2797                    break;
2798                case PARSEOP_SELECT_ROOT:
2799                    indentPrint(indent);
2800                    if (fParseTree[parseOp - 1] == -1) {
2801                        System.out.println("<select-root/>");
2802                    } else {
2803                        System.out.println("<select-root>");
2804                        dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2805                        indentPrint(indent);
2806                        System.out.println("</select-root>");
2807                    }
2808                    break;
2809                case PARSEOP_STEPS:
2810                    indentPrint(indent);
2811                    System.out.println("<relative-location-path>");
2812                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2813                    dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2814                    indentPrint(indent);
2815                    System.out.println("</relative-location-path>");
2816                    break;
2817                case PARSEOP_STEP:
2818                    indentPrint(indent);
2819                    System.out.println("<step>");
2820                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2821                    dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2822                    indentPrint(indent);
2823                    System.out.println("</step>");
2824                    break;
2825                case PARSEOP_AXIS_ANCESTOR:
2826                    indentPrint(indent);
2827                    System.out.println("<axis name=\"ancestor\"/>");
2828                    break;
2829                case PARSEOP_AXIS_ANCESTOR_OR_SELF:
2830                    indentPrint(indent);
2831                    System.out.println("<axis name=\"ancestor-or-self\"/>");
2832                    break;
2833                case PARSEOP_AXIS_ATTRIBUTE:
2834                    indentPrint(indent);
2835                    System.out.println("<axis name=\"attribute\"/>");
2836                    break;
2837                case PARSEOP_AXIS_CHILD:
2838                    indentPrint(indent);
2839                    System.out.println("<axis name=\"child\"/>");
2840                    break;
2841                case PARSEOP_AXIS_DESCENDANT:
2842                    indentPrint(indent);
2843                    System.out.println("<axis name=\"descendant\"/>");
2844                    break;
2845                case PARSEOP_AXIS_DESCENDANT_OR_SELF:
2846                    indentPrint(indent);
2847                    System.out.println("<axis name=\"descendant-or-self\"/>");
2848                    break;
2849                case PARSEOP_AXIS_FOLLOWING:
2850                    indentPrint(indent);
2851                    System.out.println("<axis name=\"following\"/>");
2852                    break;
2853                case PARSEOP_AXIS_FOLLOWING_SIBLING:
2854                    indentPrint(indent);
2855                    System.out.println("<axis name=\"following-sibling\"/>");
2856                    break;
2857                case PARSEOP_AXIS_NAMESPACE:
2858                    indentPrint(indent);
2859                    System.out.println("<axis name=\"namespace\"/>");
2860                    break;
2861                case PARSEOP_AXIS_PARENT:
2862                    indentPrint(indent);
2863                    System.out.println("<axis name=\"parent\"/>");
2864                    break;
2865                case PARSEOP_AXIS_PRECEDING:
2866                    indentPrint(indent);
2867                    System.out.println("<axis name=\"preceding\"/>");
2868                    break;
2869                case PARSEOP_AXIS_PRECEDING_SIBLING:
2870                    indentPrint(indent);
2871                    System.out.println("<axis name=\"preceding-sibling\"/>");
2872                    break;
2873                case PARSEOP_AXIS_SELF:
2874                    indentPrint(indent);
2875                    System.out.println("<axis name=\"self\"/>");
2876                    break;
2877                case PARSEOP_NODETEST_ANY:
2878                    indentPrint(indent);
2879                    System.out.println("<nodetest type=\"any\"/>");
2880                    break;
2881                case PARSEOP_NODETEST_NAMESPACE:
2882                    indentPrint(indent);
2883                    System.out.print("<nodetest type=\"namespace\"");
2884                    System.out.print(" prefix=\"" + fParseTree[parseOp - 1] + "\"");
2885                    System.out.println("/>");
2886                    break;
2887                case PARSEOP_NODETEST_QNAME:
2888                    indentPrint(indent);
2889                    System.out.print("<nodetest type=\"qname\"");
2890                    if (fParseTree[parseOp - 1] != -1) {
2891                        System.out.print(" prefix=\"" + fParseTree[parseOp - 1] + "\"");
2892                    }
2893                    System.out.print(" localpart=\"" + fParseTree[parseOp - 2] + "\"");
2894                    System.out.println("/>");
2895                    break;
2896                case PARSEOP_NODETEST_COMMENT:
2897                    indentPrint(indent);
2898                    System.out.println("<nodetest type=\"comment\"/>");
2899                    break;
2900                case PARSEOP_NODETEST_TEXT:
2901                    indentPrint(indent);
2902                    System.out.println("<nodetest type=\"text\"/>");
2903                    break;
2904                case PARSEOP_NODETEST_PI:
2905                    indentPrint(indent);
2906                    System.out.println("<nodetest type=\"processing-instruction\"/>");
2907                    break;
2908                case PARSEOP_NODETEST_PI_TARGET:
2909                    indentPrint(indent);
2910                    System.out.print("<nodetest type=\"processing-instruction\" target=\"");
2911                    System.out.print(fParseTree[parseOp - 1]);
2912                    System.out.println("\"/>");
2913                    break;
2914                case PARSEOP_NODETEST_NODE:
2915                    indentPrint(indent);
2916                    System.out.println("<nodetest type=\"node\"/>");
2917                    break;
2918                case PARSEOP_FILTER:
2919                    indentPrint(indent);
2920                    System.out.println("<step-with-predicate>");
2921                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2922                    dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2923                    indentPrint(indent);
2924                    System.out.println("</step-with-predicate>");
2925                    break;
2926                case PARSEOP_PREDICATES:
2927                    indentPrint(indent);
2928                    System.out.println("<predicates>");
2929                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2930                    dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2931                    indentPrint(indent);
2932                    System.out.println("</predicates>");
2933                    break;
2934                case PARSEOP_PREDICATE:
2935                    indentPrint(indent);
2936                    System.out.println("<predicate>");
2937                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2938                    indentPrint(indent);
2939                    System.out.println("</predicate>");
2940                    break;
2941                case PARSEOP_VARIABLE_REFERENCE:
2942                    indentPrint(indent);
2943                    System.out.print("<variable-reference");
2944                    if (fParseTree[parseOp - 1] != -1) {
2945                        System.out.print(" prefix=\"" + fParseTree[parseOp - 1] + "\"");
2946                    }
2947                    System.out.print(" localpart=\"" + fParseTree[parseOp - 2] + "\"");
2948                    System.out.println("/>");
2949                    break;
2950                case PARSEOP_GROUPING:
2951                    indentPrint(indent);
2952                    System.out.println("<grouping>");
2953                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2954                    indentPrint(indent);
2955                    System.out.println("</grouping>");
2956                    break;
2957                case PARSEOP_LITERAL:
2958                    indentPrint(indent);
2959                    System.out.print("<literal");
2960                    System.out.print(" value=\"" + fParseTree[parseOp - 1] + "\"");
2961                    System.out.println("/>");
2962                    break;
2963                case PARSEOP_NUMBER:
2964                    indentPrint(indent);
2965                    System.out.print("<number");
2966                    System.out.print(" whole=\"" + fParseTree[parseOp - 1] + "\"");
2967                    System.out.print(" part=\"" + fParseTree[parseOp - 2] + "\"");
2968                    System.out.println("/>");
2969                    break;
2970                case PARSEOP_FUNCTION:
2971                    indentPrint(indent);
2972                    System.out.println("<function-call>");
2973                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2974                    if (fParseTree[parseOp - 2] != -1) {
2975                        dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2976                    }
2977                    indentPrint(indent);
2978                    System.out.println("</function-call>");
2979                    break;
2980                case PARSEOP_FUNCTION_NAME:
2981                    indentPrint(indent);
2982                    System.out.print("<function-name");
2983                    if (fParseTree[parseOp - 1] != -1) {
2984                        System.out.print(" prefix=\"" + fParseTree[parseOp - 1] + "\"");
2985                    }
2986                    System.out.print(" localpart=\"" + fParseTree[parseOp - 2] + "\"");
2987                    System.out.println("/>");
2988                    break;
2989                case PARSEOP_FUNCTION_ARGUMENTS:
2990                    indentPrint(indent);
2991                    System.out.println("<function-args>");
2992                    dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2993                    dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2994                    indentPrint(indent);
2995                    System.out.println("</function-args>");
2996                    break;
2997                default:
2998                    throw new RuntimeException("dumpParseTreeNode("+parseOp+")");
2999                }
3000        }
3001
3002        //
3003        // Package methods
3004        //
3005
3006        /**
3007         * [14] Expr ::= OrExpr
3008         * /
3009        boolean parseExpr() throws XPathException {
3010            return parseOrExpr();
3011        }
3012
3013        /**
3014         * [21] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
3015         *
3016         * also: OrExpr ::= (AndExpr 'or')* AndExpr
3017         * /
3018        boolean parseOrExpr() throws XPathException {
3019            if (!parseAndExpr()) {
3020                return false;
3021            }
3022            while (fCurrentToken < fTokenCount) {
3023                if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_OPERATOR_OR) {
3024                    break;
3025                }
3026                int saveToken = fCurrentToken;
3027                int saveParseOp = fCurrentParseOp;
3028                int left = fCurrentParseOp;
3029                if (++fCurrentToken == fTokenCount) {
3030                    fCurrentToken = saveToken;
3031                    fCurrentParseOp = saveParseOp;
3032                    return true;
3033                }
3034                if (!parseAndExpr()) {
3035                    fCurrentToken = saveToken;
3036                    fCurrentParseOp = saveParseOp;
3037                    return true;
3038                }
3039                int right = fCurrentParseOp;
3040                pushParseOp3(PARSEOP_OR, left, right);
3041            }
3042            return true;
3043        }
3044
3045        /**
3046         * [22] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
3047         * /
3048        boolean parseAndExpr() throws XPathException {
3049            if (!parseEqualityExpr()) {
3050                return false;
3051            }
3052            while (fCurrentToken < fTokenCount) {
3053                if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_OPERATOR_AND) {
3054                    break;
3055                }
3056                int saveToken = fCurrentToken;
3057                int saveParseOp = fCurrentParseOp;
3058                int left = fCurrentParseOp;
3059                if (++fCurrentToken == fTokenCount) {
3060                    fCurrentToken = saveToken;
3061                    fCurrentParseOp = saveParseOp;
3062                    return true;
3063                }
3064                if (!parseEqualityExpr()) {
3065                    fCurrentToken = saveToken;
3066                    fCurrentParseOp = saveParseOp;
3067                    return true;
3068                }
3069                int right = fCurrentParseOp;
3070                pushParseOp3(PARSEOP_AND, left, right);
3071            }
3072            return true;
3073        }
3074
3075        /**
3076         * [23] EqualityExpr ::= RelationalExpr
3077         * | EqualityExpr '=' RelationalExpr
3078         * | EqualityExpr '!=' RelationalExpr
3079         * /
3080        boolean parseEqualityExpr() throws XPathException {
3081            if (!parseRelationalExpr()) {
3082                return false;
3083            }
3084            while (fCurrentToken < fTokenCount) {
3085                int parseOp;
3086                if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_EQUAL) {
3087                    parseOp = PARSEOP_EQUAL;
3088                } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_NOT_EQUAL) {
3089                    parseOp = PARSEOP_NOT_EQUAL;
3090                } else {
3091                    break;
3092                }
3093                int saveToken = fCurrentToken;
3094                int saveParseOp = fCurrentParseOp;
3095                int left = fCurrentParseOp;
3096                if (++fCurrentToken == fTokenCount) {
3097                    fCurrentToken = saveToken;
3098                    fCurrentParseOp = saveParseOp;
3099                    return true;
3100                }
3101                if (!parseRelationalExpr()) {
3102                    fCurrentToken = saveToken;
3103                    fCurrentParseOp = saveParseOp;
3104                    return true;
3105                }
3106                int right = fCurrentParseOp;
3107                pushParseOp3(parseOp, left, right);
3108            }
3109            return true;
3110        }
3111
3112        /**
3113         * [24] RelationalExpr ::= AdditiveExpr
3114         * | RelationalExpr '<' AdditiveExpr
3115         * | RelationalExpr '>' AdditiveExpr
3116         * | RelationalExpr '<=' AdditiveExpr
3117         * | RelationalExpr '>=' AdditiveExpr
3118         * /
3119        boolean parseRelationalExpr() throws XPathException {
3120            if (!parseAdditiveExpr()) {
3121                return false;
3122            }
3123            while (fCurrentToken < fTokenCount) {
3124                int parseOp;
3125                if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_LESS) {
3126                    parseOp = PARSEOP_LESS;
3127                } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_GREATER) {
3128                    parseOp = PARSEOP_GREATER;
3129                } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_LESS_EQUAL) {
3130                    parseOp = PARSEOP_LESS_EQUAL;
3131                } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_GREATER_EQUAL) {
3132                    parseOp = PARSEOP_GREATER_EQUAL;
3133                } else {
3134                    break;
3135                }
3136                int saveToken = fCurrentToken;
3137                int saveParseOp = fCurrentParseOp;
3138                int left = fCurrentParseOp;
3139                if (++fCurrentToken == fTokenCount) {
3140                    fCurrentToken = saveToken;
3141                    fCurrentParseOp = saveParseOp;
3142                    return true;
3143                }
3144                if (!parseAdditiveExpr()) {
3145                    fCurrentToken = saveToken;
3146                    fCurrentParseOp = saveParseOp;
3147                    return true;
3148                }
3149                int right = fCurrentParseOp;
3150                pushParseOp3(parseOp, left, right);
3151            }
3152            return true;
3153        }
3154
3155        /**
3156         * [25] AdditiveExpr ::= MultiplicativeExpr
3157         * | AdditiveExpr '+' MultiplicativeExpr
3158         * | AdditiveExpr '-' MultiplicativeExpr
3159         * /
3160        boolean parseAdditiveExpr() throws XPathException {
3161            if (!parseMultiplicativeExpr()) {
3162                return false;
3163            }
3164            while (fCurrentToken < fTokenCount) {
3165                int parseOp;
3166                if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_PLUS) {
3167                    parseOp = PARSEOP_PLUS;
3168                } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_MINUS) {
3169                    parseOp = PARSEOP_MINUS;
3170                } else {
3171                    break;
3172                }
3173                int saveToken = fCurrentToken;
3174                int saveParseOp = fCurrentParseOp;
3175                int left = fCurrentParseOp;
3176                if (++fCurrentToken == fTokenCount) {
3177                    fCurrentToken = saveToken;
3178                    fCurrentParseOp = saveParseOp;
3179                    return true;
3180                }
3181                if (!parseMultiplicativeExpr()) {
3182                    fCurrentToken = saveToken;
3183                    fCurrentParseOp = saveParseOp;
3184                    return true;
3185                }
3186                int right = fCurrentParseOp;
3187                pushParseOp3(parseOp, left, right);
3188            }
3189            return true;
3190        }
3191
3192        /**
3193         * [26] MultiplicativeExpr ::= UnaryExpr
3194         * | MultiplicativeExpr MultiplyOperator UnaryExpr
3195         * | MultiplicativeExpr 'div' UnaryExpr
3196         * | MultiplicativeExpr 'mod' UnaryExpr
3197         * [34] MultiplyOperator ::= '*'
3198         * /
3199        boolean parseMultiplicativeExpr() throws XPathException {
3200            if (!parseUnaryExpr()) {
3201                return false;
3202            }
3203            while (fCurrentToken < fTokenCount) {
3204                int parseOp;
3205                if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_MULT) {
3206                    parseOp = PARSEOP_MULT;
3207                } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_DIV) {
3208                    parseOp = PARSEOP_DIV;
3209                } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_MOD) {
3210                    parseOp = PARSEOP_MOD;
3211                } else {
3212                    break;
3213                }
3214                int saveToken = fCurrentToken;
3215                int saveParseOp = fCurrentParseOp;
3216                int left = fCurrentParseOp;
3217                if (++fCurrentToken == fTokenCount) {
3218                    fCurrentToken = saveToken;
3219                    fCurrentParseOp = saveParseOp;
3220                    return true;
3221                }
3222                if (!parseUnaryExpr()) {
3223                    fCurrentToken = saveToken;
3224                    fCurrentParseOp = saveParseOp;
3225                    return true;
3226                }
3227                int right = fCurrentParseOp;
3228                pushParseOp3(parseOp, left, right);
3229            }
3230            return true;
3231        }
3232
3233        /**
3234         * [27] UnaryExpr ::= UnionExpr | '-' UnaryExpr
3235         *
3236         * Note: "--UnionExpr" == "-(-UnionExpr)"
3237         * /
3238        boolean parseUnaryExpr() throws XPathException {
3239            if (parseUnionExpr()) {
3240                return true;
3241            }
3242            int saveToken = fCurrentToken;
3243            boolean negate = false;
3244            while (fCurrentToken < fTokenCount) {
3245                if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_OPERATOR_MINUS) {
3246                    break;
3247                }
3248                fCurrentToken++;
3249                negate = !negate;
3250            }
3251            if (fCurrentToken == fTokenCount) {
3252                fCurrentToken = saveToken;
3253                return false;
3254            }
3255            if (!parseUnionExpr()) {
3256                fCurrentToken = saveToken;
3257                return false;
3258            }
3259            if (negate) {
3260                pushParseOp2(PARSEOP_NEGATE, fCurrentParseOp);
3261            }
3262            return true;
3263        }
3264
3265        /**
3266         * [18] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
3267         * /
3268        boolean parseUnionExpr() throws XPathException {
3269            if (!parsePathExpr()) {
3270                return false;
3271            }
3272            while (fCurrentToken < fTokenCount) {
3273                if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_OPERATOR_UNION) {
3274                    break;
3275                }
3276                int saveToken = fCurrentToken;
3277                int saveParseOp = fCurrentParseOp;
3278                int left = fCurrentParseOp;
3279                if (++fCurrentToken == fTokenCount) {
3280                    fCurrentToken = saveToken;
3281                    fCurrentParseOp = saveParseOp;
3282                    return true;
3283                }
3284                if (!parsePathExpr()) {
3285                    fCurrentToken = saveToken;
3286                    fCurrentParseOp = saveParseOp;
3287                    return true;
3288                }
3289                int right = fCurrentParseOp;
3290                pushParseOp3(PARSEOP_UNION, left, right);
3291            }
3292            return true;
3293        }
3294
3295        /**
3296         * [19] PathExpr ::= RelativeLocationPath
3297         * | '/' RelativeLocationPath?
3298         * | '//' RelativeLocationPath
3299         * | PrimaryExpr Predicate*
3300         * | PrimaryExpr Predicate* '/' RelativeLocationPath
3301         * | PrimaryExpr Predicate* '//' RelativeLocationPath
3302         * /
3303        boolean parsePathExpr() throws XPathException {
3304            if (parseRelativeLocationPath()) {
3305                return true;
3306            } else {
3307                if (fCurrentToken == fTokenCount) {
3308                    return false;
3309                }
3310                if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH) {
3311                    if (++fCurrentToken < fTokenCount && parseRelativeLocationPath()) {
3312                        pushParseOp2(PARSEOP_SELECT_ROOT, fCurrentParseOp);
3313                    } else {
3314                        pushParseOp2(PARSEOP_SELECT_ROOT, -1);
3315                    }
3316                    return true;
3317                } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH) {
3318                    if (++fCurrentToken == fTokenCount) {
3319                        return false; // REVISIT - backup index
3320                    }
3321                    if (!parseRelativeLocationPath()) {
3322                        return false;
3323                    }
3324                    int left = fCurrentParseOp;
3325                    pushParseOp(PARSEOP_AXIS_DESCENDANT_OR_SELF);
3326                    int left2 = fCurrentParseOp;
3327                    pushParseOp(PARSEOP_NODETEST_NODE);
3328                    pushParseOp3(PARSEOP_STEP, left2, fCurrentParseOp);
3329                    pushParseOp3(PARSEOP_STEPS, fCurrentParseOp, left);
3330                    pushParseOp2(PARSEOP_SELECT_ROOT, fCurrentParseOp);
3331                    return true;
3332                }
3333            }
3334            if (!parsePrimaryExpr()) {
3335                return false;
3336            }
3337            int left = fCurrentParseOp;
3338            if (parsePredicates()) {
3339                pushParseOp3(PARSEOP_FILTER, left, fCurrentParseOp);
3340            }
3341            if (fCurrentToken == fTokenCount) {
3342                return true;
3343            }
3344            left = fCurrentParseOp;
3345            if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH) {
3346                if (++fCurrentToken == fTokenCount) {
3347                    return false; // REVISIT
3348                }
3349                if (!parseRelativeLocationPath()) {
3350                    return false; // REVISIT
3351                }
3352                pushParseOp3(PARSEOP_STEPS, left, fCurrentParseOp);
3353            } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH) {
3354                if (++fCurrentToken == fTokenCount) {
3355                    return false;
3356                }
3357                if (!parseRelativeLocationPath()) {
3358                    return false;
3359                }
3360                int left2 = fCurrentParseOp;
3361                pushParseOp(PARSEOP_AXIS_DESCENDANT_OR_SELF);
3362                int left3 = fCurrentParseOp;
3363                pushParseOp(PARSEOP_NODETEST_NODE);
3364                pushParseOp3(PARSEOP_STEP, left3, fCurrentParseOp);
3365                pushParseOp3(PARSEOP_STEPS, fCurrentParseOp, left2);
3366                pushParseOp3(PARSEOP_STEPS, left, fCurrentParseOp);
3367            }
3368            return true;
3369        }
3370
3371        /**
3372         * [3] RelativeLocationPath ::= Step
3373         * | RelativeLocationPath '/' Step
3374         * | RelativeLocationPath '//' Step
3375         * /
3376        boolean parseRelativeLocationPath() throws XPathException {
3377            if (!parseStep()) {
3378                return false;
3379            }
3380            while (fCurrentToken < fTokenCount) {
3381                boolean descendantOrSelf;
3382                if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH) {
3383                    descendantOrSelf = false;
3384                } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH) {
3385                    descendantOrSelf = true;
3386                } else {
3387                    break;
3388                }
3389                int saveToken = fCurrentToken;
3390                int saveParseOp = fCurrentParseOp;
3391                int left = fCurrentParseOp;
3392                if (++fCurrentToken == fTokenCount) {
3393                    fCurrentToken = saveToken;
3394                    fCurrentParseOp = saveParseOp;
3395                    return true;
3396                }
3397                if (!parseStep()) {
3398                    fCurrentToken = saveToken;
3399                    fCurrentParseOp = saveParseOp;
3400                    return true;
3401                }
3402                if (descendantOrSelf) {
3403                    int left2 = fCurrentParseOp;
3404                    pushParseOp(PARSEOP_AXIS_DESCENDANT_OR_SELF);
3405                    int left3 = fCurrentParseOp;
3406                    pushParseOp(PARSEOP_NODETEST_NODE);
3407                    pushParseOp3(PARSEOP_STEP, left3, fCurrentParseOp);
3408                    pushParseOp3(PARSEOP_STEPS, left, fCurrentParseOp);
3409                    pushParseOp3(PARSEOP_STEPS, fCurrentParseOp, left2);
3410                } else {
3411                    pushParseOp3(PARSEOP_STEPS, left, fCurrentParseOp);
3412                }
3413            }
3414            return true;
3415        }
3416
3417        /**
3418         * [4] Step ::= (AxisName '::' | '@'?) NodeTest Predicate* | '.' | '..'
3419         * [6] AxisName ::= 'ancestor' | 'ancestor-or-self'
3420         * | 'attribute'
3421         * | 'child'
3422         * | 'descendant' | 'descendant-or-self'
3423         * | 'following' | 'following-sibling'
3424         * | 'namespace'
3425         * | 'parent'
3426         * | 'preceding' | 'preceding-sibling'
3427         * | 'self'
3428         * /
3429        boolean parseStep() throws XPathException {
3430            int parseOp;
3431            int left;
3432            boolean checkDoubleColon = true;
3433            int saveToken = fCurrentToken;
3434            int saveParseOp = fCurrentParseOp;
3435            if (fCurrentToken == fTokenCount) {
3436                return false;
3437            }
3438            switch (fTokens.getToken(fCurrentToken)) {
3439            case XPath.Tokens.EXPRTOKEN_PERIOD:
3440                fCurrentToken++;
3441                pushParseOp(PARSEOP_AXIS_SELF);
3442                left = fCurrentParseOp;
3443                pushParseOp(PARSEOP_NODETEST_NODE);
3444                pushParseOp3(PARSEOP_STEP, left, fCurrentParseOp);
3445                return true;
3446            case XPath.Tokens.EXPRTOKEN_DOUBLE_PERIOD:
3447                fCurrentToken++;
3448                pushParseOp(PARSEOP_AXIS_PARENT);
3449                left = fCurrentParseOp;
3450                pushParseOp(PARSEOP_NODETEST_NODE);
3451                pushParseOp3(PARSEOP_STEP, left, fCurrentParseOp);
3452                return true;
3453            case XPath.Tokens.EXPRTOKEN_AXISNAME_ANCESTOR:
3454                fCurrentToken++;
3455                parseOp = PARSEOP_AXIS_ANCESTOR;
3456                break;
3457            case XPath.Tokens.EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF:
3458                fCurrentToken++;
3459                parseOp = PARSEOP_AXIS_ANCESTOR_OR_SELF;
3460                break;
3461            case XPath.Tokens.EXPRTOKEN_ATSIGN:
3462                checkDoubleColon = false;
3463                // fall through
3464            case XPath.Tokens.EXPRTOKEN_AXISNAME_ATTRIBUTE:
3465                fCurrentToken++;
3466                parseOp = PARSEOP_AXIS_ATTRIBUTE;
3467                break;
3468            case XPath.Tokens.EXPRTOKEN_AXISNAME_DESCENDANT:
3469                fCurrentToken++;
3470                parseOp = PARSEOP_AXIS_DESCENDANT;
3471                break;
3472            case XPath.Tokens.EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF:
3473                fCurrentToken++;
3474                parseOp = PARSEOP_AXIS_DESCENDANT_OR_SELF;
3475                break;
3476            case XPath.Tokens.EXPRTOKEN_AXISNAME_FOLLOWING:
3477                fCurrentToken++;
3478                parseOp = PARSEOP_AXIS_FOLLOWING;
3479                break;
3480            case XPath.Tokens.EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING:
3481                fCurrentToken++;
3482                parseOp = PARSEOP_AXIS_FOLLOWING_SIBLING;
3483                break;
3484            case XPath.Tokens.EXPRTOKEN_AXISNAME_NAMESPACE:
3485                fCurrentToken++;
3486                parseOp = PARSEOP_AXIS_NAMESPACE;
3487                break;
3488            case XPath.Tokens.EXPRTOKEN_AXISNAME_PARENT:
3489                fCurrentToken++;
3490                parseOp = PARSEOP_AXIS_PARENT;
3491                break;
3492            case XPath.Tokens.EXPRTOKEN_AXISNAME_PRECEDING:
3493                fCurrentToken++;
3494                parseOp = PARSEOP_AXIS_PRECEDING;
3495                break;
3496            case XPath.Tokens.EXPRTOKEN_AXISNAME_PRECEDING_SIBLING:
3497                fCurrentToken++;
3498                parseOp = PARSEOP_AXIS_PRECEDING_SIBLING;
3499                break;
3500            case XPath.Tokens.EXPRTOKEN_AXISNAME_SELF:
3501                fCurrentToken++;
3502                parseOp = PARSEOP_AXIS_SELF;
3503                break;
3504            case XPath.Tokens.EXPRTOKEN_AXISNAME_CHILD:
3505                fCurrentToken++;
3506                parseOp = PARSEOP_AXIS_CHILD;
3507                break;
3508            default:
3509                checkDoubleColon = false;
3510                parseOp = PARSEOP_AXIS_CHILD;
3511                break;
3512            }
3513            pushParseOp(parseOp);
3514            left = fCurrentParseOp;
3515            if (checkDoubleColon) {
3516                if (fCurrentToken == fTokenCount) {
3517                    fCurrentToken = saveToken;
3518                    fCurrentParseOp = saveParseOp;
3519                    return false;
3520                }
3521                if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_DOUBLE_COLON) {
3522                    fCurrentToken = saveToken;
3523                    fCurrentParseOp = saveParseOp;
3524                    return false;
3525                }
3526                fCurrentToken++;
3527            }
3528            if (fCurrentToken == fTokenCount) {
3529                fCurrentToken = saveToken;
3530                fCurrentParseOp = saveParseOp;
3531                return false;
3532            }
3533            if (!parseNodeTest()) {
3534                fCurrentToken = saveToken;
3535                fCurrentParseOp = saveParseOp;
3536                return false;
3537            }
3538            pushParseOp3(PARSEOP_STEP, left, fCurrentParseOp);
3539            left = fCurrentParseOp;
3540            if (parsePredicates()) {
3541                pushParseOp3(PARSEOP_FILTER, left, fCurrentParseOp);
3542            }
3543            return true;
3544        }
3545
3546        /**
3547         * [7] NodeTest ::= '*'
3548         * | NCName ':' '*'
3549         * | QName
3550         * | 'comment' '(' ')'
3551         * | 'text' '(' ')'
3552         * | 'processing-instruction' '(' Literal? ')'
3553         * | 'node' '(' ')'
3554         * [29] Literal ::= '"' [^"]* '"' | "'" [^']* "'"
3555         * /
3556        boolean parseNodeTest() throws XPathException {
3557            int parseOp;
3558            int prefix;
3559            int name;
3560            if (fCurrentToken == fTokenCount) {
3561                return false;
3562            }
3563            switch (fTokens.getToken(fCurrentToken)) {
3564            case XPath.Tokens.EXPRTOKEN_NAMETEST_ANY:
3565                fCurrentToken++;
3566                pushParseOp(PARSEOP_NODETEST_ANY);
3567                return true;
3568            case XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE:
3569                prefix = fTokens.getToken(++fCurrentToken);
3570                fCurrentToken++;
3571                pushParseOp2(PARSEOP_NODETEST_NAMESPACE, prefix);
3572                return true;
3573            case XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME:
3574                prefix = fTokens.getToken(++fCurrentToken);
3575                name = fTokens.getToken(++fCurrentToken);
3576                fCurrentToken++;
3577                pushParseOp3(PARSEOP_NODETEST_QNAME, prefix, name);
3578                return true;
3579            case XPath.Tokens.EXPRTOKEN_NODETYPE_COMMENT:
3580                parseOp = PARSEOP_NODETEST_COMMENT;
3581                break;
3582            case XPath.Tokens.EXPRTOKEN_NODETYPE_TEXT:
3583                parseOp = PARSEOP_NODETEST_TEXT;
3584                break;
3585            case XPath.Tokens.EXPRTOKEN_NODETYPE_PI:
3586                parseOp = PARSEOP_NODETEST_PI;
3587                break;
3588            case XPath.Tokens.EXPRTOKEN_NODETYPE_NODE:
3589                parseOp = PARSEOP_NODETEST_NODE;
3590                break;
3591            default:
3592                return false;
3593            }
3594            int saveToken = fCurrentToken;
3595            int saveParseOp = fCurrentParseOp;
3596            int left = fCurrentParseOp;
3597            if (++fCurrentToken == fTokenCount) {
3598                fCurrentToken = saveToken;
3599                fCurrentParseOp = saveParseOp;
3600                return false;
3601            }
3602            if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_OPEN_PAREN) {
3603                fCurrentToken = saveToken;
3604                fCurrentParseOp = saveParseOp;
3605                return false;
3606            }
3607            if (++fCurrentToken == fTokenCount) {
3608                fCurrentToken = saveToken;
3609                fCurrentParseOp = saveParseOp;
3610                return false;
3611            }
3612            if (parseOp == PARSEOP_NODETEST_PI && fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_LITERAL) {
3613                int target = fTokens.getToken(++fCurrentToken);
3614                if (++fCurrentToken == fTokenCount) {
3615                    fCurrentToken = saveToken;
3616                    fCurrentParseOp = saveParseOp;
3617                    return false;
3618                }
3619                if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_CLOSE_PAREN) {
3620                    fCurrentToken = saveToken;
3621                    fCurrentParseOp = saveParseOp;
3622                    return false;
3623                }
3624                fCurrentToken++;
3625                pushParseOp2(PARSEOP_NODETEST_PI_TARGET, target);
3626            } else {
3627                if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_CLOSE_PAREN) {
3628                    fCurrentToken = saveToken;
3629                    fCurrentParseOp = saveParseOp;
3630                    return false;
3631                }
3632                fCurrentToken++;
3633                pushParseOp(parseOp);
3634            }
3635            return true;
3636        }
3637
3638        /**
3639         * [8] Predicate ::= '[' PredicateExpr ']'
3640         * [9] PredicateExpr ::= Expr
3641         * [4] Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep
3642         * [20] FilterExpr ::= PrimaryExpr Predicate*
3643         * /
3644        boolean parsePredicates() throws XPathException {
3645            int left = -1;
3646            boolean found = false;
3647            while (true) {
3648                if (fCurrentToken == fTokenCount || fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_OPEN_BRACKET) {
3649                    return found;
3650                }
3651                int saveToken = fCurrentToken;
3652                int saveParseOp = fCurrentParseOp;
3653                if (++fCurrentToken == fTokenCount || !parseExpr() ||
3654                    fCurrentToken == fTokenCount || fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_CLOSE_BRACKET) {
3655                    fCurrentToken = saveToken;
3656                    fCurrentParseOp = saveParseOp;
3657                    return found;
3658                }
3659                fCurrentToken++;
3660                found = true;
3661                pushParseOp2(PARSEOP_PREDICATE, fCurrentParseOp);
3662                if (left != -1) {
3663                    pushParseOp3(PARSEOP_PREDICATES, left, fCurrentParseOp);
3664                }
3665                left = fCurrentParseOp;
3666            }
3667        }
3668
3669        /**
3670         * [15] PrimaryExpr ::= '$' QName
3671         * | '(' Expr ')'
3672         * | '"' [^"]* '"' | "'" [^']* "'"
3673         * | ([0-9]+) ('.' ([0-9]+)?)? | '.' Digits
3674         * | (QName - NodeType) '(' ( Expr ( ',' Expr )* )? ')'
3675         * /
3676        boolean parsePrimaryExpr() throws XPathException {
3677            int prefix;
3678            int handle;
3679            int saveToken;
3680            int saveParseOp;
3681            if (fCurrentToken == fTokenCount) {
3682                return false;
3683            }
3684            switch (fTokens.getToken(fCurrentToken)) {
3685            case XPath.Tokens.EXPRTOKEN_VARIABLE_REFERENCE:
3686                prefix = fTokens.getToken(++fCurrentToken);
3687                handle = fTokens.getToken(++fCurrentToken); // localpart
3688                fCurrentToken++;
3689                pushParseOp3(PARSEOP_VARIABLE_REFERENCE, prefix, handle);
3690                break;
3691            case XPath.Tokens.EXPRTOKEN_OPEN_PAREN:
3692                saveToken = fCurrentToken;
3693                saveParseOp = fCurrentParseOp;
3694                if (++fCurrentToken == fTokenCount) {
3695                    fCurrentToken = saveToken;
3696                    fCurrentParseOp = saveParseOp;
3697                    return false;
3698                }
3699                if (!parseExpr()) {
3700                    fCurrentToken = saveToken;
3701                    fCurrentParseOp = saveParseOp;
3702                    return false;
3703                }
3704                if (fCurrentToken == fTokenCount) {
3705                    fCurrentToken = saveToken;
3706                    fCurrentParseOp = saveParseOp;
3707                    return false;
3708                }
3709                if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_CLOSE_PAREN) {
3710                    fCurrentToken = saveToken;
3711                    fCurrentParseOp = saveParseOp;
3712                    return false;
3713                }
3714                fCurrentToken++;
3715                pushParseOp2(PARSEOP_GROUPING, fCurrentParseOp);
3716                break;
3717            case XPath.Tokens.EXPRTOKEN_LITERAL:
3718                handle = fTokens.getToken(++fCurrentToken);
3719                fCurrentToken++;
3720                pushParseOp2(PARSEOP_LITERAL, handle);
3721                break;
3722            case XPath.Tokens.EXPRTOKEN_NUMBER:
3723                int whole = fTokens.getToken(++fCurrentToken);
3724                int part = fTokens.getToken(++fCurrentToken);
3725                fCurrentToken++;
3726                pushParseOp3(PARSEOP_NUMBER, whole, part);
3727                break;
3728            case XPath.Tokens.EXPRTOKEN_FUNCTION_NAME:
3729                saveToken = fCurrentToken;
3730                saveParseOp = fCurrentParseOp;
3731                prefix = fTokens.getToken(++fCurrentToken);
3732                handle = fTokens.getToken(++fCurrentToken); // localpart
3733                fCurrentToken++;
3734                pushParseOp3(PARSEOP_FUNCTION_NAME, prefix, handle);
3735                if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_OPEN_PAREN) {
3736                    fCurrentToken = saveToken;
3737                    fCurrentParseOp = saveParseOp;
3738                    return false;
3739                }
3740                fCurrentToken++;
3741                int funcName = fCurrentParseOp;
3742                int nextArg = -1;
3743                if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_CLOSE_PAREN) {
3744                    fCurrentToken++;
3745                } else {
3746                    while (true) {
3747                        if (!parseExpr()) {
3748                            fCurrentToken = saveToken;
3749                            fCurrentParseOp = saveParseOp;
3750                            return false;
3751                        }
3752                        if (nextArg != -1) {
3753                            pushParseOp3(PARSEOP_FUNCTION_ARGUMENTS, nextArg, fCurrentParseOp);
3754                        }
3755                        nextArg = fCurrentParseOp;
3756                        if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_CLOSE_PAREN) {
3757                            fCurrentToken++;
3758                            break;
3759                        }
3760                        if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_COMMA) {
3761                            fCurrentToken = saveToken;
3762                            fCurrentParseOp = saveParseOp;
3763                            return false;
3764                        }
3765                        fCurrentToken++;
3766                    }
3767                }
3768                pushParseOp3(PARSEOP_FUNCTION, funcName, nextArg);
3769                break;
3770            default:
3771                return false;
3772            }
3773            return true;
3774        }
3775
3776        //
3777        // MAIN
3778        //
3779
3780        public static void main(String argv[]) {
3781            for (int i = 0; i < argv.length; i++) {
3782                String expression = argv[i];
3783                System.out.println("# XPath expression: "+expression);
3784                XPathExprParser parser = new XPathExprParser();
3785                try {
3786                    parser.parseExpr(expression);
3787                }
3788                catch (Exception e) {
3789                    e.printStackTrace();
3790                }
3791            }
3792        }
3793
3794    } // class XPathExprParser
3795    /***/

3796
3797    //
3798
// MAIN
3799
//
3800

3801    /** Main program entry. */
3802    public static void main(String JavaDoc[] argv) throws Exception JavaDoc {
3803
3804        for (int i = 0; i < argv.length; i++) {
3805            final String JavaDoc expression = argv[i];
3806            System.out.println("# XPath expression: \""+expression+'"');
3807            try {
3808                StringPool stringPool = new StringPool();
3809                XPath xpath = new XPath(expression, stringPool,
3810                                        null);
3811                System.out.println("expanded xpath: \""+xpath.toString()+'"');
3812            }
3813            catch (XPathException e) {
3814                System.out.println("error: "+e.getMessage());
3815            }
3816        }
3817
3818    } // main(String[])
3819

3820    /** Location paths. */
3821    protected LocationPath[] fLocationPaths; //
3822
// Public methods
3823
//
3824

3825    /** Returns a representation of all location paths for this XPath.
3826        XPath = locationPath ( '|' locationPath)*
3827    */

3828    public LocationPath[] getLocationPaths() {
3829        LocationPath[] ret=new LocationPath[fLocationPaths.length];
3830        for (int i=0;i<fLocationPaths.length;i++){
3831            ret[i]=(LocationPath)fLocationPaths[i].clone();
3832        }
3833        return ret;
3834    } // getLocationPath(LocationPath)
3835
} // class XPath
3836
Popular Tags