Code

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