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