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