Code

323fe4feadba40715c3b43c95d0f5d93441de564
[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"
36 #include "core/time.h"
38 #include "utils/error.h"
39 #include "utils/llist.h"
41 #include <assert.h>
43 #include <stdio.h>
44 #include <string.h>
46 /*
47  * private helper functions
48  */
50 static sdb_store_matcher_t *
51 name_iter_matcher(int m_type, int type, const char *cmp,
52                 sdb_store_expr_t *expr);
54 /*
55  * public API
56  */
58 int
59 sdb_fe_yylex(YYSTYPE *yylval, YYLTYPE *yylloc, sdb_fe_yyscan_t yyscanner);
61 sdb_fe_yyextra_t *
62 sdb_fe_yyget_extra(sdb_fe_yyscan_t scanner);
64 void
65 sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg);
66 void
67 sdb_fe_yyerrorf(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *fmt, ...);
69 /* quick access to the current parse tree */
70 #define pt sdb_fe_yyget_extra(scanner)->parsetree
72 /* quick access to the parser mode */
73 #define parser_mode sdb_fe_yyget_extra(scanner)->mode
75 /* quick access to the parser's error buffer */
76 #define errbuf sdb_fe_yyget_extra(scanner)->errbuf
78 #define MODE_TO_STRING(m) \
79         (((m) == SDB_PARSE_DEFAULT) ? "statement" \
80                 : ((m) == SDB_PARSE_COND) ? "condition" \
81                 : ((m) == SDB_PARSE_EXPR) ? "expression" \
82                 : "UNKNOWN")
84 %}
86 %pure-parser
87 %lex-param {sdb_fe_yyscan_t scanner}
88 %parse-param {sdb_fe_yyscan_t scanner}
89 %locations
90 %error-verbose
91 %expect 0
92 %name-prefix "sdb_fe_yy"
94 %union {
95         const char *sstr; /* static string */
96         char *str;
97         int integer;
99         sdb_data_t data;
100         sdb_time_t datetime;
102         sdb_llist_t     *list;
103         sdb_conn_node_t *node;
105         sdb_store_matcher_t *m;
106         sdb_store_expr_t *expr;
108         sdb_metric_store_t metric_store;
111 %start statements
113 %token SCANNER_ERROR
115 %token AND OR IS NOT MATCHING FILTER
116 %token CMP_EQUAL CMP_NEQUAL CMP_REGEX CMP_NREGEX
117 %token CMP_LT CMP_LE CMP_GE CMP_GT ALL ANY IN
118 %token CONCAT
120 %token HOST_T HOSTS_T SERVICE_T SERVICES_T METRIC_T METRICS_T
121 %token ATTRIBUTE_T ATTRIBUTES_T
122 %token NAME_T LAST_UPDATE_T AGE_T INTERVAL_T BACKEND_T
124 %token LAST UPDATE
126 %token START END
128 /* NULL token */
129 %token NULL_T
131 %token FETCH LIST LOOKUP STORE TIMESERIES
133 %token <str> IDENTIFIER STRING
135 %token <data> INTEGER FLOAT
137 %token <datetime> DATE TIME
139 /* Precedence (lowest first): */
140 %left OR
141 %left AND
142 %right NOT
143 %left CMP_EQUAL CMP_NEQUAL
144 %left CMP_LT CMP_LE CMP_GE CMP_GT
145 %nonassoc CMP_REGEX CMP_NREGEX
146 %nonassoc IN
147 %left CONCAT
148 %nonassoc IS
149 %left '+' '-'
150 %left '*' '/' '%'
151 %left '[' ']'
152 %left '(' ')'
153 %left '.'
155 %type <list> statements
156 %type <node> statement
157         fetch_statement
158         list_statement
159         lookup_statement
160         store_statement
161         timeseries_statement
162         matching_clause
163         filter_clause
164         condition
166 %type <m> matcher
167         compare_matcher
169 %type <expr> expression object_expression
171 %type <integer> object_type object_type_plural
172 %type <integer> iterable
173 %type <integer> field
175 %type <sstr> cmp
177 %type <data> data
178         interval interval_elem
179         array array_elem_list
181 %type <datetime> datetime
182         start_clause end_clause
183         last_update_clause
185 %type <metric_store> metric_store_clause
187 %destructor { free($$); } <str>
188 %destructor { sdb_object_deref(SDB_OBJ($$)); } <node> <m> <expr>
189 %destructor { sdb_data_free_datum(&$$); } <data>
191 %%
193 statements:
194         statements ';' statement
195                 {
196                         /* only accepted in default parse mode */
197                         if (parser_mode != SDB_PARSE_DEFAULT) {
198                                 sdb_fe_yyerrorf(&yylloc, scanner,
199                                                 YY_("syntax error, unexpected statement, "
200                                                         "expecting %s"), MODE_TO_STRING(parser_mode));
201                                 sdb_object_deref(SDB_OBJ($3));
202                                 YYABORT;
203                         }
205                         if ($3) {
206                                 sdb_llist_append(pt, SDB_OBJ($3));
207                                 sdb_object_deref(SDB_OBJ($3));
208                         }
209                 }
210         |
211         statement
212                 {
213                         /* only accepted in default parse mode */
214                         if (parser_mode != SDB_PARSE_DEFAULT) {
215                                 sdb_fe_yyerrorf(&yylloc, scanner,
216                                                 YY_("syntax error, unexpected statement, "
217                                                         "expecting %s"), MODE_TO_STRING(parser_mode));
218                                 sdb_object_deref(SDB_OBJ($1));
219                                 YYABORT;
220                         }
222                         if ($1) {
223                                 sdb_llist_append(pt, SDB_OBJ($1));
224                                 sdb_object_deref(SDB_OBJ($1));
225                         }
226                 }
227         |
228         condition
229                 {
230                         /* only accepted in condition parse mode */
231                         if (! (parser_mode & SDB_PARSE_COND)) {
232                                 sdb_fe_yyerrorf(&yylloc, scanner,
233                                                 YY_("syntax error, unexpected condition, "
234                                                         "expecting %s"), MODE_TO_STRING(parser_mode));
235                                 sdb_object_deref(SDB_OBJ($1));
236                                 YYABORT;
237                         }
239                         if ($1) {
240                                 sdb_llist_append(pt, SDB_OBJ($1));
241                                 sdb_object_deref(SDB_OBJ($1));
242                         }
243                 }
244         |
245         expression
246                 {
247                         /* only accepted in expression parse mode */
248                         if (! (parser_mode & SDB_PARSE_EXPR)) {
249                                 sdb_fe_yyerrorf(&yylloc, scanner,
250                                                 YY_("syntax error, unexpected expression, "
251                                                         "expecting %s"), MODE_TO_STRING(parser_mode));
252                                 sdb_object_deref(SDB_OBJ($1));
253                                 YYABORT;
254                         }
256                         if ($1) {
257                                 sdb_conn_node_t *n;
258                                 n = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
259                                                         conn_expr_t, conn_expr_destroy));
260                                 n->cmd = SDB_CONNECTION_EXPR;
261                                 CONN_EXPR(n)->expr = $1;
263                                 sdb_llist_append(pt, SDB_OBJ(n));
264                                 sdb_object_deref(SDB_OBJ(n));
265                         }
266                 }
267         ;
269 statement:
270         fetch_statement
271         |
272         list_statement
273         |
274         lookup_statement
275         |
276         store_statement
277         |
278         timeseries_statement
279         |
280         /* empty */
281                 {
282                         $$ = NULL;
283                 }
284         ;
286 /*
287  * FETCH <type> <hostname> [FILTER <condition>];
288  *
289  * Retrieve detailed information about a single host.
290  */
291 fetch_statement:
292         FETCH object_type STRING filter_clause
293                 {
294                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
295                                                 conn_fetch_t, conn_fetch_destroy));
296                         CONN_FETCH($$)->type = $2;
297                         CONN_FETCH($$)->host = $3;
298                         CONN_FETCH($$)->name = NULL;
299                         CONN_FETCH($$)->filter = CONN_MATCHER($4);
300                         $$->cmd = SDB_CONNECTION_FETCH;
301                 }
302         |
303         FETCH object_type STRING '.' STRING filter_clause
304                 {
305                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
306                                                 conn_fetch_t, conn_fetch_destroy));
307                         CONN_FETCH($$)->type = $2;
308                         CONN_FETCH($$)->host = $3;
309                         CONN_FETCH($$)->name = $5;
310                         CONN_FETCH($$)->filter = CONN_MATCHER($6);
311                         $$->cmd = SDB_CONNECTION_FETCH;
312                 }
313         ;
315 /*
316  * LIST <type> [FILTER <condition>];
317  *
318  * Returns a list of all hosts in the store.
319  */
320 list_statement:
321         LIST object_type_plural filter_clause
322                 {
323                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
324                                                 conn_list_t, conn_list_destroy));
325                         CONN_LIST($$)->type = $2;
326                         CONN_LIST($$)->filter = CONN_MATCHER($3);
327                         $$->cmd = SDB_CONNECTION_LIST;
328                 }
329         ;
331 /*
332  * LOOKUP <type> MATCHING <condition> [FILTER <condition>];
333  *
334  * Returns detailed information about <type> matching condition.
335  */
336 lookup_statement:
337         LOOKUP object_type_plural matching_clause filter_clause
338                 {
339                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
340                                                 conn_lookup_t, conn_lookup_destroy));
341                         CONN_LOOKUP($$)->type = $2;
342                         CONN_LOOKUP($$)->matcher = CONN_MATCHER($3);
343                         CONN_LOOKUP($$)->filter = CONN_MATCHER($4);
344                         $$->cmd = SDB_CONNECTION_LOOKUP;
345                 }
346         ;
348 matching_clause:
349         MATCHING condition { $$ = $2; }
350         |
351         /* empty */ { $$ = NULL; }
353 filter_clause:
354         FILTER condition { $$ = $2; }
355         |
356         /* empty */ { $$ = NULL; }
358 /*
359  * STORE <type> <name>|<host>.<name> [LAST UPDATE <datetime>];
360  * STORE METRIC <host>.<name> STORE <type> <id> [LAST UPDATE <datetime>];
361  * STORE <type> ATTRIBUTE <parent>.<key> <datum> [LAST UPDATE <datetime>];
362  *
363  * Store or update an object in the database.
364  */
365 store_statement:
366         STORE HOST_T STRING last_update_clause
367                 {
368                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
369                                                 conn_store_host_t, conn_store_host_destroy));
370                         CONN_STORE_HOST($$)->name = $3;
371                         CONN_STORE_HOST($$)->last_update = $4;
372                         $$->cmd = SDB_CONNECTION_STORE_HOST;
373                 }
374         |
375         STORE SERVICE_T STRING '.' STRING last_update_clause
376                 {
377                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
378                                                 conn_store_svc_t, conn_store_svc_destroy));
379                         CONN_STORE_SVC($$)->hostname = $3;
380                         CONN_STORE_SVC($$)->name = $5;
381                         CONN_STORE_SVC($$)->last_update = $6;
382                         $$->cmd = SDB_CONNECTION_STORE_SERVICE;
383                 }
384         |
385         STORE METRIC_T STRING '.' STRING metric_store_clause last_update_clause
386                 {
387                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
388                                                 conn_store_metric_t, conn_store_metric_destroy));
389                         CONN_STORE_METRIC($$)->hostname = $3;
390                         CONN_STORE_METRIC($$)->name = $5;
391                         CONN_STORE_METRIC($$)->store_type = $6.type;
392                         CONN_STORE_METRIC($$)->store_id = $6.id;
393                         CONN_STORE_METRIC($$)->last_update = $7;
394                         $$->cmd = SDB_CONNECTION_STORE_METRIC;
395                 }
396         |
397         STORE HOST_T ATTRIBUTE_T STRING '.' STRING data last_update_clause
398                 {
399                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
400                                                 conn_store_attr_t, conn_store_attr_destroy));
401                         CONN_STORE_ATTR($$)->parent_type = SDB_HOST;
402                         CONN_STORE_ATTR($$)->hostname = NULL;
403                         CONN_STORE_ATTR($$)->parent = $4;
404                         CONN_STORE_ATTR($$)->key = $6;
405                         CONN_STORE_ATTR($$)->value = $7;
406                         CONN_STORE_ATTR($$)->last_update = $8;
407                         $$->cmd = SDB_CONNECTION_STORE_ATTRIBUTE;
408                 }
409         |
410         STORE SERVICE_T ATTRIBUTE_T STRING '.' STRING '.' STRING data last_update_clause
411                 {
412                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
413                                                 conn_store_attr_t, conn_store_attr_destroy));
414                         CONN_STORE_ATTR($$)->parent_type = SDB_SERVICE;
415                         CONN_STORE_ATTR($$)->hostname = $4;
416                         CONN_STORE_ATTR($$)->parent = $6;
417                         CONN_STORE_ATTR($$)->key = $8;
418                         CONN_STORE_ATTR($$)->value = $9;
419                         CONN_STORE_ATTR($$)->last_update = $10;
420                         $$->cmd = SDB_CONNECTION_STORE_ATTRIBUTE;
421                 }
422         |
423         STORE METRIC_T ATTRIBUTE_T STRING '.' STRING '.' STRING data last_update_clause
424                 {
425                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
426                                                 conn_store_attr_t, conn_store_attr_destroy));
427                         CONN_STORE_ATTR($$)->parent_type = SDB_METRIC;
428                         CONN_STORE_ATTR($$)->hostname = $4;
429                         CONN_STORE_ATTR($$)->parent = $6;
430                         CONN_STORE_ATTR($$)->key = $8;
431                         CONN_STORE_ATTR($$)->value = $9;
432                         CONN_STORE_ATTR($$)->last_update = $10;
433                         $$->cmd = SDB_CONNECTION_STORE_ATTRIBUTE;
434                 }
435         ;
437 last_update_clause:
438         LAST UPDATE datetime { $$ = $3; }
439         |
440         /* empty */ { $$ = sdb_gettime(); }
442 metric_store_clause:
443         STORE STRING STRING { $$.type = $2; $$.id = $3; }
444         |
445         /* empty */ { $$.type = $$.id = NULL; }
447 /*
448  * TIMESERIES <host>.<metric> [START <datetime>] [END <datetime>];
449  *
450  * Returns a time-series for the specified host's metric.
451  */
452 timeseries_statement:
453         TIMESERIES STRING '.' STRING start_clause end_clause
454                 {
455                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
456                                                 conn_ts_t, conn_ts_destroy));
457                         CONN_TS($$)->hostname = $2;
458                         CONN_TS($$)->metric = $4;
459                         CONN_TS($$)->opts.start = $5;
460                         CONN_TS($$)->opts.end = $6;
461                         $$->cmd = SDB_CONNECTION_TIMESERIES;
462                 }
463         ;
465 start_clause:
466         START datetime { $$ = $2; }
467         |
468         /* empty */ { $$ = sdb_gettime() - SDB_INTERVAL_HOUR; }
470 end_clause:
471         END datetime { $$ = $2; }
472         |
473         /* empty */ { $$ = sdb_gettime(); }
475 /*
476  * Basic expressions.
477  */
479 condition:
480         matcher
481                 {
482                         if (! $1) {
483                                 /* TODO: improve error reporting */
484                                 sdb_fe_yyerror(&yylloc, scanner,
485                                                 YY_("syntax error, invalid condition"));
486                                 YYABORT;
487                         }
489                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
490                                                 conn_matcher_t, conn_matcher_destroy));
491                         $$->cmd = SDB_CONNECTION_MATCHER;
492                         CONN_MATCHER($$)->matcher = $1;
493                 }
494         ;
496 matcher:
497         '(' matcher ')'
498                 {
499                         $$ = $2;
500                 }
501         |
502         matcher AND matcher
503                 {
504                         $$ = sdb_store_con_matcher($1, $3);
505                         sdb_object_deref(SDB_OBJ($1));
506                         sdb_object_deref(SDB_OBJ($3));
507                 }
508         |
509         matcher OR matcher
510                 {
511                         $$ = sdb_store_dis_matcher($1, $3);
512                         sdb_object_deref(SDB_OBJ($1));
513                         sdb_object_deref(SDB_OBJ($3));
514                 }
515         |
516         NOT matcher
517                 {
518                         $$ = sdb_store_inv_matcher($2);
519                         sdb_object_deref(SDB_OBJ($2));
520                 }
521         |
522         compare_matcher
523                 {
524                         $$ = $1;
525                 }
526         ;
528 compare_matcher:
529         expression cmp expression
530                 {
531                         sdb_store_matcher_op_cb cb = sdb_store_parse_matcher_op($2);
532                         assert(cb); /* else, the grammar accepts invalid 'cmp' */
533                         $$ = cb($1, $3);
534                         sdb_object_deref(SDB_OBJ($1));
535                         sdb_object_deref(SDB_OBJ($3));
536                 }
537         |
538         ANY iterable cmp expression
539                 {
540                         $$ = name_iter_matcher(MATCHER_ANY, $2, $3, $4);
541                         sdb_object_deref(SDB_OBJ($4));
542                 }
543         |
544         ALL iterable cmp expression
545                 {
546                         $$ = name_iter_matcher(MATCHER_ALL, $2, $3, $4);
547                         sdb_object_deref(SDB_OBJ($4));
548                 }
549         |
550         expression IS NULL_T
551                 {
552                         $$ = sdb_store_isnull_matcher($1);
553                         sdb_object_deref(SDB_OBJ($1));
554                 }
555         |
556         expression IS NOT NULL_T
557                 {
558                         $$ = sdb_store_isnnull_matcher($1);
559                         sdb_object_deref(SDB_OBJ($1));
560                 }
561         |
562         expression IN expression
563                 {
564                         $$ = sdb_store_in_matcher($1, $3);
565                         sdb_object_deref(SDB_OBJ($1));
566                         sdb_object_deref(SDB_OBJ($3));
567                 }
568         |
569         expression NOT IN expression
570                 {
571                         $$ = sdb_store_nin_matcher($1, $4);
572                         sdb_object_deref(SDB_OBJ($1));
573                         sdb_object_deref(SDB_OBJ($4));
574                 }
575         ;
577 expression:
578         '(' expression ')'
579                 {
580                         $$ = $2;
581                 }
582         |
583         expression '+' expression
584                 {
585                         $$ = sdb_store_expr_create(SDB_DATA_ADD, $1, $3);
586                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
587                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
588                 }
589         |
590         expression '-' expression
591                 {
592                         $$ = sdb_store_expr_create(SDB_DATA_SUB, $1, $3);
593                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
594                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
595                 }
596         |
597         expression '*' expression
598                 {
599                         $$ = sdb_store_expr_create(SDB_DATA_MUL, $1, $3);
600                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
601                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
602                 }
603         |
604         expression '/' expression
605                 {
606                         $$ = sdb_store_expr_create(SDB_DATA_DIV, $1, $3);
607                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
608                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
609                 }
610         |
611         expression '%' expression
612                 {
613                         $$ = sdb_store_expr_create(SDB_DATA_MOD, $1, $3);
614                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
615                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
616                 }
617         |
618         expression CONCAT expression
619                 {
620                         $$ = sdb_store_expr_create(SDB_DATA_CONCAT, $1, $3);
621                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
622                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
623                 }
624         |
625         object_expression
626                 {
627                         $$ = $1;
628                 }
629         |
630         data
631                 {
632                         $$ = sdb_store_expr_constvalue(&$1);
633                         sdb_data_free_datum(&$1);
634                 }
635         ;
637 object_expression:
638         object_type '.' object_expression
639                 {
640                         $$ = sdb_store_expr_typed($1, $3);
641                         sdb_object_deref(SDB_OBJ($3));
642                 }
643         |
644         field
645                 {
646                         $$ = sdb_store_expr_fieldvalue($1);
647                 }
648         |
649         ATTRIBUTE_T '[' STRING ']'
650                 {
651                         $$ = sdb_store_expr_attrvalue($3);
652                         free($3); $3 = NULL;
653                 }
654         ;
656 object_type:
657         HOST_T { $$ = SDB_HOST; }
658         |
659         SERVICE_T { $$ = SDB_SERVICE; }
660         |
661         METRIC_T { $$ = SDB_METRIC; }
662         ;
664 object_type_plural:
665         HOSTS_T { $$ = SDB_HOST; }
666         |
667         SERVICES_T { $$ = SDB_SERVICE; }
668         |
669         METRICS_T { $$ = SDB_METRIC; }
670         ;
672 iterable:
673         SERVICE_T { $$ = SDB_SERVICE; }
674         |
675         METRIC_T { $$ = SDB_METRIC; }
676         |
677         ATTRIBUTE_T { $$ = SDB_ATTRIBUTE; }
678         |
679         BACKEND_T { $$ = SDB_FIELD_BACKEND; }
680         ;
682 field:
683         NAME_T { $$ = SDB_FIELD_NAME; }
684         |
685         LAST_UPDATE_T { $$ = SDB_FIELD_LAST_UPDATE; }
686         |
687         AGE_T { $$ = SDB_FIELD_AGE; }
688         |
689         INTERVAL_T { $$ = SDB_FIELD_INTERVAL; }
690         |
691         BACKEND_T { $$ = SDB_FIELD_BACKEND; }
692         ;
694 cmp:
695         CMP_EQUAL { $$ = "="; }
696         |
697         CMP_NEQUAL { $$ = "!="; }
698         |
699         CMP_REGEX { $$ = "=~"; }
700         |
701         CMP_NREGEX { $$ = "!~"; }
702         |
703         CMP_LT { $$ = "<"; }
704         |
705         CMP_LE { $$ = "<="; }
706         |
707         CMP_GE { $$ = ">="; }
708         |
709         CMP_GT { $$ = ">"; }
710         ;
712 data:
713         STRING { $$.type = SDB_TYPE_STRING; $$.data.string = $1; }
714         |
715         INTEGER { $$ = $1; }
716         |
717         FLOAT { $$ = $1; }
718         |
719         datetime { $$.type = SDB_TYPE_DATETIME; $$.data.datetime = $1; }
720         |
721         interval { $$ = $1; }
722         |
723         array { $$ = $1; }
724         ;
726 datetime:
727         DATE TIME { $$ = $1 + $2; }
728         |
729         DATE { $$ = $1; }
730         |
731         TIME { $$ = $1; }
732         ;
734 interval:
735         interval interval_elem
736                 {
737                         $$.data.datetime = $1.data.datetime + $2.data.datetime;
738                 }
739         |
740         interval_elem { $$ = $1; }
741         ;
743 interval_elem:
744         INTEGER IDENTIFIER
745                 {
746                         sdb_time_t unit = 1;
748                         unit = sdb_strpunit($2);
749                         if (! unit) {
750                                 sdb_fe_yyerrorf(&yylloc, scanner,
751                                                 YY_("syntax error, invalid time unit %s"), $2);
752                                 free($2); $2 = NULL;
753                                 YYABORT;
754                         }
755                         free($2); $2 = NULL;
757                         $$.type = SDB_TYPE_DATETIME;
758                         $$.data.datetime = (sdb_time_t)$1.data.integer * unit;
760                         if ($1.data.integer < 0) {
761                                 sdb_fe_yyerror(&yylloc, scanner,
762                                                 YY_("syntax error, negative intervals not supported"));
763                                 YYABORT;
764                         }
765                 }
766         ;
768 array:
769         '[' array_elem_list ']'
770                 {
771                         $$ = $2;
772                 }
773         ;
775 array_elem_list:
776         array_elem_list ',' data
777                 {
778                         size_t elem_size;
780                         if (($3.type & SDB_TYPE_ARRAY) || (($1.type & 0xff) != $3.type)) {
781                                 sdb_fe_yyerrorf(&yylloc, scanner, YY_("syntax error, "
782                                                 "cannot use element of type %s in array of type %s"),
783                                                 SDB_TYPE_TO_STRING($3.type),
784                                                 SDB_TYPE_TO_STRING($1.type));
785                                 sdb_data_free_datum(&$1);
786                                 sdb_data_free_datum(&$3);
787                                 YYABORT;
788                         }
790                         elem_size = sdb_data_sizeof($3.type);
791                         $1.data.array.values = realloc($1.data.array.values,
792                                         ($1.data.array.length + 1) * elem_size);
793                         if (! $1.data.array.values) {
794                                 sdb_fe_yyerror(&yylloc, scanner, YY_("out of memory"));
795                                 YYABORT;
796                         }
798                         memcpy((char *)$1.data.array.values
799                                                 + $1.data.array.length * elem_size,
800                                         &$3.data, elem_size);
801                         ++$1.data.array.length;
803                         $$ = $1;
804                 }
805         |
806         data
807                 {
808                         size_t elem_size;
810                         if ($1.type & SDB_TYPE_ARRAY) {
811                                 sdb_fe_yyerrorf(&yylloc, scanner, YY_("syntax error, "
812                                                 "cannot construct array of type %s"),
813                                                 SDB_TYPE_TO_STRING($1.type));
814                                 sdb_data_free_datum(&$1);
815                                 YYABORT;
816                         }
818                         $$ = $1;
819                         $$.type = $1.type | SDB_TYPE_ARRAY;
820                         $$.data.array.length = 1;
821                         elem_size = sdb_data_sizeof($1.type);
822                         $$.data.array.values = malloc(elem_size);
823                         if (! $$.data.array.values ) {
824                                 sdb_fe_yyerror(&yylloc, scanner, YY_("out of memory"));
825                                 YYABORT;
826                         }
827                         memcpy($$.data.array.values, &$1.data, elem_size);
828                 }
829         ;
831 %%
833 void
834 sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg)
836         sdb_log(SDB_LOG_ERR, "frontend: parse error: %s", msg);
837         sdb_strbuf_sprintf(errbuf, "%s", msg);
838 } /* sdb_fe_yyerror */
840 void
841 sdb_fe_yyerrorf(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *fmt, ...)
843         va_list ap, aq;
844         va_start(ap, fmt);
845         va_copy(aq, ap);
846         sdb_vlog(SDB_LOG_ERR, fmt, ap);
847         sdb_strbuf_vsprintf(errbuf, "%s", aq);
848         va_end(ap);
849 } /* sdb_fe_yyerrorf */
851 static sdb_store_matcher_t *
852 name_iter_matcher(int m_type, int type, const char *cmp,
853                 sdb_store_expr_t *expr)
855         sdb_store_matcher_op_cb cb = sdb_store_parse_matcher_op(cmp);
856         sdb_store_expr_t *e;
857         sdb_store_matcher_t *m, *tmp = NULL;
858         assert(cb);
860         /* hosts are never iterable */
861         if (type == SDB_HOST) {
862                 return NULL;
863         }
865         if (type == SDB_FIELD_BACKEND)
866                 e = sdb_store_expr_fieldvalue(type);
867         else
868                 e = sdb_store_expr_fieldvalue(SDB_FIELD_NAME);
869         m = cb(e, expr);
870         if (m_type == MATCHER_ANY)
871                 tmp = sdb_store_any_matcher(type, m);
872         else if (m_type == MATCHER_ALL)
873                 tmp = sdb_store_all_matcher(type, m);
874         sdb_object_deref(SDB_OBJ(m));
875         sdb_object_deref(SDB_OBJ(e));
876         return tmp;
877 } /* name_iter_matcher */
879 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */