/*
* 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.
* */
/* [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.
* */
/* [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(")"));
}
;
%%
void xslpattern_error(parser_param* 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"
" err=%i\n"
" }\n"
" scanner=%p\n",
msg, param->yyscanner, param->in, param->pos, param->len,
param->out, ++param->err, scanner);
}
#endif /* HAVE_LIBXML2 */