Code

limit the smallest exponent in transforms; anything smaller is written as 0
[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  * [1]  LocationPath ::=\r
623  *        RelativeLocationPath\r
624  *        | AbsoluteLocationPath\r
625  */\r
626 int XPathParser::getLocationPath(int p0, int depth)\r
627 {\r
628     traceStack("getLocationPath", p0, depth);\r
629     int p = p0;\r
630 \r
631     p = skipwhite(p);\r
632 \r
633     int p2 = getAbsoluteLocationPath(p, depth+1);\r
634     if (p2 > p)\r
635         {\r
636         tokens.add(new TokAbsolute());\r
637         return p2;\r
638         }\r
639 \r
640     p2 = getRelativeLocationPath(p, depth+1);\r
641     if (p2 > p)\r
642         {\r
643         tokens.add(new TokRelative());\r
644         return p2;\r
645         }\r
646 \r
647     return p0;\r
648 }\r
649 \r
650 \r
651 /**\r
652  * [2]  AbsoluteLocationPath ::=\r
653  *        '/' RelativeLocationPath?\r
654  *         | AbbreviatedAbsoluteLocationPath\r
655  */\r
656 int XPathParser::getAbsoluteLocationPath(int p0, int depth)\r
657 {\r
658     traceStack("getAbsoluteLocationPath", p0, depth);\r
659 \r
660     int p = p0;\r
661     LexTok t = lexTok(p);\r
662     if (t.getType() == OPERATOR && t.getIntValue()==SLASH)\r
663         {\r
664         p++;\r
665         int p2 = getRelativeLocationPath(p, depth+1);\r
666         if (p2 <= p)\r
667             {\r
668             error("Relative path after '/'");\r
669             return -1;\r
670             }\r
671         p = p2;\r
672         return p;\r
673         }\r
674 \r
675     //AbbreviatedAbsoluteLocationPath\r
676     if (t.getType() == OPERATOR && t.getIntValue()==DOUBLE_SLASH)\r
677         {\r
678         p++;\r
679         int p2 = getRelativeLocationPath(p, depth+1);\r
680         if (p2 <= p)\r
681             {\r
682             error("Relative path after '//'");\r
683             return -1;\r
684             }\r
685         p = p2;\r
686         return p;\r
687         }\r
688 \r
689 \r
690     return p0;\r
691 }\r
692 \r
693 \r
694 /**\r
695  * [3] RelativeLocationPath ::=\r
696  *       Step\r
697  *       | RelativeLocationPath '/' Step\r
698  *       | AbbreviatedRelativeLocationPath\r
699  */\r
700 int XPathParser::getRelativeLocationPath(int p0, int depth)\r
701 {\r
702     traceStack("getRelativeLocationPath", p0, depth);\r
703     int p = p0;\r
704     int p2 = getStep(p, depth+1);\r
705     if (p2 < 0)\r
706         return -1;\r
707     if (p2 > p)\r
708         {\r
709         p = p2;\r
710         LexTok t = lexTok(p);\r
711         if (t.getType() == OPERATOR && t.getIntValue()==SLASH)\r
712             {\r
713             p++;\r
714             p2 = getRelativeLocationPath(p, depth+1);\r
715             if (p2 < 0)\r
716                 {\r
717                 error("Relative path after '/'");\r
718                 return -1;\r
719                 }\r
720             p = p2;\r
721             return p;\r
722             }\r
723         //AbbreviatedRelativeLocationPath\r
724         if (t.getType() == OPERATOR && t.getIntValue()==DOUBLE_SLASH)\r
725             {\r
726             p++;\r
727             p2 = getRelativeLocationPath(p, depth+1);\r
728             if (p2 < 0)\r
729                 {\r
730                 error("Relative path after '//'");\r
731                 return -1;\r
732                 }\r
733             p = p2;\r
734             return p;\r
735             }\r
736         return p;\r
737         }\r
738 \r
739 \r
740     return p0;\r
741 }\r
742 \r
743 \r
744 /**\r
745  * [4] Step ::=\r
746  *       AxisSpecifier NodeTest Predicate*\r
747  *       | AbbreviatedStep\r
748  */\r
749 int XPathParser::getStep(int p0, int depth)\r
750 {\r
751     traceStack("getStep", p0, depth);\r
752 \r
753     int p = p0;\r
754 \r
755     lexTok(p).print();\r
756 \r
757     //This can be (and usually is) 0-length\r
758     int p2 = getAxisSpecifier(p, depth+1);\r
759     if (p2 < 0)\r
760         {\r
761         error("Axis specifier in step section");\r
762         return -1;\r
763         }\r
764     p = p2;\r
765     p2 = getNodeTest(p, depth+1);\r
766     if (p2 < 0)\r
767         {\r
768         error("Node test in step section");\r
769         return -1;\r
770         }\r
771 \r
772     if (p2 > p)\r
773         {\r
774         p = p2;\r
775         p2 = getPredicate(p, depth+1);\r
776         if (p2 < 0)\r
777             {\r
778             error("Predicate in step section");\r
779             return -1;\r
780             }\r
781         p = p2;\r
782         return p;\r
783         }\r
784 \r
785     //AbbreviatedStep\r
786     if (lexTokType(p) == DOT)\r
787         {\r
788         p++;\r
789         return p;\r
790         }\r
791 \r
792     //AbbreviatedStep\r
793     if (lexTokType(p) == DOUBLE_DOT)\r
794         {\r
795         p++;\r
796         return p;\r
797         }\r
798 \r
799     return p0;\r
800 }\r
801 \r
802 \r
803 /**\r
804  * [5] AxisSpecifier ::=\r
805  *         AxisName '::'\r
806  *         | AbbreviatedAxisSpecifier\r
807  */\r
808 int XPathParser::getAxisSpecifier(int p0, int depth)\r
809 {\r
810     traceStack("getAxisSpecifier", p0, depth);\r
811     int p = p0;\r
812     if (lexTokType(p) == AXIS_NAME)\r
813         {\r
814         p++;\r
815         if (lexTokType(p) != DOUBLE_COLON)\r
816             {\r
817             error("'::' required after axis name literal");\r
818             return -1;\r
819             }\r
820         p++;\r
821         return p;\r
822         }\r
823 \r
824     //AbbreviatedAxisSpecifier\r
825     if (lexTokType(p) == AMPR)\r
826         {\r
827         p++;\r
828         return p;\r
829         }\r
830 \r
831     return p0;\r
832 }\r
833 \r
834 \r
835 /**\r
836  * [6]  AxisName ::=\r
837  *         'ancestor'\r
838  *         | 'ancestor-or-self'\r
839  *         | 'attribute'\r
840  *         | 'child'\r
841  *         | 'descendant'\r
842  *         | 'descendant-or-self'\r
843  *         | 'following'\r
844  *         | 'following-sibling'\r
845  *         | 'namespace'\r
846  *         | 'parent'\r
847  *         | 'preceding'\r
848  *         | 'preceding-sibling'\r
849  *         | 'self'\r
850  * NOTE: This definition, and those at the bottom, is not\r
851  *   needed.  Its functionality is handled by lexical scanning.\r
852  *   It is left here for reference.\r
853  */\r
854 int XPathParser::getAxisName(int p0, int depth)\r
855 {\r
856     traceStack("getAxisName", p0, depth);\r
857     return p0;\r
858 }\r
859 \r
860 \r
861 /**\r
862  * [7] NodeTest ::=\r
863  *       NameTest\r
864  *       | NodeType '(' ')'\r
865  *       | 'processing-instruction' '(' Literal ')'\r
866  */\r
867 int XPathParser::getNodeTest(int p0, int depth)\r
868 {\r
869     traceStack("getNodeTest", p0, depth);\r
870     int p = p0;\r
871 \r
872     LexTok t = lexTok(p);\r
873     if (t.getType() == NAME_TEST)\r
874         {\r
875         p++;\r
876         printf("xxx\n");\r
877         return p;\r
878         }\r
879     if (t.getType() == NODE_TYPE)\r
880         {\r
881         if (t.getIntValue() == PROCESSING_INSTRUCTION)\r
882             {\r
883             if (lexTokType(p)   != LPAREN   ||\r
884                 lexTokType(p+1) != LITERAL  ||\r
885                 lexTokType(p+2) != RPAREN   )\r
886                 {\r
887                 error("processing instruction requires (\"literal string\")");\r
888                 return -1;\r
889                 }\r
890             p += 3;\r
891             }\r
892         else\r
893             {\r
894             if (lexTokType(p+1) != LPAREN ||\r
895                 lexTokType(p+2) != RPAREN )\r
896                 {\r
897                 error("processing instruction requires ()");\r
898                 return -1;\r
899                 }\r
900             p += 2;\r
901             }\r
902         return p;\r
903         }\r
904 \r
905     return p0;\r
906 }\r
907 \r
908 \r
909 /**\r
910  * [8]  Predicate ::=\r
911  *         '[' PredicateExpr ']'\r
912  */\r
913 int XPathParser::getPredicate(int p0, int depth)\r
914 {\r
915     traceStack("getPredicate", p0, depth);\r
916 \r
917     int p = p0;\r
918     if (lexTokType(p) != LBRACKET)\r
919         return p0;\r
920 \r
921     p++;\r
922     int p2 = getPredicateExpr(p, depth+1);\r
923     if (p2 <= p)\r
924         {\r
925         error("Predicate expression in predicate");\r
926         return -1;\r
927         }\r
928 \r
929     p = p2;\r
930     lexTok(p).print();\r
931     if (lexTokType(p) != RBRACKET)\r
932         {\r
933         error("Predicate expression requires closing ']'");\r
934         return -1;\r
935         }\r
936     p++;\r
937     return p;\r
938 }\r
939 \r
940 \r
941 /**\r
942  * [9]  PredicateExpr ::=\r
943  *         Expr\r
944  */\r
945 int XPathParser::getPredicateExpr(int p0, int depth)\r
946 {\r
947     traceStack("getPredicateExpr", p0, depth);\r
948     int p = p0;\r
949     int p2 = getExpr(p, depth+1);\r
950     if (p2 < 0)\r
951         {\r
952         error("Expression in predicate expression");\r
953         return -1;\r
954         }\r
955     p = p2;\r
956     return p;\r
957 }\r
958 \r
959 \r
960 /**\r
961  * [10] AbbreviatedAbsoluteLocationPath ::=\r
962  *        '//' RelativeLocationPath\r
963  * NOTE: not used. handled in getAbsoluteLocationPath()\r
964  */\r
965 int XPathParser::getAbbreviatedAbsoluteLocationPath(int p0, int depth)\r
966 {\r
967     traceStack("getAbbreviatedAbsoluteLocationPath", p0, depth);\r
968 \r
969      return p0;\r
970 }\r
971 \r
972 /**\r
973  * [11] AbbreviatedRelativeLocationPath ::=\r
974  *         RelativeLocationPath '//' Step\r
975  * NOTE: not used. handled in getRelativeLocationPath()\r
976  */\r
977 int XPathParser::getAbbreviatedRelativeLocationPath(int p0, int depth)\r
978 {\r
979     traceStack("getAbbreviatedRelativeLocationPath", p0, depth);\r
980     return p0;\r
981 }\r
982 \r
983 /**\r
984  * [12]  AbbreviatedStep ::=\r
985  *           '.'\r
986  *           | '..'\r
987  * NOTE: not used. handled in getStep()\r
988  */\r
989 int XPathParser::getAbbreviatedStep(int p0, int depth)\r
990 {\r
991     traceStack("getAbbreviatedStep", p0, depth);\r
992     return p0;\r
993 }\r
994 \r
995 \r
996 /**\r
997  * [13] AbbreviatedAxisSpecifier ::=\r
998  *        '@'?\r
999  * NOTE: not used. handled in getAxisSpecifier()\r
1000  */\r
1001 int XPathParser::getAbbreviatedAxisSpecifier(int p0, int depth)\r
1002 {\r
1003     traceStack("getAbbreviatedAxisSpecifier", p0, depth);\r
1004     return p0;\r
1005 }\r
1006 \r
1007 \r
1008 /**\r
1009  * [14] Expr ::=\r
1010  *         OrExpr\r
1011  */\r
1012 int XPathParser::getExpr(int p0, int depth)\r
1013 {\r
1014     traceStack("getExpr", p0, depth);\r
1015 \r
1016     int p = p0;\r
1017 \r
1018     int p2 = getOrExpr(p, depth+1);\r
1019     if (p2 < 0)\r
1020         {\r
1021         error("OR expression in expression");\r
1022         return -1;\r
1023         }\r
1024     p = p2;\r
1025 \r
1026     return p;\r
1027 }\r
1028 \r
1029 \r
1030 /**\r
1031  * [15]  PrimaryExpr ::=\r
1032  *          VariableReference\r
1033  *          | '(' Expr ')'\r
1034  *          | Literal\r
1035  *          | Number\r
1036  *          | FunctionCall\r
1037  */\r
1038 int XPathParser::getPrimaryExpr(int p0, int depth)\r
1039 {\r
1040     traceStack("getPrimaryExpr", p0, depth);\r
1041     int p = p0;\r
1042     int p2 = p;\r
1043 \r
1044     if (lexTokType(p) == VARIABLE_REFERENCE)\r
1045         {\r
1046         p++;\r
1047         return p;\r
1048         }\r
1049 \r
1050     if (lexTokType(p) == LPAREN)\r
1051         {\r
1052         p++;\r
1053         p2 = getExpr(p, depth+1);\r
1054         if (p2 <= p)\r
1055             {\r
1056             error("Expression in primary expression");\r
1057             return -1;\r
1058             }\r
1059         p += p2;\r
1060         if (lexTokType(p) != RPAREN)\r
1061             {\r
1062             error("Primary expression requires closing ')'");\r
1063             return -1;\r
1064             }\r
1065         }\r
1066 \r
1067     if (lexTokType(p) == LITERAL)\r
1068         {\r
1069         tokens.add(new TokStr(lexTok(p).getStringValue()));\r
1070         p++;\r
1071         return p;\r
1072         }\r
1073 \r
1074     if (lexTokType(p) == NUMBER)\r
1075         {\r
1076         tokens.add(new TokFloat(lexTok(p).getDoubleValue()));\r
1077         p++;\r
1078         return p;\r
1079         }\r
1080 \r
1081     p2 = getFunctionCall(p, depth+1);\r
1082     if (p2 < 0)\r
1083         {\r
1084         error("Function call in primary expression");\r
1085         return -1;\r
1086         }\r
1087     if (p2 > p)\r
1088         {\r
1089         p = p2;\r
1090         return p;\r
1091         }\r
1092 \r
1093     return p0;\r
1094 }\r
1095 \r
1096 \r
1097 /**\r
1098  * [16] FunctionCall ::=\r
1099  *         FunctionName '(' ( Argument ( ',' Argument )* )? ')'\r
1100  */\r
1101 int XPathParser::getFunctionCall(int p0, int depth)\r
1102 {\r
1103     traceStack("getFunctionCall", p0, depth);\r
1104     int p = p0;\r
1105 \r
1106     if (lexTokType(p) != FUNCTION_NAME)\r
1107         return p0;\r
1108 \r
1109     DOMString name = lexTok(p).getStringValue();\r
1110 \r
1111     p++;\r
1112 \r
1113     if (lexTokType(p) != LPAREN) //this makes a function\r
1114         return p0;\r
1115     p++;\r
1116 \r
1117     int argCount = 0;\r
1118 \r
1119     int p2 = getArgument(p, depth+1);\r
1120     if (p2 < 0)\r
1121         {\r
1122         error("Error in function argument");\r
1123         return -1;\r
1124         }\r
1125     if (p2 > p)\r
1126         {\r
1127         argCount++;\r
1128         p = p2;\r
1129         while (lexTokType(p) == COMMA)\r
1130             {\r
1131             p++;\r
1132             p2 = getArgument(p, depth+1);\r
1133             if (p2 <= p)\r
1134                 {\r
1135                 error("Error in function argument");\r
1136                 return -1;\r
1137                 }\r
1138             if (p2 > p)\r
1139                 argCount++;\r
1140             //do we add a token here?  i dont think so\r
1141             p = p2;\r
1142             }\r
1143         }\r
1144 \r
1145     if (lexTokType(p) != RPAREN) //mandatory\r
1146         {\r
1147         error("Function requires closing ')'");\r
1148         return -1;\r
1149         }\r
1150     p++;\r
1151 \r
1152     if (name == "position")\r
1153         tokens.add(new TokPosition());\r
1154     else\r
1155         {\r
1156         error("unknown function name:'%s'", name.c_str());\r
1157         return -1;\r
1158         }\r
1159     return p;\r
1160 }\r
1161 \r
1162 \r
1163 /**\r
1164  * [17] Argument ::=\r
1165  *         Expr\r
1166  */\r
1167 int XPathParser::getArgument(int p0, int depth)\r
1168 {\r
1169     traceStack("getArgument", p0, depth);\r
1170     int p = p0;\r
1171     int p2 = getExpr(p, depth+1);\r
1172     if (p2 < 0)\r
1173         {\r
1174         error("Argument expression");\r
1175         return -1;\r
1176         }\r
1177     p = p2;\r
1178     return p;\r
1179 }\r
1180 \r
1181 \r
1182 /**\r
1183  * [18]  UnionExpr ::=\r
1184  *           PathExpr\r
1185  *           | UnionExpr '|' PathExpr\r
1186  */\r
1187 int XPathParser::getUnionExpr(int p0, int depth)\r
1188 {\r
1189     traceStack("getUnionExpr", p0, depth);\r
1190     int p = p0;\r
1191     int p2 = getPathExpr(p, depth+1);\r
1192     if (p2 < 0)\r
1193         {\r
1194         error("Path expression for union");\r
1195         return -1;\r
1196         }\r
1197     p = p2;\r
1198     LexTok t = lexTok(p);\r
1199     if (t.getType() == OPERATOR && t.getIntValue() == PIPE)\r
1200         {\r
1201         p++;\r
1202         p2 = getUnionExpr(p, depth+1);\r
1203         if (p2 < 0)\r
1204             {\r
1205             error("OR (|) requires union expression on the left");\r
1206             return -1;\r
1207             }\r
1208         tokens.add(new TokUnion());\r
1209         p = p2;\r
1210         }\r
1211     return p;\r
1212 }\r
1213 \r
1214 \r
1215 /**\r
1216  * [19]  PathExpr ::=\r
1217  *          LocationPath\r
1218  *          | FilterExpr\r
1219  *          | FilterExpr '/' RelativeLocationPath\r
1220  *          | FilterExpr '//' RelativeLocationPath\r
1221  */\r
1222 int XPathParser::getPathExpr(int p0, int depth)\r
1223 {\r
1224     traceStack("getPathExpr", p0, depth);\r
1225     int p = p0;\r
1226     int p2;\r
1227 \r
1228     p2 = getLocationPath(p, depth+1);\r
1229     if (p2 < 0)\r
1230         {\r
1231         error("Location path in path expression");\r
1232         return -1;\r
1233         }\r
1234     if (p2 > p)\r
1235         {\r
1236         p = p2;\r
1237         return p;\r
1238         }\r
1239 \r
1240     p2 = getFilterExpr(p, depth+1);\r
1241     if (p2 < 0)\r
1242         {\r
1243         error("Filter expression in path expression");\r
1244         return -1;\r
1245         }\r
1246     if (p2 <= p)\r
1247         return p0;\r
1248     p = p2;\r
1249 \r
1250     LexTok t = lexTok(p);\r
1251     if (t.getType() == OPERATOR && t.getIntValue() == SLASH)\r
1252         {\r
1253         p++;\r
1254         p2 = getRelativeLocationPath(p, depth+1);\r
1255         if (p2 < 0)\r
1256             {\r
1257             error("Relative location after / in path expression");\r
1258             return -1;\r
1259             }\r
1260         p = p2;\r
1261         return p;\r
1262         }\r
1263 \r
1264     if (t.getType() == OPERATOR && t.getIntValue() == DOUBLE_SLASH)\r
1265         {\r
1266         p++;\r
1267         p2 = getRelativeLocationPath(p, depth+1);\r
1268         if (p2 < 0)\r
1269             {\r
1270             error("Relative location after // in path expression");\r
1271             return -1;\r
1272             }\r
1273         p = p2;\r
1274         return p;\r
1275         }\r
1276     return p;\r
1277 }\r
1278 \r
1279 \r
1280 /**\r
1281  * [20] FilterExpr ::=\r
1282  *         PrimaryExpr\r
1283  *         | FilterExpr Predicate\r
1284  */\r
1285 int XPathParser::getFilterExpr(int p0, int depth)\r
1286 {\r
1287     traceStack("getFilterExpr", p0, depth);\r
1288     int p = p0;\r
1289 \r
1290     int p2 = getPrimaryExpr(p, depth+1);\r
1291     if (p2 < 0)\r
1292         {\r
1293         error("Primary expression in path expression");\r
1294         return -1;\r
1295         }\r
1296     if (p2 > p)\r
1297         {\r
1298         p = p2;\r
1299         while (true)\r
1300             {\r
1301             p2 = getPredicate(p, depth+1);\r
1302             if (p2 < 0)\r
1303                 {\r
1304                 error("Predicate in primary expression");\r
1305                 return -1;\r
1306                 }\r
1307             if (p2 > p)\r
1308                 {\r
1309                 p = p2;\r
1310                 }\r
1311             else\r
1312                 break;\r
1313            }\r
1314         return p;\r
1315         }\r
1316 \r
1317     return p0;\r
1318 }\r
1319 \r
1320 \r
1321 /**\r
1322  * [21]  OrExpr ::=\r
1323  *           AndExpr\r
1324  *           | OrExpr 'or' AndExpr\r
1325  */\r
1326 int XPathParser::getOrExpr(int p0, int depth)\r
1327 {\r
1328     traceStack("getOrExpr", p0, depth);\r
1329     int p = p0;\r
1330     int p2 = getAndExpr(p, depth+1);\r
1331     if (p2 < 0)\r
1332         {\r
1333         error("AND expression in OR expression");\r
1334         return -1;\r
1335         }\r
1336     if (p2 > p)\r
1337         {\r
1338         p = p2;\r
1339         LexTok t = lexTok(p);\r
1340         if (t.getType() == OPERATOR && t.getIntValue() == OR)\r
1341             {\r
1342             p++;\r
1343             p2 = getAndExpr(p, depth+1);\r
1344             if (p2 <= p)\r
1345                 {\r
1346                 error("AND expression in OR expression");\r
1347                 return -1;\r
1348                 }\r
1349             p = p2;\r
1350             return p;\r
1351             }\r
1352         tokens.add(new TokOr());\r
1353         return p;\r
1354         }\r
1355 \r
1356     return p0;\r
1357 }\r
1358 \r
1359 \r
1360 /**\r
1361  * [22] AndExpr ::=\r
1362  *         EqualityExpr\r
1363  *         | AndExpr 'and' EqualityExpr\r
1364  */\r
1365 int XPathParser::getAndExpr(int p0, int depth)\r
1366 {\r
1367     traceStack("getAndExpr", p0, depth);\r
1368     int p = p0;\r
1369     int p2 = getEqualityExpr(p, depth+1);\r
1370     if (p2 < 0)\r
1371         {\r
1372         error("Equality expression in AND expression");\r
1373         return -1;\r
1374         }\r
1375     if (p2 > p)\r
1376         {\r
1377         p = p2;\r
1378         LexTok t = lexTok(p);\r
1379         if (t.getType() == OPERATOR && t.getIntValue() == AND)\r
1380             {\r
1381             p++;\r
1382             p2 = getAndExpr(p, depth+1);\r
1383             if (p2 <= p)\r
1384                 {\r
1385                 error("AND expression after 'and'");\r
1386                 return -1;\r
1387                 }\r
1388             p = p2;\r
1389             return p;\r
1390             }\r
1391         tokens.add(new TokAnd());\r
1392         return p;\r
1393         }\r
1394 \r
1395     return p0;\r
1396 }\r
1397 \r
1398 \r
1399 /**\r
1400  * [23]  EqualityExpr ::=\r
1401  *           RelationalExpr\r
1402  *           | EqualityExpr '=' RelationalExpr\r
1403  *           | EqualityExpr '!=' RelationalExpr\r
1404  */\r
1405 int XPathParser::getEqualityExpr(int p0, int depth)\r
1406 {\r
1407     traceStack("getEqualityExpr", p0, depth);\r
1408     int p = p0;\r
1409     int p2 = getRelationalExpr(p, depth+1);\r
1410     if (p2 < 0)\r
1411         {\r
1412         error("Relation expression in equality expression");\r
1413         return -1;\r
1414         }\r
1415     if (p2 > p)\r
1416         {\r
1417         p = p2;\r
1418         LexTok t = lexTok(p);\r
1419         if (t.getType() == OPERATOR && t.getIntValue() == EQUALS)\r
1420             {\r
1421             p++;\r
1422             p2 = getEqualityExpr(p, depth+1);\r
1423             if (p2 <= p)\r
1424                 {\r
1425                 error("Equality expression expected after ==");\r
1426                 return -1;\r
1427                 }\r
1428             tokens.add(new TokEquals());\r
1429             p = p2;\r
1430             return p;\r
1431             }\r
1432 \r
1433         if (t.getType() == OPERATOR && t.getIntValue() == NOT_EQUALS)\r
1434             {\r
1435             p++;\r
1436             p2 = getEqualityExpr(p, depth+1);\r
1437             if (p2 <= p)\r
1438                 {\r
1439                 error("Equality expression expected after !=");\r
1440                 return -1;\r
1441                 }\r
1442             tokens.add(new TokNotEquals());\r
1443             p = p2;\r
1444             return p;\r
1445             }\r
1446 \r
1447         return p;\r
1448         }\r
1449 \r
1450     return p0;\r
1451 }\r
1452 \r
1453 \r
1454 /**\r
1455  * [24] RelationalExpr ::=\r
1456  *         AdditiveExpr\r
1457  *         | RelationalExpr '<' AdditiveExpr\r
1458  *         | RelationalExpr '>' AdditiveExpr\r
1459  *         | RelationalExpr '<=' AdditiveExpr\r
1460  *         | RelationalExpr '>=' AdditiveExpr\r
1461  */\r
1462 int XPathParser::getRelationalExpr(int p0, int depth)\r
1463 {\r
1464     traceStack("getRelationalExpr", p0, depth);\r
1465     int p = p0;\r
1466     int p2 = getAdditiveExpr(p, depth+1);\r
1467     if (p2 < 0)\r
1468         {\r
1469         error("Additive expression in relational 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 \r
1477         if (t.getType() == OPERATOR && t.getIntValue() == GREATER_THAN)\r
1478             {\r
1479             p++;\r
1480             p2 = getRelationalExpr(p, depth+1);\r
1481             if (p2 <= p)\r
1482                 {\r
1483                 error("Relational expression after '>'");\r
1484                 return -1;\r
1485                 }\r
1486             tokens.add(new TokGreaterThan());\r
1487             p = p2;\r
1488             return p;\r
1489             }\r
1490         if (t.getType() == OPERATOR && t.getIntValue() == LESS_THAN)\r
1491             {\r
1492             p++;\r
1493             p2 = getRelationalExpr(p, depth+1);\r
1494             if (p2 <= p)\r
1495                 {\r
1496                 error("Relational expression after '<'");\r
1497                 return -1;\r
1498                 }\r
1499             tokens.add(new TokLessThan());\r
1500             p = p2;\r
1501             return p;\r
1502             }\r
1503         if (t.getType() == OPERATOR && t.getIntValue() == GREATER_THAN_EQUALS)\r
1504             {\r
1505             p++;\r
1506             p2 = getRelationalExpr(p, depth+1);\r
1507             if (p2 <= p)\r
1508                 {\r
1509                 error("Relational expression after '>='");\r
1510                 return -1;\r
1511                 }\r
1512             tokens.add(new TokGreaterThanEquals());\r
1513             p = p2;\r
1514             return p;\r
1515             }\r
1516         if (t.getType() == OPERATOR && t.getIntValue() == LESS_THAN_EQUALS)\r
1517             {\r
1518             p++;\r
1519             p2 = getRelationalExpr(p, depth+1);\r
1520             if (p2 <= p)\r
1521                 {\r
1522                 error("Relational expression after '<='");\r
1523                 return -1;\r
1524                 }\r
1525             tokens.add(new TokLessThanEquals());\r
1526             p = p2;\r
1527             return p;\r
1528             }\r
1529 \r
1530 \r
1531         return p;\r
1532         }\r
1533 \r
1534     return p0;\r
1535 }\r
1536 \r
1537 \r
1538 /**\r
1539  * [25]  AdditiveExp ::=\r
1540  *           MultiplicativeExpr\r
1541  *           | AdditiveExpr '+' MultiplicativeExpr\r
1542  *           | AdditiveExpr '-' MultiplicativeExpr\r
1543  */\r
1544 int XPathParser::getAdditiveExpr(int p0, int depth)\r
1545 {\r
1546     traceStack("getAdditiveExpr", p0, depth);\r
1547     int p = p0;\r
1548     int p2 = getMultiplicativeExpr(p, depth+1);\r
1549     if (p2 < 0)\r
1550         {\r
1551         error("Multiplicative expression in additive expression");\r
1552         return -1;\r
1553         }\r
1554     if (p2 > p)\r
1555         {\r
1556         p = p2;\r
1557         LexTok t = lexTok(p);\r
1558 \r
1559         if (t.getType() == OPERATOR && t.getIntValue() == PLUS)\r
1560             {\r
1561             p++;\r
1562             p2 = getAdditiveExpr(p, depth+1);\r
1563             if (p2 <= p)\r
1564                 {\r
1565                 error("Additive expression after '+'");\r
1566                 return -1;\r
1567                 }\r
1568             tokens.add(new TokPlus());\r
1569             p = p2;\r
1570             return p;\r
1571             }\r
1572         if (t.getType() == OPERATOR && t.getIntValue() == MINUS)\r
1573             {\r
1574             p++;\r
1575             p2 = getAdditiveExpr(p, depth+1);\r
1576             if (p2 <= p)\r
1577                 {\r
1578                 error("Additive expression after '-'");\r
1579                 return -1;\r
1580                 }\r
1581             tokens.add(new TokMinus());\r
1582             p = p2;\r
1583             return p;\r
1584             }\r
1585 \r
1586 \r
1587         return p;\r
1588         }\r
1589 \r
1590     return p0;\r
1591 }\r
1592 \r
1593 \r
1594 /**\r
1595  * [26]  MultiplicativeExpr ::=\r
1596  *          UnaryExpr\r
1597  *          | MultiplicativeExpr MultiplyOperator UnaryExpr\r
1598  *          | MultiplicativeExpr 'div' UnaryExpr\r
1599  *          | MultiplicativeExpr 'mod' UnaryExpr\r
1600  */\r
1601 int XPathParser::getMultiplicativeExpr(int p0, int depth)\r
1602 {\r
1603     traceStack("getMultiplicativeExpr", p0, depth);\r
1604     int p = p0;\r
1605     int p2 = getUnaryExpr(p, depth+1);\r
1606     if (p2 < 0)\r
1607         {\r
1608         error("Unary expression in multiplicative expression");\r
1609         return -1;\r
1610         }\r
1611     if (p2 > p)\r
1612         {\r
1613         p = p2;\r
1614         LexTok t = lexTok(p);\r
1615 \r
1616         if (t.getType() == OPERATOR && t.getIntValue() == MULTIPLY)\r
1617             {\r
1618             p++;\r
1619             p2 = getMultiplicativeExpr(p, depth+1);\r
1620             if (p2 <= p)\r
1621                 {\r
1622                 error("Multiplicative expression after '*'");\r
1623                 return -1;\r
1624                 }\r
1625             tokens.add(new TokMul());\r
1626             p = p2;\r
1627             return p;\r
1628             }\r
1629 \r
1630         if (t.getType() == OPERATOR && t.getIntValue() == DIV)\r
1631             {\r
1632             p++;\r
1633             p2 = getMultiplicativeExpr(p, depth+1);\r
1634             if (p2 <= p)\r
1635                 {\r
1636                 error("Multiplicative expression after 'div'");\r
1637                 return -1;\r
1638                 }\r
1639             tokens.add(new TokDiv());\r
1640             p = p2;\r
1641             return p;\r
1642             }\r
1643 \r
1644         if (t.getType() == OPERATOR && t.getIntValue() == MOD)\r
1645             {\r
1646             p++;\r
1647             p2 = getMultiplicativeExpr(p, depth+1);\r
1648             if (p2 <= p)\r
1649                 {\r
1650                 error("Multiplicative expression after 'mod'");\r
1651                 return -1;\r
1652                 }\r
1653             tokens.add(new TokMod());\r
1654             p = p2;\r
1655             return p;\r
1656             }\r
1657 \r
1658 \r
1659         return p;\r
1660         }\r
1661 \r
1662     return p0;\r
1663 }\r
1664 \r
1665 \r
1666 /**\r
1667  * [27]  UnaryExpr ::=\r
1668  *          UnionExpr\r
1669  *          | '-' UnaryExpr\r
1670  */\r
1671 int XPathParser::getUnaryExpr(int p0, int depth)\r
1672 {\r
1673     traceStack("getUnaryExpr", p0, depth);\r
1674     int p = p0;\r
1675     int p2 = getUnionExpr(p, depth+1);\r
1676     if (p2 < 0)\r
1677         {\r
1678         error("Union expression in unary expression");\r
1679         return -1;\r
1680         }\r
1681     if (p2 > p)\r
1682         {\r
1683         p = p2;\r
1684         return p;\r
1685         }\r
1686 \r
1687     if (lexTokType(p) == '-')\r
1688         {\r
1689         p++;\r
1690         p2 = getUnaryExpr(p, depth+1);\r
1691         if (p2 < 0)\r
1692             {\r
1693             error("Unary expression after '-'");\r
1694             return -1;\r
1695             }\r
1696         tokens.add(new TokNeg());\r
1697         p = p2;\r
1698         return p;\r
1699         }\r
1700 \r
1701     return p0;\r
1702 }\r
1703 \r
1704 \r
1705 //######################################################\r
1706 //# NOT USED!!!\r
1707 //## The grammar definitions below are\r
1708 //## handled by lexical parsing, and will not be used\r
1709 //######################################################\r
1710 \r
1711 /**\r
1712  * [28] ExprToken ::=\r
1713  *         '(' | ')' | '[' | ']' | '.' | '..' | '@' | ',' | '::'\r
1714  *         | NameTest\r
1715  *         | NodeType\r
1716  *         | Operator\r
1717  *         | FunctionName\r
1718  *         | AxisName\r
1719  *         | Literal\r
1720  *         | Number\r
1721  *         | VariableReference\r
1722  */\r
1723 int XPathParser::getExprToken(int p0, int depth)\r
1724 {\r
1725     traceStack("getExprToken", p0, depth);\r
1726     return p0;\r
1727 }\r
1728 \r
1729 \r
1730 /**\r
1731  * [29]  Literal ::=\r
1732  *           '"' [^"]* '"'\r
1733  *           | "'" [^']* "'"\r
1734  */\r
1735 int XPathParser::getLiteral(int p0, int depth)\r
1736 {\r
1737     traceStack("getLiteral", p0, depth);\r
1738     return p0;\r
1739 }\r
1740 \r
1741 \r
1742 /**\r
1743  * [30] Number ::=\r
1744  *        Digits ('.' Digits?)?\r
1745  *        | '.' Digits\r
1746  */\r
1747 int XPathParser::getNumber(int p0, int depth)\r
1748 {\r
1749     traceStack("getNumber", p0, depth);\r
1750     return p0;\r
1751 }\r
1752 \r
1753 \r
1754 /**\r
1755  * [31] Digits ::=\r
1756  *         [0-9]+\r
1757  */\r
1758 int XPathParser::getDigits(int p0, int depth)\r
1759 {\r
1760     traceStack("getDigits", p0, depth);\r
1761     return p0;\r
1762 }\r
1763 \r
1764 \r
1765 /**\r
1766  * [32] Operator ::=\r
1767  *         OperatorName\r
1768  *         | MultiplyOperator\r
1769  *         | '/' | '//' | '|' | '+' | '-' | '='\r
1770  *         | '!=' | '<' | '<=' | '>' | '>='\r
1771  */\r
1772 int XPathParser::getOperator(int p0, int depth)\r
1773 {\r
1774     traceStack("getOperator", p0, depth);\r
1775     return p0;\r
1776 }\r
1777 \r
1778 \r
1779 /**\r
1780  * [33]  OperatorName ::=\r
1781  *          'and' | 'or' | 'mod' | 'div'\r
1782  */\r
1783 int XPathParser::getOperatorName(int p0, int depth)\r
1784 {\r
1785     traceStack("getOperatorName", p0, depth);\r
1786     return p0;\r
1787 }\r
1788 \r
1789 \r
1790 /**\r
1791  * [34] MultiplyOperator ::=\r
1792  *          '*'\r
1793  */\r
1794 int XPathParser::getMultiplyOperator(int p0, int depth)\r
1795 {\r
1796     traceStack("getMultiplyOperator", p0, depth);\r
1797     return p0;\r
1798 }\r
1799 \r
1800 \r
1801 /**\r
1802  * [35] FunctionName ::=\r
1803  *          QName - NodeType\r
1804  */\r
1805 int XPathParser::getFunctionName(int p0, int depth)\r
1806 {\r
1807     traceStack("getFunctionName", p0, depth);\r
1808     return p0;\r
1809 }\r
1810 \r
1811 \r
1812 /**\r
1813  * [36] VariableReference ::=\r
1814  *          '$' QName\r
1815  */\r
1816 int XPathParser::getVariableReference(int p0, int depth)\r
1817 {\r
1818     traceStack("getVariableReference", p0, depth);\r
1819     return p0;\r
1820 }\r
1821 \r
1822 \r
1823 /**\r
1824  * [37] NameTest ::=\r
1825  *         '*'\r
1826  *         | NCName ':' '*'\r
1827  *         | QName\r
1828  */\r
1829 int XPathParser::getNameTest(int p0, int depth)\r
1830 {\r
1831     traceStack("getNameTest", p0, depth);\r
1832     return p0;\r
1833 }\r
1834 \r
1835 \r
1836 /**\r
1837  * [38] NodeType ::=\r
1838  *         'comment'\r
1839  *         | 'text'\r
1840  *         | 'processing-instruction'\r
1841  *         | 'node'\r
1842  */\r
1843 int XPathParser::getNodeType(int p0, int depth)\r
1844 {\r
1845     traceStack("getNodeType", p0, depth);\r
1846     return p0;\r
1847 }\r
1848 \r
1849 \r
1850 /**\r
1851  * [39] ExprWhitespace ::=\r
1852  *           S\r
1853  */\r
1854 int XPathParser::getExprWhitespace(int p0, int depth)\r
1855 {\r
1856     traceStack("getExprWhitespace", p0, depth);\r
1857     return p0;\r
1858 }\r
1859 \r
1860 \r
1861 \r
1862 \r
1863 \r
1864 //#########################################################################\r
1865 //# H I G H    L E V E L    P A R S I N G\r
1866 //#########################################################################\r
1867 \r
1868 /**\r
1869  * Parse a candidate XPath string.  Leave a copy in 'tokens.'\r
1870  */\r
1871 bool XPathParser::parse(const DOMString &xpathString)\r
1872 {\r
1873     int p0 = 0;\r
1874 \r
1875     DOMString str = xpathString;\r
1876 \r
1877     parsebuf = (char *)str.c_str();\r
1878     parselen = (int)   str.size();\r
1879     position = 0;\r
1880 \r
1881     trace("## parsing string: '%s'", parsebuf);\r
1882 \r
1883     lexicalScan();\r
1884     lexicalTokenDump();\r
1885 \r
1886     tokens.clear();//Get ready to store new tokens\r
1887 \r
1888     int p = getLocationPath(p0, 0);\r
1889 \r
1890     parsebuf = NULL;\r
1891     parselen = 0;\r
1892 \r
1893     if (p <= p0)\r
1894         {\r
1895         //return false;\r
1896         }\r
1897 \r
1898     return true;\r
1899 }\r
1900 \r
1901 \r
1902 \r
1903 \r
1904 \r
1905 //#########################################################################\r
1906 //# E V A L U A T E\r
1907 //#########################################################################\r
1908 \r
1909 \r
1910 \r
1911 \r
1912 /**\r
1913  * This wraps the two-step call to parse(), then execute() to get a NodeList\r
1914  * of matching DOM nodes\r
1915  */\r
1916 NodeList XPathParser::evaluate(const Node *root,\r
1917                                const DOMString &xpathString)\r
1918 {\r
1919     NodeList list;\r
1920 \r
1921     //### Maybe do caching for speed here\r
1922 \r
1923     //### Parse and execute\r
1924     //### Error message can be generated as a side effect\r
1925     if (!parse(xpathString))\r
1926         return list;\r
1927 \r
1928     if (debug)\r
1929         tokens.dump();\r
1930 \r
1931     //### Execute the token list\r
1932     list = tokens.execute(root);\r
1933 \r
1934     return list;\r
1935 }\r
1936 \r
1937 \r
1938 \r
1939 } // namespace xpath\r
1940 } // namespace dom\r
1941 } // namespace w3c\r
1942 } // namespace org\r
1943 //#########################################################################\r
1944 //# E N D    O F    F I L E\r
1945 //#########################################################################\r
1946 \r
1947 \r
1948 \r
1949 \r