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