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 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 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 /* [2.3] Node Tests */ 192 NodeTest : NameTest 193 | FunctionCall 194 ; 195 NameTest : '*' 196 { 197 TRACE("Got NameTest: \"*\"\n"); 198 $$=xmlStrdup(U("*")); 199 } 200 | TOK_NCName TOK_Colon '*' 201 { 202 TRACE("Got NameTest: \"%s:*\"\n", $1); 203 $$=$1; 204 $$=xmlStrcat($$,U(":*")); 205 } 206 | TOK_NCName TOK_Colon TOK_NCName 207 { /* PrefixedName */ 208 xmlChar const* registeredNsURI = xmlXPathNsLookup(p->ctx, $1); 209 TRACE("Got PrefixedName: \"%s:%s\"\n", $1, $3); 210 211 if (registeredNsURI) 212 $$=xmlStrdup(U("")); 213 else 214 $$=xmlStrdup(NameTest_mod_pre); 215 216 $$=xmlStrcat($$,$1); 217 xmlFree($1); 218 $$=xmlStrcat($$,U(":")); 219 $$=xmlStrcat($$,$3); 220 xmlFree($3); 221 222 if (!registeredNsURI) 223 $$=xmlStrcat($$,NameTest_mod_post); 224 } 225 | UnprefixedName 226 { 227 $$=xmlStrdup(NameTest_mod_pre); 228 $$=xmlStrcat($$,$1); 229 xmlFree($1); 230 $$=xmlStrcat($$,NameTest_mod_post); 231 } 232 /* [2.4] Predicates */ 233 Predicates : Predicates Predicate 234 { 235 $$=$1; 236 $$=xmlStrcat($$,$2); 237 xmlFree($2); 238 } 239 | Predicate 240 ; 241 Predicate : '[' PredicateExpr ']' 242 { 243 TRACE("Got Predicate: \"[%s]\"\n", $2); 244 $$=xmlStrdup(U("[")); 245 $$=xmlStrcat($$,$2); 246 xmlFree($2); 247 $$=xmlStrcat($$,U("]")); 248 } 249 ; 250 PredicateExpr : TOK_Number 251 { 252 $$=xmlStrdup(U("index()=")); 253 $$=xmlStrcat($$,$1); 254 xmlFree($1); 255 } 256 | BoolExpr 257 | Attribute 258 | TOK_NCName 259 ; 260 /* [2.5] Abbreviated Syntax */ 261 AbbreviatedAbsoluteLocationPath : TOK_DblFSlash RelativeLocationPath 262 { 263 TRACE("Got AbbreviatedAbsoluteLocationPath: \"//%s\"\n", $2); 264 $$=xmlStrdup(U("//")); 265 $$=xmlStrcat($$,$2); 266 xmlFree($2); 267 } 268 ; 269 AbbreviatedRelativeLocationPath : RelativeLocationPath TOK_DblFSlash Step 270 { 271 TRACE("Got AbbreviatedRelativeLocationPath: \"%s//%s\"\n", $1, $3); 272 $$=$1; 273 $$=xmlStrcat($$,U("//")); 274 $$=xmlStrcat($$,$3); 275 xmlFree($3); 276 } 277 ; 278 AbbreviatedStep : TOK_Parent 279 { 280 TRACE("Got AbbreviatedStep: \"..\"\n"); 281 $$=xmlStrdup(U("..")); 282 } 283 | TOK_Self 284 { 285 TRACE("Got AbbreviatedStep: \".\"\n"); 286 $$=xmlStrdup(U(".")); 287 } 288 ; 289 290 /* [3] Expressions */ 291 /* [3.1] Basics */ 292 Expr : OrExpr 293 ; 294 BoolExpr : FunctionCall 295 | BoolUnaryExpr 296 | BoolRelationalExpr 297 | BoolEqualityExpr 298 | BoolAndExpr 299 | BoolOrExpr 300 ; 301 PrimaryExpr : '(' Expr ')' 302 { 303 TRACE("Got PrimaryExpr: \"(%s)\"\n", $1); 304 $$=xmlStrdup(U("(")); 305 $$=xmlStrcat($$,$2); 306 xmlFree($2); 307 $$=xmlStrcat($$,U(")")); 308 } 309 | PathExpr '!' FunctionCall 310 { 311 TRACE("Got PrimaryExpr: \"%s!%s\"\n", $1, $3); 312 $$=$1; 313 $$=xmlStrcat($$,U("/")); 314 $$=xmlStrcat($$,$3); 315 xmlFree($3); 316 } 317 | TOK_Literal 318 | TOK_Number 319 ; 320 /* [3.2] Function Calls */ 321 FunctionCall : QName '(' Arguments ')' 322 { 323 TRACE("Got FunctionCall: \"%s(%s)\"\n", $1, $3); 324 if (xmlStrEqual($1,U("ancestor"))) 325 { 326 $$=$1; 327 $$=xmlStrcat($$,U("::")); 328 $$=xmlStrcat($$,$3); 329 xmlFree($3); 330 } 331 else if (xmlStrEqual($1,U("attribute"))) 332 { 333 if (is_literal($3)) 334 { 335 $$=xmlStrdup(U("@*[name()=")); 336 xmlFree($1); 337 $$=xmlStrcat($$,$3); 338 xmlFree($3); 339 $$=xmlStrcat($$,U("]")); 340 } 341 else 342 { 343 /* XML_XPATH_INVALID_TYPE */ 344 $$=xmlStrdup(U("error(1211, 'Error: attribute(")); 345 xmlFree($1); 346 $$=xmlStrcat($$,$3); 347 xmlFree($3); 348 $$=xmlStrcat($$,U("): invalid argument')")); 349 } 350 } 351 else if (xmlStrEqual($1,U("element"))) 352 { 353 if (is_literal($3)) 354 { 355 $$=xmlStrdup(U("node()[nodeType()=1][name()=")); 356 xmlFree($1); 357 $$=xmlStrcat($$,$3); 358 xmlFree($3); 359 $$=xmlStrcat($$,U("]")); 360 } 361 else 362 { 363 /* XML_XPATH_INVALID_TYPE */ 364 $$=xmlStrdup(U("error(1211, 'Error: element(")); 365 xmlFree($1); 366 $$=xmlStrcat($$,$3); 367 xmlFree($3); 368 $$=xmlStrcat($$,U("): invalid argument')")); 369 } 370 } 371 else 372 { 373 $$=$1; 374 $$=xmlStrcat($$,U("(")); 375 $$=xmlStrcat($$,$3); 376 xmlFree($3); 377 $$=xmlStrcat($$,U(")")); 378 } 379 } 380 | QName '(' ')' 381 { 382 TRACE("Got FunctionCall: \"%s()\"\n", $1); 383 /* comment() & node() work the same in XPath */ 384 if (xmlStrEqual($1,U("attribute"))) 385 { 386 $$=xmlStrdup(U("@*")); 387 xmlFree($1); 388 } 389 else if (xmlStrEqual($1,U("element"))) 390 { 391 $$=xmlStrdup(U("node()[nodeType()=1]")); 392 xmlFree($1); 393 } 394 else if (xmlStrEqual($1,U("pi"))) 395 { 396 $$=xmlStrdup(U("processing-instruction()")); 397 xmlFree($1); 398 } 399 else if (xmlStrEqual($1,U("textnode"))) 400 { 401 $$=xmlStrdup(U("text()")); 402 xmlFree($1); 403 } 404 else 405 { 406 $$=$1; 407 $$=xmlStrcat($$,U("()")); 408 } 409 } 410 ; 411 Arguments : Argument ',' Arguments 412 { 413 $$=$1; 414 $$=xmlStrcat($$,U(",")); 415 $$=xmlStrcat($$,$3); 416 xmlFree($3); 417 } 418 | Argument 419 ; 420 Argument : Expr 421 ; 422 /* [3.3] Node-sets */ 423 UnionExpr : PathExpr 424 | UnionExpr '|' PathExpr 425 { 426 TRACE("Got UnionExpr: \"%s|%s\"\n", $1, $3); 427 $$=$1; 428 $$=xmlStrcat($$,U("|")); 429 $$=xmlStrcat($$,$3); 430 xmlFree($3); 431 } 432 ; 433 PathExpr : LocationPath 434 | FilterExpr TOK_FSlash RelativeLocationPath 435 { 436 TRACE("Got PathExpr: \"%s/%s\"\n", $1, $3); 437 $$=$1; 438 $$=xmlStrcat($$,U("/")); 439 $$=xmlStrcat($$,$3); 440 xmlFree($3); 441 } 442 | FilterExpr TOK_DblFSlash RelativeLocationPath 443 { 444 TRACE("Got PathExpr: \"%s//%s\"\n", $1, $3); 445 $$=$1; 446 $$=xmlStrcat($$,U("//")); 447 $$=xmlStrcat($$,$3); 448 xmlFree($3); 449 } 450 | FilterExpr 451 ; 452 FilterExpr : PrimaryExpr 453 | FilterExpr Predicate 454 { 455 TRACE("Got FilterExpr: \"%s%s\"\n", $1, $2); 456 $$=$1; 457 $$=xmlStrcat($$,$2); 458 xmlFree($2); 459 } 460 ; 461 /* [3.4] Booleans */ 462 OrExpr : AndExpr 463 | BoolOrExpr 464 ; 465 BoolOrExpr : OrExpr TOK_OpOr AndExpr 466 { 467 TRACE("Got OrExpr: \"%s $or$ %s\"\n", $1, $3); 468 $$=$1; 469 $$=xmlStrcat($$,U(" or ")); 470 $$=xmlStrcat($$,$3); 471 xmlFree($3); 472 } 473 ; 474 AndExpr : EqualityExpr 475 | BoolAndExpr 476 ; 477 BoolAndExpr : AndExpr TOK_OpAnd EqualityExpr 478 { 479 TRACE("Got AndExpr: \"%s $and$ %s\"\n", $1, $3); 480 $$=$1; 481 $$=xmlStrcat($$,U(" and ")); 482 $$=xmlStrcat($$,$3); 483 xmlFree($3); 484 } 485 ; 486 EqualityExpr : RelationalExpr 487 | BoolEqualityExpr 488 ; 489 BoolEqualityExpr : EqualityExpr TOK_OpEq RelationalExpr 490 { 491 TRACE("Got EqualityExpr: \"%s $eq$ %s\"\n", $1, $3); 492 $$=$1; 493 $$=xmlStrcat($$,U("=")); 494 $$=xmlStrcat($$,$3); 495 xmlFree($3); 496 } 497 | EqualityExpr TOK_OpIEq RelationalExpr 498 { 499 TRACE("Got EqualityExpr: \"%s $ieq$ %s\"\n", $1, $3); 500 $$=xmlStrdup(U("OP_IEq(")); 501 $$=xmlStrcat($$,$1); 502 xmlFree($1); 503 $$=xmlStrcat($$,U(",")); 504 $$=xmlStrcat($$,$3); 505 xmlFree($3); 506 $$=xmlStrcat($$,U(")")); 507 } 508 | EqualityExpr TOK_OpNEq RelationalExpr 509 { 510 TRACE("Got EqualityExpr: \"%s $ne$ %s\"\n", $1, $3); 511 $$=$1; 512 $$=xmlStrcat($$,U("!=")); 513 $$=xmlStrcat($$,$3); 514 xmlFree($3); 515 } 516 | EqualityExpr TOK_OpINEq RelationalExpr 517 { 518 TRACE("Got EqualityExpr: \"%s $ine$ %s\"\n", $1, $3); 519 $$=xmlStrdup(U("OP_INEq(")); 520 $$=xmlStrcat($$,$1); 521 xmlFree($1); 522 $$=xmlStrcat($$,U(",")); 523 $$=xmlStrcat($$,$3); 524 xmlFree($3); 525 $$=xmlStrcat($$,U(")")); 526 } 527 ; 528 RelationalExpr : UnaryExpr 529 | BoolRelationalExpr 530 ; 531 BoolRelationalExpr : RelationalExpr TOK_OpLt UnaryExpr 532 { 533 TRACE("Got RelationalExpr: \"%s $lt$ %s\"\n", $1, $3); 534 $$=$1; 535 $$=xmlStrcat($$,U("<")); 536 $$=xmlStrcat($$,$3); 537 xmlFree($3); 538 } 539 | RelationalExpr TOK_OpILt UnaryExpr 540 { 541 TRACE("Got RelationalExpr: \"%s $ilt$ %s\"\n", $1, $3); 542 $$=xmlStrdup(U("OP_ILt(")); 543 $$=xmlStrcat($$,$1); 544 xmlFree($1); 545 $$=xmlStrcat($$,U(",")); 546 $$=xmlStrcat($$,$3); 547 xmlFree($3); 548 $$=xmlStrcat($$,U(")")); 549 } 550 | RelationalExpr TOK_OpGt UnaryExpr 551 { 552 TRACE("Got RelationalExpr: \"%s $gt$ %s\"\n", $1, $3); 553 $$=$1; 554 $$=xmlStrcat($$,U(">")); 555 $$=xmlStrcat($$,$3); 556 xmlFree($3); 557 } 558 | RelationalExpr TOK_OpIGt UnaryExpr 559 { 560 TRACE("Got RelationalExpr: \"%s $igt$ %s\"\n", $1, $3); 561 $$=xmlStrdup(U("OP_IGt(")); 562 $$=xmlStrcat($$,$1); 563 xmlFree($1); 564 $$=xmlStrcat($$,U(",")); 565 $$=xmlStrcat($$,$3); 566 xmlFree($3); 567 $$=xmlStrcat($$,U(")")); 568 } 569 | RelationalExpr TOK_OpLEq UnaryExpr 570 { 571 TRACE("Got RelationalExpr: \"%s $le$ %s\"\n", $1, $3); 572 $$=$1; 573 $$=xmlStrcat($$,U("<=")); 574 $$=xmlStrcat($$,$3); 575 xmlFree($3); 576 } 577 | RelationalExpr TOK_OpILEq UnaryExpr 578 { 579 TRACE("Got RelationalExpr: \"%s $ile$ %s\"\n", $1, $3); 580 $$=xmlStrdup(U("OP_ILEq(")); 581 $$=xmlStrcat($$,$1); 582 xmlFree($1); 583 $$=xmlStrcat($$,U(",")); 584 $$=xmlStrcat($$,$3); 585 xmlFree($3); 586 $$=xmlStrcat($$,U(")")); 587 } 588 | RelationalExpr TOK_OpGEq UnaryExpr 589 { 590 TRACE("Got RelationalExpr: \"%s $ge$ %s\"\n", $1, $3); 591 $$=$1; 592 $$=xmlStrcat($$,U(">=")); 593 $$=xmlStrcat($$,$3); 594 xmlFree($3); 595 } 596 | RelationalExpr TOK_OpIGEq UnaryExpr 597 { 598 TRACE("Got RelationalExpr: \"%s $ige$ %s\"\n", $1, $3); 599 $$=xmlStrdup(U("OP_IGEq(")); 600 $$=xmlStrcat($$,$1); 601 xmlFree($1); 602 $$=xmlStrcat($$,U(",")); 603 $$=xmlStrcat($$,$3); 604 xmlFree($3); 605 $$=xmlStrcat($$,U(")")); 606 } 607 ; 608 609 /* [3.5] Numbers */ 610 UnaryExpr : UnionExpr 611 | BoolUnaryExpr 612 ; 613 BoolUnaryExpr : TOK_OpNot UnaryExpr 614 { 615 TRACE("Got UnaryExpr: \"$not$ %s\"\n", $2); 616 $$=xmlStrdup(U(" not(")); 617 $$=xmlStrcat($$,$2); 618 xmlFree($2); 619 $$=xmlStrcat($$,U(")")); 620 } 621 | TOK_OpAny Expr 622 { 623 TRACE("Got UnaryExpr: \"$any$ %s\"\n", $2); 624 $$=xmlStrdup(U("boolean(")); 625 $$=xmlStrcat($$,$2); 626 xmlFree($2); 627 $$=xmlStrcat($$,U(")")); 628 } 629 | TOK_OpAll AllExpr 630 { 631 TRACE("Got UnaryExpr: \"$all$ %s\"\n", $2); 632 $$=xmlStrdup(U("not(")); 633 $$=xmlStrcat($$,$2); 634 xmlFree($2); 635 $$=xmlStrcat($$,U(")")); 636 } 637 | TOK_OpAll 638 { 639 FIXME("Unrecognized $all$ expression - ignoring\n"); 640 $$=xmlStrdup(U("")); 641 } 642 ; 643 AllExpr : PathExpr TOK_OpEq PathExpr 644 { 645 $$=$1; 646 $$=xmlStrcat($$,U("!=")); 647 $$=xmlStrcat($$,$3); 648 xmlFree($3); 649 } 650 | PathExpr TOK_OpNEq PathExpr 651 { 652 $$=$1; 653 $$=xmlStrcat($$,U("=")); 654 $$=xmlStrcat($$,$3); 655 xmlFree($3); 656 } 657 | PathExpr TOK_OpLt PathExpr 658 { 659 $$=$1; 660 $$=xmlStrcat($$,U(">=")); 661 $$=xmlStrcat($$,$3); 662 xmlFree($3); 663 } 664 | PathExpr TOK_OpLEq PathExpr 665 { 666 $$=$1; 667 $$=xmlStrcat($$,U(">")); 668 $$=xmlStrcat($$,$3); 669 xmlFree($3); 670 } 671 | PathExpr TOK_OpGt PathExpr 672 { 673 $$=$1; 674 $$=xmlStrcat($$,U("<=")); 675 $$=xmlStrcat($$,$3); 676 xmlFree($3); 677 } 678 | PathExpr TOK_OpGEq PathExpr 679 { 680 $$=$1; 681 $$=xmlStrcat($$,U("<")); 682 $$=xmlStrcat($$,$3); 683 xmlFree($3); 684 } 685 | PathExpr TOK_OpIEq PathExpr 686 { 687 $$=xmlStrdup(U("OP_INEq(")); 688 $$=xmlStrcat($$,$1); 689 xmlFree($1); 690 $$=xmlStrcat($$,U(",")); 691 $$=xmlStrcat($$,$3); 692 xmlFree($3); 693 $$=xmlStrcat($$,U(")")); 694 } 695 | PathExpr TOK_OpINEq PathExpr 696 { 697 $$=xmlStrdup(U("OP_IEq(")); 698 $$=xmlStrcat($$,$1); 699 xmlFree($1); 700 $$=xmlStrcat($$,U(",")); 701 $$=xmlStrcat($$,$3); 702 xmlFree($3); 703 $$=xmlStrcat($$,U(")")); 704 } 705 | PathExpr TOK_OpILt PathExpr 706 { 707 $$=xmlStrdup(U("OP_IGEq(")); 708 $$=xmlStrcat($$,$1); 709 xmlFree($1); 710 $$=xmlStrcat($$,U(",")); 711 $$=xmlStrcat($$,$3); 712 xmlFree($3); 713 $$=xmlStrcat($$,U(")")); 714 } 715 | PathExpr TOK_OpILEq PathExpr 716 { 717 $$=xmlStrdup(U("OP_IGt(")); 718 $$=xmlStrcat($$,$1); 719 xmlFree($1); 720 $$=xmlStrcat($$,U(",")); 721 $$=xmlStrcat($$,$3); 722 xmlFree($3); 723 $$=xmlStrcat($$,U(")")); 724 } 725 | PathExpr TOK_OpIGt PathExpr 726 { 727 $$=xmlStrdup(U("OP_ILEq(")); 728 $$=xmlStrcat($$,$1); 729 xmlFree($1); 730 $$=xmlStrcat($$,U(",")); 731 $$=xmlStrcat($$,$3); 732 xmlFree($3); 733 $$=xmlStrcat($$,U(")")); 734 } 735 | PathExpr TOK_OpIGEq PathExpr 736 { 737 $$=xmlStrdup(U("OP_ILt(")); 738 $$=xmlStrcat($$,$1); 739 xmlFree($1); 740 $$=xmlStrcat($$,U(",")); 741 $$=xmlStrcat($$,$3); 742 xmlFree($3); 743 $$=xmlStrcat($$,U(")")); 744 } 745 ; 746 747 %% 748 749 #endif /* HAVE_LIBXML2 */ 750