package edu.berkeley.cs.db.yfilterplus.queryparser.xpathparser; import java_cup.runtime.*; import java.util.ArrayList; parser code {: public parser (java.io.Reader input) { super(new Lexer(input)); } /* control the output of the parser: - print debugging messages - generate an actual Query module list tree in abstract syntax */ static boolean debug = false; // set debug flag from the command line public void setDebug (boolean flag) { debug = flag; } :}; // Terminals terminal fn_position, fn_text; // from java_cup.sym terminal STAR, SLASH, L_BRACKET, R_BRACKET, UNDERSCORE, AT, DOT, L_PAREN, R_PAREN, DOUBLE_SLASH; // defns for yfilter.flex terminal NUMBER, LITERAL, EQUALS, NOT_EQUALS, LESS_THAN, GREATER_THAN, LESS_THAN_EQUALS, GREATER_THAN_EQUALS, NCNAMECHAR, LETTER; terminal String NCNAME; // Non terminals non terminal path_expr, path_expr1, step_expr1, step_expr, additional_select; non terminal qname, predicate1, predicate, simple_predicate, simple_predicate1, path_predicate; non terminal simple_step_expr1, simple_step_expr, simple_step_expr2, simple_step_expr3; non terminal comparator; // FIXME handle literals with quotes, along with optional number (return as string) // non terminal literal; // Precedence // Productions // 1. path_expr ::= ((/ | //) step_expr)+ ( / additional_select)? // ((/ | //)step_expr)+ path_expr ::= path_expr1:pe1 {: if (parser.debug) System.err.println("1.1.1"+pe1); RESULT = pe1; :} | path_expr1:pe1 additional_select:as {: if (((String) as).startsWith("text()")) { ((PathQuery) pe1).addExtraTextSelect(); } else { ((PathQuery) pe1).addExtraAttrSelect(as.toString()); } if (parser.debug) System.err.println("1.1.2 " + pe1); RESULT = pe1; :} ; additional_select ::= SLASH AT qname:qn {: if (parser.debug) System.err.println("as attr: " + qn); RESULT = qn; :} | SLASH qname:qn L_PAREN R_PAREN {: if (!qn.equals("text")) { throw new Exception("xpathparser.parser -- function at the end of the path expression is not supported!"); } if (parser.debug) System.err.println("as text: " + qn); RESULT = qn + "()"; :} ; path_expr1 ::= step_expr1:se1 {: PathQuery pq = new PathQuery((StepExpression) se1); if (parser.debug) System.err.println("1.2.1: " + pq); RESULT = pq; :} | path_expr1:pe1 step_expr1:se1 {: ((PathQuery) pe1).addStepExpr((StepExpression) se1); if (parser.debug) System.err.println("1.2.2 " + pe1); RESULT = pe1; :} ; step_expr1 ::= DOUBLE_SLASH step_expr:se {: ((StepExpression) se).setAxis(StepExpression.DESCENDANT); if (parser.debug) System.err.println("1.3.1" + se); RESULT = se; :} | SLASH step_expr:se {: ((StepExpression) se).setAxis(StepExpression.CHILD); if (parser.debug) System.err.println("1.3.2" + se); RESULT = se; :} ; // 2. step_expr ::= (qname | *) ([ predicate ])* step_expr ::= qname:qn {: if (parser.debug) System.err.println("2.1.1 "+qn); RESULT = new StepExpression((String) qn); :} | qname:qn predicate1:pd1 {: StepExpression se = new StepExpression((String) qn, (ArrayList) pd1); if (parser.debug) System.err.println("2.1.2 " + se); RESULT = se; :} | STAR {: StepExpression se = new StepExpression("*"); if (parser.debug) System.err.println("2.1.3" + se); RESULT = se; :} | STAR predicate1:p1 {: StepExpression se = new StepExpression("*", (ArrayList) p1); if (parser.debug) System.err.println("2.1.4" + se); RESULT = se; :} ; // ([predicate])* predicate1 ::= L_BRACKET predicate:p R_BRACKET {: ArrayList arl = new ArrayList(); arl.add(p); if (parser.debug) System.err.println("2.2.1" + arl); RESULT = arl; :} | predicate1:p1 L_BRACKET predicate:p R_BRACKET {: if (parser.debug) System.err.println("2.2.2 " + p1); ((ArrayList) p1).add(p); RESULT = p1; :} ; // 3. predicate ::= simple_predicate | path_predicate predicate ::= simple_predicate:sp {: if (parser.debug) System.err.println("3.1 "+sp); RESULT = sp; :} | path_predicate:pp {: if (parser.debug) System.err.println("3.2 "+pp); RESULT = pp; :} ; /* 5. path_predicate ::= (.//)? simple_step_expr ((/ | //) simple_step_expr)* ***/ /* (.//)? simple_step_expr */ path_predicate ::= DOT DOUBLE_SLASH simple_step_expr:se /* FIXME: how do i set the axis ? */ {: ((StepExpression)se).setAxis(StepExpression.DESCENDANT); if (parser.debug) System.err.println("5.1.1 " + se); RESULT = new PathPredicate((StepExpression) se); :} | DOT SLASH simple_step_expr:sse {: ((StepExpression)sse).setAxis(StepExpression.CHILD); if (parser.debug) System.err.println("5.1.2 " + sse); RESULT = new PathPredicate((StepExpression) sse); :} | simple_step_expr:sse {: ((StepExpression)sse).setAxis(StepExpression.CHILD); if (parser.debug) System.err.println("5.1.3 " + sse); RESULT = new PathPredicate((StepExpression) sse); :} | path_predicate:pp simple_step_expr1:sse1 {: ((PathPredicate) pp).addStepExpr((StepExpression) sse1); if (parser.debug) System.err.println("5.1.4 " + pp); RESULT = pp; :} ; /* ((/ | //) simple_step_expr)* */ simple_step_expr1 ::= SLASH simple_step_expr:sse {: ((StepExpression) sse).setAxis(StepExpression.CHILD); if (parser.debug) System.err.println("5.2.1 " + sse); RESULT = sse; :} | DOUBLE_SLASH simple_step_expr:sse {: ((StepExpression) sse).setAxis(StepExpression.DESCENDANT); if (parser.debug) System.err.println("5.2.2 " + sse); RESULT = sse; :} ; /* 6. simple_step_expr ::= (qname | *) ([ simple_predicate ])* ***/ /* (qname | *) simple_predicate1 ***/ simple_step_expr ::= qname:qn {: StepExpression se = new StepExpression(qn.toString()); if (parser.debug) System.err.println("6.1.1 " + se); RESULT = se; :} | qname:qn simple_predicate1:sp1 {: StepExpression se = new StepExpression(qn.toString(), (ArrayList) sp1); if (parser.debug) System.err.println("6.1.2 " + se); RESULT = se; :} | STAR {: StepExpression se = new StepExpression("*"); if (parser.debug) System.err.println("6.1.3 " + se); RESULT = se; :} | STAR simple_predicate1:sp1 {: StepExpression se = new StepExpression("*", (ArrayList) sp1); if (parser.debug) System.err.println("6.1.4 " + se); RESULT = se; :} ; /* [ simple_predicate] * ***/ simple_predicate1 ::= L_BRACKET simple_predicate:sp R_BRACKET {: ArrayList arl = new ArrayList(); arl.add(sp); if (parser.debug) System.err.println("6.2.1 " + arl); RESULT = arl; :} | simple_predicate1:sp1 L_BRACKET simple_predicate:sp R_BRACKET {: ((ArrayList) sp1).add(sp); if (parser.debug) System.err.println("6.2.2 " + sp1); RESULT = sp1; :} ; /* 4. simple_predicate ::= @ qname = LITERAL | number | position() comparator number | text() = literal ***/ simple_predicate ::= AT qname:qn EQUALS LITERAL:lit {: String literal = lit.toString(); literal = literal.substring(literal.indexOf("\"") + 1, literal.lastIndexOf("\"")); SimplePredicate sp = new SimplePredicate(SimplePredicate.PREDICATE_ATTRIBUTE, qn.toString(), SimplePredicate.OPERATOR_EQ, literal); if (parser.debug) System.err.println("4.1 " + sp); RESULT = sp; :} | AT qname:qn EQUALS NUMBER:n // FIXME: do we want to support @qname=num ? {: SimplePredicate sp = new SimplePredicate(SimplePredicate.PREDICATE_ATTRIBUTE, qn.toString(), SimplePredicate.OPERATOR_EQ, String.valueOf(n)); if (parser.debug) System.err.println("4.2 " + sp); RESULT = sp; :} | NUMBER:n {: SimplePredicate sp = new SimplePredicate(SimplePredicate.PREDICATE_POSITION, new Integer(String.valueOf(n))); if (parser.debug) System.err.println("4.3 " + sp); RESULT = sp; :} | qname:qn L_PAREN R_PAREN comparator:op NUMBER:n /* check if the function name is 'position' */ {: String str = qn.toString(); if (str.equals("text")) { if (((Integer) op).intValue() != sym.EQUALS) throw new Exception("xpathparser.parser -- only '=' operator is supported after the function text()!"); SimplePredicate sp = new SimplePredicate(SimplePredicate.PREDICATE_TEXT, SimplePredicate.OPERATOR_EQ, String.valueOf(n)); if (parser.debug) System.err.println("4.4 " + sp); RESULT = sp; } else if (str.equals("position")) { char cop = '\0'; switch (((Integer) op).intValue()) { case sym.EQUALS: cop = SimplePredicate.OPERATOR_EQ; break; case sym.NOT_EQUALS: cop = SimplePredicate.OPERATOR_NE; break; case sym.GREATER_THAN: cop = SimplePredicate.OPERATOR_GT; break; case sym.GREATER_THAN_EQUALS: cop = SimplePredicate.OPERATOR_GE; break; case sym.LESS_THAN: cop = SimplePredicate.OPERATOR_LT; break; case sym.LESS_THAN_EQUALS: cop = SimplePredicate.OPERATOR_LE; break; default: if (parser.debug) System.err.println("Rule: position() op value: incorrect operator: " + op); break; } SimplePredicate sp = new SimplePredicate(SimplePredicate.PREDICATE_POSITION, cop, new Integer(String.valueOf(n))); if (parser.debug) System.err.println("4.4 " + sp); RESULT = sp; } else { if (parser.debug) System.err.println("Rule: (position|text)() op value: incorrect function name: " + str); } :} | qname:qn L_PAREN R_PAREN EQUALS LITERAL:lit /* check if the function name is 'text' */ {: String str = qn.toString(); if (!str.equals("text")) { System.err.println("Rule: text() = literal: incorrect function name: " + str); } String literal = lit.toString(); literal = literal.substring(literal.indexOf("\"") + 1, literal.lastIndexOf("\"")); SimplePredicate sp = new SimplePredicate(SimplePredicate.PREDICATE_TEXT, SimplePredicate.OPERATOR_EQ, literal); if (parser.debug) System.err.println("4.5 " + sp); RESULT = sp; :} ; /* 8. comparator ::= op_eq | op_ne | op_gt | op_lt | op_ge | op_le */ comparator ::= EQUALS {: if (parser.debug) System.err.println("="); RESULT = new Integer(sym.EQUALS); :} | NOT_EQUALS {: if (parser.debug) System.err.println("!="); RESULT = new Integer(sym.NOT_EQUALS); :} | GREATER_THAN {: if (parser.debug) System.err.println(">"); RESULT = new Integer(sym.GREATER_THAN); :} | LESS_THAN {: if (parser.debug) System.err.println("<"); RESULT = new Integer(sym.LESS_THAN); :} | GREATER_THAN_EQUALS {: if (parser.debug) System.err.println(">="); RESULT = new Integer(sym.GREATER_THAN_EQUALS); :} | LESS_THAN_EQUALS {: if (parser.debug) System.err.println("<="); RESULT = new Integer(sym.LESS_THAN_EQUALS); :} ; /* 9. qname ::= ncname ***/ qname ::= NCNAME:nc {: if (parser.debug) System.err.println("9 "+nc); RESULT = nc; :} ; /* 10. ncname ::= (letter | _ ) ncnamechar* ***/ /* defined in yfilter.flex */ /* 11. ncnamechar ::= letter | digit | . | - | _ defined in yfilter.flex */ /* 12. literal, number, digit, letter defined in yfilter.flex */ // FIXME handle literals with quotes, along with optional number (return as string) //literal ::= NUMBER:n // {: // RESULT = String.valueOf(n); // :} // ;