1 // $Id: CQLParser.java,v 1.10 2002-10-30 09:19:26 mike Exp $
3 package org.z3950.zing.cql;
4 import java.io.IOException;
8 * Compiles a CQL string into a parse tree.
11 * @version $Id: CQLParser.java,v 1.10 2002-10-30 09:19:26 mike Exp $
12 * @see <A href="http://zing.z3950.org/cql/index.html"
13 * >http://zing.z3950.org/cql/index.html</A>
15 public class CQLParser {
16 private CQLLexer lexer;
17 static private boolean DEBUG = false;
18 static private boolean LEXDEBUG = false;
20 private static void debug(String str) {
22 System.err.println("PARSEDEBUG: " + str);
25 public CQLNode parse(String cql)
26 throws CQLParseException, IOException {
27 lexer = new CQLLexer(cql, LEXDEBUG);
30 debug("about to parse_query()");
31 CQLNode root = parse_query("srw.serverChoice", new CQLRelation("="));
32 if (lexer.ttype != lexer.TT_EOF)
33 throw new CQLParseException("junk after end: " + lexer.render());
38 private CQLNode parse_query(String qualifier, CQLRelation relation)
39 throws CQLParseException, IOException {
40 debug("in parse_query()");
42 CQLNode term = parse_term(qualifier, relation);
43 while (lexer.ttype != lexer.TT_EOF &&
45 if (lexer.ttype == lexer.TT_AND) {
47 CQLNode term2 = parse_term(qualifier, relation);
48 term = new CQLAndNode(term, term2);
49 } else if (lexer.ttype == lexer.TT_OR) {
51 CQLNode term2 = parse_term(qualifier, relation);
52 term = new CQLOrNode(term, term2);
53 } else if (lexer.ttype == lexer.TT_NOT) {
55 CQLNode term2 = parse_term(qualifier, relation);
56 term = new CQLNotNode(term, term2);
57 } else if (lexer.ttype == lexer.TT_PROX) {
60 throw new CQLParseException("expected boolean, got " +
69 private CQLNode parse_term(String qualifier, CQLRelation relation)
70 throws CQLParseException, IOException {
71 debug("in parse_term()");
75 if (lexer.ttype == '(') {
76 debug("parenthesised term");
78 CQLNode expr = parse_query(qualifier, relation);
81 } else if (lexer.ttype != lexer.TT_WORD && lexer.ttype != '"') {
82 throw new CQLParseException("expected qualifier or term, " +
83 "got " + lexer.render());
86 debug("non-parenthesised term");
89 if (!isBaseRelation())
93 relation = new CQLRelation(lexer.render(lexer.ttype, false));
96 while (lexer.ttype == '/') {
98 // ### could insist on known modifiers only
99 if (lexer.ttype != lexer.TT_WORD)
100 throw new CQLParseException("expected relation modifier, "
101 + "got " + lexer.render());
102 relation.addModifier(lexer.sval);
103 match(lexer.TT_WORD);
106 debug("qualifier='" + qualifier + ", " +
107 "relation='" + relation.toCQL() + "'");
110 CQLTermNode node = new CQLTermNode(qualifier, relation, word);
111 debug("made term node " + node.toCQL());
115 boolean isBaseRelation() {
116 debug("isBaseRelation: checking ttype=" + lexer.ttype +
117 " (" + lexer.render() + ")");
118 return (lexer.ttype == '<' ||
119 lexer.ttype == '>' ||
120 lexer.ttype == '=' ||
121 lexer.ttype == lexer.TT_LE ||
122 lexer.ttype == lexer.TT_GE ||
123 lexer.ttype == lexer.TT_NE ||
124 lexer.ttype == lexer.TT_ANY ||
125 lexer.ttype == lexer.TT_ALL ||
126 lexer.ttype == lexer.TT_EXACT);
129 private void match(int token)
130 throws CQLParseException, IOException {
131 debug("in match(" + lexer.render(token, true) + ")");
132 if (lexer.ttype != token)
133 throw new CQLParseException("expected " +
134 lexer.render(token, true) +
135 ", " + "got " + lexer.render());
136 int tmp = lexer.nextToken();
137 debug("match() got token=" + lexer.ttype + ", " +
138 "nval=" + lexer.nval + ", sval='" + lexer.sval + "'" +
139 " (tmp=" + tmp + ")");
145 // e.g. echo '(au=Kerninghan or au=Ritchie) and ti=Unix' |
146 // java org.z3950.zing.cql.CQLParser
149 // <boolean>and</boolean>
151 // <boolean>or</boolean>
154 // <relation>=<relation>
155 // <term>Kerninghan<term>
159 // <relation>=<relation>
160 // <term>Ritchie<term>
165 // <relation>=<relation>
170 public static void main (String[] args) {
171 if (args.length != 0) {
172 System.err.println("Usage: " + args[0]);
176 byte[] bytes = new byte[10000];
178 // Read in the whole of standard input in one go
179 int nbytes = System.in.read(bytes);
180 } catch (java.io.IOException ex) {
181 System.err.println("Can't read query: " + ex.getMessage());
184 String cql = new String(bytes);
185 CQLParser parser = new CQLParser();
188 root = parser.parse(cql);
189 debug("root='" + root + "'");
190 System.out.println(root.toXCQL(0));
191 } catch (CQLParseException ex) {
192 System.err.println("Syntax error: " + ex.getMessage());
194 } catch (java.io.IOException ex) {
195 System.err.println("Can't compile query: " + ex.getMessage());