Code

Cleaned up nomenclature in the parser.
[sysdb.git] / src / frontend / grammar.y
1 /*
2  * SysDB - src/frontend/grammar.y
3  * Copyright (C) 2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
28 %{
30 #include "frontend/connection-private.h"
31 #include "frontend/parser.h"
32 #include "frontend/grammar.h"
34 #include "core/store.h"
35 #include "core/store-private.h"
37 #include "utils/error.h"
38 #include "utils/llist.h"
40 #include <stdio.h>
41 #include <string.h>
43 int
44 sdb_fe_yylex(YYSTYPE *yylval, YYLTYPE *yylloc, sdb_fe_yyscan_t yyscanner);
46 sdb_fe_yyextra_t *
47 sdb_fe_yyget_extra(sdb_fe_yyscan_t scanner);
49 void
50 sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg);
52 /* quick access to the current parse tree */
53 #define pt sdb_fe_yyget_extra(scanner)->parsetree
55 /* quick access to the parser mode */
56 #define parser_mode sdb_fe_yyget_extra(scanner)->mode
58 %}
60 %pure-parser
61 %lex-param {sdb_fe_yyscan_t scanner}
62 %parse-param {sdb_fe_yyscan_t scanner}
63 %locations
64 %error-verbose
65 %expect 0
66 %name-prefix "sdb_fe_yy"
68 %union {
69         const char *sstr; /* static string */
70         char *str;
72         sdb_data_t data;
74         sdb_llist_t     *list;
75         sdb_conn_node_t *node;
77         sdb_store_matcher_t *m;
78 }
80 %start statements
82 %token SCANNER_ERROR
84 %token AND OR IS NOT WHERE
85 %token CMP_EQUAL CMP_NEQUAL CMP_REGEX CMP_NREGEX
86 %token CMP_LT CMP_LE CMP_GE CMP_GT
88 /* NULL token */
89 %token NULL_T
91 %token FETCH LIST LOOKUP
93 %token <str> IDENTIFIER STRING
95 %token <data> INTEGER FLOAT
97 /* Precedence (lowest first): */
98 %left OR
99 %left AND
100 %right NOT
101 %left CMP_EQUAL CMP_NEQUAL
102 %left CMP_LT CMP_LE CMP_GE CMP_GT
103 %nonassoc CMP_REGEX CMP_NREGEX
104 %nonassoc IS
105 %left '(' ')'
106 %left '.'
108 %type <list> statements
109 %type <node> statement
110         fetch_statement
111         list_statement
112         lookup_statement
113         condition
115 %type <m> matcher
116         compare_matcher
118 %type <sstr> op
120 %type <data> data
122 %destructor { free($$); } <str>
123 %destructor { sdb_object_deref(SDB_OBJ($$)); } <node> <m>
125 %%
127 statements:
128         statements ';' statement
129                 {
130                         /* only accept this in default parse mode */
131                         if (parser_mode != SDB_PARSE_DEFAULT) {
132                                 sdb_fe_yyerror(&yylloc, scanner,
133                                                 YY_("syntax error, unexpected statement, "
134                                                         "expecting condition"));
135                                 sdb_object_deref(SDB_OBJ($3));
136                                 YYABORT;
137                         }
139                         if ($3) {
140                                 sdb_llist_append(pt, SDB_OBJ($3));
141                                 sdb_object_deref(SDB_OBJ($3));
142                         }
143                 }
144         |
145         statement
146                 {
147                         /* only accept this in default parse mode */
148                         if (parser_mode != SDB_PARSE_DEFAULT) {
149                                 sdb_fe_yyerror(&yylloc, scanner,
150                                                 YY_("syntax error, unexpected statement, "
151                                                         "expecting condition"));
152                                 sdb_object_deref(SDB_OBJ($1));
153                                 YYABORT;
154                         }
156                         if ($1) {
157                                 sdb_llist_append(pt, SDB_OBJ($1));
158                                 sdb_object_deref(SDB_OBJ($1));
159                         }
160                 }
161         |
162         condition
163                 {
164                         /* only accept this in condition parse mode */
165                         if (! (parser_mode & SDB_PARSE_COND)) {
166                                 sdb_fe_yyerror(&yylloc, scanner,
167                                                 YY_("syntax error, unexpected condition, "
168                                                         "expecting statement"));
169                                 sdb_object_deref(SDB_OBJ($1));
170                                 YYABORT;
171                         }
173                         if ($1) {
174                                 sdb_llist_append(pt, SDB_OBJ($1));
175                                 sdb_object_deref(SDB_OBJ($1));
176                         }
177                 }
178         ;
180 statement:
181         fetch_statement
182         |
183         list_statement
184         |
185         lookup_statement
186         |
187         /* empty */
188                 {
189                         $$ = NULL;
190                 }
191         ;
193 /*
194  * FETCH <hostname>;
195  *
196  * Retrieve detailed information about a single host.
197  */
198 fetch_statement:
199         FETCH STRING
200                 {
201                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
202                                                 conn_fetch_t, conn_fetch_destroy));
203                         CONN_FETCH($$)->name = strdup($2);
204                         $$->cmd = CONNECTION_FETCH;
205                         free($2); $2 = NULL;
206                 }
207         ;
209 /*
210  * LIST;
211  *
212  * Returns a list of all hosts in the store.
213  */
214 list_statement:
215         LIST
216                 {
217                         $$ = SDB_CONN_NODE(sdb_object_create_T(/* name = */ NULL,
218                                                 sdb_conn_node_t));
219                         $$->cmd = CONNECTION_LIST;
220                 }
221         ;
223 /*
224  * LOOKUP <type> WHERE <condition>;
225  *
226  * Returns detailed information about <type> matching condition.
227  */
228 lookup_statement:
229         LOOKUP IDENTIFIER WHERE condition
230                 {
231                         /* TODO: support other types as well */
232                         if (strcasecmp($2, "hosts")) {
233                                 char errmsg[strlen($2) + 32];
234                                 snprintf(errmsg, sizeof(errmsg),
235                                                 YY_("unknown table %s"), $2);
236                                 sdb_fe_yyerror(&yylloc, scanner, errmsg);
237                                 free($2); $2 = NULL;
238                                 sdb_object_deref(SDB_OBJ($4));
239                                 YYABORT;
240                         }
242                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
243                                                 conn_lookup_t, conn_lookup_destroy));
244                         CONN_LOOKUP($$)->matcher = CONN_MATCHER($4);
245                         $$->cmd = CONNECTION_LOOKUP;
246                         free($2); $2 = NULL;
247                 }
248         ;
250 condition:
251         matcher
252                 {
253                         if (! $1) {
254                                 /* TODO: improve error reporting */
255                                 sdb_fe_yyerror(&yylloc, scanner,
256                                                 YY_("syntax error, invalid condition"));
257                                 YYABORT;
258                         }
260                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
261                                                 conn_node_matcher_t, conn_matcher_destroy));
262                         $$->cmd = CONNECTION_EXPR;
263                         CONN_MATCHER($$)->matcher = $1;
264                 }
265         ;
267 matcher:
268         '(' matcher ')'
269                 {
270                         $$ = $2;
271                 }
272         |
273         matcher AND matcher
274                 {
275                         $$ = sdb_store_con_matcher($1, $3);
276                         sdb_object_deref(SDB_OBJ($1));
277                         sdb_object_deref(SDB_OBJ($3));
278                 }
279         |
280         matcher OR matcher
281                 {
282                         $$ = sdb_store_dis_matcher($1, $3);
283                         sdb_object_deref(SDB_OBJ($1));
284                         sdb_object_deref(SDB_OBJ($3));
285                 }
286         |
287         NOT matcher
288                 {
289                         $$ = sdb_store_inv_matcher($2);
290                         sdb_object_deref(SDB_OBJ($2));
291                 }
292         |
293         compare_matcher
294                 {
295                         $$ = $1;
296                 }
297         ;
299 /*
300  * <object_type>.<object_attr> <op> <value>
301  *
302  * Parse matchers comparing object attributes with a value.
303  */
304 compare_matcher:
305         IDENTIFIER op data
306                 {
307                         $$ = sdb_store_matcher_parse_cmp($1, NULL, $2, &$3);
308                         free($1); $1 = NULL;
309                         sdb_data_free_datum(&$3);
310                 }
311         |
312         IDENTIFIER '.' IDENTIFIER op data
313                 {
314                         $$ = sdb_store_matcher_parse_cmp($1, $3, $4, &$5);
315                         free($1); $1 = NULL;
316                         free($3); $3 = NULL;
317                         sdb_data_free_datum(&$5);
318                 }
319         |
320         IDENTIFIER '.' IDENTIFIER IS NULL_T
321                 {
322                         $$ = sdb_store_matcher_parse_cmp($1, $3, "IS", NULL);
323                         free($1); $1 = NULL;
324                         free($3); $3 = NULL;
325                 }
326         |
327         IDENTIFIER '.' IDENTIFIER IS NOT NULL_T
328                 {
329                         sdb_store_matcher_t *m;
330                         m = sdb_store_matcher_parse_cmp($1, $3, "IS", NULL);
331                         free($1); $1 = NULL;
332                         free($3); $3 = NULL;
334                         /* sdb_store_inv_matcher return NULL if m==NULL */
335                         $$ = sdb_store_inv_matcher(m);
336                         sdb_object_deref(SDB_OBJ(m));
337                 }
338         ;
340 op:
341         CMP_EQUAL { $$ = "="; }
342         |
343         CMP_NEQUAL { $$ = "!="; }
344         |
345         CMP_REGEX { $$ = "=~"; }
346         |
347         CMP_NREGEX { $$ = "!~"; }
348         |
349         CMP_LT { $$ = "<"; }
350         |
351         CMP_LE { $$ = "<="; }
352         |
353         CMP_GE { $$ = ">="; }
354         |
355         CMP_GT { $$ = ">"; }
356         ;
358 data:
359         STRING { $$.type = SDB_TYPE_STRING; $$.data.string = $1; }
360         |
361         INTEGER { $$ = $1; }
362         |
363         FLOAT { $$ = $1; }
364         ;
366 %%
368 void
369 sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg)
371         sdb_log(SDB_LOG_ERR, "frontend: parse error: %s", msg);
372 } /* sdb_fe_yyerror */
374 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */