Update CQL parser to use CQL 1.1 modifiers for booleans and
[yaz-moved-to-github.git] / src / cql.y
1 /* $Id: cql.y,v 1.2 2004-03-10 16:34:29 adam Exp $
2    Copyright (C) 2002-2004
3    Index Data Aps
4
5 This file is part of the YAZ toolkit.
6
7 See the file LICENSE.
8
9  bison parser for CQL grammar.
10 */
11 %{
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <ctype.h>
16 #include <yaz/nmem.h>
17 #include <yaz/cql.h>
18     
19     typedef struct {
20         struct cql_node *rel;
21         struct cql_node *cql;
22         char *buf;
23         size_t len;
24         size_t size;
25     } token;        
26
27     struct cql_parser {
28         int (*getbyte)(void *client_data);
29         void (*ungetbyte)(int b, void *client_data);
30         void *client_data;
31         int last_error;
32         int last_pos;
33         struct cql_node *top;
34         NMEM nmem;
35     };
36
37 #define YYSTYPE token
38     
39 #define YYPARSE_PARAM parm
40 #define YYLEX_PARAM parm
41     
42     int yylex(YYSTYPE *lval, void *vp);
43     int yyerror(char *s);
44 %}
45
46 %pure_parser
47 %token TERM AND OR NOT PROX GE LE NE
48 %expect 9
49
50 %%
51
52 top: { 
53     $$.rel = cql_node_mk_sc("cql.serverChoice", "scr", 0);
54     ((CQL_parser) parm)->top = 0;
55 } cqlQuery1 {
56     cql_node_destroy($$.rel);
57     ((CQL_parser) parm)->top = $2.cql; 
58 }
59 ;
60
61 cqlQuery1: cqlQuery
62 | cqlQuery error {
63     cql_node_destroy($1.cql);
64     $$.cql = 0;
65 }
66 ;
67
68 cqlQuery: 
69   searchClause
70 |
71   cqlQuery boolean modifiers { 
72       $$.rel = $0.rel;
73   } searchClause {
74       struct cql_node *cn = cql_node_mk_boolean($2.buf);
75       
76       cn->u.boolean.modifiers = $3.cql;
77       cn->u.boolean.left = $1.cql;
78       cn->u.boolean.right = $5.cql;
79
80       $$.cql = cn;
81   }
82 ;
83
84 searchClause: 
85   '(' { 
86       $$.rel = $0.rel;
87       
88   } cqlQuery ')' {
89       $$.cql = $3.cql;
90   }
91 |
92   searchTerm {
93       struct cql_node *st = cql_node_dup ($0.rel);
94       st->u.st.term = strdup($1.buf);
95       $$.cql = st;
96   }
97
98   index relation modifiers {
99       $$.rel = cql_node_mk_sc($1.buf, $2.buf, 0);
100       $$.rel->u.st.modifiers = $3.cql;
101   } searchClause {
102       $$.cql = $5.cql;
103       cql_node_destroy($4.rel);
104   }
105 | '>' searchTerm '=' searchTerm {
106       $$.rel = $0.rel;
107   } cqlQuery {
108     $$.cql = cql_node_prefix($6.cql, $2.buf, $4.buf);
109   }
110 | '>' searchTerm {
111       $$.rel = $0.rel;
112   } cqlQuery {
113     $$.cql = cql_node_prefix($4.cql, 0, $2.buf);
114    }
115 ;
116
117 /* unary NOT search TERM here .. */
118
119 boolean: 
120   AND | OR | NOT | PROX 
121   ;
122
123 modifiers: modifiers '/' searchTerm
124
125     struct cql_node *mod = cql_node_mk_sc($3.buf, "=", 0);
126
127     mod->u.st.modifiers = $1.cql;
128     $$.cql = mod;
129 }
130 |
131 modifiers '/' searchTerm mrelation searchTerm
132 {
133     struct cql_node *mod = cql_node_mk_sc($3.buf, $4.buf, $5.buf);
134
135     mod->u.st.modifiers = $1.cql;
136     $$.cql = mod;
137 }
138 |
139
140     $$.cql = 0;
141 }
142 ;
143
144 mrelation:
145   '=' 
146 | '>' 
147 | '<'
148 | GE
149 | LE
150 | NE
151 ;
152
153 relation: 
154   '=' 
155 | '>' 
156 | '<'
157 | GE
158 | LE
159 | NE
160 | TERM
161 ;
162
163 index: 
164   searchTerm;
165
166 searchTerm:
167   TERM
168 | AND
169 | OR
170 | NOT
171 | PROX
172 ;
173
174 %%
175
176 int yyerror(char *s)
177 {
178     return 0;
179 }
180
181 /*
182  * bison lexer for CQL.
183  */
184
185 static void putb(YYSTYPE *lval, CQL_parser cp, int c)
186 {
187     if (lval->len+1 >= lval->size)
188     {
189         char *nb = nmem_malloc(cp->nmem, (lval->size = lval->len * 2 + 20));
190         memcpy (nb, lval->buf, lval->len);
191         lval->buf = nb;
192     }
193     if (c)
194         lval->buf[lval->len++] = c;
195     lval->buf[lval->len] = '\0';
196 }
197
198
199 int yylex(YYSTYPE *lval, void *vp)
200 {
201     CQL_parser cp = (CQL_parser) vp;
202     int c;
203     lval->cql = 0;
204     lval->rel = 0;
205     lval->len = 0;
206     lval->size = 10;
207     lval->buf = nmem_malloc(cp->nmem, lval->size);
208     lval->buf[0] = '\0';
209     do
210     {
211         c = cp->getbyte(cp->client_data);
212         if (c == 0)
213             return 0;
214         if (c == '\n')
215             return 0;
216     } while (isspace(c));
217     if (strchr("()=></", c))
218     {
219         int c1;
220         putb(lval, cp, c);
221         if (c == '>')
222         {
223             c1 = cp->getbyte(cp->client_data);
224             if (c1 == '=')
225             {
226                 putb(lval, cp, c1);
227                 return GE;
228             }
229             else
230                 cp->ungetbyte(c1, cp->client_data);
231         }
232         else if (c == '<')
233         {
234             c1 = cp->getbyte(cp->client_data);
235             if (c1 == '=')
236             {
237                 putb(lval, cp, c1);
238                 return LE;
239             }
240             else if (c1 == '>')
241             {
242                 putb(lval, cp, c1);
243                 return NE;
244             }
245             else
246                 cp->ungetbyte(c1, cp->client_data);
247         }
248         return c;
249     }
250     if (c == '"')
251     {
252         while ((c = cp->getbyte(cp->client_data)) != EOF && c != '"')
253         {
254             if (c == '\\')
255                 c = cp->getbyte(cp->client_data);
256             putb(lval, cp, c);
257         }
258         putb(lval, cp, 0);
259     }
260     else
261     {
262         putb(lval, cp, c);
263         while ((c = cp->getbyte(cp->client_data)) != 0 &&
264                !strchr(" \n()=<>/", c))
265         {
266             if (c == '\\')
267                 c = cp->getbyte(cp->client_data);
268             putb(lval, cp, c);
269         }
270 #if YYDEBUG
271         printf ("got %s\n", lval->buf);
272 #endif
273         if (c != 0)
274             cp->ungetbyte(c, cp->client_data);
275         if (!strcmp(lval->buf, "and"))
276             return AND;
277         if (!strcmp(lval->buf, "or"))
278             return OR;
279         if (!strcmp(lval->buf, "not"))
280             return NOT;
281         if (!strncmp(lval->buf, "prox", 4))
282             return PROX;
283     }
284     return TERM;
285 }
286
287
288 int cql_parser_stream(CQL_parser cp,
289                       int (*getbyte)(void *client_data),
290                       void (*ungetbyte)(int b, void *client_data),
291                       void *client_data)
292 {
293     nmem_reset(cp->nmem);
294     cp->getbyte = getbyte;
295     cp->ungetbyte = ungetbyte;
296     cp->client_data = client_data;
297     if (cp->top)
298         cql_node_destroy(cp->top);
299     cql_parse(cp);
300     if (cp->top)
301         return 0;
302     return -1;
303 }
304
305 CQL_parser cql_parser_create(void)
306 {
307     CQL_parser cp = (CQL_parser) malloc (sizeof(*cp));
308
309     cp->top = 0;
310     cp->getbyte = 0;
311     cp->ungetbyte = 0;
312     cp->client_data = 0;
313     cp->last_error = 0;
314     cp->last_pos = 0;
315     cp->nmem = nmem_create();
316     return cp;
317 }
318
319 void cql_parser_destroy(CQL_parser cp)
320 {
321     cql_node_destroy(cp->top);
322     nmem_destroy(cp->nmem);
323     free (cp);
324 }
325
326 struct cql_node *cql_parser_result(CQL_parser cp)
327 {
328     return cp->top;
329 }