Code

r11451@tres: ted | 2006-04-17 22:21:33 -0700
[inkscape.git] / src / dom / xpathparser.cpp
1 /**\r
2  * Phoebe DOM Implementation.\r
3  *\r
4  * This is a C++ approximation of the W3C DOM model, which follows\r
5  * fairly closely the specifications in the various .idl files, copies of\r
6  * which are provided for reference.  Most important is this one:\r
7  *\r
8  * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html\r
9  *\r
10  * Authors:\r
11  *   Bob Jamison\r
12  *\r
13  * Copyright (C) 2006 Bob Jamison\r
14  *\r
15  *  This library is free software; you can redistribute it and/or\r
16  *  modify it under the terms of the GNU Lesser General Public\r
17  *  License as published by the Free Software Foundation; either\r
18  *  version 2.1 of the License, or (at your option) any later version.\r
19  *\r
20  *  This library is distributed in the hope that it will be useful,\r
21  *  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
22  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
23  *  Lesser General Public License for more details.\r
24  *\r
25  *  You should have received a copy of the GNU Lesser General Public\r
26  *  License along with this library; if not, write to the Free Software\r
27  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
28  */\r
29 \r
30 \r
31 #include "charclass.h"\r
32 #include "xpathparser.h"\r
33 \r
34 \r
35 namespace org\r
36 {\r
37 namespace w3c\r
38 {\r
39 namespace dom\r
40 {\r
41 namespace xpath\r
42 {\r
43 \r
44 \r
45 //#########################################################################\r
46 //# M E S S A G E S\r
47 //#########################################################################\r
48 \r
49 \r
50 \r
51 void XPathParser::trace(const char *fmt, ...)\r
52 {\r
53     if (!debug)\r
54         return;\r
55 \r
56     FILE *f = stdout;\r
57 \r
58     va_list args;\r
59     va_start(args, fmt);\r
60     fprintf(f, "XPathParser: ");\r
61     vfprintf(f, fmt, args);\r
62     fprintf(f, "\n");\r
63     va_end(args);\r
64 }\r
65 \r
66 \r
67 \r
68 void XPathParser::error(const char *fmt, ...)\r
69 {\r
70     FILE *f = stdout;\r
71     va_list args;\r
72     va_start(args, fmt);\r
73     fprintf(f, "XPathParser ERROR: ");\r
74     vfprintf(f, fmt, args);\r
75     fprintf(f, "\n");\r
76     va_end(args);\r
77 \r
78     //Print location in string\r
79     fprintf(f, "%s\n", parsebuf);\r
80     for (int i=0 ; i<position ; i++)\r
81         fprintf(f, " ");\r
82     fprintf(f, "^\n");\r
83 }\r
84 \r
85 \r
86 \r
87 void XPathParser::traceStack(const char *name, int pos, int depth)\r
88 {\r
89     if (!debug)\r
90         return;\r
91     return;\r
92     int indent = depth;\r
93 \r
94     for (int i=0 ; i<indent ; i++)\r
95         fprintf(stdout, " ");\r
96     fprintf(stdout, "%d %d %s\n", pos, depth, name);\r
97 \r
98 }\r
99 \r
100 \r
101 //#########################################################################\r
102 //# L E X I C A L    S C A N N I N G\r
103 //#########################################################################\r
104 \r
105 void XPathParser::lexTokAdd(int type, int loc)\r
106 {\r
107     LexTok tok(type, loc);\r
108     lexicalTokens.push_back(tok);\r
109 }\r
110 \r
111 void XPathParser::lexTokAdd(int type, int loc, const DOMString &val)\r
112 {\r
113     LexTok tok(type, loc, val);\r
114     lexicalTokens.push_back(tok);\r
115 }\r
116 \r
117 void XPathParser::lexTokAdd(int type, int loc, double val)\r
118 {\r
119     LexTok tok(type, loc, val);\r
120     lexicalTokens.push_back(tok);\r
121 }\r
122 \r
123 void XPathParser::lexTokAdd(int type, int loc, long   val)\r
124 {\r
125     LexTok tok(type, loc, val);\r
126     lexicalTokens.push_back(tok);\r
127 }\r
128 \r
129 void XPathParser::lexicalTokenDump()\r
130 {\r
131     printf("####### LEXICAL TOKENS #######\n");\r
132     for (unsigned int i=0 ; i<lexicalTokens.size() ; i++)\r
133         {\r
134         printf("%d : ", i);\r
135         lexicalTokens[i].print();\r
136         }\r
137     printf("##### END LEXICAL TOKENS #####\n\n");\r
138 }\r
139 \r
140 \r
141 \r
142 LexTok XPathParser::lexTok(int p)\r
143 {\r
144     if (p < 0 || p>=(int)lexicalTokens.size())\r
145         {\r
146         LexTok tok;\r
147         return tok;\r
148         }\r
149     return lexicalTokens[p];\r
150 }\r
151 \r
152 int XPathParser::lexTokType(int p)\r
153 {\r
154     if (p < 0 || p>=(int)lexicalTokens.size())\r
155         return -1;\r
156     return lexicalTokens[p].getType();\r
157 }\r
158 \r
159 \r
160 \r
161 \r
162 \r
163 \r
164 \r
165 \r
166 int XPathParser::peek(int p)\r
167 {\r
168     if (p >= parselen)\r
169         return -1;\r
170     position = p;\r
171     return parsebuf[p] ;\r
172 }\r
173 \r
174 \r
175 int XPathParser::get(int p)\r
176 {\r
177     if (p >= parselen)\r
178         return -1;\r
179     position = p;\r
180     return parsebuf[p];\r
181 }\r
182 \r
183 int XPathParser::skipwhite(int p0)\r
184 {\r
185     int p = p0;\r
186 \r
187     while (p < parselen)\r
188         {\r
189         int ch = peek(p);\r
190         if (!isWhitespace(ch))\r
191             break;\r
192         ch = get(p++);\r
193         }\r
194     return p;\r
195 }\r
196 \r
197 int XPathParser::getword(int p0, DOMString &str)\r
198 {\r
199     int p = p0;\r
200     while (p < parselen)\r
201         {\r
202         int ch = peek(p);\r
203         if (!isLetterOrDigit(ch))\r
204             break;\r
205         ch = get(p++);\r
206         str.push_back((XMLCh)ch);\r
207         }\r
208     return p;\r
209 }\r
210 \r
211 int XPathParser::match(int p, const char *str)\r
212 {\r
213     while (*str)\r
214         {\r
215         if (p >= parselen)\r
216             return -1;\r
217         if (parsebuf[p] != *str)\r
218             return -1;\r
219         p++; str++;\r
220         }\r
221     return p;\r
222 }\r
223 \r
224 \r
225 \r
226 \r
227 int XPathParser::getNumber(int p0, double &dresult)\r
228 {\r
229     int p = p0;\r
230     if (p >= parselen)\r
231         return p0;/*need at least x*/\r
232 \r
233     bool isdouble = false;\r
234     bool negative = false;\r
235 \r
236     int ch = parsebuf[p];\r
237     if (ch=='-')\r
238         {\r
239         p++;\r
240         negative = true;\r
241         if (p >= parselen) return p0;\r
242         }\r
243 \r
244     bool seen_dot    = false;\r
245     bool seen_e      = false;\r
246     bool seen_eminus = false;\r
247 \r
248     DOMString num;\r
249 \r
250     int i = p;\r
251     while (i < parselen)\r
252         {\r
253         ch = parsebuf[i];\r
254         if (ch=='.')\r
255             {\r
256             if (seen_dot)\r
257                 return p0;\r
258             seen_dot = true;\r
259             isdouble = true;\r
260             }\r
261         else if (ch=='e' || ch=='E')\r
262             {\r
263             if (seen_e || !seen_dot)\r
264                 return p0;\r
265             seen_e = true;\r
266             }\r
267         else if (ch=='-' && seen_e)\r
268             {\r
269             if (seen_eminus || !seen_dot)\r
270                 return p0;\r
271             seen_eminus = true;\r
272             }\r
273         else if (!isDigit(ch))\r
274             break;\r
275         num.push_back((XMLCh)ch);\r
276         i++;\r
277         }\r
278 \r
279     if (i == p)/*no digits*/\r
280         return p0;\r
281     if (isdouble)\r
282         {\r
283         const char *begin = num.c_str();\r
284         char *end;\r
285         dresult = strtod(begin,&end);\r
286         if (!end)/*not a number?*/\r
287             {\r
288             error("Error formatting double: %s\n", num.c_str());\r
289             return p0;\r
290             }\r
291         }\r
292     else\r
293         {\r
294         const char *begin = num.c_str();\r
295         char *end;\r
296         dresult = (double)strtol(begin,&end,10);\r
297         if (!end)/*not a number?*/\r
298             {\r
299             error("Error formatting integer: %s\n", num.c_str());\r
300             return p0;\r
301             }\r
302         }\r
303     p = i;\r
304     return p;\r
305 }\r
306 \r
307 \r
308 \r
309 int XPathParser::getLiteral(int p0, DOMString &result)\r
310 {\r
311     int p = p0;\r
312     int ch = peek(p);\r
313     int quotechar = 0;\r
314     if (ch == '"' || ch == '\'')\r
315         {\r
316         quotechar = ch;\r
317         }\r
318     else\r
319         return p0;\r
320     p++;\r
321     while (true)\r
322         {\r
323         if (p >= parselen)\r
324             {\r
325             error("Unterminated literal string");\r
326             return -1;\r
327             }\r
328         ch = peek(p);\r
329         if (ch == quotechar)\r
330             break;\r
331         result.push_back((XMLCh)ch);\r
332         p++;\r
333         }\r
334     p++; //skip over closing "\r
335     return p;\r
336 }\r
337 \r
338 \r
339 \r
340 /**\r
341  * NCName is a 'non-colonized' name\r
342  */\r
343 int XPathParser::getNCName(int p0, DOMString &result)\r
344 {\r
345     int p = p0;\r
346     int ch = peek(p);\r
347     if (ch != '_' && !isLetter(ch))\r
348         return p0;\r
349 \r
350     result.push_back((XMLCh)ch);\r
351     p++;\r
352     while (p < parselen)\r
353         {\r
354         ch = peek(p);\r
355         if (   isLetterOrDigit(ch) ||\r
356                isCombiningChar(ch) ||\r
357                isExtender(ch)      ||\r
358                ch == '.' || ch == '-' || ch == '_' )\r
359            {\r
360            result.push_back((XMLCh)ch);\r
361            p++;\r
362            }\r
363        else\r
364            break;\r
365        }\r
366     return p;\r
367 }\r
368 \r
369 \r
370 \r
371 /**\r
372  * Name parsing with post-parsing\r
373  */\r
374 int XPathParser::getNameTest(int p0, DOMString &result)\r
375 {\r
376     int p = p0;\r
377     int ch = peek(p);\r
378     if (ch == '*')\r
379         {\r
380         result.push_back((XMLCh)ch);\r
381         p++;\r
382         return p;\r
383         }\r
384 \r
385     DOMString ncName;\r
386     int p2 = getNCName(p, ncName);\r
387     if (p2 <= p)\r
388         return p0;\r
389 \r
390     result = ncName;\r
391     p = p2;\r
392 \r
393     ch = peek(p);\r
394     if (ch != ':' )//short name. we are done\r
395         {\r
396         return p;\r
397         }\r
398 \r
399      if (peek(p+1) == ':')  //was  name::  which is ok\r
400         return p;\r
401 \r
402     result.push_back(':');\r
403 \r
404     p++;\r
405     ch = peek(p);\r
406     if (ch == '*')\r
407         {\r
408         result.push_back((XMLCh)ch);\r
409         p++;\r
410         return p;\r
411         }\r
412 \r
413     DOMString ncName2;\r
414     p2 = getNCName(p, ncName2);\r
415     if (p2 <= p)\r
416         {\r
417         if (peek(p) == ':')  //was  name::  which is ok\r
418             return p0;\r
419         error("Nothing after ':' in QName");\r
420         return -1;\r
421         }\r
422 \r
423     result.append(ncName2);\r
424 \r
425     p = p2;\r
426 \r
427     return p;\r
428 }\r
429 \r
430 \r
431 \r
432 int XPathParser::lexicalScan()\r
433 {\r
434     lexicalTokens.clear();\r
435 \r
436     int p  = 0;\r
437     int p2 = p;\r
438 \r
439     while (p < parselen)\r
440         {\r
441         p2 = skipwhite(p);\r
442         p = p2;\r
443 \r
444         //trace("nextChar:%c", peek(p));\r
445         bool selected = false;\r
446 \r
447         //### LITERAL EXPR TOKENS\r
448         for (int i=2 ; i<=10 ; i++)\r
449             {\r
450             p2 = match(p, exprTokenTable[i].sval);\r
451             if (p2 > p)\r
452                 {\r
453                 lexTokAdd(exprTokenTable[i].ival, p);\r
454                 p = p2;\r
455                 selected = true;\r
456                 break;\r
457                 }\r
458             }\r
459         if (selected)\r
460             continue;\r
461 \r
462         //### OPERATORS\r
463         for (LookupEntry *entry = operatorTable; entry->sval ; entry++)\r
464             {\r
465             p2 = match(p, entry->sval);\r
466             if (p2 > p)\r
467                 {\r
468                 long op = (long)entry->ival;\r
469                 //according to the disambiguating rule for * in the spec\r
470                 if (op == MULTIPLY && lexicalTokens.size() > 0)\r
471                     {\r
472                     int ltyp = lexTokType(lexicalTokens.size()-1);\r
473                     if (ltyp != AMPR   && ltyp != DOUBLE_COLON &&\r
474                         ltyp != LPAREN && ltyp != RBRACKET     &&\r
475                         ltyp != COMMA  && ltyp != OPERATOR        )\r
476                         {\r
477                         lexTokAdd(OPERATOR, p, (long)entry->ival);\r
478                         p = p2;\r
479                         selected = true;\r
480                         break;\r
481                         }\r
482                     }\r
483                 else\r
484                     {\r
485                     lexTokAdd(OPERATOR, p, (long)entry->ival);\r
486                     p = p2;\r
487                     selected = true;\r
488                     break;\r
489                     }\r
490                 }\r
491             }\r
492         if (selected)\r
493             continue;\r
494 \r
495         //### NODE TYPES\r
496         for (LookupEntry *entry = nodeTypeTable; entry->sval ; entry++)\r
497             {\r
498             p2 = match(p, entry->sval);\r
499             if (p2 > p)\r
500                 {\r
501                 lexTokAdd(NODE_TYPE, p, (long)entry->ival);\r
502                 p = p2;\r
503                 selected = true;\r
504                 break;\r
505                 }\r
506             }\r
507         if (selected)\r
508             continue;\r
509 \r
510         //### AXIS NAMES\r
511         for (LookupEntry *entry = axisNameTable; entry->sval ; entry++)\r
512             {\r
513             p2 = match(p, entry->sval);\r
514             if (p2 > p)\r
515                 {\r
516                 lexTokAdd(AXIS_NAME, p, (long)entry->ival);\r
517                 p = p2;\r
518                 selected = true;\r
519                 break;\r
520                 }\r
521             }\r
522         if (selected)\r
523             continue;\r
524 \r
525         //### NAME TEST\r
526         DOMString ntResult;\r
527         p2 = getNameTest(p, ntResult);\r
528         if (p2 > p)\r
529             {\r
530             int p3 = skipwhite(p2);\r
531             if (peek(p3) == '(')\r
532                 lexTokAdd(FUNCTION_NAME, p, ntResult);\r
533             else\r
534                 lexTokAdd(NAME_TEST, p, ntResult);\r
535             p = p2;\r
536             selected = true;\r
537             }\r
538         if (selected)\r
539             continue;\r
540 \r
541         //### VARIABLE REFERENCE\r
542         if (peek(p) == '$')\r
543             {\r
544             p++;\r
545             DOMString qnResult;\r
546             p2 = getNCName(p, qnResult);\r
547             if (p2 > p)\r
548                 {\r
549                 lexTokAdd(VARIABLE_REFERENCE, p, qnResult);\r
550                 p = p2;\r
551                 selected = true;\r
552                 }\r
553             else\r
554                 {\r
555                 error("Variable referenced with '$' requires a qualified name\n");\r
556                 return -1;\r
557                 }\r
558             }\r
559         if (selected)\r
560             continue;\r
561 \r
562         //### NUMBER\r
563         double numval;\r
564         p2 = getNumber(p, numval);\r
565         if (p2 > p)\r
566             {\r
567             lexTokAdd(NUMBER, p, numval);\r
568             p = p2;\r
569             selected = true;\r
570             }\r
571         if (selected)\r
572             continue;\r
573 \r
574         //### LITERAL\r
575         DOMString strval;\r
576         p2 = getLiteral(p, strval);\r
577         if (p2 > p)\r
578             {\r
579             lexTokAdd(LITERAL, p, strval);\r
580             p = p2;\r
581             selected = true;\r
582             }\r
583         if (selected)\r
584             continue;\r
585 \r
586         //### CHAR  (default, none of the above)\r
587         lexTokAdd(CHAR, p, (long) peek(p));\r
588         p++;\r
589 \r
590         }//while p\r
591 \r
592 \r
593     return p;\r
594 }\r
595 \r
596 \r
597 \r
598 \r
599 \r
600 \r
601 \r
602 \r
603 \r
604 \r
605 \r
606 \r
607 \r
608 \r
609 \r
610 \r
611 \r
612 \r
613 \r
614 \r
615 \r
616 \r
617 //#########################################################################\r
618 //# X P A T H    G R A M M A R    P A R S I N G\r
619 //#########################################################################\r
620 \r
621 \r
622 void XPathParser::tokAdd(Token *tok)\r
623 {\r
624     tokens.add(tok);\r
625 }\r
626 \r
627 /**\r
628  * [1]  LocationPath ::=\r
629  *        RelativeLocationPath\r
630  *        | AbsoluteLocationPath\r
631  */\r
632 int XPathParser::getLocationPath(int p0, int depth)\r
633 {\r
634     traceStack("getLocationPath", p0, depth);\r
635     int p = p0;\r
636 \r
637     p = skipwhite(p);\r
638 \r
639     int p2 = getAbsoluteLocationPath(p, depth+1);\r
640     if (p2 > p)\r
641         {\r
642         tokens.add(new TokAbsolute());\r
643         return p2;\r
644         }\r
645 \r
646     p2 = getRelativeLocationPath(p, depth+1);\r
647     if (p2 > p)\r
648         {\r
649         tokens.add(new TokRelative());\r
650         return p2;\r
651         }\r
652 \r
653     return p0;\r
654 }\r
655 \r
656 \r
657 /**\r
658  * [2]  AbsoluteLocationPath ::=\r
659  *        '/' RelativeLocationPath?\r
660  *         | AbbreviatedAbsoluteLocationPath\r
661  */\r
662 int XPathParser::getAbsoluteLocationPath(int p0, int depth)\r
663 {\r
664     traceStack("getAbsoluteLocationPath", p0, depth);\r
665 \r
666     int p = p0;\r
667     LexTok t = lexTok(p);\r
668     if (t.getType() == OPERATOR && t.getIntValue()==SLASH)\r
669         {\r
670         p++;\r
671         int p2 = getRelativeLocationPath(p, depth+1);\r
672         if (p2 <= p)\r
673             {\r
674             error("Relative path after '/'");\r
675             return -1;\r
676             }\r
677         p = p2;\r
678         return p;\r
679         }\r
680 \r
681     //AbbreviatedAbsoluteLocationPath\r
682     if (t.getType() == OPERATOR && t.getIntValue()==DOUBLE_SLASH)\r
683         {\r
684         p++;\r
685         int p2 = getRelativeLocationPath(p, depth+1);\r
686         if (p2 <= p)\r
687             {\r
688             error("Relative path after '//'");\r
689             return -1;\r
690             }\r
691         p = p2;\r
692         return p;\r
693         }\r
694 \r
695 \r
696     return p0;\r
697 }\r
698 \r
699 \r
700 /**\r
701  * [3] RelativeLocationPath ::=\r
702  *       Step\r
703  *       | RelativeLocationPath '/' Step\r
704  *       | AbbreviatedRelativeLocationPath\r
705  */\r
706 int XPathParser::getRelativeLocationPath(int p0, int depth)\r
707 {\r
708     traceStack("getRelativeLocationPath", p0, depth);\r
709     int p = p0;\r
710     int p2 = getStep(p, depth+1);\r
711     if (p2 < 0)\r
712         return -1;\r
713     if (p2 > p)\r
714         {\r
715         p = p2;\r
716         LexTok t = lexTok(p);\r
717         if (t.getType() == OPERATOR && t.getIntValue()==SLASH)\r
718             {\r
719             p++;\r
720             p2 = getRelativeLocationPath(p, depth+1);\r
721             if (p2 < 0)\r
722                 {\r
723                 error("Relative path after '/'");\r
724                 return -1;\r
725                 }\r
726             p = p2;\r
727             return p;\r
728             }\r
729         //AbbreviatedRelativeLocationPath\r
730         if (t.getType() == OPERATOR && t.getIntValue()==DOUBLE_SLASH)\r
731             {\r
732             p++;\r
733             // a '//' is an abbreviation for /descendant-or-self:node()/\r
734             tokAdd(new TokAxisDescendantOrSelf());\r
735             p2 = getRelativeLocationPath(p, depth+1);\r
736             if (p2 < 0)\r
737                 {\r
738                 error("Relative path after '//'");\r
739                 return -1;\r
740                 }\r
741             p = p2;\r
742             return p;\r
743             }\r
744         return p;\r
745         }\r
746 \r
747 \r
748     return p0;\r
749 }\r
750 \r
751 \r
752 /**\r
753  * [4] Step ::=\r
754  *       AxisSpecifier NodeTest Predicate*\r
755  *       | AbbreviatedStep\r
756  */\r
757 int XPathParser::getStep(int p0, int depth)\r
758 {\r
759     traceStack("getStep", p0, depth);\r
760 \r
761     int p = p0;\r
762 \r
763     lexTok(p).print();\r
764 \r
765     //This can be (and usually is) 0-length\r
766     int p2 = getAxisSpecifier(p, depth+1);\r
767     if (p2 < 0)\r
768         {\r
769         error("Axis specifier in step section");\r
770         return -1;\r
771         }\r
772     p = p2;\r
773     p2 = getNodeTest(p, depth+1);\r
774     if (p2 < 0)\r
775         {\r
776         error("Node test in step section");\r
777         return -1;\r
778         }\r
779 \r
780     if (p2 > p)\r
781         {\r
782         p = p2;\r
783         p2 = getPredicate(p, depth+1);\r
784         if (p2 < 0)\r
785             {\r
786             error("Predicate in step section");\r
787             return -1;\r
788             }\r
789         p = p2;\r
790         return p;\r
791         }\r
792 \r
793     //AbbreviatedStep\r
794     if (lexTokType(p) == DOT)\r
795         {\r
796         p++;\r
797         return p;\r
798         }\r
799 \r
800     //AbbreviatedStep\r
801     if (lexTokType(p) == DOUBLE_DOT)\r
802         {\r
803         p++;\r
804         return p;\r
805         }\r
806 \r
807     return p0;\r
808 }\r
809 \r
810 \r
811 /**\r
812  * [5] AxisSpecifier ::=\r
813  *         AxisName '::'\r
814  *         | AbbreviatedAxisSpecifier\r
815  */\r
816 int XPathParser::getAxisSpecifier(int p0, int depth)\r
817 {\r
818     traceStack("getAxisSpecifier", p0, depth);\r
819     int p = p0;\r
820     if (lexTokType(p) == AXIS_NAME)\r
821         {\r
822         LexTok t = lexTok(p);\r
823         int axisType = t.getIntValue();\r
824         p++;\r
825         if (lexTokType(p) != DOUBLE_COLON)\r
826             {\r
827             error("'::' required after axis name literal");\r
828             return -1;\r
829             }\r
830         p++;\r
831         switch (axisType)\r
832             {\r
833             case ANCESTOR_OR_SELF:\r
834                 tokAdd(new TokAxisAncestorOrSelf());\r
835             case ANCESTOR:\r
836                 tokAdd(new TokAxisAncestor());\r
837             case ATTRIBUTE:\r
838                 tokAdd(new TokAxisAttribute());\r
839             case CHILD:\r
840                 tokAdd(new TokAxisChild());\r
841             case DESCENDANT_OR_SELF:\r
842                 tokAdd(new TokAxisDescendantOrSelf());\r
843             case DESCENDANT:\r
844                 tokAdd(new TokAxisDescendant());\r
845             case FOLLOWING_SIBLING:\r
846                 tokAdd(new TokAxisFollowingSibling());\r
847             case FOLLOWING:\r
848                 tokAdd(new TokAxisFollowing());\r
849             case NAMESPACE:\r
850                 tokAdd(new TokAxisNamespace());\r
851             case PARENT:\r
852                 tokAdd(new TokAxisParent());\r
853             case PRECEDING_SIBLING:\r
854                 tokAdd(new TokAxisPrecedingSibling());\r
855             case PRECEDING:\r
856                 tokAdd(new TokAxisPreceding());\r
857             case SELF:\r
858                 tokAdd(new TokAxisSelf());\r
859             default:\r
860                 {\r
861                 error("unknown axis type %d", axisType);\r
862                 return -1;\r
863                 }\r
864             }\r
865         return p;\r
866         }\r
867 \r
868     //AbbreviatedAxisSpecifier\r
869     if (lexTokType(p) == AMPR)\r
870         {\r
871         p++;\r
872         return p;\r
873         }\r
874 \r
875     return p0;\r
876 }\r
877 \r
878 \r
879 /**\r
880  * [6]  AxisName ::=\r
881  *         'ancestor'\r
882  *         | 'ancestor-or-self'\r
883  *         | 'attribute'\r
884  *         | 'child'\r
885  *         | 'descendant'\r
886  *         | 'descendant-or-self'\r
887  *         | 'following'\r
888  *         | 'following-sibling'\r
889  *         | 'namespace'\r
890  *         | 'parent'\r
891  *         | 'preceding'\r
892  *         | 'preceding-sibling'\r
893  *         | 'self'\r
894  * NOTE: This definition, and those at the bottom, is not\r
895  *   needed.  Its functionality is handled by lexical scanning.\r
896  *   It is left here for reference.\r
897  */\r
898 int XPathParser::getAxisName(int p0, int depth)\r
899 {\r
900     traceStack("getAxisName", p0, depth);\r
901     return p0;\r
902 }\r
903 \r
904 \r
905 /**\r
906  * [7] NodeTest ::=\r
907  *       NameTest\r
908  *       | NodeType '(' ')'\r
909  *       | 'processing-instruction' '(' Literal ')'\r
910  */\r
911 int XPathParser::getNodeTest(int p0, int depth)\r
912 {\r
913     traceStack("getNodeTest", p0, depth);\r
914     int p = p0;\r
915 \r
916     LexTok t = lexTok(p);\r
917     if (t.getType() == NAME_TEST)\r
918         {\r
919         p++;\r
920         tokAdd(new TokNameTest(t.getStringValue()));\r
921         return p;\r
922         }\r
923     if (t.getType() == NODE_TYPE)\r
924         {\r
925         if (t.getIntValue() == PROCESSING_INSTRUCTION)\r
926             {\r
927             if (lexTokType(p)   != LPAREN   ||\r
928                 lexTokType(p+1) != LITERAL  ||\r
929                 lexTokType(p+2) != RPAREN   )\r
930                 {\r
931                 error("processing instruction requires (\"literal string\")");\r
932                 return -1;\r
933                 }\r
934             p += 3;\r
935             }\r
936         else\r
937             {\r
938             if (lexTokType(p+1) != LPAREN ||\r
939                 lexTokType(p+2) != RPAREN )\r
940                 {\r
941                 error("processing instruction requires ()");\r
942                 return -1;\r
943                 }\r
944             p += 2;\r
945             }\r
946         return p;\r
947         }\r
948 \r
949     return p0;\r
950 }\r
951 \r
952 \r
953 /**\r
954  * [8]  Predicate ::=\r
955  *         '[' PredicateExpr ']'\r
956  */\r
957 int XPathParser::getPredicate(int p0, int depth)\r
958 {\r
959     traceStack("getPredicate", p0, depth);\r
960 \r
961     int p = p0;\r
962     if (lexTokType(p) != LBRACKET)\r
963         return p0;\r
964 \r
965     p++;\r
966     int p2 = getPredicateExpr(p, depth+1);\r
967     if (p2 <= p)\r
968         {\r
969         error("Predicate expression in predicate");\r
970         return -1;\r
971         }\r
972 \r
973     p = p2;\r
974     lexTok(p).print();\r
975     if (lexTokType(p) != RBRACKET)\r
976         {\r
977         error("Predicate expression requires closing ']'");\r
978         return -1;\r
979         }\r
980     p++;\r
981     return p;\r
982 }\r
983 \r
984 \r
985 /**\r
986  * [9]  PredicateExpr ::=\r
987  *         Expr\r
988  */\r
989 int XPathParser::getPredicateExpr(int p0, int depth)\r
990 {\r
991     traceStack("getPredicateExpr", p0, depth);\r
992     int p = p0;\r
993     int p2 = getExpr(p, depth+1);\r
994     if (p2 < 0)\r
995         {\r
996         error("Expression in predicate expression");\r
997         return -1;\r
998         }\r
999     p = p2;\r
1000     return p;\r
1001 }\r
1002 \r
1003 \r
1004 /**\r
1005  * [10] AbbreviatedAbsoluteLocationPath ::=\r
1006  *        '//' RelativeLocationPath\r
1007  * NOTE: not used. handled in getAbsoluteLocationPath()\r
1008  */\r
1009 int XPathParser::getAbbreviatedAbsoluteLocationPath(int p0, int depth)\r
1010 {\r
1011     traceStack("getAbbreviatedAbsoluteLocationPath", p0, depth);\r
1012 \r
1013      return p0;\r
1014 }\r
1015 \r
1016 /**\r
1017  * [11] AbbreviatedRelativeLocationPath ::=\r
1018  *         RelativeLocationPath '//' Step\r
1019  * NOTE: not used. handled in getRelativeLocationPath()\r
1020  */\r
1021 int XPathParser::getAbbreviatedRelativeLocationPath(int p0, int depth)\r
1022 {\r
1023     traceStack("getAbbreviatedRelativeLocationPath", p0, depth);\r
1024     return p0;\r
1025 }\r
1026 \r
1027 /**\r
1028  * [12]  AbbreviatedStep ::=\r
1029  *           '.'\r
1030  *           | '..'\r
1031  * NOTE: not used. handled in getStep()\r
1032  */\r
1033 int XPathParser::getAbbreviatedStep(int p0, int depth)\r
1034 {\r
1035     traceStack("getAbbreviatedStep", p0, depth);\r
1036     return p0;\r
1037 }\r
1038 \r
1039 \r
1040 /**\r
1041  * [13] AbbreviatedAxisSpecifier ::=\r
1042  *        '@'?\r
1043  * NOTE: not used. handled in getAxisSpecifier()\r
1044  */\r
1045 int XPathParser::getAbbreviatedAxisSpecifier(int p0, int depth)\r
1046 {\r
1047     traceStack("getAbbreviatedAxisSpecifier", p0, depth);\r
1048     return p0;\r
1049 }\r
1050 \r
1051 \r
1052 /**\r
1053  * [14] Expr ::=\r
1054  *         OrExpr\r
1055  */\r
1056 int XPathParser::getExpr(int p0, int depth)\r
1057 {\r
1058     traceStack("getExpr", p0, depth);\r
1059 \r
1060     int p = p0;\r
1061 \r
1062     int p2 = getOrExpr(p, depth+1);\r
1063     if (p2 < 0)\r
1064         {\r
1065         error("OR expression in expression");\r
1066         return -1;\r
1067         }\r
1068     p = p2;\r
1069 \r
1070     return p;\r
1071 }\r
1072 \r
1073 \r
1074 /**\r
1075  * [15]  PrimaryExpr ::=\r
1076  *          VariableReference\r
1077  *          | '(' Expr ')'\r
1078  *          | Literal\r
1079  *          | Number\r
1080  *          | FunctionCall\r
1081  */\r
1082 int XPathParser::getPrimaryExpr(int p0, int depth)\r
1083 {\r
1084     traceStack("getPrimaryExpr", p0, depth);\r
1085     int p = p0;\r
1086     int p2 = p;\r
1087 \r
1088     if (lexTokType(p) == VARIABLE_REFERENCE)\r
1089         {\r
1090         p++;\r
1091         return p;\r
1092         }\r
1093 \r
1094     if (lexTokType(p) == LPAREN)\r
1095         {\r
1096         p++;\r
1097         p2 = getExpr(p, depth+1);\r
1098         if (p2 <= p)\r
1099             {\r
1100             error("Expression in primary expression");\r
1101             return -1;\r
1102             }\r
1103         p += p2;\r
1104         if (lexTokType(p) != RPAREN)\r
1105             {\r
1106             error("Primary expression requires closing ')'");\r
1107             return -1;\r
1108             }\r
1109         }\r
1110 \r
1111     if (lexTokType(p) == LITERAL)\r
1112         {\r
1113         tokens.add(new TokStr(lexTok(p).getStringValue()));\r
1114         p++;\r
1115         return p;\r
1116         }\r
1117 \r
1118     if (lexTokType(p) == NUMBER)\r
1119         {\r
1120         tokens.add(new TokFloat(lexTok(p).getDoubleValue()));\r
1121         p++;\r
1122         return p;\r
1123         }\r
1124 \r
1125     p2 = getFunctionCall(p, depth+1);\r
1126     if (p2 < 0)\r
1127         {\r
1128         error("Function call in primary expression");\r
1129         return -1;\r
1130         }\r
1131     if (p2 > p)\r
1132         {\r
1133         p = p2;\r
1134         return p;\r
1135         }\r
1136 \r
1137     return p0;\r
1138 }\r
1139 \r
1140 \r
1141 /**\r
1142  * [16] FunctionCall ::=\r
1143  *         FunctionName '(' ( Argument ( ',' Argument )* )? ')'\r
1144  */\r
1145 int XPathParser::getFunctionCall(int p0, int depth)\r
1146 {\r
1147     traceStack("getFunctionCall", p0, depth);\r
1148     int p = p0;\r
1149 \r
1150     if (lexTokType(p) != FUNCTION_NAME)\r
1151         return p0;\r
1152 \r
1153     DOMString name = lexTok(p).getStringValue();\r
1154 \r
1155     p++;\r
1156 \r
1157     if (lexTokType(p) != LPAREN) //this makes a function\r
1158         return p0;\r
1159     p++;\r
1160 \r
1161     int argCount = 0;\r
1162 \r
1163     int p2 = getArgument(p, depth+1);\r
1164     if (p2 < 0)\r
1165         {\r
1166         error("Error in function argument");\r
1167         return -1;\r
1168         }\r
1169     if (p2 > p)\r
1170         {\r
1171         argCount++;\r
1172         p = p2;\r
1173         while (lexTokType(p) == COMMA)\r
1174             {\r
1175             p++;\r
1176             p2 = getArgument(p, depth+1);\r
1177             if (p2 <= p)\r
1178                 {\r
1179                 error("Error in function argument");\r
1180                 return -1;\r
1181                 }\r
1182             if (p2 > p)\r
1183                 argCount++;\r
1184             //do we add a token here?  i dont think so\r
1185             p = p2;\r
1186             }\r
1187         }\r
1188 \r
1189     if (lexTokType(p) != RPAREN) //mandatory\r
1190         {\r
1191         error("Function requires closing ')'");\r
1192         return -1;\r
1193         }\r
1194     p++;\r
1195 \r
1196     // Function names from http://www.w3.org/TR/xpath#NT-FunctionName\r
1197     if (name == "last")\r
1198         tokens.add(new TokFuncLast());\r
1199     else if (name == "position")\r
1200         tokens.add(new TokFuncPosition());\r
1201     else if (name == "count")\r
1202         tokens.add(new TokFuncCount());\r
1203     else if (name == "id")\r
1204         tokens.add(new TokFuncId());\r
1205     else if (name == "local-name")\r
1206         tokens.add(new TokFuncLocalName());\r
1207     else if (name == "namespace-uri")\r
1208         tokens.add(new TokFuncNamespaceUri());\r
1209     else if (name == "name")\r
1210         tokens.add(new TokFuncName());\r
1211     else if (name == "string")\r
1212         tokens.add(new TokFuncString());\r
1213     else if (name == "concat")\r
1214         tokens.add(new TokFuncConcat());\r
1215     else if (name == "starts-with")\r
1216         tokens.add(new TokFuncStartsWith());\r
1217     else if (name == "contains")\r
1218         tokens.add(new TokFuncContains());\r
1219     else if (name == "substring-before")\r
1220         tokens.add(new TokFuncSubstringBefore());\r
1221     else if (name == "substring-after")\r
1222         tokens.add(new TokFuncSubstringAfter());\r
1223     else if (name == "substring")\r
1224         tokens.add(new TokFuncSubstring());\r
1225     else if (name == "string-length")\r
1226         tokens.add(new TokFuncStringLength());\r
1227     else if (name == "normalize-space")\r
1228         tokens.add(new TokFuncNormalizeSpace());\r
1229     else if (name == "translate")\r
1230         tokens.add(new TokFuncTranslate());\r
1231     else if (name == "boolean")\r
1232         tokens.add(new TokFuncBoolean());\r
1233     else if (name == "not")\r
1234         tokens.add(new TokFuncNot());\r
1235     else if (name == "true")\r
1236         tokens.add(new TokFuncTrue());\r
1237     else if (name == "false")\r
1238         tokens.add(new TokFuncFalse());\r
1239     else if (name == "lang")\r
1240         tokens.add(new TokFuncLang());\r
1241     else if (name == "number")\r
1242         tokens.add(new TokFuncNumber());\r
1243     else if (name == "sum")\r
1244         tokens.add(new TokFuncSum());\r
1245     else if (name == "floor")\r
1246         tokens.add(new TokFuncFloor());\r
1247     else if (name == "ceiling")\r
1248         tokens.add(new TokFuncCeiling());\r
1249     else if (name == "round")\r
1250         tokens.add(new TokFuncRound());\r
1251     else\r
1252         {\r
1253         error("unknown function name:'%s'", name.c_str());\r
1254         return -1;\r
1255         }\r
1256     return p;\r
1257 }\r
1258 \r
1259 \r
1260 /**\r
1261  * [17] Argument ::=\r
1262  *         Expr\r
1263  */\r
1264 int XPathParser::getArgument(int p0, int depth)\r
1265 {\r
1266     traceStack("getArgument", p0, depth);\r
1267     int p = p0;\r
1268     int p2 = getExpr(p, depth+1);\r
1269     if (p2 < 0)\r
1270         {\r
1271         error("Argument expression");\r
1272         return -1;\r
1273         }\r
1274     p = p2;\r
1275     return p;\r
1276 }\r
1277 \r
1278 \r
1279 /**\r
1280  * [18]  UnionExpr ::=\r
1281  *           PathExpr\r
1282  *           | UnionExpr '|' PathExpr\r
1283  */\r
1284 int XPathParser::getUnionExpr(int p0, int depth)\r
1285 {\r
1286     traceStack("getUnionExpr", p0, depth);\r
1287     int p = p0;\r
1288     int p2 = getPathExpr(p, depth+1);\r
1289     if (p2 < 0)\r
1290         {\r
1291         error("Path expression for union");\r
1292         return -1;\r
1293         }\r
1294     p = p2;\r
1295     LexTok t = lexTok(p);\r
1296     if (t.getType() == OPERATOR && t.getIntValue() == PIPE)\r
1297         {\r
1298         p++;\r
1299         p2 = getUnionExpr(p, depth+1);\r
1300         if (p2 < 0)\r
1301             {\r
1302             error("OR (|) requires union expression on the left");\r
1303             return -1;\r
1304             }\r
1305         tokens.add(new TokUnion());\r
1306         p = p2;\r
1307         }\r
1308     return p;\r
1309 }\r
1310 \r
1311 \r
1312 /**\r
1313  * [19]  PathExpr ::=\r
1314  *          LocationPath\r
1315  *          | FilterExpr\r
1316  *          | FilterExpr '/' RelativeLocationPath\r
1317  *          | FilterExpr '//' RelativeLocationPath\r
1318  */\r
1319 int XPathParser::getPathExpr(int p0, int depth)\r
1320 {\r
1321     traceStack("getPathExpr", p0, depth);\r
1322     int p = p0;\r
1323     int p2;\r
1324 \r
1325     p2 = getLocationPath(p, depth+1);\r
1326     if (p2 < 0)\r
1327         {\r
1328         error("Location path in path expression");\r
1329         return -1;\r
1330         }\r
1331     if (p2 > p)\r
1332         {\r
1333         p = p2;\r
1334         return p;\r
1335         }\r
1336 \r
1337     p2 = getFilterExpr(p, depth+1);\r
1338     if (p2 < 0)\r
1339         {\r
1340         error("Filter expression in path expression");\r
1341         return -1;\r
1342         }\r
1343     if (p2 <= p)\r
1344         return p0;\r
1345     p = p2;\r
1346 \r
1347     LexTok t = lexTok(p);\r
1348     if (t.getType() == OPERATOR && t.getIntValue() == SLASH)\r
1349         {\r
1350         p++;\r
1351         p2 = getRelativeLocationPath(p, depth+1);\r
1352         if (p2 < 0)\r
1353             {\r
1354             error("Relative location after / in path expression");\r
1355             return -1;\r
1356             }\r
1357         p = p2;\r
1358         return p;\r
1359         }\r
1360 \r
1361     if (t.getType() == OPERATOR && t.getIntValue() == DOUBLE_SLASH)\r
1362         {\r
1363         p++;\r
1364         p2 = getRelativeLocationPath(p, depth+1);\r
1365         if (p2 < 0)\r
1366             {\r
1367             error("Relative location after // in path expression");\r
1368             return -1;\r
1369             }\r
1370         p = p2;\r
1371         return p;\r
1372         }\r
1373     return p;\r
1374 }\r
1375 \r
1376 \r
1377 /**\r
1378  * [20] FilterExpr ::=\r
1379  *         PrimaryExpr\r
1380  *         | FilterExpr Predicate\r
1381  */\r
1382 int XPathParser::getFilterExpr(int p0, int depth)\r
1383 {\r
1384     traceStack("getFilterExpr", p0, depth);\r
1385     int p = p0;\r
1386 \r
1387     int p2 = getPrimaryExpr(p, depth+1);\r
1388     if (p2 < 0)\r
1389         {\r
1390         error("Primary expression in path expression");\r
1391         return -1;\r
1392         }\r
1393     if (p2 > p)\r
1394         {\r
1395         p = p2;\r
1396         while (true)\r
1397             {\r
1398             p2 = getPredicate(p, depth+1);\r
1399             if (p2 < 0)\r
1400                 {\r
1401                 error("Predicate in primary expression");\r
1402                 return -1;\r
1403                 }\r
1404             if (p2 > p)\r
1405                 {\r
1406                 p = p2;\r
1407                 }\r
1408             else\r
1409                 break;\r
1410            }\r
1411         return p;\r
1412         }\r
1413 \r
1414     return p0;\r
1415 }\r
1416 \r
1417 \r
1418 /**\r
1419  * [21]  OrExpr ::=\r
1420  *           AndExpr\r
1421  *           | OrExpr 'or' AndExpr\r
1422  */\r
1423 int XPathParser::getOrExpr(int p0, int depth)\r
1424 {\r
1425     traceStack("getOrExpr", p0, depth);\r
1426     int p = p0;\r
1427     int p2 = getAndExpr(p, depth+1);\r
1428     if (p2 < 0)\r
1429         {\r
1430         error("AND expression in OR expression");\r
1431         return -1;\r
1432         }\r
1433     if (p2 > p)\r
1434         {\r
1435         p = p2;\r
1436         LexTok t = lexTok(p);\r
1437         if (t.getType() == OPERATOR && t.getIntValue() == OR)\r
1438             {\r
1439             p++;\r
1440             p2 = getAndExpr(p, depth+1);\r
1441             if (p2 <= p)\r
1442                 {\r
1443                 error("AND expression in OR expression");\r
1444                 return -1;\r
1445                 }\r
1446             p = p2;\r
1447             return p;\r
1448             }\r
1449         tokens.add(new TokOr());\r
1450         return p;\r
1451         }\r
1452 \r
1453     return p0;\r
1454 }\r
1455 \r
1456 \r
1457 /**\r
1458  * [22] AndExpr ::=\r
1459  *         EqualityExpr\r
1460  *         | AndExpr 'and' EqualityExpr\r
1461  */\r
1462 int XPathParser::getAndExpr(int p0, int depth)\r
1463 {\r
1464     traceStack("getAndExpr", p0, depth);\r
1465     int p = p0;\r
1466     int p2 = getEqualityExpr(p, depth+1);\r
1467     if (p2 < 0)\r
1468         {\r
1469         error("Equality expression in AND expression");\r
1470         return -1;\r
1471         }\r
1472     if (p2 > p)\r
1473         {\r
1474         p = p2;\r
1475         LexTok t = lexTok(p);\r
1476         if (t.getType() == OPERATOR && t.getIntValue() == AND)\r
1477             {\r
1478             p++;\r
1479             p2 = getAndExpr(p, depth+1);\r
1480             if (p2 <= p)\r
1481                 {\r
1482                 error("AND expression after 'and'");\r
1483                 return -1;\r
1484                 }\r
1485             p = p2;\r
1486             return p;\r
1487             }\r
1488         tokens.add(new TokAnd());\r
1489         return p;\r
1490         }\r
1491 \r
1492     return p0;\r
1493 }\r
1494 \r
1495 \r
1496 /**\r
1497  * [23]  EqualityExpr ::=\r
1498  *           RelationalExpr\r
1499  *           | EqualityExpr '=' RelationalExpr\r
1500  *           | EqualityExpr '!=' RelationalExpr\r
1501  */\r
1502 int XPathParser::getEqualityExpr(int p0, int depth)\r
1503 {\r
1504     traceStack("getEqualityExpr", p0, depth);\r
1505     int p = p0;\r
1506     int p2 = getRelationalExpr(p, depth+1);\r
1507     if (p2 < 0)\r
1508         {\r
1509         error("Relation expression in equality expression");\r
1510         return -1;\r
1511         }\r
1512     if (p2 > p)\r
1513         {\r
1514         p = p2;\r
1515         LexTok t = lexTok(p);\r
1516         if (t.getType() == OPERATOR && t.getIntValue() == EQUALS)\r
1517             {\r
1518             p++;\r
1519             p2 = getEqualityExpr(p, depth+1);\r
1520             if (p2 <= p)\r
1521                 {\r
1522                 error("Equality expression expected after ==");\r
1523                 return -1;\r
1524                 }\r
1525             tokens.add(new TokEquals());\r
1526             p = p2;\r
1527             return p;\r
1528             }\r
1529 \r
1530         if (t.getType() == OPERATOR && t.getIntValue() == NOT_EQUALS)\r
1531             {\r
1532             p++;\r
1533             p2 = getEqualityExpr(p, depth+1);\r
1534             if (p2 <= p)\r
1535                 {\r
1536                 error("Equality expression expected after !=");\r
1537                 return -1;\r
1538                 }\r
1539             tokens.add(new TokNotEquals());\r
1540             p = p2;\r
1541             return p;\r
1542             }\r
1543 \r
1544         return p;\r
1545         }\r
1546 \r
1547     return p0;\r
1548 }\r
1549 \r
1550 \r
1551 /**\r
1552  * [24] RelationalExpr ::=\r
1553  *         AdditiveExpr\r
1554  *         | RelationalExpr '<' AdditiveExpr\r
1555  *         | RelationalExpr '>' AdditiveExpr\r
1556  *         | RelationalExpr '<=' AdditiveExpr\r
1557  *         | RelationalExpr '>=' AdditiveExpr\r
1558  */\r
1559 int XPathParser::getRelationalExpr(int p0, int depth)\r
1560 {\r
1561     traceStack("getRelationalExpr", p0, depth);\r
1562     int p = p0;\r
1563     int p2 = getAdditiveExpr(p, depth+1);\r
1564     if (p2 < 0)\r
1565         {\r
1566         error("Additive expression in relational expression");\r
1567         return -1;\r
1568         }\r
1569     if (p2 > p)\r
1570         {\r
1571         p = p2;\r
1572         LexTok t = lexTok(p);\r
1573 \r
1574         if (t.getType() == OPERATOR && t.getIntValue() == GREATER_THAN)\r
1575             {\r
1576             p++;\r
1577             p2 = getRelationalExpr(p, depth+1);\r
1578             if (p2 <= p)\r
1579                 {\r
1580                 error("Relational expression after '>'");\r
1581                 return -1;\r
1582                 }\r
1583             tokens.add(new TokGreaterThan());\r
1584             p = p2;\r
1585             return p;\r
1586             }\r
1587         if (t.getType() == OPERATOR && t.getIntValue() == LESS_THAN)\r
1588             {\r
1589             p++;\r
1590             p2 = getRelationalExpr(p, depth+1);\r
1591             if (p2 <= p)\r
1592                 {\r
1593                 error("Relational expression after '<'");\r
1594                 return -1;\r
1595                 }\r
1596             tokens.add(new TokLessThan());\r
1597             p = p2;\r
1598             return p;\r
1599             }\r
1600         if (t.getType() == OPERATOR && t.getIntValue() == GREATER_THAN_EQUALS)\r
1601             {\r
1602             p++;\r
1603             p2 = getRelationalExpr(p, depth+1);\r
1604             if (p2 <= p)\r
1605                 {\r
1606                 error("Relational expression after '>='");\r
1607                 return -1;\r
1608                 }\r
1609             tokens.add(new TokGreaterThanEquals());\r
1610             p = p2;\r
1611             return p;\r
1612             }\r
1613         if (t.getType() == OPERATOR && t.getIntValue() == LESS_THAN_EQUALS)\r
1614             {\r
1615             p++;\r
1616             p2 = getRelationalExpr(p, depth+1);\r
1617             if (p2 <= p)\r
1618                 {\r
1619                 error("Relational expression after '<='");\r
1620                 return -1;\r
1621                 }\r
1622             tokens.add(new TokLessThanEquals());\r
1623             p = p2;\r
1624             return p;\r
1625             }\r
1626 \r
1627 \r
1628         return p;\r
1629         }\r
1630 \r
1631     return p0;\r
1632 }\r
1633 \r
1634 \r
1635 /**\r
1636  * [25]  AdditiveExp ::=\r
1637  *           MultiplicativeExpr\r
1638  *           | AdditiveExpr '+' MultiplicativeExpr\r
1639  *           | AdditiveExpr '-' MultiplicativeExpr\r
1640  */\r
1641 int XPathParser::getAdditiveExpr(int p0, int depth)\r
1642 {\r
1643     traceStack("getAdditiveExpr", p0, depth);\r
1644     int p = p0;\r
1645     int p2 = getMultiplicativeExpr(p, depth+1);\r
1646     if (p2 < 0)\r
1647         {\r
1648         error("Multiplicative expression in additive expression");\r
1649         return -1;\r
1650         }\r
1651     if (p2 > p)\r
1652         {\r
1653         p = p2;\r
1654         LexTok t = lexTok(p);\r
1655 \r
1656         if (t.getType() == OPERATOR && t.getIntValue() == PLUS)\r
1657             {\r
1658             p++;\r
1659             p2 = getAdditiveExpr(p, depth+1);\r
1660             if (p2 <= p)\r
1661                 {\r
1662                 error("Additive expression after '+'");\r
1663                 return -1;\r
1664                 }\r
1665             tokens.add(new TokPlus());\r
1666             p = p2;\r
1667             return p;\r
1668             }\r
1669         if (t.getType() == OPERATOR && t.getIntValue() == MINUS)\r
1670             {\r
1671             p++;\r
1672             p2 = getAdditiveExpr(p, depth+1);\r
1673             if (p2 <= p)\r
1674                 {\r
1675                 error("Additive expression after '-'");\r
1676                 return -1;\r
1677                 }\r
1678             tokens.add(new TokMinus());\r
1679             p = p2;\r
1680             return p;\r
1681             }\r
1682 \r
1683 \r
1684         return p;\r
1685         }\r
1686 \r
1687     return p0;\r
1688 }\r
1689 \r
1690 \r
1691 /**\r
1692  * [26]  MultiplicativeExpr ::=\r
1693  *          UnaryExpr\r
1694  *          | MultiplicativeExpr MultiplyOperator UnaryExpr\r
1695  *          | MultiplicativeExpr 'div' UnaryExpr\r
1696  *          | MultiplicativeExpr 'mod' UnaryExpr\r
1697  */\r
1698 int XPathParser::getMultiplicativeExpr(int p0, int depth)\r
1699 {\r
1700     traceStack("getMultiplicativeExpr", p0, depth);\r
1701     int p = p0;\r
1702     int p2 = getUnaryExpr(p, depth+1);\r
1703     if (p2 < 0)\r
1704         {\r
1705         error("Unary expression in multiplicative expression");\r
1706         return -1;\r
1707         }\r
1708     if (p2 > p)\r
1709         {\r
1710         p = p2;\r
1711         LexTok t = lexTok(p);\r
1712 \r
1713         if (t.getType() == OPERATOR && t.getIntValue() == MULTIPLY)\r
1714             {\r
1715             p++;\r
1716             p2 = getMultiplicativeExpr(p, depth+1);\r
1717             if (p2 <= p)\r
1718                 {\r
1719                 error("Multiplicative expression after '*'");\r
1720                 return -1;\r
1721                 }\r
1722             tokens.add(new TokMul());\r
1723             p = p2;\r
1724             return p;\r
1725             }\r
1726 \r
1727         if (t.getType() == OPERATOR && t.getIntValue() == DIV)\r
1728             {\r
1729             p++;\r
1730             p2 = getMultiplicativeExpr(p, depth+1);\r
1731             if (p2 <= p)\r
1732                 {\r
1733                 error("Multiplicative expression after 'div'");\r
1734                 return -1;\r
1735                 }\r
1736             tokens.add(new TokDiv());\r
1737             p = p2;\r
1738             return p;\r
1739             }\r
1740 \r
1741         if (t.getType() == OPERATOR && t.getIntValue() == MOD)\r
1742             {\r
1743             p++;\r
1744             p2 = getMultiplicativeExpr(p, depth+1);\r
1745             if (p2 <= p)\r
1746                 {\r
1747                 error("Multiplicative expression after 'mod'");\r
1748                 return -1;\r
1749                 }\r
1750             tokens.add(new TokMod());\r
1751             p = p2;\r
1752             return p;\r
1753             }\r
1754 \r
1755 \r
1756         return p;\r
1757         }\r
1758 \r
1759     return p0;\r
1760 }\r
1761 \r
1762 \r
1763 /**\r
1764  * [27]  UnaryExpr ::=\r
1765  *          UnionExpr\r
1766  *          | '-' UnaryExpr\r
1767  */\r
1768 int XPathParser::getUnaryExpr(int p0, int depth)\r
1769 {\r
1770     traceStack("getUnaryExpr", p0, depth);\r
1771     int p = p0;\r
1772     int p2 = getUnionExpr(p, depth+1);\r
1773     if (p2 < 0)\r
1774         {\r
1775         error("Union expression in unary expression");\r
1776         return -1;\r
1777         }\r
1778     if (p2 > p)\r
1779         {\r
1780         p = p2;\r
1781         return p;\r
1782         }\r
1783 \r
1784     if (lexTokType(p) == '-')\r
1785         {\r
1786         p++;\r
1787         p2 = getUnaryExpr(p, depth+1);\r
1788         if (p2 < 0)\r
1789             {\r
1790             error("Unary expression after '-'");\r
1791             return -1;\r
1792             }\r
1793         tokens.add(new TokNeg());\r
1794         p = p2;\r
1795         return p;\r
1796         }\r
1797 \r
1798     return p0;\r
1799 }\r
1800 \r
1801 \r
1802 //######################################################\r
1803 //# NOT USED!!!\r
1804 //## The grammar definitions below are\r
1805 //## handled by lexical parsing, and will not be used\r
1806 //######################################################\r
1807 \r
1808 /**\r
1809  * [28] ExprToken ::=\r
1810  *         '(' | ')' | '[' | ']' | '.' | '..' | '@' | ',' | '::'\r
1811  *         | NameTest\r
1812  *         | NodeType\r
1813  *         | Operator\r
1814  *         | FunctionName\r
1815  *         | AxisName\r
1816  *         | Literal\r
1817  *         | Number\r
1818  *         | VariableReference\r
1819  */\r
1820 int XPathParser::getExprToken(int p0, int depth)\r
1821 {\r
1822     traceStack("getExprToken", p0, depth);\r
1823     return p0;\r
1824 }\r
1825 \r
1826 \r
1827 /**\r
1828  * [29]  Literal ::=\r
1829  *           '"' [^"]* '"'\r
1830  *           | "'" [^']* "'"\r
1831  */\r
1832 int XPathParser::getLiteral(int p0, int depth)\r
1833 {\r
1834     traceStack("getLiteral", p0, depth);\r
1835     return p0;\r
1836 }\r
1837 \r
1838 \r
1839 /**\r
1840  * [30] Number ::=\r
1841  *        Digits ('.' Digits?)?\r
1842  *        | '.' Digits\r
1843  */\r
1844 int XPathParser::getNumber(int p0, int depth)\r
1845 {\r
1846     traceStack("getNumber", p0, depth);\r
1847     return p0;\r
1848 }\r
1849 \r
1850 \r
1851 /**\r
1852  * [31] Digits ::=\r
1853  *         [0-9]+\r
1854  */\r
1855 int XPathParser::getDigits(int p0, int depth)\r
1856 {\r
1857     traceStack("getDigits", p0, depth);\r
1858     return p0;\r
1859 }\r
1860 \r
1861 \r
1862 /**\r
1863  * [32] Operator ::=\r
1864  *         OperatorName\r
1865  *         | MultiplyOperator\r
1866  *         | '/' | '//' | '|' | '+' | '-' | '='\r
1867  *         | '!=' | '<' | '<=' | '>' | '>='\r
1868  */\r
1869 int XPathParser::getOperator(int p0, int depth)\r
1870 {\r
1871     traceStack("getOperator", p0, depth);\r
1872     return p0;\r
1873 }\r
1874 \r
1875 \r
1876 /**\r
1877  * [33]  OperatorName ::=\r
1878  *          'and' | 'or' | 'mod' | 'div'\r
1879  */\r
1880 int XPathParser::getOperatorName(int p0, int depth)\r
1881 {\r
1882     traceStack("getOperatorName", p0, depth);\r
1883     return p0;\r
1884 }\r
1885 \r
1886 \r
1887 /**\r
1888  * [34] MultiplyOperator ::=\r
1889  *          '*'\r
1890  */\r
1891 int XPathParser::getMultiplyOperator(int p0, int depth)\r
1892 {\r
1893     traceStack("getMultiplyOperator", p0, depth);\r
1894     return p0;\r
1895 }\r
1896 \r
1897 \r
1898 /**\r
1899  * [35] FunctionName ::=\r
1900  *          QName - NodeType\r
1901  */\r
1902 int XPathParser::getFunctionName(int p0, int depth)\r
1903 {\r
1904     traceStack("getFunctionName", p0, depth);\r
1905     return p0;\r
1906 }\r
1907 \r
1908 \r
1909 /**\r
1910  * [36] VariableReference ::=\r
1911  *          '$' QName\r
1912  */\r
1913 int XPathParser::getVariableReference(int p0, int depth)\r
1914 {\r
1915     traceStack("getVariableReference", p0, depth);\r
1916     return p0;\r
1917 }\r
1918 \r
1919 \r
1920 /**\r
1921  * [37] NameTest ::=\r
1922  *         '*'\r
1923  *         | NCName ':' '*'\r
1924  *         | QName\r
1925  */\r
1926 int XPathParser::getNameTest(int p0, int depth)\r
1927 {\r
1928     traceStack("getNameTest", p0, depth);\r
1929     return p0;\r
1930 }\r
1931 \r
1932 \r
1933 /**\r
1934  * [38] NodeType ::=\r
1935  *         'comment'\r
1936  *         | 'text'\r
1937  *         | 'processing-instruction'\r
1938  *         | 'node'\r
1939  */\r
1940 int XPathParser::getNodeType(int p0, int depth)\r
1941 {\r
1942     traceStack("getNodeType", p0, depth);\r
1943     return p0;\r
1944 }\r
1945 \r
1946 \r
1947 /**\r
1948  * [39] ExprWhitespace ::=\r
1949  *           S\r
1950  */\r
1951 int XPathParser::getExprWhitespace(int p0, int depth)\r
1952 {\r
1953     traceStack("getExprWhitespace", p0, depth);\r
1954     return p0;\r
1955 }\r
1956 \r
1957 \r
1958 \r
1959 \r
1960 \r
1961 //#########################################################################\r
1962 //# H I G H    L E V E L    P A R S I N G\r
1963 //#########################################################################\r
1964 \r
1965 /**\r
1966  * Parse a candidate XPath string.  Leave a copy in 'tokens.'\r
1967  */\r
1968 bool XPathParser::parse(const DOMString &xpathString)\r
1969 {\r
1970     int p0 = 0;\r
1971 \r
1972     DOMString str = xpathString;\r
1973 \r
1974     parsebuf = (char *)str.c_str();\r
1975     parselen = (int)   str.size();\r
1976     position = 0;\r
1977 \r
1978     trace("## parsing string: '%s'", parsebuf);\r
1979 \r
1980     lexicalScan();\r
1981     lexicalTokenDump();\r
1982 \r
1983     tokens.clear();//Get ready to store new tokens\r
1984 \r
1985     int p = getLocationPath(p0, 0);\r
1986 \r
1987     parsebuf = NULL;\r
1988     parselen = 0;\r
1989 \r
1990     if (p <= p0)\r
1991         {\r
1992         //return false;\r
1993         }\r
1994 \r
1995     return true;\r
1996 }\r
1997 \r
1998 \r
1999 \r
2000 \r
2001 \r
2002 //#########################################################################\r
2003 //# E V A L U A T E\r
2004 //#########################################################################\r
2005 \r
2006 \r
2007 \r
2008 \r
2009 /**\r
2010  * This wraps the two-step call to parse(), then execute() to get a NodeList\r
2011  * of matching DOM nodes\r
2012  */\r
2013 NodeList XPathParser::evaluate(const Node *root,\r
2014                                const DOMString &xpathString)\r
2015 {\r
2016     NodeList list;\r
2017 \r
2018     //### Maybe do caching for speed here\r
2019 \r
2020     //### Parse and execute\r
2021     //### Error message can be generated as a side effect\r
2022     if (!parse(xpathString))\r
2023         return list;\r
2024 \r
2025     if (debug)\r
2026         tokens.dump();\r
2027 \r
2028     //### Execute the token list\r
2029     TokenExecutor executor;\r
2030     list = executor.execute(tokens, root);\r
2031 \r
2032     return list;\r
2033 }\r
2034 \r
2035 \r
2036 \r
2037 } // namespace xpath\r
2038 } // namespace dom\r
2039 } // namespace w3c\r
2040 } // namespace org\r
2041 //#########################################################################\r
2042 //# E N D    O F    F I L E\r
2043 //#########################################################################\r
2044 \r
2045 \r
2046 \r
2047 \r