[PATCH 5/6] msxml3: XSLPattern support (basic)

Adam Martinson amartinson at codeweavers.com
Mon Sep 27 20:15:06 CDT 2010


---
 dlls/msxml3/Makefile.in    |    4 +
 dlls/msxml3/domdoc.c       |    2 +-
 dlls/msxml3/queryresult.c  |  146 ++++++++++-
 dlls/msxml3/tests/domdoc.c |  214 +++++++++++++++-
 dlls/msxml3/xslpattern.h   |   55 ++++
 dlls/msxml3/xslpattern.l   |  172 ++++++++++++
 dlls/msxml3/xslpattern.y   |  641 ++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 1228 insertions(+), 6 deletions(-)
 create mode 100644 dlls/msxml3/xslpattern.h
 create mode 100644 dlls/msxml3/xslpattern.l
 create mode 100644 dlls/msxml3/xslpattern.y

diff --git a/dlls/msxml3/Makefile.in b/dlls/msxml3/Makefile.in
index 7f9d0bb..629e7c8 100644
--- a/dlls/msxml3/Makefile.in
+++ b/dlls/msxml3/Makefile.in
@@ -32,6 +32,10 @@ C_SRCS = \
 	xmldoc.c \
 	xmlelem.c
 
+LEX_SRCS = xslpattern.l
+
+BISON_SRCS = xslpattern.y
+
 RC_SRCS = version.rc
 
 IDL_TLB_SRCS = msxml3_v1.idl
diff --git a/dlls/msxml3/domdoc.c b/dlls/msxml3/domdoc.c
index 8d6c5f1..a580ca0 100644
--- a/dlls/msxml3/domdoc.c
+++ b/dlls/msxml3/domdoc.c
@@ -155,7 +155,7 @@ static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
     return priv_from_xmlDocPtr(doc)->properties;
 }
 
-static inline BOOL is_xpathmode(const xmlDocPtr doc)
+inline BOOL is_xpathmode(const xmlDocPtr doc)
 {
     return properties_from_xmlDocPtr(doc)->XPath;
 }
diff --git a/dlls/msxml3/queryresult.c b/dlls/msxml3/queryresult.c
index 739faae..3ce2098 100644
--- a/dlls/msxml3/queryresult.c
+++ b/dlls/msxml3/queryresult.c
@@ -1,8 +1,9 @@
 /*
- *    XPath query result node list implementation (TODO: XSLPattern support)
+ *    XPath/XSLPattern query result node list implementation
  *
  * Copyright 2005 Mike McCormack
  * Copyright 2007 Mikolaj Zalewski
+ * Copyright 2010 Adam Martinson for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -41,7 +42,6 @@
  *    execution of the query
  *  - supports IXMLDOMSelection (TODO)
  *
- * TODO: XSLPattern support
  */
 
 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
@@ -49,8 +49,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(msxml);
 #ifdef HAVE_LIBXML2
 
 #include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
 
 int registerNamespaces(xmlXPathContextPtr ctxt);
+inline BOOL is_xpathmode(const xmlDocPtr doc);
+xmlChar* XSLPattern_to_XPath(xmlChar const* xslpat_str);
 
 typedef struct _queryresult
 {
@@ -374,6 +377,120 @@ static dispex_static_data_t queryresult_dispex = {
     queryresult_iface_tids
 };
 
+void XSLPattern_invalid(xmlXPathParserContextPtr pctx, int nargs)
+{
+    xmlXPathObjectPtr obj;
+    for (; nargs > 0; --nargs)
+    {
+        obj = valuePop(pctx);
+        xmlXPathFreeObject(obj);
+    }
+
+    obj = xmlMalloc(sizeof(xmlXPathObject));
+    obj->type = XPATH_UNDEFINED;
+    valuePush(pctx,obj);
+}
+
+#define XSLPATTERN_CHECK_ARGS(n) \
+    if (nargs != n) { \
+        FIXME("XSLPattern syntax error: Expected 0 arguments, got %i\n", nargs); \
+        XSLPattern_invalid(pctx, nargs); \
+        return; \
+    }
+
+
+void XSLPattern_index(xmlXPathParserContextPtr pctx, int nargs)
+{
+    XSLPATTERN_CHECK_ARGS(0);
+
+    xmlXPathPositionFunction(pctx, 0);
+    valuePush(pctx, xmlXPathNewFloat(xmlXPathPopNumber(pctx) - 1.0));
+}
+
+void XSLPattern_end(xmlXPathParserContextPtr pctx, int nargs)
+{
+    double pos, last;
+    XSLPATTERN_CHECK_ARGS(0);
+
+    xmlXPathPositionFunction(pctx, 0);
+    pos = xmlXPathPopNumber(pctx);
+    xmlXPathLastFunction(pctx, 0);
+    last = xmlXPathPopNumber(pctx);
+    valuePush(pctx, xmlXPathNewBoolean(pos == last));
+}
+
+void XSLPattern_OP_IEq(xmlXPathParserContextPtr pctx, int nargs)
+{
+    xmlChar *arg1, *arg2;
+    XSLPATTERN_CHECK_ARGS(2);
+
+    arg2 = xmlXPathPopString(pctx);
+    arg1 = xmlXPathPopString(pctx);
+    valuePush(pctx, xmlXPathNewBoolean(xmlStrcasecmp(arg1, arg2) == 0));
+    xmlFree(arg1);
+    xmlFree(arg2);
+}
+
+void XSLPattern_OP_INEq(xmlXPathParserContextPtr pctx, int nargs)
+{
+    xmlChar *arg1, *arg2;
+    XSLPATTERN_CHECK_ARGS(2);
+
+    arg2 = xmlXPathPopString(pctx);
+    arg1 = xmlXPathPopString(pctx);
+    valuePush(pctx, xmlXPathNewBoolean(xmlStrcasecmp(arg1, arg2) != 0));
+    xmlFree(arg1);
+    xmlFree(arg2);
+}
+
+void XSLPattern_OP_ILt(xmlXPathParserContextPtr pctx, int nargs)
+{
+    xmlChar *arg1, *arg2;
+    XSLPATTERN_CHECK_ARGS(2);
+
+    arg2 = xmlXPathPopString(pctx);
+    arg1 = xmlXPathPopString(pctx);
+    valuePush(pctx, xmlXPathNewBoolean(xmlStrcasecmp(arg1, arg2) < 0));
+    xmlFree(arg1);
+    xmlFree(arg2);
+}
+
+void XSLPattern_OP_ILEq(xmlXPathParserContextPtr pctx, int nargs)
+{
+    xmlChar *arg1, *arg2;
+    XSLPATTERN_CHECK_ARGS(2);
+
+    arg2 = xmlXPathPopString(pctx);
+    arg1 = xmlXPathPopString(pctx);
+    valuePush(pctx, xmlXPathNewBoolean(xmlStrcasecmp(arg1, arg2) <= 0));
+    xmlFree(arg1);
+    xmlFree(arg2);
+}
+
+void XSLPattern_OP_IGt(xmlXPathParserContextPtr pctx, int nargs)
+{
+    xmlChar *arg1, *arg2;
+    XSLPATTERN_CHECK_ARGS(2);
+
+    arg2 = xmlXPathPopString(pctx);
+    arg1 = xmlXPathPopString(pctx);
+    valuePush(pctx, xmlXPathNewBoolean(xmlStrcasecmp(arg1, arg2) > 0));
+    xmlFree(arg1);
+    xmlFree(arg2);
+}
+
+void XSLPattern_OP_IGEq(xmlXPathParserContextPtr pctx, int nargs)
+{
+    xmlChar *arg1, *arg2;
+    XSLPATTERN_CHECK_ARGS(2);
+
+    arg2 = xmlXPathPopString(pctx);
+    arg1 = xmlXPathPopString(pctx);
+    valuePush(pctx, xmlXPathNewBoolean(xmlStrcasecmp(arg1, arg2) >= 0));
+    xmlFree(arg1);
+    xmlFree(arg2);
+}
+
 HRESULT queryresult_create(xmlNodePtr node, LPCWSTR szQuery, IXMLDOMNodeList **out)
 {
     queryresult *This = heap_alloc_zero(sizeof(queryresult));
@@ -399,6 +516,31 @@ HRESULT queryresult_create(xmlNodePtr node, LPCWSTR szQuery, IXMLDOMNodeList **o
     ctxt->node = node;
     registerNamespaces(ctxt);
 
+    if (is_xpathmode(This->node->doc))
+    {
+        xmlXPathRegisterAllFunctions(ctxt);
+    }
+    else
+    {
+        xmlChar* tmp = str;
+        WARN("Attempting XSLPattern emulation (experimental).\n");
+        str = XSLPattern_to_XPath(str);
+        heap_free(tmp);
+
+        xmlXPathRegisterFunc(ctxt, (xmlChar const*)"not", xmlXPathNotFunction);
+        xmlXPathRegisterFunc(ctxt, (xmlChar const*)"boolean", xmlXPathBooleanFunction);
+
+        xmlXPathRegisterFunc(ctxt, (xmlChar const*)"index", XSLPattern_index);
+        xmlXPathRegisterFunc(ctxt, (xmlChar const*)"end", XSLPattern_end);
+
+        xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_IEq", XSLPattern_OP_IEq);
+        xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_INEq", XSLPattern_OP_INEq);
+        xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_ILt", XSLPattern_OP_ILt);
+        xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_ILEq", XSLPattern_OP_ILEq);
+        xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_IGt", XSLPattern_OP_IGt);
+        xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_IGEq", XSLPattern_OP_IGEq);
+    }
+
     This->result = xmlXPathEval(str, ctxt);
     if (!This->result || This->result->type != XPATH_NODESET)
     {
diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c
index e855ecd..f884a0c 100644
--- a/dlls/msxml3/tests/domdoc.c
+++ b/dlls/msxml3/tests/domdoc.c
@@ -3,6 +3,7 @@
  *
  * Copyright 2005 Mike McCormack for CodeWeavers
  * Copyright 2007-2008 Alistair Leslie-Hughes
+ * Copyright 2010 Adam Martinson for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -5486,16 +5487,223 @@ static void test_XSLPattern(void)
     len = 0;
     ole_check(IXMLDOMNodeList_get_length(list, &len));
     /* should select <elem><c> and <elem xmlns='...'><c> but not <elem><foo:c> */
-    todo_wine ok(len == 3, "expected 3 entries in list, got %d\n", len);
+    ok(len == 3, "expected 3 entries in list, got %d\n", len);
     IXMLDOMNodeList_Release(list);
 
     /* for XSLPattern start index is 0, for XPath it's 1 */
     ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[0]"), &list));
     len = 0;
     ole_check(IXMLDOMNodeList_get_length(list, &len));
-    todo_wine ok(len != 0, "expected filled list\n");
+    ok(len != 0, "expected filled list\n");
     if (len)
-        todo_wine expect_list_and_release(list, "E1.E2.D1");
+        expect_list_and_release(list, "E1.E2.D1");
+
+    /* index() */
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[index()=1]"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E2.E2.D1");
+
+    /* $eq$ */
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[index() $eq$ 1]"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E2.E2.D1");
+
+    /* end() */
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[end()]"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E4.E2.D1");
+
+    /* $not$ */
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[$not$ end()]"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E1.E2.D1 E2.E2.D1 E3.E2.D1");
+
+    /* !=/$ne$ */
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[index() != 0]"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E2.E2.D1 E3.E2.D1 E4.E2.D1");
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[index() $ne$ 0]"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E2.E2.D1 E3.E2.D1 E4.E2.D1");
+
+    /* </$lt$ */
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[index() < 2]"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E1.E2.D1 E2.E2.D1");
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[index() $lt$ 2]"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E1.E2.D1 E2.E2.D1");
+
+    /* <=/$le$ */
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[index() <= 1]"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E1.E2.D1 E2.E2.D1");
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[index() $le$ 1]"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E1.E2.D1 E2.E2.D1");
+
+    /* >/$gt$ */
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[index() > 1]"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E3.E2.D1 E4.E2.D1");
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[index() $gt$ 1]"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E3.E2.D1 E4.E2.D1");
+
+    /* >=/$ge$ */
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[index() >= 2]"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E3.E2.D1 E4.E2.D1");
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[index() $ge$ 2]"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E3.E2.D1 E4.E2.D1");
+
+    /* $ieq$ */
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[a $ieq$ 'a2 field']"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E2.E2.D1");
+
+    /* $ine$ */
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[a $ine$ 'a2 field']"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E1.E2.D1 E3.E2.D1 E4.E2.D1");
+
+    /* $ilt$ */
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[a $ilt$ 'a3 field']"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E1.E2.D1 E2.E2.D1");
+
+    /* $ile$ */
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[a $ile$ 'a2 field']"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E1.E2.D1 E2.E2.D1");
+
+    /* $igt$ */
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[a $igt$ 'a2 field']"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E3.E2.D1 E4.E2.D1");
+
+    /* $ige$ */
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[a $ige$ 'a3 field']"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E3.E2.D1 E4.E2.D1");
+
+    /* $any$ */
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[$any$ *='B2 field']"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E2.E2.D1");
+
+    /* $all$ */
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[$all$ *!='B2 field']"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E1.E2.D1 E3.E2.D1 E4.E2.D1");
+
+    /* or/$or$/|| */
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[index()=0 or end()]"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E1.E2.D1 E4.E2.D1");
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[index()=0 $or$ end()]"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E1.E2.D1 E4.E2.D1");
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[index()=0 || end()]"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E1.E2.D1 E4.E2.D1");
+
+    /* and/$and$/&& */
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[index()>0 and $not$ end()]"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E2.E2.D1 E3.E2.D1");
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[index()>0 $and$ $not$ end()]"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E2.E2.D1 E3.E2.D1");
+    ole_check(IXMLDOMDocument2_selectNodes(doc, _bstr_("root//elem[index()>0 && $not$ end()]"), &list));
+    len = 0;
+    ole_check(IXMLDOMNodeList_get_length(list, &len));
+    ok(len != 0, "expected filled list\n");
+    if (len)
+        expect_list_and_release(list, "E2.E2.D1 E3.E2.D1");
+
 
     IXMLDOMDocument2_Release(doc);
     free_bstrs();
diff --git a/dlls/msxml3/xslpattern.h b/dlls/msxml3/xslpattern.h
new file mode 100644
index 0000000..7b7cd7f
--- /dev/null
+++ b/dlls/msxml3/xslpattern.h
@@ -0,0 +1,55 @@
+/*
+ *    XSLPattern lexer/parser shared internals
+ *
+ * Copyright 2010 Adam Martinson for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __XSLPATTERN__
+#define __XSLPATTERN__
+
+#ifndef __WINE_CONFIG_H
+    #error You must include config.h to use this header
+#endif
+
+#include "wine/debug.h"
+
+#ifndef HAVE_LIBXML2
+    #error You must have libxml2 to use this header
+#endif
+
+#include <libxml/tree.h>
+#include <libxml/xmlstring.h>
+
+typedef struct _parser_param {
+    void* yyscanner;
+    xmlChar const* in;
+    int pos;
+    int len;
+    xmlChar* out;
+} parser_param;
+
+#define YYSTYPE xmlChar*
+#define YY_EXTRA_TYPE parser_param*
+
+int  xslpattern_lex(xmlChar**, void*);
+int  xslpattern_lex_init(void**);
+int  xslpattern_lex_destroy(void*);
+void xslpattern_set_extra(parser_param*, void*);
+int  xslpattern_parse(parser_param*, void*);
+inline void xslpattern_error(parser_param const* param, void const* scanner, char const* msg);
+
+#endif /* __XSLPATTERN__ */
diff --git a/dlls/msxml3/xslpattern.l b/dlls/msxml3/xslpattern.l
new file mode 100644
index 0000000..b21ec0e
--- /dev/null
+++ b/dlls/msxml3/xslpattern.l
@@ -0,0 +1,172 @@
+/*
+ *    XSLPattern lexer
+ *
+ * Copyright 2010 Adam Martinson for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+%{
+#include "config.h"
+#include "wine/port.h"
+
+#ifdef HAVE_LIBXML2
+
+#include "xslpattern.h"
+#include "xslpattern.tab.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msxml);
+
+#define SCAN    xslpattern_get_extra(yyscanner)
+
+#define YY_INPUT(tok_buf, tok_len, max) \
+        do { \
+            if (SCAN->pos <= SCAN->len) \
+            { \
+                tok_len = SCAN->len - SCAN->pos; \
+                if (tok_len > max) tok_len = max; \
+                memcpy(tok_buf, SCAN->in + SCAN->pos, tok_len); \
+                SCAN->pos += tok_len; \
+            } \
+            else \
+            { \
+                tok_len = YY_NULL; \
+            } \
+        } while (0);
+
+#define TOK(tok)    TRACE("token: %s : %s\n", #tok, yytext); return tok
+#define OP(tok)     *yylval=NULL; TOK(tok)
+#define SYM(tok)    *yylval=NULL; TOK(tok)
+#define STR(tok)    *yylval=xmlStrdup(BAD_CAST yytext); TOK(tok)
+
+
+%}
+
+%option reentrant bison-bridge
+%option noyywrap
+%option prefix="xslpattern_"
+%option noinput nounput
+
+/* From the w3c XML standard
+ * <http://www.w3.org/TR/REC-xml/> */
+
+    /* [2.3] Common Syntactic Constructs */
+WSpace          ([[:space:]])
+
+NCNameStartChar ([A-Za-z_]|[\xc0-\xd6\xd8-\xf6\xf8-\xff])
+
+NameCharEx      ([0-9]|[-._\xb7])
+
+NCNameChar      ({NCNameStartChar}|{NameCharEx})
+
+/* From the w3c XML Namespace standard
+ * <http://www.w3.org/TR/REC-xml-names/> */
+
+    /* [3] Declaring Namespaces*/
+NCName          ({NCNameStartChar}{NCNameChar}*)
+
+/* Mostly verbatim from the w3c XPath standard.
+ * <http://www.w3.org/TR/xpath/> */
+
+
+    /* [3.4] Booleans
+     * ||, &&, $foo$ are XSLPattern only */
+
+OP_Or           ("or"|"||"|"$or$")
+OP_And          ("and"|"&&"|"$and$")
+OP_Eq           ("="|"$eq$")
+OP_IEq          ("$ieq$")
+OP_NEq          ("!="|"$ne$")
+OP_INEq         ("$ine$")
+OP_Lt           ("<"|"$lt$")
+OP_ILt          ("$ilt$")
+OP_Gt           (">"|"$gt$")
+OP_IGt          ("$igt$")
+OP_LEq          ("<="|"$le$")
+OP_ILEq         ("$ile$")
+OP_GEq          (">="|"$ge$")
+OP_IGEq         ("$ige$")
+OP_Not          ("$not$")
+OP_All          ("$all$")
+OP_Any          ("$any$")
+
+    /* [3.7] Lexical Structure */
+Literal             (([\x22]([^\x22]*)[\x22])|([\x27]([^\x27]*)[\x27]))
+Number              ({Digits}("."{Digits}?)?|"."{Digits})
+Digits              ([0-9]+)
+
+ANY                 (.)
+
+%%
+
+{WSpace}+                   { /* ignored */ }
+{Literal}                   { STR(TOK_Literal); }
+"//"                        { SYM(TOK_DblFSlash); }
+"/"                         { SYM(TOK_FSlash); }
+".."                        { SYM(TOK_Parent); }
+"."                         { SYM(TOK_Self); }
+"::"                        { SYM(TOK_Axis); }
+":"                         { SYM(TOK_Colon); }
+"("                         { SYM('('); }
+")"                         { SYM(')'); }
+"["                         { SYM('['); }
+"]"                         { SYM(']'); }
+"@"                         { SYM('@'); }
+","                         { SYM(','); }
+"*"                         { SYM('*'); }
+{OP_And}                    { OP(TOK_OpAnd); }
+{OP_Or}                     { OP(TOK_OpOr); }
+{OP_Not}                    { OP(TOK_OpNot); }
+{OP_Eq}                     { OP(TOK_OpEq); }
+{OP_IEq}                    { OP(TOK_OpIEq); }
+{OP_NEq}                    { OP(TOK_OpNEq); }
+{OP_INEq}                   { OP(TOK_OpINEq); }
+{OP_Lt}                     { OP(TOK_OpLt); }
+{OP_ILt}                    { OP(TOK_OpILt); }
+{OP_Gt}                     { OP(TOK_OpGt); }
+{OP_IGt}                    { OP(TOK_OpIGt); }
+{OP_LEq}                    { OP(TOK_OpLEq); }
+{OP_ILEq}                   { OP(TOK_OpILEq); }
+{OP_GEq}                    { OP(TOK_OpGEq); }
+{OP_IGEq}                   { OP(TOK_OpIGEq); }
+{OP_All}                    { OP(TOK_OpAll); }
+{OP_Any}                    { OP(TOK_OpAny); }
+"|"                         { SYM('|'); }
+"!"                         { SYM('!'); }
+{NCName}                    { STR(TOK_NCName); }
+{Number}                    { STR(TOK_Number); }
+{ANY}                       { FIXME("Unexpected character '%s'.",yytext); }
+
+%%
+
+xmlChar* XSLPattern_to_XPath(xmlChar const* xslpat_str)
+{
+    parser_param p;
+    TRACE("(%s)\n", wine_dbgstr_a((char const*)xslpat_str));
+    memset(&p, 0, sizeof(parser_param));
+    p.in = xslpat_str;
+    p.len = xmlStrlen(xslpat_str);
+
+    xslpattern_lex_init(&p.yyscanner);
+    xslpattern_set_extra(&p, p.yyscanner);
+
+    xslpattern_parse(&p, p.yyscanner);
+
+    TRACE("=> %s\n", wine_dbgstr_a((char const*)p.out));
+    xslpattern_lex_destroy(p.yyscanner);
+    return p.out;
+}
+
+#endif /* HAVE_LIBXML2 */
diff --git a/dlls/msxml3/xslpattern.y b/dlls/msxml3/xslpattern.y
new file mode 100644
index 0000000..2fe4d6a
--- /dev/null
+++ b/dlls/msxml3/xslpattern.y
@@ -0,0 +1,641 @@
+/*
+ *    XSLPattern parser (XSLPattern => XPath)
+ *
+ * Copyright 2010 Adam Martinson for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+%{
+#include "config.h"
+#include "wine/port.h"
+
+#ifdef HAVE_LIBXML2
+#include "xslpattern.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msxml);
+
+
+static const xmlChar NameTest_mod_pre[] = "*[namespace-uri()=namespace::*[local-name()=''] or namespace-uri()=''][local-name()='";
+static const xmlChar NameTest_mod_post[] = "']";
+
+#define U(str) BAD_CAST str
+#define DBG(str) wine_dbgstr_a((char const*)str)
+%}
+
+%token TOK_Parent TOK_Self TOK_DblFSlash TOK_FSlash TOK_Axis TOK_Colon
+%token TOK_OpAnd TOK_OpOr TOK_OpNot
+%token TOK_OpEq TOK_OpIEq TOK_OpNEq TOK_OpINEq
+%token TOK_OpLt TOK_OpILt TOK_OpGt TOK_OpIGt TOK_OpLEq TOK_OpILEq TOK_OpGEq TOK_OpIGEq
+%token TOK_OpAll TOK_OpAny
+%token TOK_NCName TOK_Literal TOK_Number
+
+%start XSLPattern
+
+%pure_parser
+%parse-param {parser_param* p}
+%parse-param {void* scanner}
+%lex-param {yyscan_t* scanner}
+
+%left TOK_OpAnd TOK_OpOr
+%left TOK_OpEq TOK_OpIEq TOK_OpNEq TOK_OpINEq
+%left TOK_OpLt TOK_OpILt TOK_OpGt TOK_OpIGt TOK_OpLEq TOK_OpILEq TOK_OpGEq TOK_OpIGEq
+
+%%
+
+    XSLPattern              : Expr
+                            {
+                                p->out = $1;
+                            }
+    ;
+
+/* Mostly verbatim from the w3c XML Namespaces standard.
+ * <http://www.w3.org/TR/REC-xml-names/> */
+
+    /* [4] Qualified Names */
+    QName                   : PrefixedName
+                            | UnprefixedName
+    ;
+    PrefixedName            : TOK_NCName TOK_Colon TOK_NCName
+                            {
+                                TRACE("Got PrefixedName: %s:%s\n", DBG($1), DBG($3));
+                                $$=$1;
+                                $$=xmlStrcat($$, U(":"));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+    ;
+    UnprefixedName          : TOK_NCName
+                            {
+                                TRACE("Got UnprefixedName: %s\n", DBG($1));
+                                $$=$1;
+                            }
+    ;
+
+/* Based on the w3c XPath standard, adapted where needed.
+ * <http://www.w3.org/TR/xpath/> */
+
+    /* [2] Location Paths */
+    LocationPath            : RelativeLocationPath
+                            | AbsoluteLocationPath
+    ;
+    AbsoluteLocationPath    : TOK_FSlash RelativeLocationPath
+                            {
+                                TRACE("Got AbsoluteLocationPath: /%s\n", DBG($1));
+                                $$=xmlStrdup(U("/"));
+                                $$=xmlStrcat($$,$2);
+                                xmlFree($2);
+                            }
+                            | TOK_FSlash
+                            {
+                                TRACE("Got AbsoluteLocationPath: /\n");
+                                $$=xmlStrdup(U("/"));
+                            }
+                            | AbbreviatedAbsoluteLocationPath
+    ;
+    RelativeLocationPath    : Step
+                            | RelativeLocationPath TOK_FSlash Step
+                            {
+                                TRACE("Got RelativeLocationPath: %s/%s\n", DBG($1), DBG($3));
+                                $$=$1;
+                                $$=xmlStrcat($$,U("/"));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+                            | AbbreviatedRelativeLocationPath
+    ;
+    /* [2.1] Location Steps */
+    Step                    : AxisSpecifier NameTest Predicates
+                            {
+                                TRACE("Got Step: %s%s%s\n", DBG($1), DBG($2), DBG($3));
+                                $$=$1;
+                                $$=xmlStrcat($$,$2);
+                                xmlFree($2);
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+                            | NameTest Predicates
+                            {
+                                TRACE("Got Step: %s%s\n", DBG($1), DBG($2));
+                                $$=$1;
+                                $$=xmlStrcat($$,$2);
+                                xmlFree($2);
+                            }
+                            | AxisSpecifier NameTest
+                            {
+                                TRACE("Got Step: %s%s\n", DBG($1), DBG($2));
+                                $$=$1;
+                                $$=xmlStrcat($$,$2);
+                                xmlFree($2);
+                            }
+                            | NameTest
+                            | Attribute
+                            | AbbreviatedStep
+    ;
+    AxisSpecifier           : TOK_NCName TOK_Axis
+                            {
+                                TRACE("Got AxisSpecifier: %s::\n", DBG($1));
+                                $$=$1;
+                                $$=xmlStrcat($$,U("::"));
+                            }
+    ;
+    Attribute               : '@' TOK_NCName
+                            {
+                                TRACE("Got Attribute: @%s\n", DBG($2));
+                                $$=xmlStrdup(U("@"));
+                                $$=xmlStrcat($$,$2);
+                                xmlFree($2);
+                            }
+    ;
+
+    /* [2.3] Node Tests */
+    NameTest                : '*'
+                            {
+                                TRACE("Got NameTest: *\n");
+                                $$=xmlStrdup(U("*"));
+                            }
+                            | TOK_NCName TOK_Colon '*'
+                            {
+                                TRACE("Got NameTest: %s:*\n", DBG($1));
+                                $$=$1;
+                                $$=xmlStrcat($$,U(":*"));
+                            }
+                            | PrefixedName
+                            | UnprefixedName
+                            {
+                                $$=xmlStrdup(NameTest_mod_pre);
+                                $$=xmlStrcat($$,$1);
+                                xmlFree($1);
+                                $$=xmlStrcat($$,NameTest_mod_post);
+                            }
+    /* [2.4] Predicates */
+    Predicates              : Predicates Predicate
+                            {
+                                $$=$1;
+                                $$=xmlStrcat($$,$2);
+                                xmlFree($2);
+                            }
+                            | Predicate
+    ;
+    Predicate               : '[' PredicateExpr ']'
+                            {
+                                TRACE("Got Predicate: [%s]\n", DBG($2));
+                                $$=xmlStrdup(U("["));
+                                $$=xmlStrcat($$,$2);
+                                xmlFree($2);
+                                $$=xmlStrcat($$,U("]"));
+                            }
+    ;
+    PredicateExpr           : TOK_Number
+                            {
+                                $$=xmlStrdup(U("index()="));
+                                $$=xmlStrcat($$,$1);
+                                xmlFree($1);
+                            }
+                            | BoolExpr
+                            | Attribute
+    ;
+    /* [2.5] Abbreviated Syntax */
+    AbbreviatedAbsoluteLocationPath : TOK_DblFSlash RelativeLocationPath
+                            {
+                                TRACE("Got AbbreviatedAbsoluteLocationPath: //%s\n", DBG($2));
+                                $$=xmlStrdup(U("//"));
+                                $$=xmlStrcat($$,$2);
+                                xmlFree($2);
+                            }
+    ;
+    AbbreviatedRelativeLocationPath : RelativeLocationPath TOK_DblFSlash Step
+                            {
+                                TRACE("Got AbbreviatedRelativeLocationPath: %s//%s\n", DBG($1), DBG($2));
+                                $$=$1;
+                                $$=xmlStrcat($$,U("//"));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+    ;
+    AbbreviatedStep         : TOK_Parent
+                            {
+                                TRACE("Got AbbreviatedStep: ..\n");
+                                $$=xmlStrdup(U(".."));
+                            }
+                            | TOK_Self
+                            {
+                                TRACE("Got AbbreviatedStep: .\n");
+                                $$=xmlStrdup(U("."));
+                            }
+    ;
+
+    /* [3] Expressions */
+    /* [3.1] Basics */
+    Expr                    : OrExpr
+    ;
+    BoolExpr                : FunctionCall
+                            | BoolUnaryExpr
+                            | BoolRelationalExpr
+                            | BoolEqualityExpr
+                            | BoolAndExpr
+                            | BoolOrExpr
+    ;
+    PrimaryExpr             : '(' Expr ')'
+                            {
+                                TRACE("Got PrimaryExpr: (%s)\n", DBG($1));
+                                $$=xmlStrdup(U("("));
+                                $$=xmlStrcat($$,$2);
+                                xmlFree($2);
+                                $$=xmlStrcat($$,U(")"));
+                            }
+                            | PathExpr '!' FunctionCall
+                            {
+                                TRACE("Got PrimaryExpr: %s!%s\n", DBG($1), DBG($3));
+                                $$=$1;
+                                $$=xmlStrcat($$,U("/"));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+                            | TOK_Literal
+                            | TOK_Number
+                            | FunctionCall
+    ;
+    /* [3.2] Function Calls */
+    FunctionCall            : QName '(' Arguments ')'
+                            {
+                                TRACE("Got FunctionCall: %s(%s)\n", DBG($1), DBG($3));
+                                $$=$1;
+                                $$=xmlStrcat($$,U("("));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                                $$=xmlStrcat($$,U(")"));
+                            }
+                            | QName '(' ')'
+                            {
+                                TRACE("Got FunctionCall: %s()\n", DBG($1));
+                                $$=$1;
+                                $$=xmlStrcat($$,U("()"));
+                            }
+    ;
+    Arguments               : Argument ',' Arguments
+                            {
+                                $$=$1;
+                                $$=xmlStrcat($$,U(","));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+                            | Argument
+    ;
+    Argument                : Expr
+    ;
+    /* [3.3] Node-sets */
+    UnionExpr               : PathExpr
+                            | UnionExpr '|' PathExpr
+                            {
+                                TRACE("Got UnionExpr: %s|%s\n", DBG($1), DBG($3));
+                                $$=$1;
+                                $$=xmlStrcat($$,U("|"));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+    ;
+    PathExpr                : LocationPath
+                            | FilterExpr TOK_FSlash RelativeLocationPath
+                            {
+                                TRACE("Got PathExpr: %s/%s\n", DBG($1), DBG($3));
+                                $$=$1;
+                                $$=xmlStrcat($$,U("/"));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+                            | FilterExpr TOK_DblFSlash RelativeLocationPath
+                            {
+                                TRACE("Got PathExpr: %s//%s\n", DBG($1), DBG($3));
+                                $$=$1;
+                                $$=xmlStrcat($$,U("//"));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+                            | FilterExpr
+    ;
+    FilterExpr              : PrimaryExpr
+                            | FilterExpr Predicate
+                            {
+                                TRACE("Got FilterExpr: %s%s\n", DBG($1), DBG($2));
+                                $$=$1;
+                                $$=xmlStrcat($$,$2);
+                                xmlFree($2);
+                            }
+    ;
+    /* [3.4] Booleans */
+    OrExpr                  : AndExpr
+                            | BoolOrExpr
+    ;
+    BoolOrExpr              : OrExpr TOK_OpOr AndExpr
+                            {
+                                TRACE("Got OrExpr: %s or %s\n", DBG($1), DBG($3));
+                                $$=$1;
+                                $$=xmlStrcat($$,U(" or "));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+    ;
+    AndExpr                 : EqualityExpr
+                            | BoolAndExpr
+    ;
+    BoolAndExpr             : AndExpr TOK_OpAnd EqualityExpr
+                            {
+                                TRACE("Got AndExpr: %s and %s\n", DBG($1), DBG($3));
+                                $$=$1;
+                                $$=xmlStrcat($$,U(" and "));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+    ;
+    EqualityExpr            : RelationalExpr
+                            | BoolEqualityExpr
+    ;
+    BoolEqualityExpr        : EqualityExpr TOK_OpEq RelationalExpr
+                            {
+                                TRACE("Got EqualityExpr: %s $eq$ %s\n", DBG($1), DBG($3));
+                                $$=$1;
+                                $$=xmlStrcat($$,U("="));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+                            | EqualityExpr TOK_OpIEq RelationalExpr
+                            {
+                                TRACE("Got EqualityExpr: %s $ieq$ %s\n", DBG($1), DBG($3));
+                                $$=xmlStrdup(U("OP_IEq("));
+                                $$=xmlStrcat($$,$1);
+                                xmlFree($1);
+                                $$=xmlStrcat($$,U(","));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                                $$=xmlStrcat($$,U(")"));
+                            }
+                            | EqualityExpr TOK_OpNEq RelationalExpr
+                            {
+                                TRACE("Got EqualityExpr: %s $ne$ %s\n", DBG($1), DBG($3));
+                                $$=$1;
+                                $$=xmlStrcat($$,U("!="));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+                            | EqualityExpr TOK_OpINEq RelationalExpr
+                            {
+                                TRACE("Got EqualityExpr: %s $ine$ %s\n", DBG($1), DBG($3));
+                                $$=xmlStrdup(U("OP_INEq("));
+                                $$=xmlStrcat($$,$1);
+                                xmlFree($1);
+                                $$=xmlStrcat($$,U(","));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                                $$=xmlStrcat($$,U(")"));
+                            }
+    ;
+    RelationalExpr          : UnaryExpr
+                            | BoolRelationalExpr
+    ;
+    BoolRelationalExpr      : RelationalExpr TOK_OpLt UnaryExpr
+                            {
+                                TRACE("Got RelationalExpr: %s $lt$ %s\n", DBG($1), DBG($3));
+                                $$=$1;
+                                $$=xmlStrcat($$,U("<"));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+                            | RelationalExpr TOK_OpILt UnaryExpr
+                            {
+                                TRACE("Got RelationalExpr: %s $ilt$ %s\n", DBG($1), DBG($3));
+                                $$=xmlStrdup(U("OP_ILt("));
+                                $$=xmlStrcat($$,$1);
+                                xmlFree($1);
+                                $$=xmlStrcat($$,U(","));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                                $$=xmlStrcat($$,U(")"));
+                            }
+                            | RelationalExpr TOK_OpGt UnaryExpr
+                            {
+                                TRACE("Got RelationalExpr: %s $gt$ %s\n", DBG($1), DBG($3));
+                                $$=$1;
+                                $$=xmlStrcat($$,U(">"));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+                            | RelationalExpr TOK_OpIGt UnaryExpr
+                            {
+                                TRACE("Got RelationalExpr: %s $igt$ %s\n", DBG($1), DBG($3));
+                                $$=xmlStrdup(U("OP_IGt("));
+                                $$=xmlStrcat($$,$1);
+                                xmlFree($1);
+                                $$=xmlStrcat($$,U(","));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                                $$=xmlStrcat($$,U(")"));
+                            }
+                            | RelationalExpr TOK_OpLEq UnaryExpr
+                            {
+                                TRACE("Got RelationalExpr: %s $le$ %s\n", DBG($1), DBG($3));
+                                $$=$1;
+                                $$=xmlStrcat($$,U("<="));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+                            | RelationalExpr TOK_OpILEq UnaryExpr
+                            {
+                                TRACE("Got RelationalExpr: %s $ile$ %s\n", DBG($1), DBG($3));
+                                $$=xmlStrdup(U("OP_ILEq("));
+                                $$=xmlStrcat($$,$1);
+                                xmlFree($1);
+                                $$=xmlStrcat($$,U(","));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                                $$=xmlStrcat($$,U(")"));
+                            }
+                            | RelationalExpr TOK_OpGEq UnaryExpr
+                            {
+                                TRACE("Got RelationalExpr: %s $ge$ %s\n", DBG($1), DBG($3));
+                                $$=$1;
+                                $$=xmlStrcat($$,U(">="));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+                            | RelationalExpr TOK_OpIGEq UnaryExpr
+                            {
+                                TRACE("Got RelationalExpr: %s $ige$ %s\n", DBG($1), DBG($3));
+                                $$=xmlStrdup(U("OP_IGEq("));
+                                $$=xmlStrcat($$,$1);
+                                xmlFree($1);
+                                $$=xmlStrcat($$,U(","));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                                $$=xmlStrcat($$,U(")"));
+                            }
+    ;
+
+    /* [3.5] Numbers */
+    UnaryExpr               : UnionExpr
+                            | BoolUnaryExpr
+    ;
+    BoolUnaryExpr           : TOK_OpNot UnaryExpr
+                            {
+                                TRACE("Got UnaryExpr: $not$ %s\n", DBG($2));
+                                $$=xmlStrdup(U(" not("));
+                                $$=xmlStrcat($$,$2);
+                                xmlFree($2);
+                                $$=xmlStrcat($$,U(")"));
+                            }
+                            | TOK_OpAny Expr
+                            {
+                                TRACE("Got UnaryExpr: $any$ %s\n", DBG($2));
+                                $$=xmlStrdup(U("boolean("));
+                                $$=xmlStrcat($$,$2);
+                                xmlFree($2);
+                                $$=xmlStrcat($$,U(")"));
+                            }
+                            | TOK_OpAll AllExpr
+                            {
+                                TRACE("Got UnaryExpr: $all$ %s\n", DBG($2));
+                                $$=xmlStrdup(U("not("));
+                                $$=xmlStrcat($$,$2);
+                                xmlFree($2);
+                                $$=xmlStrcat($$,U(")"));
+                            }
+                            | TOK_OpAll
+                            {
+                                FIXME("Unrecognized $all$ expression - ignoring\n");
+                                $$=xmlStrdup(U(""));
+                            }
+    ;
+    AllExpr                 : PathExpr TOK_OpEq PathExpr
+                            {
+                                $$=$1;
+                                $$=xmlStrcat($$,U("!="));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+                            | PathExpr TOK_OpNEq PathExpr
+                            {
+                                $$=$1;
+                                $$=xmlStrcat($$,U("="));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+                            | PathExpr TOK_OpLt PathExpr
+                            {
+                                $$=$1;
+                                $$=xmlStrcat($$,U(">="));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+                            | PathExpr TOK_OpLEq PathExpr
+                            {
+                                $$=$1;
+                                $$=xmlStrcat($$,U(">"));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+                            | PathExpr TOK_OpGt PathExpr
+                            {
+                                $$=$1;
+                                $$=xmlStrcat($$,U("<="));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+                            | PathExpr TOK_OpGEq PathExpr
+                            {
+                                $$=$1;
+                                $$=xmlStrcat($$,U("<"));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                            }
+                            | PathExpr TOK_OpIEq PathExpr
+                            {
+                                $$=xmlStrdup(U("OP_INEq("));
+                                $$=xmlStrcat($$,$1);
+                                xmlFree($1);
+                                $$=xmlStrcat($$,U(","));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                                $$=xmlStrcat($$,U(")"));
+                            }
+                            | PathExpr TOK_OpINEq PathExpr
+                            {
+                                $$=xmlStrdup(U("OP_IEq("));
+                                $$=xmlStrcat($$,$1);
+                                xmlFree($1);
+                                $$=xmlStrcat($$,U(","));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                                $$=xmlStrcat($$,U(")"));
+                            }
+                            | PathExpr TOK_OpILt PathExpr
+                            {
+                                $$=xmlStrdup(U("OP_IGEq("));
+                                $$=xmlStrcat($$,$1);
+                                xmlFree($1);
+                                $$=xmlStrcat($$,U(","));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                                $$=xmlStrcat($$,U(")"));
+                            }
+                            | PathExpr TOK_OpILEq PathExpr
+                            {
+                                $$=xmlStrdup(U("OP_IGt("));
+                                $$=xmlStrcat($$,$1);
+                                xmlFree($1);
+                                $$=xmlStrcat($$,U(","));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                                $$=xmlStrcat($$,U(")"));
+                            }
+                            | PathExpr TOK_OpIGt PathExpr
+                            {
+                                $$=xmlStrdup(U("OP_ILEq("));
+                                $$=xmlStrcat($$,$1);
+                                xmlFree($1);
+                                $$=xmlStrcat($$,U(","));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                                $$=xmlStrcat($$,U(")"));
+                            }
+                            | PathExpr TOK_OpIGEq PathExpr
+                            {
+                                $$=xmlStrdup(U("OP_ILt("));
+                                $$=xmlStrcat($$,$1);
+                                xmlFree($1);
+                                $$=xmlStrcat($$,U(","));
+                                $$=xmlStrcat($$,$3);
+                                xmlFree($3);
+                                $$=xmlStrcat($$,U(")"));
+                            }
+    ;
+
+%%
+
+inline void xslpattern_error(parser_param const* param, void const* scanner, char const* msg)
+{
+    FIXME("%s:\n"
+          "  param {\n"
+          "    yyscanner=%p\n"
+          "    in=\"%s\"\n"
+          "    pos=%i\n"
+          "    len=%i\n"
+          "    out=\"%s\"\n"
+          "  }\n"
+          "  scanner=%p\n",
+          msg, param->yyscanner, param->in, param->pos, param->len, param->out, scanner);
+}
+
+
+#endif  /* HAVE_LIBXML2 */
-- 
1.7.2.3


--------------040800030204050701060603--



More information about the wine-patches mailing list