X-Git-Url: http://git.indexdata.com/?a=blobdiff_plain;f=src%2Fmain%2Fjava%2Forg%2Fz3950%2Fzing%2Fcql%2FCQLParser.java;h=8a0fc172592a572a6cf25e9802009a59414d5905;hb=738438f3da478a1d0121cbbdab620c47f222c73e;hp=c373f092807079ee525fa907b0814e90fa402ccb;hpb=277aa21b21ccafbb392f58ba30390040bdb47c94;p=cql-java-moved-to-github.git diff --git a/src/main/java/org/z3950/zing/cql/CQLParser.java b/src/main/java/org/z3950/zing/cql/CQLParser.java index c373f09..8a0fc17 100644 --- a/src/main/java/org/z3950/zing/cql/CQLParser.java +++ b/src/main/java/org/z3950/zing/cql/CQLParser.java @@ -1,12 +1,12 @@ package org.z3950.zing.cql; + +import java.io.BufferedReader; import java.io.IOException; import java.util.Properties; import java.io.InputStream; import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.Reader; -import java.io.StringReader; +import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -20,7 +20,7 @@ import java.util.Set; * >http://zing.z3950.org/cql/index.html */ public class CQLParser { - private CQLLexer lexer; + private CQLTokenizer lexer; private final int compat; // When false, implement CQL 1.2 private final Set customRelations = new HashSet(); @@ -112,13 +112,13 @@ public class CQLParser { * tree representing the query. */ public CQLNode parse(String cql) throws CQLParseException, IOException { - lexer = new CQLLexerSimple(cql, LEXDEBUG); + lexer = new CQLLexer(cql, LEXDEBUG); lexer.move(); debug("about to parseQuery()"); CQLNode root = parseTopLevelPrefixes("cql.serverChoice", new CQLRelation(compat == V1POINT2 ? "=" : "scr")); - if (lexer.what() != CQLLexer.TT_EOF) + if (lexer.what() != CQLTokenizer.TT_EOF) throw new CQLParseException("junk after end: " + lexer.render(), lexer.pos()); @@ -135,12 +135,12 @@ public class CQLParser { CQLNode node = parseQuery(index, relation); if ((compat == V1POINT2 || compat == V1POINT1SORT) && - lexer.what() == CQLLexer.TT_SORTBY) { + lexer.what() == CQLTokenizer.TT_SORTBY) { match(lexer.what()); debug("sortspec"); CQLSortNode sortnode = new CQLSortNode(node); - while (lexer.what() != CQLLexer.TT_EOF) { + while (lexer.what() != CQLTokenizer.TT_EOF) { String sortindex = matchSymbol("sort index"); ModifierSet ms = gatherModifiers(sortindex); sortnode.addSortIndex(ms); @@ -161,21 +161,21 @@ public class CQLParser { debug("in parseQuery()"); CQLNode term = parseTerm(index, relation); - while (lexer.what() != CQLLexer.TT_EOF && + while (lexer.what() != CQLTokenizer.TT_EOF && lexer.what() != ')' && - lexer.what() != CQLLexer.TT_SORTBY) { - if (lexer.what() == CQLLexer.TT_AND || - lexer.what() == CQLLexer.TT_OR || - lexer.what() == CQLLexer.TT_NOT || - lexer.what() == CQLLexer.TT_PROX) { + lexer.what() != CQLTokenizer.TT_SORTBY) { + if (lexer.what() == CQLTokenizer.TT_AND || + lexer.what() == CQLTokenizer.TT_OR || + lexer.what() == CQLTokenizer.TT_NOT || + lexer.what() == CQLTokenizer.TT_PROX) { int type = lexer.what(); String val = lexer.value(); match(type); ModifierSet ms = gatherModifiers(val); CQLNode term2 = parseTerm(index, relation); - term = ((type == CQLLexer.TT_AND) ? new CQLAndNode(term, term2, ms) : - (type == CQLLexer.TT_OR) ? new CQLOrNode (term, term2, ms) : - (type == CQLLexer.TT_NOT) ? new CQLNotNode(term, term2, ms) : + term = ((type == CQLTokenizer.TT_AND) ? new CQLAndNode(term, term2, ms) : + (type == CQLTokenizer.TT_OR) ? new CQLOrNode (term, term2, ms) : + (type == CQLTokenizer.TT_NOT) ? new CQLNotNode(term, term2, ms) : new CQLProxNode(term, term2, ms)); } else { throw new CQLParseException("expected boolean, got " + @@ -194,7 +194,7 @@ public class CQLParser { ModifierSet ms = new ModifierSet(base); while (lexer.what() == '/') { match('/'); - if (lexer.what() != CQLLexer.TT_WORD) + if (lexer.what() != CQLTokenizer.TT_WORD) throw new CQLParseException("expected modifier, " + "got " + lexer.render(), lexer.pos()); @@ -219,7 +219,8 @@ public class CQLParser { throws CQLParseException, IOException { debug("in parseTerm()"); - String word; + String first; + StringBuilder all; while (true) { if (lexer.what() == '(') { debug("parenthesised term"); @@ -232,17 +233,24 @@ public class CQLParser { } debug("non-parenthesised term"); - word = matchSymbol("index or term"); - while (lexer.what() == CQLLexer.TT_WORD && !isRelation()) { - word = word + " " + lexer.value(); - match(CQLLexer.TT_WORD); + first = matchSymbol("index or term"); + all = new StringBuilder(first); + //match relation only on second postion + while (isWordOrString() && (all.length() > first.length() || !isRelation())) { + all.append(" ").append(lexer.value()); + match(lexer.what()); } if (!isRelation()) - break; - - index = word; - String relstr = (lexer.what() == CQLLexer.TT_WORD ? + break; //we're done if no relation + + //we have relation, but it only makes sense if preceded by a single term + if (all.length() > first.length()) { + throw new CQLParseException("unexpected relation '"+lexer.value()+"'" + , lexer.pos()); + } + index = first; + String relstr = (lexer.what() == CQLTokenizer.TT_WORD ? lexer.value() : lexer.render(lexer.what(), false)); relation = new CQLRelation(relstr); match(lexer.what()); @@ -251,8 +259,7 @@ public class CQLParser { debug("index='" + index + ", " + "relation='" + relation.toCQL() + "'"); } - - CQLTermNode node = new CQLTermNode(index, relation, word); + CQLTermNode node = new CQLTermNode(index, relation, all.toString()); debug("made term node " + node.toCQL()); return node; } @@ -276,11 +283,16 @@ public class CQLParser { return new CQLPrefixNode(name, identifier, node); } + + private boolean isWordOrString() { + return CQLTokenizer.TT_WORD == lexer.what() + || CQLTokenizer.TT_STRING == lexer.what(); + } private boolean isRelation() { debug("isRelation: checking what()=" + lexer.what() + " (" + lexer.render() + ")"); - if (lexer.what() == CQLLexer.TT_WORD && + if (lexer.what() == CQLTokenizer.TT_WORD && (lexer.value().indexOf('.') >= 0 || lexer.value().equals("any") || lexer.value().equals("all") || @@ -301,10 +313,10 @@ public class CQLParser { return (lexer.what() == '<' || lexer.what() == '>' || lexer.what() == '=' || - lexer.what() == CQLLexer.TT_LE || - lexer.what() == CQLLexer.TT_GE || - lexer.what() == CQLLexer.TT_NE || - lexer.what() == CQLLexer.TT_EQEQ); + lexer.what() == CQLTokenizer.TT_LE || + lexer.what() == CQLTokenizer.TT_GE || + lexer.what() == CQLTokenizer.TT_NE || + lexer.what() == CQLTokenizer.TT_EQEQ); } private void match(int token) @@ -323,19 +335,17 @@ public class CQLParser { throws CQLParseException, IOException { debug("in matchSymbol()"); - if (lexer.what() == CQLLexer.TT_WORD || - lexer.what() == '"' || + if (lexer.what() == CQLTokenizer.TT_WORD || + lexer.what() == CQLTokenizer.TT_STRING || // The following is a complete list of keywords. Because // they're listed here, they can be used unquoted as // indexes, terms, prefix names and prefix identifiers. - // ### Instead, we should ask the lexer whether what we - // have is a keyword, and let the knowledge reside there. (allowKeywordTerms && - lexer.what() == CQLLexer.TT_AND || - lexer.what() == CQLLexer.TT_OR || - lexer.what() == CQLLexer.TT_NOT || - lexer.what() == CQLLexer.TT_PROX || - lexer.what() == CQLLexer.TT_SORTBY)) { + lexer.what() == CQLTokenizer.TT_AND || + lexer.what() == CQLTokenizer.TT_OR || + lexer.what() == CQLTokenizer.TT_NOT || + lexer.what() == CQLTokenizer.TT_PROX || + lexer.what() == CQLTokenizer.TT_SORTBY)) { String symbol = lexer.value(); match(lexer.what()); return symbol; @@ -446,47 +456,59 @@ public class CQLParser { if (argv.size() == 1) { cql = (String) argv.get(0); } else { - byte[] bytes = new byte[10000]; + BufferedReader buff = new BufferedReader(new InputStreamReader(System.in)); try { - // Read in the whole of standard input in one go - int nbytes = System.in.read(bytes); + // read a single line of input + cql = buff.readLine(); + if (cql == null) { + System.err.println("Can't read query from stdin"); + System.exit(2); + return; + } } catch (IOException ex) { System.err.println("Can't read query: " + ex.getMessage()); System.exit(2); + return; } - cql = new String(bytes); } CQLParser parser = new CQLParser(compat); - CQLNode root = null; + CQLNode root; try { root = parser.parse(cql); } catch (CQLParseException ex) { System.err.println("Syntax error: " + ex.getMessage()); + StringBuilder space = new StringBuilder(cql.length()); + System.out.println(cql); + for (int i=0; i