X-Git-Url: http://jsfdemo.indexdata.com/?a=blobdiff_plain;f=src%2Forg%2Fz3950%2Fzing%2Fcql%2FCQLParser.java;h=9ccb1398a89764fe857836332a6370a9654f2dd2;hb=0cf2302a18eacaa327f40743c4ac59cf6c630183;hp=6d49c56830a88b99478c8147a9ef7a5a0af0d9da;hpb=8e35f984081a29de9b53af7c1b2fbf981c474d88;p=cql-java-moved-to-github.git diff --git a/src/org/z3950/zing/cql/CQLParser.java b/src/org/z3950/zing/cql/CQLParser.java index 6d49c56..9ccb139 100644 --- a/src/org/z3950/zing/cql/CQLParser.java +++ b/src/org/z3950/zing/cql/CQLParser.java @@ -1,4 +1,4 @@ -// $Id: CQLParser.java,v 1.33 2007-06-29 12:27:08 mike Exp $ +// $Id: CQLParser.java,v 1.38 2007-07-03 16:40:41 mike Exp $ package org.z3950.zing.cql; import java.io.IOException; @@ -12,15 +12,44 @@ import java.io.FileNotFoundException; /** * Compiles CQL strings into parse trees of CQLNode subtypes. * - * @version $Id: CQLParser.java,v 1.33 2007-06-29 12:27:08 mike Exp $ + * @version $Id: CQLParser.java,v 1.38 2007-07-03 16:40:41 mike Exp $ * @see http://zing.z3950.org/cql/index.html */ public class CQLParser { private CQLLexer lexer; + private int compat; // When false, implement CQL 1.2 + public static int V1POINT1 = 12368; + public static int V1POINT2 = 12369; + public static int V1POINT1SORT = 12370; + static private boolean DEBUG = false; static private boolean LEXDEBUG = false; + /** + * The new parser implements a dialect of CQL specified by the + * compat argument: + * + */ + CQLParser(int compat) { + this.compat = compat; + } + + /** + * The new parser implements CQL 1.2 + */ + CQLParser() { + this.compat = V1POINT2; + } + private static void debug(String str) { if (DEBUG) System.err.println("PARSEDEBUG: " + str); @@ -48,19 +77,53 @@ public class CQLParser { lexer.nextToken(); debug("about to parseQuery()"); - CQLNode root = parseQuery("srw.serverChoice", new CQLRelation("scr")); + CQLNode root = parseTopLevelPrefixes("cql.serverChoice", + new CQLRelation(compat == V1POINT2 ? "=" : "scr")); if (lexer.ttype != lexer.TT_EOF) throw new CQLParseException("junk after end: " + lexer.render()); return root; } + private CQLNode parseTopLevelPrefixes(String index, CQLRelation relation) + throws CQLParseException, IOException { + debug("top-level prefix mapping"); + + if (lexer.ttype == '>') { + return parsePrefix(index, relation, true); + } + + CQLNode node = parseQuery(index, relation); + if ((compat == V1POINT2 || compat == V1POINT1SORT) && + lexer.ttype == lexer.TT_SORTBY) { + match(lexer.ttype); + debug("sortspec"); + + CQLSortNode sortnode = new CQLSortNode(node); + while (lexer.ttype != lexer.TT_EOF) { + String sortindex = matchSymbol("sort index"); + ModifierSet ms = gatherModifiers(sortindex); + sortnode.addSortIndex(ms); + } + + if (sortnode.keys.size() == 0) { + throw new CQLParseException("no sort keys"); + } + + node = sortnode; + } + + return node; + } + private CQLNode parseQuery(String index, CQLRelation relation) throws CQLParseException, IOException { debug("in parseQuery()"); CQLNode term = parseTerm(index, relation); - while (lexer.ttype != lexer.TT_EOF && lexer.ttype != ')') { + while (lexer.ttype != lexer.TT_EOF && + lexer.ttype != ')' && + lexer.ttype != lexer.TT_SORTBY) { if (lexer.ttype == lexer.TT_AND || lexer.ttype == lexer.TT_OR || lexer.ttype == lexer.TT_NOT || @@ -124,8 +187,7 @@ public class CQLParser { match(')'); return expr; } else if (lexer.ttype == '>') { - match('>'); - return parsePrefix(index, relation); + return parsePrefix(index, relation, false); } debug("non-parenthesised term"); @@ -149,10 +211,12 @@ public class CQLParser { return node; } - private CQLNode parsePrefix(String index, CQLRelation relation) + private CQLNode parsePrefix(String index, CQLRelation relation, + boolean topLevel) throws CQLParseException, IOException { debug("prefix mapping"); + match('>'); String name = null; String identifier = matchSymbol("prefix-name"); if (lexer.ttype == '=') { @@ -160,8 +224,11 @@ public class CQLParser { name = identifier; identifier = matchSymbol("prefix-identifer"); } - CQLNode term = parseQuery(index, relation); - return new CQLPrefixNode(name, identifier, term); + CQLNode node = topLevel ? + parseTopLevelPrefixes(index, relation) : + parseQuery(index, relation); + + return new CQLPrefixNode(name, identifier, node); } // Checks for a relation @@ -173,7 +240,8 @@ public class CQLParser { lexer.ttype == '=' || lexer.ttype == lexer.TT_LE || lexer.ttype == lexer.TT_GE || - lexer.ttype == lexer.TT_NE); + lexer.ttype == lexer.TT_NE || + lexer.ttype == lexer.TT_EQEQ); } private void match(int token) @@ -205,12 +273,7 @@ public class CQLParser { lexer.ttype == lexer.TT_OR || lexer.ttype == lexer.TT_NOT || lexer.ttype == lexer.TT_PROX || - lexer.ttype == lexer.TT_pWORD || - lexer.ttype == lexer.TT_SENTENCE || - lexer.ttype == lexer.TT_PARAGRAPH || - lexer.ttype == lexer.TT_ELEMENT || - lexer.ttype == lexer.TT_ORDERED || - lexer.ttype == lexer.TT_UNORDERED) { + lexer.ttype == lexer.TT_SORTBY) { String symbol = (lexer.ttype == lexer.TT_NUMBER) ? lexer.render() : lexer.sval; match(lexer.ttype); @@ -269,6 +332,10 @@ public class CQLParser { * </triple> * *

+ * @param -1 + * CQL version 1.1 (default version 1.2) + * @param -d + * Debug mode: extra output written to stderr. * @param -c * Causes the output to be written in CQL rather than XCQL - that * is, a query equivalent to that which was input, is output. In @@ -286,6 +353,12 @@ public class CQLParser { argv.add(args[i]); } + int compat = V1POINT2; + if (argv.size() > 0 && argv.get(0).equals("-1")) { + compat = V1POINT1; + argv.remove(0); + } + if (argv.size() > 0 && argv.get(0).equals("-d")) { DEBUG = true; argv.remove(0); @@ -302,7 +375,8 @@ public class CQLParser { } if (argv.size() > 1) { - System.err.println("Usage: CQLParser [-d] [-c] [-p []"); + System.err.println("Usage: CQLParser [-1] [-d] [-c] " + + "[-p []"); System.err.println("If unspecified, query is read from stdin"); System.exit(1); } @@ -322,7 +396,7 @@ public class CQLParser { cql = new String(bytes); } - CQLParser parser = new CQLParser(); + CQLParser parser = new CQLParser(compat); CQLNode root = null; try { root = parser.parse(cql);