Fixed the asn1 for facets
[yaz-moved-to-github.git] / src / cql.y
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2008 Index Data
3  * See the file LICENSE for details.
4  */ 
5 /* bison parser for CQL grammar. */
6 %{
7 /** 
8  * \file cql.c
9  * \brief Implements CQL parser.
10  *
11  * This is a YACC parser, but since it must be reentrant, Bison is required.
12  * The original source file is cql.y.
13  */
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include <yaz/xmalloc.h>
19 #include <yaz/nmem.h>
20 #include <yaz/cql.h>
21
22     /** Node in the LALR parse tree. */
23     typedef struct {
24         /** Inhereted attribute: relation */
25         struct cql_node *rel;
26         /** Synthesized attribute: CQL node */
27         struct cql_node *cql;
28         /** string buffer with token */
29         char *buf;
30         /** length of token */
31         size_t len;
32         /** size of buffer (len <= size) */
33         size_t size;
34     } token;        
35
36     struct cql_parser {
37         int (*getbyte)(void *client_data);
38         void (*ungetbyte)(int b, void *client_data);
39         void *client_data;
40         int last_error;
41         int last_pos;
42         struct cql_node *top;
43         NMEM nmem;
44     };
45
46 #define YYSTYPE token
47     
48 #define YYPARSE_PARAM parm
49 #define YYLEX_PARAM parm
50     
51     int yylex(YYSTYPE *lval, void *vp);
52     int yyerror(char *s);
53 %}
54
55 %pure_parser
56 %token DOTTERM TERM AND OR NOT PROX GE LE NE EXACT SORTBY
57
58 %%
59
60 top: { 
61     $$.rel = cql_node_mk_sc(((CQL_parser) parm)->nmem,
62                             "cql.serverChoice", "=", 0);
63     ((CQL_parser) parm)->top = 0;
64 } cqlQuery1 sortby {
65     cql_node_destroy($$.rel);
66     ((CQL_parser) parm)->top = $2.cql; 
67 }
68 ;
69
70 sortby: /* empty */
71 | SORTBY sortSpec;
72
73 sortSpec: sortSpec singleSpec
74 | singleSpec; 
75
76 singleSpec: index modifiers ;
77
78 cqlQuery1: cqlQuery
79 | cqlQuery error {
80     cql_node_destroy($1.cql);
81     $$.cql = 0;
82 }
83 ;
84
85 cqlQuery:
86   scopedClause
87  |
88   '>' searchTerm '=' searchTerm {
89     $$.rel = $0.rel;
90   } cqlQuery {
91     $$.cql = cql_apply_prefix(((CQL_parser) parm)->nmem,
92                               $6.cql, $2.buf, $4.buf);
93   }
94 | '>' searchTerm {
95       $$.rel = $0.rel;
96   } cqlQuery {
97     $$.cql = cql_apply_prefix(((CQL_parser) parm)->nmem, 
98                               $4.cql, 0, $2.buf);
99    }
100 ;
101
102 scopedClause: 
103   searchClause
104 |
105   scopedClause boolean modifiers { 
106       $$.rel = $0.rel;
107   } searchClause {
108       struct cql_node *cn = cql_node_mk_boolean(((CQL_parser) parm)->nmem,
109                                                 $2.buf);
110       
111       cn->u.boolean.modifiers = $3.cql;
112       cn->u.boolean.left = $1.cql;
113       cn->u.boolean.right = $5.cql;
114
115       $$.cql = cn;
116   }
117 ;
118
119 searchClause: 
120   '(' { 
121       $$.rel = $0.rel;
122       
123   } cqlQuery ')' {
124       $$.cql = $3.cql;
125   }
126 |
127 searchTerm extraTerms {
128       struct cql_node *st = cql_node_dup(((CQL_parser) parm)->nmem, $0.rel);
129       st->u.st.extra_terms = $2.cql;
130       st->u.st.term = nmem_strdup(((CQL_parser)parm)->nmem, $1.buf);
131       $$.cql = st;
132   }
133
134   index relation modifiers {
135       $$.rel = cql_node_mk_sc(((CQL_parser) parm)->nmem, $1.buf, $2.buf, 0);
136       $$.rel->u.st.modifiers = $3.cql;
137   } searchClause {
138       $$.cql = $5.cql;
139       cql_node_destroy($4.rel);
140   }
141 ;
142
143 extraTerms:
144 extraTerms TERM {
145     struct cql_node *st = cql_node_mk_sc(((CQL_parser) parm)->nmem, 
146                                          /* index */ 0, /* rel */ 0, $2.buf);
147     st->u.st.extra_terms = $1.cql;
148     $$.cql = st;
149 }
150
151 { $$.cql = 0; }
152 ;
153
154
155 /* unary NOT search TERM here .. */
156
157 boolean: 
158   AND | OR | NOT | PROX ;
159
160 modifiers: modifiers '/' searchTerm
161
162     struct cql_node *mod = cql_node_mk_sc(((CQL_parser)parm)->nmem,
163                                           $3.buf, 0, 0);
164
165     mod->u.st.modifiers = $1.cql;
166     $$.cql = mod;
167 }
168 |
169 modifiers '/' searchTerm mrelation searchTerm
170 {
171     struct cql_node *mod = cql_node_mk_sc(((CQL_parser)parm)->nmem,
172                                           $3.buf, $4.buf, $5.buf);
173
174     mod->u.st.modifiers = $1.cql;
175     $$.cql = mod;
176 }
177 |
178
179     $$.cql = 0;
180 }
181 ;
182
183 mrelation:
184   '=' 
185 | '>' 
186 | '<'
187 | GE
188 | LE
189 | NE
190 | EXACT
191 ;
192
193 relation: 
194   '=' 
195 | '>' 
196 | '<'
197 | GE
198 | LE
199 | NE
200 | EXACT
201 | DOTTERM
202 ;
203
204 index: 
205   searchTerm;
206
207 searchTerm:
208   TERM
209 | DOTTERM
210 | AND
211 | OR
212 | NOT
213 | PROX
214 | SORTBY
215 ;
216
217 %%
218
219 int yyerror(char *s)
220 {
221     return 0;
222 }
223
224 /**
225  * putb is a utility that puts one character to the string
226  * in current lexical token. This routine deallocates as
227  * necessary using NMEM.
228  */
229
230 static void putb(YYSTYPE *lval, CQL_parser cp, int c)
231 {
232     if (lval->len+1 >= lval->size)
233     {
234         char *nb = (char *)
235             nmem_malloc(cp->nmem, (lval->size = lval->len * 2 + 20));
236         memcpy (nb, lval->buf, lval->len);
237         lval->buf = nb;
238     }
239     if (c)
240         lval->buf[lval->len++] = c;
241     lval->buf[lval->len] = '\0';
242 }
243
244
245 /**
246  * yylex returns next token for Bison to be read. In this
247  * case one of the CQL terminals are returned.
248  */
249 int yylex(YYSTYPE *lval, void *vp)
250 {
251     CQL_parser cp = (CQL_parser) vp;
252     int c;
253     lval->cql = 0;
254     lval->rel = 0;
255     lval->len = 0;
256     lval->size = 10;
257     lval->buf = (char *) nmem_malloc(cp->nmem, lval->size);
258     lval->buf[0] = '\0';
259     do
260     {
261         c = cp->getbyte(cp->client_data);
262         if (c == 0)
263             return 0;
264         if (c == '\n')
265             return 0;
266     } while (isspace(c));
267     if (strchr("()=></", c))
268     {
269         int c1;
270         putb(lval, cp, c);
271         if (c == '=')
272         {
273             c1 = cp->getbyte(cp->client_data);
274             if (c1 == '=')
275             {
276                 putb(lval, cp, c1);
277                 return EXACT;
278             }
279             else
280                 cp->ungetbyte(c1, cp->client_data);
281         }
282         else if (c == '>')
283         {
284             c1 = cp->getbyte(cp->client_data);
285             if (c1 == '=')
286             {
287                 putb(lval, cp, c1);
288                 return GE;
289             }
290             else
291                 cp->ungetbyte(c1, cp->client_data);
292         }
293         else if (c == '<')
294         {
295             c1 = cp->getbyte(cp->client_data);
296             if (c1 == '=')
297             {
298                 putb(lval, cp, c1);
299                 return LE;
300             }
301             else if (c1 == '>')
302             {
303                 putb(lval, cp, c1);
304                 return NE;
305             }
306             else
307                 cp->ungetbyte(c1, cp->client_data);
308         }
309         return c;
310     }
311     if (c == '"')
312     {
313         while ((c = cp->getbyte(cp->client_data)) != 0 && c != '"')
314         {
315             if (c == '\\')
316             {
317                 putb(lval, cp, c);
318                 c = cp->getbyte(cp->client_data);
319                 if (!c)
320                     break;
321             }
322             putb(lval, cp, c);
323         }
324         putb(lval, cp, 0);
325         return TERM;
326     }
327     else
328     {
329         int relation_like = 0;
330         while (c != 0 && !strchr(" \n()=<>/", c))
331         {
332             if (c == '.')
333                 relation_like = 1;
334             if (c == '\\')
335             {
336                 putb(lval, cp, c);
337                 c = cp->getbyte(cp->client_data);
338                 if (!c)
339                     break;
340             }
341             putb(lval, cp, c);
342             c = cp->getbyte(cp->client_data);
343         }
344         putb(lval, cp, 0);
345 #if YYDEBUG
346         printf ("got %s\n", lval->buf);
347 #endif
348         if (c != 0)
349             cp->ungetbyte(c, cp->client_data);
350         if (!cql_strcmp(lval->buf, "and"))
351         {
352             lval->buf = "and";
353             return AND;
354         }
355         if (!cql_strcmp(lval->buf, "or"))
356         {
357             lval->buf = "or";
358             return OR;
359         }
360         if (!cql_strcmp(lval->buf, "not"))
361         {
362             lval->buf = "not";
363             return NOT;
364         }
365         if (!cql_strcmp(lval->buf, "prox"))
366         {
367             lval->buf = "prox";
368             return PROX;
369         }
370         if (!cql_strcmp(lval->buf, "sortby"))
371         {
372             lval->buf = "sortby";
373             return SORTBY;
374         }
375         if (!cql_strcmp(lval->buf, "all"))
376             relation_like = 1;
377         if (!cql_strcmp(lval->buf, "any"))
378             relation_like = 1;
379         if (relation_like)
380             return DOTTERM;
381     }
382     return TERM;
383 }
384
385
386 int cql_parser_stream(CQL_parser cp,
387                       int (*getbyte)(void *client_data),
388                       void (*ungetbyte)(int b, void *client_data),
389                       void *client_data)
390 {
391     nmem_reset(cp->nmem);
392     cp->getbyte = getbyte;
393     cp->ungetbyte = ungetbyte;
394     cp->client_data = client_data;
395     if (cp->top)
396         cql_node_destroy(cp->top);
397     cql_parse(cp);
398     if (cp->top)
399         return 0;
400     return -1;
401 }
402
403 CQL_parser cql_parser_create(void)
404 {
405     CQL_parser cp = (CQL_parser) xmalloc (sizeof(*cp));
406
407     cp->top = 0;
408     cp->getbyte = 0;
409     cp->ungetbyte = 0;
410     cp->client_data = 0;
411     cp->last_error = 0;
412     cp->last_pos = 0;
413     cp->nmem = nmem_create();
414     return cp;
415 }
416
417 void cql_parser_destroy(CQL_parser cp)
418 {
419     cql_node_destroy(cp->top);
420     nmem_destroy(cp->nmem);
421     xfree (cp);
422 }
423
424 struct cql_node *cql_parser_result(CQL_parser cp)
425 {
426     return cp->top;
427 }