%{ // XPath/XSLT Pattern parser // // Author: Piers Haken // Atsushi Enomoto // // IMPORTANT: // Do not edit "PatternParser.jay". It is autogenerated from // Parser.jay. It will be overwritten! // using System; using System.Collections; using System.Xml; using System.Xml.XPath; #if XSLT_PATTERN namespace Mono.Xml.Xsl #else namespace Mono.Xml.XPath #endif { #if XSLT_PATTERN internal class XsltPatternParser #else internal class XPathParser #endif { internal System.Xml.Xsl.IStaticXsltContext Context; #if XSLT_PATTERN public XsltPatternParser () : this (null) {} internal XsltPatternParser (System.Xml.Xsl.IStaticXsltContext context) #else public XPathParser () : this (null) {} internal XPathParser (System.Xml.Xsl.IStaticXsltContext context) #endif { Context = context; ErrorOutput = System.IO.TextWriter.Null; // debug = new yydebug.yyDebugSimple (); } internal Expression Compile (string xpath) { try { Tokenizer tokenizer = new Tokenizer (xpath); return (Expression) yyparse (tokenizer); } catch (XPathException) { throw; } catch (Exception e) { throw new XPathException ("Error during parse of " + xpath, e); } } static int yacc_verbose_flag; private NodeSet CreateNodeTest (Axes axis, object nodeTest, ArrayList plist) { NodeSet test = CreateNodeTest (axis, nodeTest); if (plist != null) { for (int i = 0; i < plist.Count; i++) test = new ExprFilter (test, (Expression) plist [i]); } return test; } private NodeTest CreateNodeTest (Axes axis, object test) { if (test is XPathNodeType) return new NodeTypeTest (axis, (XPathNodeType) test, null); else if (test is string || test == null) return new NodeTypeTest (axis, XPathNodeType.ProcessingInstruction, (string) test); XmlQualifiedName q = (XmlQualifiedName) test; if (q == XmlQualifiedName.Empty) return new NodeTypeTest (axis); else return new NodeNameTest (axis, q, Context); } %} %token ERROR %token EOF %token SLASH "/" %token SLASH2 "//" %token DOT "." %token DOT2 ".." %token COLON2 "::" %token COMMA "," %token AT "@" %token FUNCTION_NAME %token BRACKET_OPEN "[" %token BRACKET_CLOSE "]" %token PAREN_OPEN "(" %token PAREN_CLOSE ")" %token AND "and" %token OR "or" %token DIV "div" %token MOD "mod" %token PLUS "+" %token MINUS "-" %token ASTERISK "*" %token DOLLAR "$" %token BAR "|" %token EQ "=" %token NE "!=" %token LE "<=" %token GE ">=" %token LT "<" %token GT ">" %token ANCESTOR "ancestor" %token ANCESTOR_OR_SELF "ancstor-or-self" %token ATTRIBUTE "attribute" %token CHILD "child" %token DESCENDANT "descendant" %token DESCENDANT_OR_SELF "descendant-or-self" %token FOLLOWING "following" %token FOLLOWING_SIBLING "sibling" %token NAMESPACE "NameSpace" %token PARENT "parent" %token PRECEDING "preceding" %token PRECEDING_SIBLING "preceding-sibling" %token SELF "self" %token COMMENT "comment" %token TEXT "text" %token PROCESSING_INSTRUCTION "processing-instruction" %token NODE "node" %token MULTIPLY "*" %token NUMBER %token LITERAL %token QName %start Expr %left AND %left OR %left EQ %left NE %left LE %left GE %left LT %left GT %left DIV %left MOD %left PLUS %left MINUS %% /* XSLT Pattern */ Pattern : LocationPathPattern | Pattern BAR LocationPathPattern { $$ = new ExprUNION ((NodeSet) $1, (NodeSet) $3); } ; LocationPathPattern : SLASH { $$ = new ExprRoot (); } | SLASH RelativePathPattern { $$ = new ExprSLASH (new ExprRoot (), (NodeSet) $2); } | IdKeyPattern | IdKeyPattern SLASH RelativePathPattern { $$ = new ExprSLASH ((Expression) $1, (NodeSet) $3); } | IdKeyPattern SLASH2 RelativePathPattern { $$ = new ExprSLASH2 ((Expression) $1, (NodeSet) $3); } | SLASH2 RelativePathPattern { $$ = new ExprSLASH2 (new ExprRoot (), (NodeSet) $2); } | RelativePathPattern ; // to avoid context-sensitive tokenizer, I just reuse FUNCTION_NAME IdKeyPattern : FUNCTION_NAME PAREN_OPEN LITERAL PAREN_CLOSE { XmlQualifiedName name = (XmlQualifiedName) $1; if (name.Name != "id" || name.Namespace != String.Empty) throw new XPathException (String.Format ("Expected 'id' but got '{0}'", name)); $$ = ExprFunctionCall.Factory (name, new FunctionArguments ( new ExprLiteral ((string) $3), null), Context); } | FUNCTION_NAME PAREN_OPEN LITERAL COMMA LITERAL PAREN_CLOSE { XmlQualifiedName name = (XmlQualifiedName) $1; if (name.Name != "key" || name.Namespace != String.Empty) throw new XPathException (String.Format ("Expected 'key' but got '{0}'", name)); $$ = Context.TryGetFunction (name, new FunctionArguments ( new ExprLiteral ((string) $3), new FunctionArguments ( new ExprLiteral ((string) $5), null))); } ; RelativePathPattern : StepPattern | RelativePathPattern SLASH StepPattern { $$ = new ExprSLASH ((Expression) $1, (NodeSet) $3); } | RelativePathPattern SLASH2 StepPattern { $$ = new ExprSLASH2 ((Expression) $1, (NodeSet) $3); } ; StepPattern : ChildOrAttributeAxisSpecifier NodeTest Predicates { $$ = CreateNodeTest ((Axes) $1, $2, (ArrayList) $3); } ; ChildOrAttributeAxisSpecifier : AbbreviatedAxisSpecifier | CHILD COLON2 { $$ = Axes.Child; } | ATTRIBUTE COLON2 { $$ = Axes.Attribute; } ; Predicates : // empty { $$ = null; } | Predicates Predicate { ArrayList al = (ArrayList) $1; if (al == null) al = new ArrayList (); al.Add ((Expression) $2); $$ = al; } ; /* ---- end of XSLT Pattern ---- */ Expr : OrExpr ; OrExpr : AndExpr | OrExpr OR AndExpr { $$ = new ExprOR ((Expression) $1, (Expression) $3); } ; AndExpr : EqualityExpr | AndExpr AND EqualityExpr { $$ = new ExprAND ((Expression) $1, (Expression) $3); } ; EqualityExpr : RelationalExpr | EqualityExpr EQ RelationalExpr { $$ = new ExprEQ ((Expression) $1, (Expression) $3); } | EqualityExpr NE RelationalExpr { $$ = new ExprNE ((Expression) $1, (Expression) $3); } ; RelationalExpr : AdditiveExpr | RelationalExpr LT AdditiveExpr { $$ = new ExprLT ((Expression) $1, (Expression) $3); } | RelationalExpr GT AdditiveExpr { $$ = new ExprGT ((Expression) $1, (Expression) $3); } | RelationalExpr LE AdditiveExpr { $$ = new ExprLE ((Expression) $1, (Expression) $3); } | RelationalExpr GE AdditiveExpr { $$ = new ExprGE ((Expression) $1, (Expression) $3); } ; AdditiveExpr : MultiplicativeExpr | AdditiveExpr PLUS MultiplicativeExpr { $$ = new ExprPLUS ((Expression) $1, (Expression) $3); } | AdditiveExpr MINUS MultiplicativeExpr { $$ = new ExprMINUS ((Expression) $1, (Expression) $3); } ; MultiplicativeExpr : UnaryExpr | MultiplicativeExpr MULTIPLY UnaryExpr { $$ = new ExprMULT ((Expression) $1, (Expression) $3); } | MultiplicativeExpr DIV UnaryExpr { $$ = new ExprDIV ((Expression) $1, (Expression) $3); } | MultiplicativeExpr MOD UnaryExpr { $$ = new ExprMOD ((Expression) $1, (Expression) $3); } ; UnaryExpr : UnionExpr | MINUS UnaryExpr { $$ = new ExprNEG ((Expression) $2); } ; UnionExpr : PathExpr | UnionExpr BAR PathExpr { $$ = new ExprUNION ((Expression) $1, (Expression) $3); } ; PathExpr : LocationPath | FilterExpr | FilterExpr SLASH RelativeLocationPath { $$ = new ExprSLASH ((Expression) $1, (NodeSet) $3); } | FilterExpr SLASH2 RelativeLocationPath { $$ = new ExprSLASH2 ((Expression) $1, (NodeSet) $3); } ; LocationPath : RelativeLocationPath | AbsoluteLocationPath ; AbsoluteLocationPath : SLASH { $$ = new ExprRoot (); } | SLASH RelativeLocationPath { $$ = new ExprSLASH (new ExprRoot (), (NodeSet) $2); } | SLASH2 RelativeLocationPath { $$ = new ExprSLASH2 (new ExprRoot (), (NodeSet) $2); } ; RelativeLocationPath : Step | RelativeLocationPath SLASH Step { $$ = new ExprSLASH ((NodeSet) $1, (NodeSet) $3); } | RelativeLocationPath SLASH2 Step { $$ = new ExprSLASH2 ((NodeSet) $1, (NodeSet) $3); } ; Step : AxisSpecifier NodeTest Predicates { $$ = CreateNodeTest ((Axes) $1, $2, (ArrayList) $3); } | AbbreviatedStep ; NodeTest // QName, XPathNodeType or string : NameTest | NodeType PAREN_OPEN PAREN_CLOSE { $$ = (XPathNodeType) $1; } | PROCESSING_INSTRUCTION PAREN_OPEN OptionalLiteral PAREN_CLOSE { $$ = (string) $3; } ; NameTest : ASTERISK { $$ = XmlQualifiedName.Empty; } | QName // token QName also contains "blah:*" ; AbbreviatedStep : DOT { $$ = new NodeTypeTest (Axes.Self, XPathNodeType.All); } | DOT2 { $$ = new NodeTypeTest (Axes.Parent, XPathNodeType.All); } ; Predicates : /* empty */ { $$ = null; } | Predicates Predicate { ArrayList al = (ArrayList) $1; if (al == null) al = new ArrayList (); al.Add ($2); $$ = al; } ; AxisSpecifier : AxisName COLON2 { $$ = $1; } | AbbreviatedAxisSpecifier ; AbbreviatedAxisSpecifier : /* empty */ { $$ = Axes.Child; } | AT { $$ = Axes.Attribute; } ; NodeType : COMMENT { $$ = XPathNodeType.Comment; } | TEXT { $$ = XPathNodeType.Text; } | PROCESSING_INSTRUCTION { $$ = XPathNodeType.ProcessingInstruction; } | NODE { $$ = XPathNodeType.All; } ; FilterExpr : PrimaryExpr | FilterExpr Predicate { $$ = new ExprFilter ((Expression) $1, (Expression) $2); } ; PrimaryExpr : DOLLAR QName { Expression ret = null; if (Context != null) ret = Context.TryGetVariable (((XmlQualifiedName) $2).ToString ()); if (ret == null) ret = new ExprVariable ((XmlQualifiedName) $2, Context); $$ = ret; } | PAREN_OPEN Expr PAREN_CLOSE { $$ = new ExprParens ((Expression) $2); } | LITERAL { $$ = new ExprLiteral ((String) $1); } | NUMBER { $$ = new ExprNumber ((double) $1); } | FunctionCall ; FunctionCall : FUNCTION_NAME PAREN_OPEN OptionalArgumentList PAREN_CLOSE { Expression ret = null; if (Context != null) ret = Context.TryGetFunction ((XmlQualifiedName) $1, (FunctionArguments) $3); if (ret == null) ret = ExprFunctionCall.Factory ((XmlQualifiedName) $1, (FunctionArguments) $3, Context); $$ = ret; } ; OptionalArgumentList : /* empty */ | Expr OptionalArgumentListTail { $$ = new FunctionArguments ((Expression) $1, (FunctionArguments) $2); } ; OptionalArgumentListTail : /* empty */ | COMMA Expr OptionalArgumentListTail { $$ = new FunctionArguments ((Expression) $2, (FunctionArguments) $3); } ; Predicate : BRACKET_OPEN Expr BRACKET_CLOSE { $$ = $2; } ; AxisName : ANCESTOR { $$ = Axes.Ancestor; } | ANCESTOR_OR_SELF { $$ = Axes.AncestorOrSelf; } | ATTRIBUTE { $$ = Axes.Attribute; } | CHILD { $$ = Axes.Child; } | DESCENDANT { $$ = Axes.Descendant; } | DESCENDANT_OR_SELF { $$ = Axes.DescendantOrSelf; } | FOLLOWING { $$ = Axes.Following; } | FOLLOWING_SIBLING { $$ = Axes.FollowingSibling; } | NAMESPACE { $$ = Axes.Namespace; } | PARENT { $$ = Axes.Parent; } | PRECEDING { $$ = Axes.Preceding; } | PRECEDING_SIBLING { $$ = Axes.PrecedingSibling; } | SELF { $$ = Axes.Self; } ; OptionalLiteral : /* empty */ | LITERAL ; %% }