1 /*
2 * XSLPattern parser (XSLPattern => XPath)
3 *
4 * Copyright 2010 Adam Martinson for CodeWeavers
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 %{
22 #include "config.h"
23 #include "wine/port.h"
24
25 #ifdef HAVE_LIBXML2
26 #include "xslpattern.h"
27 #include <libxml/xpathInternals.h>
28 #include "wine/debug.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
31
32
33 static const xmlChar NameTest_mod_pre[] = "*[name()='";
34 static const xmlChar NameTest_mod_post[] = "']";
35
36 #define U(str) BAD_CAST str
37
is_literal(xmlChar const * tok)38 static inline BOOL is_literal(xmlChar const* tok)
39 {
40 return (tok && tok[0] && tok[1] &&
41 tok[0]== tok[xmlStrlen(tok)-1] &&
42 (tok[0] == '\'' || tok[0] == '"'));
43 }
44
xslpattern_error(parser_param * param,void const * scanner,char const * msg)45 static void xslpattern_error(parser_param* param, void const* scanner, char const* msg)
46 {
47 FIXME("%s:\n"
48 " param {\n"
49 " yyscanner=%p\n"
50 " ctx=%p\n"
51 " in=\"%s\"\n"
52 " pos=%i\n"
53 " len=%i\n"
54 " out=\"%s\"\n"
55 " err=%i\n"
56 " }\n"
57 " scanner=%p\n",
58 msg, param->yyscanner, param->ctx, param->in, param->pos,
59 param->len, param->out, ++param->err, scanner);
60 }
61
62 %}
63
64 %token TOK_Parent TOK_Self TOK_DblFSlash TOK_FSlash TOK_Axis TOK_Colon
65 %token TOK_OpAnd TOK_OpOr TOK_OpNot
66 %token TOK_OpEq TOK_OpIEq TOK_OpNEq TOK_OpINEq
67 %token TOK_OpLt TOK_OpILt TOK_OpGt TOK_OpIGt TOK_OpLEq TOK_OpILEq TOK_OpGEq TOK_OpIGEq
68 %token TOK_OpAll TOK_OpAny
69 %token TOK_NCName TOK_Literal TOK_Number
70
71 %start XSLPattern
72
73 %pure-parser
74 %parse-param {parser_param* p}
75 %parse-param {void* scanner}
76 %lex-param {yyscan_t* scanner}
77
78 %left TOK_OpAnd TOK_OpOr
79 %left TOK_OpEq TOK_OpIEq TOK_OpNEq TOK_OpINEq
80 %left TOK_OpLt TOK_OpILt TOK_OpGt TOK_OpIGt TOK_OpLEq TOK_OpILEq TOK_OpGEq TOK_OpIGEq
81
82 %expect 14
83
84 %%
85
86 XSLPattern : Expr
87 {
88 p->out = $1;
89 }
90 ;
91
92 /* Mostly verbatim from the w3c XML Namespaces standard.
93 * <http://www.w3.org/TR/REC-xml-names/> */
94
95 /* [4] Qualified Names */
96 QName : PrefixedName
97 | UnprefixedName
98 ;
99 PrefixedName : TOK_NCName TOK_Colon TOK_NCName
100 {
101 TRACE("Got PrefixedName: \"%s:%s\"\n", $1, $3);
102 $$=$1;
103 $$=xmlStrcat($$,U(":"));
104 $$=xmlStrcat($$,$3);
105 xmlFree($3);
106 }
107 ;
108 UnprefixedName : TOK_NCName
109 {
110 TRACE("Got UnprefixedName: \"%s\"\n", $1);
111 $$=$1;
112 }
113 ;
114
115 /* Based on the w3c XPath standard, adapted where needed.
116 * <http://www.w3.org/TR/xpath/> */
117
118 /* [2] Location Paths */
119 LocationPath : RelativeLocationPath
120 | AbsoluteLocationPath
121 ;
122 AbsoluteLocationPath : TOK_FSlash RelativeLocationPath
123 {
124 TRACE("Got AbsoluteLocationPath: \"/%s\"\n", $2);
125 $$=xmlStrdup(U("/"));
126 $$=xmlStrcat($$,$2);
127 xmlFree($2);
128 }
129 | TOK_FSlash
130 {
131 TRACE("Got AbsoluteLocationPath: \"/\"\n");
132 $$=xmlStrdup(U("/"));
133 }
134 | AbbreviatedAbsoluteLocationPath
135 ;
136 RelativeLocationPath : Step
137 | RelativeLocationPath TOK_FSlash Step
138 {
139 TRACE("Got RelativeLocationPath: \"%s/%s\"\n", $1, $3);
140 $$=$1;
141 $$=xmlStrcat($$,U("/"));
142 $$=xmlStrcat($$,$3);
143 xmlFree($3);
144 }
145 | AbbreviatedRelativeLocationPath
146 ;
147 /* [2.1] Location Steps */
148 Step : AxisSpecifier NodeTest Predicates
149 {
150 TRACE("Got Step: \"%s%s%s\"\n", $1, $2, $3);
151 $$=$1;
152 $$=xmlStrcat($$,$2);
153 xmlFree($2);
154 $$=xmlStrcat($$,$3);
155 xmlFree($3);
156 }
157 | NodeTest Predicates
158 {
159 TRACE("Got Step: \"%s%s\"\n", $1, $2);
160 $$=$1;
161 $$=xmlStrcat($$,$2);
162 xmlFree($2);
163 }
164 | AxisSpecifier NodeTest
165 {
166 TRACE("Got Step: \"%s%s\"\n", $1, $2);
167 $$=$1;
168 $$=xmlStrcat($$,$2);
169 xmlFree($2);
170 }
171 | NodeTest
172 | Attribute
173 | AbbreviatedStep
174 ;
175 AxisSpecifier : TOK_NCName TOK_Axis
176 {
177 TRACE("Got AxisSpecifier: \"%s::\"\n", $1);
178 $$=$1;
179 $$=xmlStrcat($$,U("::"));
180 }
181 ;
182 Attribute : '@' QName
183 {
184 TRACE("Got Attribute: \"@%s\"\n", $2);
185 $$=xmlStrdup(U("@"));
186 $$=xmlStrcat($$,$2);
187 xmlFree($2);
188 }
189 | '@' '*'
190 {
191 TRACE("Got All attributes pattern: \"@*\"\n");
192 $$=xmlStrdup(U("@*"));
193 }
194 ;
195
196 /* [2.3] Node Tests */
197 NodeTest : NameTest
198 | FunctionCall
199 ;
200 NameTest : '*'
201 {
202 TRACE("Got NameTest: \"*\"\n");
203 $$=xmlStrdup(U("*"));
204 }
205 | TOK_NCName TOK_Colon '*'
206 {
207 TRACE("Got NameTest: \"%s:*\"\n", $1);
208 $$=$1;
209 $$=xmlStrcat($$,U(":*"));
210 }
211 | TOK_NCName TOK_Colon TOK_NCName
212 { /* PrefixedName */
213 xmlChar const* registeredNsURI = xmlXPathNsLookup(p->ctx, $1);
214 TRACE("Got PrefixedName: \"%s:%s\"\n", $1, $3);
215
216 if (registeredNsURI)
217 $$=xmlStrdup(U(""));
218 else
219 $$=xmlStrdup(NameTest_mod_pre);
220
221 $$=xmlStrcat($$,$1);
222 xmlFree($1);
223 $$=xmlStrcat($$,U(":"));
224 $$=xmlStrcat($$,$3);
225 xmlFree($3);
226
227 if (!registeredNsURI)
228 $$=xmlStrcat($$,NameTest_mod_post);
229 }
230 | UnprefixedName
231 {
232 $$=xmlStrdup(NameTest_mod_pre);
233 $$=xmlStrcat($$,$1);
234 xmlFree($1);
235 $$=xmlStrcat($$,NameTest_mod_post);
236 }
237 /* [2.4] Predicates */
238 Predicates : Predicates Predicate
239 {
240 $$=$1;
241 $$=xmlStrcat($$,$2);
242 xmlFree($2);
243 }
244 | Predicate
245 ;
246 Predicate : '[' PredicateExpr ']'
247 {
248 TRACE("Got Predicate: \"[%s]\"\n", $2);
249 $$=xmlStrdup(U("["));
250 $$=xmlStrcat($$,$2);
251 xmlFree($2);
252 $$=xmlStrcat($$,U("]"));
253 }
254 ;
255 PredicateExpr : TOK_Number
256 {
257 $$=xmlStrdup(U("index()="));
258 $$=xmlStrcat($$,$1);
259 xmlFree($1);
260 }
261 | BoolExpr
262 | Attribute
263 | TOK_NCName
264 ;
265 /* [2.5] Abbreviated Syntax */
266 AbbreviatedAbsoluteLocationPath : TOK_DblFSlash RelativeLocationPath
267 {
268 TRACE("Got AbbreviatedAbsoluteLocationPath: \"//%s\"\n", $2);
269 $$=xmlStrdup(U("//"));
270 $$=xmlStrcat($$,$2);
271 xmlFree($2);
272 }
273 ;
274 AbbreviatedRelativeLocationPath : RelativeLocationPath TOK_DblFSlash Step
275 {
276 TRACE("Got AbbreviatedRelativeLocationPath: \"%s//%s\"\n", $1, $3);
277 $$=$1;
278 $$=xmlStrcat($$,U("//"));
279 $$=xmlStrcat($$,$3);
280 xmlFree($3);
281 }
282 ;
283 AbbreviatedStep : TOK_Parent
284 {
285 TRACE("Got AbbreviatedStep: \"..\"\n");
286 $$=xmlStrdup(U(".."));
287 }
288 | TOK_Self
289 {
290 TRACE("Got AbbreviatedStep: \".\"\n");
291 $$=xmlStrdup(U("."));
292 }
293 ;
294
295 /* [3] Expressions */
296 /* [3.1] Basics */
297 Expr : OrExpr
298 ;
299 BoolExpr : FunctionCall
300 | BoolUnaryExpr
301 | BoolRelationalExpr
302 | BoolEqualityExpr
303 | BoolAndExpr
304 | BoolOrExpr
305 ;
306 PrimaryExpr : '(' Expr ')'
307 {
308 TRACE("Got PrimaryExpr: \"(%s)\"\n", $1);
309 $$=xmlStrdup(U("("));
310 $$=xmlStrcat($$,$2);
311 xmlFree($2);
312 $$=xmlStrcat($$,U(")"));
313 }
314 | PathExpr '!' FunctionCall
315 {
316 TRACE("Got PrimaryExpr: \"%s!%s\"\n", $1, $3);
317 $$=$1;
318 $$=xmlStrcat($$,U("/"));
319 $$=xmlStrcat($$,$3);
320 xmlFree($3);
321 }
322 | TOK_Literal
323 | TOK_Number
324 ;
325 /* [3.2] Function Calls */
326 FunctionCall : QName '(' Arguments ')'
327 {
328 TRACE("Got FunctionCall: \"%s(%s)\"\n", $1, $3);
329 if (xmlStrEqual($1,U("ancestor")))
330 {
331 $$=$1;
332 $$=xmlStrcat($$,U("::"));
333 $$=xmlStrcat($$,$3);
334 xmlFree($3);
335 }
336 else if (xmlStrEqual($1,U("attribute")))
337 {
338 if (is_literal($3))
339 {
340 $$=xmlStrdup(U("@*[name()="));
341 xmlFree($1);
342 $$=xmlStrcat($$,$3);
343 xmlFree($3);
344 $$=xmlStrcat($$,U("]"));
345 }
346 else
347 {
348 /* XML_XPATH_INVALID_TYPE */
349 $$=xmlStrdup(U("error(1211, 'Error: attribute("));
350 xmlFree($1);
351 $$=xmlStrcat($$,$3);
352 xmlFree($3);
353 $$=xmlStrcat($$,U("): invalid argument')"));
354 }
355 }
356 else if (xmlStrEqual($1,U("element")))
357 {
358 if (is_literal($3))
359 {
360 $$=xmlStrdup(U("node()[nodeType()=1][name()="));
361 xmlFree($1);
362 $$=xmlStrcat($$,$3);
363 xmlFree($3);
364 $$=xmlStrcat($$,U("]"));
365 }
366 else
367 {
368 /* XML_XPATH_INVALID_TYPE */
369 $$=xmlStrdup(U("error(1211, 'Error: element("));
370 xmlFree($1);
371 $$=xmlStrcat($$,$3);
372 xmlFree($3);
373 $$=xmlStrcat($$,U("): invalid argument')"));
374 }
375 }
376 else
377 {
378 $$=$1;
379 $$=xmlStrcat($$,U("("));
380 $$=xmlStrcat($$,$3);
381 xmlFree($3);
382 $$=xmlStrcat($$,U(")"));
383 }
384 }
385 | QName '(' ')'
386 {
387 TRACE("Got FunctionCall: \"%s()\"\n", $1);
388 /* comment() & node() work the same in XPath */
389 if (xmlStrEqual($1,U("attribute")))
390 {
391 $$=xmlStrdup(U("@*"));
392 xmlFree($1);
393 }
394 else if (xmlStrEqual($1,U("element")))
395 {
396 $$=xmlStrdup(U("node()[nodeType()=1]"));
397 xmlFree($1);
398 }
399 else if (xmlStrEqual($1,U("pi")))
400 {
401 $$=xmlStrdup(U("processing-instruction()"));
402 xmlFree($1);
403 }
404 else if (xmlStrEqual($1,U("textnode")))
405 {
406 $$=xmlStrdup(U("text()"));
407 xmlFree($1);
408 }
409 else
410 {
411 $$=$1;
412 $$=xmlStrcat($$,U("()"));
413 }
414 }
415 ;
416 Arguments : Argument ',' Arguments
417 {
418 $$=$1;
419 $$=xmlStrcat($$,U(","));
420 $$=xmlStrcat($$,$3);
421 xmlFree($3);
422 }
423 | Argument
424 ;
425 Argument : Expr
426 ;
427 /* [3.3] Node-sets */
428 UnionExpr : PathExpr
429 | UnionExpr '|' PathExpr
430 {
431 TRACE("Got UnionExpr: \"%s|%s\"\n", $1, $3);
432 $$=$1;
433 $$=xmlStrcat($$,U("|"));
434 $$=xmlStrcat($$,$3);
435 xmlFree($3);
436 }
437 ;
438 PathExpr : LocationPath
439 | FilterExpr TOK_FSlash RelativeLocationPath
440 {
441 TRACE("Got PathExpr: \"%s/%s\"\n", $1, $3);
442 $$=$1;
443 $$=xmlStrcat($$,U("/"));
444 $$=xmlStrcat($$,$3);
445 xmlFree($3);
446 }
447 | FilterExpr TOK_DblFSlash RelativeLocationPath
448 {
449 TRACE("Got PathExpr: \"%s//%s\"\n", $1, $3);
450 $$=$1;
451 $$=xmlStrcat($$,U("//"));
452 $$=xmlStrcat($$,$3);
453 xmlFree($3);
454 }
455 | FilterExpr
456 ;
457 FilterExpr : PrimaryExpr
458 | FilterExpr Predicate
459 {
460 TRACE("Got FilterExpr: \"%s%s\"\n", $1, $2);
461 $$=$1;
462 $$=xmlStrcat($$,$2);
463 xmlFree($2);
464 }
465 ;
466 /* [3.4] Booleans */
467 OrExpr : AndExpr
468 | BoolOrExpr
469 ;
470 BoolOrExpr : OrExpr TOK_OpOr AndExpr
471 {
472 TRACE("Got OrExpr: \"%s $or$ %s\"\n", $1, $3);
473 $$=$1;
474 $$=xmlStrcat($$,U(" or "));
475 $$=xmlStrcat($$,$3);
476 xmlFree($3);
477 }
478 ;
479 AndExpr : EqualityExpr
480 | BoolAndExpr
481 ;
482 BoolAndExpr : AndExpr TOK_OpAnd EqualityExpr
483 {
484 TRACE("Got AndExpr: \"%s $and$ %s\"\n", $1, $3);
485 $$=$1;
486 $$=xmlStrcat($$,U(" and "));
487 $$=xmlStrcat($$,$3);
488 xmlFree($3);
489 }
490 ;
491 EqualityExpr : RelationalExpr
492 | BoolEqualityExpr
493 ;
494 BoolEqualityExpr : EqualityExpr TOK_OpEq RelationalExpr
495 {
496 TRACE("Got EqualityExpr: \"%s $eq$ %s\"\n", $1, $3);
497 $$=$1;
498 $$=xmlStrcat($$,U("="));
499 $$=xmlStrcat($$,$3);
500 xmlFree($3);
501 }
502 | EqualityExpr TOK_OpIEq RelationalExpr
503 {
504 TRACE("Got EqualityExpr: \"%s $ieq$ %s\"\n", $1, $3);
505 $$=xmlStrdup(U("OP_IEq("));
506 $$=xmlStrcat($$,$1);
507 xmlFree($1);
508 $$=xmlStrcat($$,U(","));
509 $$=xmlStrcat($$,$3);
510 xmlFree($3);
511 $$=xmlStrcat($$,U(")"));
512 }
513 | EqualityExpr TOK_OpNEq RelationalExpr
514 {
515 TRACE("Got EqualityExpr: \"%s $ne$ %s\"\n", $1, $3);
516 $$=$1;
517 $$=xmlStrcat($$,U("!="));
518 $$=xmlStrcat($$,$3);
519 xmlFree($3);
520 }
521 | EqualityExpr TOK_OpINEq RelationalExpr
522 {
523 TRACE("Got EqualityExpr: \"%s $ine$ %s\"\n", $1, $3);
524 $$=xmlStrdup(U("OP_INEq("));
525 $$=xmlStrcat($$,$1);
526 xmlFree($1);
527 $$=xmlStrcat($$,U(","));
528 $$=xmlStrcat($$,$3);
529 xmlFree($3);
530 $$=xmlStrcat($$,U(")"));
531 }
532 ;
533 RelationalExpr : UnaryExpr
534 | BoolRelationalExpr
535 ;
536 BoolRelationalExpr : RelationalExpr TOK_OpLt UnaryExpr
537 {
538 TRACE("Got RelationalExpr: \"%s $lt$ %s\"\n", $1, $3);
539 $$=$1;
540 $$=xmlStrcat($$,U("<"));
541 $$=xmlStrcat($$,$3);
542 xmlFree($3);
543 }
544 | RelationalExpr TOK_OpILt UnaryExpr
545 {
546 TRACE("Got RelationalExpr: \"%s $ilt$ %s\"\n", $1, $3);
547 $$=xmlStrdup(U("OP_ILt("));
548 $$=xmlStrcat($$,$1);
549 xmlFree($1);
550 $$=xmlStrcat($$,U(","));
551 $$=xmlStrcat($$,$3);
552 xmlFree($3);
553 $$=xmlStrcat($$,U(")"));
554 }
555 | RelationalExpr TOK_OpGt UnaryExpr
556 {
557 TRACE("Got RelationalExpr: \"%s $gt$ %s\"\n", $1, $3);
558 $$=$1;
559 $$=xmlStrcat($$,U(">"));
560 $$=xmlStrcat($$,$3);
561 xmlFree($3);
562 }
563 | RelationalExpr TOK_OpIGt UnaryExpr
564 {
565 TRACE("Got RelationalExpr: \"%s $igt$ %s\"\n", $1, $3);
566 $$=xmlStrdup(U("OP_IGt("));
567 $$=xmlStrcat($$,$1);
568 xmlFree($1);
569 $$=xmlStrcat($$,U(","));
570 $$=xmlStrcat($$,$3);
571 xmlFree($3);
572 $$=xmlStrcat($$,U(")"));
573 }
574 | RelationalExpr TOK_OpLEq UnaryExpr
575 {
576 TRACE("Got RelationalExpr: \"%s $le$ %s\"\n", $1, $3);
577 $$=$1;
578 $$=xmlStrcat($$,U("<="));
579 $$=xmlStrcat($$,$3);
580 xmlFree($3);
581 }
582 | RelationalExpr TOK_OpILEq UnaryExpr
583 {
584 TRACE("Got RelationalExpr: \"%s $ile$ %s\"\n", $1, $3);
585 $$=xmlStrdup(U("OP_ILEq("));
586 $$=xmlStrcat($$,$1);
587 xmlFree($1);
588 $$=xmlStrcat($$,U(","));
589 $$=xmlStrcat($$,$3);
590 xmlFree($3);
591 $$=xmlStrcat($$,U(")"));
592 }
593 | RelationalExpr TOK_OpGEq UnaryExpr
594 {
595 TRACE("Got RelationalExpr: \"%s $ge$ %s\"\n", $1, $3);
596 $$=$1;
597 $$=xmlStrcat($$,U(">="));
598 $$=xmlStrcat($$,$3);
599 xmlFree($3);
600 }
601 | RelationalExpr TOK_OpIGEq UnaryExpr
602 {
603 TRACE("Got RelationalExpr: \"%s $ige$ %s\"\n", $1, $3);
604 $$=xmlStrdup(U("OP_IGEq("));
605 $$=xmlStrcat($$,$1);
606 xmlFree($1);
607 $$=xmlStrcat($$,U(","));
608 $$=xmlStrcat($$,$3);
609 xmlFree($3);
610 $$=xmlStrcat($$,U(")"));
611 }
612 ;
613
614 /* [3.5] Numbers */
615 UnaryExpr : UnionExpr
616 | BoolUnaryExpr
617 ;
618 BoolUnaryExpr : TOK_OpNot UnaryExpr
619 {
620 TRACE("Got UnaryExpr: \"$not$ %s\"\n", $2);
621 $$=xmlStrdup(U(" not("));
622 $$=xmlStrcat($$,$2);
623 xmlFree($2);
624 $$=xmlStrcat($$,U(")"));
625 }
626 | TOK_OpAny Expr
627 {
628 TRACE("Got UnaryExpr: \"$any$ %s\"\n", $2);
629 $$=xmlStrdup(U("boolean("));
630 $$=xmlStrcat($$,$2);
631 xmlFree($2);
632 $$=xmlStrcat($$,U(")"));
633 }
634 | TOK_OpAll AllExpr
635 {
636 TRACE("Got UnaryExpr: \"$all$ %s\"\n", $2);
637 $$=xmlStrdup(U("not("));
638 $$=xmlStrcat($$,$2);
639 xmlFree($2);
640 $$=xmlStrcat($$,U(")"));
641 }
642 | TOK_OpAll
643 {
644 FIXME("Unrecognized $all$ expression - ignoring\n");
645 $$=xmlStrdup(U(""));
646 }
647 ;
648 AllExpr : PathExpr TOK_OpEq PathExpr
649 {
650 $$=$1;
651 $$=xmlStrcat($$,U("!="));
652 $$=xmlStrcat($$,$3);
653 xmlFree($3);
654 }
655 | PathExpr TOK_OpNEq PathExpr
656 {
657 $$=$1;
658 $$=xmlStrcat($$,U("="));
659 $$=xmlStrcat($$,$3);
660 xmlFree($3);
661 }
662 | PathExpr TOK_OpLt PathExpr
663 {
664 $$=$1;
665 $$=xmlStrcat($$,U(">="));
666 $$=xmlStrcat($$,$3);
667 xmlFree($3);
668 }
669 | PathExpr TOK_OpLEq PathExpr
670 {
671 $$=$1;
672 $$=xmlStrcat($$,U(">"));
673 $$=xmlStrcat($$,$3);
674 xmlFree($3);
675 }
676 | PathExpr TOK_OpGt PathExpr
677 {
678 $$=$1;
679 $$=xmlStrcat($$,U("<="));
680 $$=xmlStrcat($$,$3);
681 xmlFree($3);
682 }
683 | PathExpr TOK_OpGEq PathExpr
684 {
685 $$=$1;
686 $$=xmlStrcat($$,U("<"));
687 $$=xmlStrcat($$,$3);
688 xmlFree($3);
689 }
690 | PathExpr TOK_OpIEq PathExpr
691 {
692 $$=xmlStrdup(U("OP_INEq("));
693 $$=xmlStrcat($$,$1);
694 xmlFree($1);
695 $$=xmlStrcat($$,U(","));
696 $$=xmlStrcat($$,$3);
697 xmlFree($3);
698 $$=xmlStrcat($$,U(")"));
699 }
700 | PathExpr TOK_OpINEq PathExpr
701 {
702 $$=xmlStrdup(U("OP_IEq("));
703 $$=xmlStrcat($$,$1);
704 xmlFree($1);
705 $$=xmlStrcat($$,U(","));
706 $$=xmlStrcat($$,$3);
707 xmlFree($3);
708 $$=xmlStrcat($$,U(")"));
709 }
710 | PathExpr TOK_OpILt PathExpr
711 {
712 $$=xmlStrdup(U("OP_IGEq("));
713 $$=xmlStrcat($$,$1);
714 xmlFree($1);
715 $$=xmlStrcat($$,U(","));
716 $$=xmlStrcat($$,$3);
717 xmlFree($3);
718 $$=xmlStrcat($$,U(")"));
719 }
720 | PathExpr TOK_OpILEq PathExpr
721 {
722 $$=xmlStrdup(U("OP_IGt("));
723 $$=xmlStrcat($$,$1);
724 xmlFree($1);
725 $$=xmlStrcat($$,U(","));
726 $$=xmlStrcat($$,$3);
727 xmlFree($3);
728 $$=xmlStrcat($$,U(")"));
729 }
730 | PathExpr TOK_OpIGt PathExpr
731 {
732 $$=xmlStrdup(U("OP_ILEq("));
733 $$=xmlStrcat($$,$1);
734 xmlFree($1);
735 $$=xmlStrcat($$,U(","));
736 $$=xmlStrcat($$,$3);
737 xmlFree($3);
738 $$=xmlStrcat($$,U(")"));
739 }
740 | PathExpr TOK_OpIGEq PathExpr
741 {
742 $$=xmlStrdup(U("OP_ILt("));
743 $$=xmlStrcat($$,$1);
744 xmlFree($1);
745 $$=xmlStrcat($$,U(","));
746 $$=xmlStrcat($$,$3);
747 xmlFree($3);
748 $$=xmlStrcat($$,U(")"));
749 }
750 ;
751
752 %%
753
754 #endif /* HAVE_LIBXML2 */
755