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