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