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