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