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