1 // $Id: CQLParser.java,v 1.6 2002-10-25 16:11:05 mike Exp $
3 package org.z3950.zing.cql;
4 import java.util.Properties;
5 import java.io.InputStream;
6 import java.io.FileNotFoundException;
7 import java.io.IOException;
8 import java.io.StringReader;
9 import java.io.StreamTokenizer;
13 * Compiles a CQL string into a parse tree ...
16 * @version $Id: CQLParser.java,v 1.6 2002-10-25 16:11:05 mike Exp $
17 * @see <A href="http://zing.z3950.org/cql/index.html"
18 * >http://zing.z3950.org/cql/index.html</A>
20 public class CQLParser {
22 private StreamTokenizer st;
24 private class CQLParseException extends Exception {
25 CQLParseException(String s) { super(s); }
29 // Nothing to do: do we need this constructor, then?
32 public CQLNode parse(String cql)
33 throws FileNotFoundException, IOException {
35 st = new StreamTokenizer(new StringReader(cql));
36 // ### these settings are wrong
37 st.wordChars('/', '/');
38 st.wordChars('0', '9'); // ### but 1 is still recognised as TT_NUM
39 st.wordChars('.', '.');
40 st.wordChars('-', '-');
47 // while ((token = st.nextToken()) != st.TT_EOF) {
48 // System.out.println("token=" + token + ", " +
49 // "nval=" + st.nval + ", " +
50 // "sval=" + st.sval);
56 root = parse_expression();
57 } catch (CQLParseException ex) {
58 System.err.println("### Oops: " + ex);
62 if (st.ttype != st.TT_EOF) {
63 System.err.println("### Extra bits: " + render(st));
70 private CQLNode parse_expression()
71 throws CQLParseException, IOException {
72 CQLNode term = parse_term();
74 while (st.ttype == st.TT_WORD) {
75 String op = st.sval.toLowerCase();
76 if (st.sval.equals("and")) {
78 CQLNode term2 = parse_term();
79 term = new CQLAndNode(term, term2);
80 } else if (st.sval.equals("or")) {
82 CQLNode term2 = parse_term();
83 term = new CQLOrNode(term, term2);
84 } else if (st.sval.equals("not")) {
86 CQLNode term2 = parse_term();
87 term = new CQLNotNode(term, term2);
94 private CQLNode parse_term()
95 throws CQLParseException, IOException {
96 if (st.ttype == '(') {
98 CQLNode expr = parse_expression();
103 String word = st.sval;
104 return new CQLTermNode("x", "=", word);
107 private void match(int token)
108 throws CQLParseException, IOException {
109 if (st.ttype != token)
110 throw new CQLParseException("expected " + render(st, token, null) +
111 ", " + "got " + render(st));
115 // ### This utility should surely be a method of the StreamTokenizer class
116 private static String render(StreamTokenizer st) {
117 return render(st, st.ttype, null);
120 private static String render(StreamTokenizer st, int token, String str) {
123 if (token == st.TT_EOF) {
125 } else if (token == st.TT_EOL) {
127 } else if (token == st.TT_NUMBER) {
129 } else if (token == st.TT_WORD) {
131 } else if (token == '"' && token == '\'') {
135 return "'" + String.valueOf((char) token) + "'";
141 // e.g. echo '(au=Kerninghan or au=Ritchie) and ti=Unix' |
142 // java org.z3950.zing.cql.CQLParser
146 public static void main (String[] args) {
147 if (args.length != 0) {
148 System.err.println("Usage: " + args[0]);
152 byte[] bytes = new byte[1000];
154 int nbytes = System.in.read(bytes);
155 } catch (java.io.IOException ex) {
156 System.err.println("Can't read query: " + ex);
159 String cql = new String(bytes);
160 CQLParser parser = new CQLParser();
163 root = parser.parse(cql);
164 System.out.println(root.toXCQL(0));
165 } catch (java.io.IOException ex) {
166 System.err.println("Can't compile query: " + ex);