Code

frontend/grammar: Fixed format argument used in yyerrorf().
[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 arithmetic_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         arithmetic_expression
579                 {
580                         if (! $1) {
581                                 /* we should have better error messages here
582                                  * TODO: maybe let the analyzer handle this instead */
583                                 sdb_fe_yyerror(&yylloc, scanner,
584                                                 YY_("syntax error, invalid arithmetic expression"));
585                                 YYABORT;
586                         }
587                         $$ = $1;
588                 }
589         |
590         object_expression
591                 {
592                         $$ = $1;
593                 }
594         |
595         data
596                 {
597                         $$ = sdb_store_expr_constvalue(&$1);
598                         sdb_data_free_datum(&$1);
599                 }
600         ;
602 arithmetic_expression:
603         '(' expression ')'
604                 {
605                         $$ = $2;
606                 }
607         |
608         expression '+' expression
609                 {
610                         $$ = sdb_store_expr_create(SDB_DATA_ADD, $1, $3);
611                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
612                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
613                 }
614         |
615         expression '-' expression
616                 {
617                         $$ = sdb_store_expr_create(SDB_DATA_SUB, $1, $3);
618                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
619                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
620                 }
621         |
622         expression '*' expression
623                 {
624                         $$ = sdb_store_expr_create(SDB_DATA_MUL, $1, $3);
625                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
626                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
627                 }
628         |
629         expression '/' expression
630                 {
631                         $$ = sdb_store_expr_create(SDB_DATA_DIV, $1, $3);
632                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
633                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
634                 }
635         |
636         expression '%' expression
637                 {
638                         $$ = sdb_store_expr_create(SDB_DATA_MOD, $1, $3);
639                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
640                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
641                 }
642         |
643         expression CONCAT expression
644                 {
645                         $$ = sdb_store_expr_create(SDB_DATA_CONCAT, $1, $3);
646                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
647                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
648                 }
649         ;
651 object_expression:
652         object_type '.' object_expression
653                 {
654                         $$ = sdb_store_expr_typed($1, $3);
655                         sdb_object_deref(SDB_OBJ($3));
656                 }
657         |
658         field
659                 {
660                         $$ = sdb_store_expr_fieldvalue($1);
661                 }
662         |
663         ATTRIBUTE_T '[' STRING ']'
664                 {
665                         $$ = sdb_store_expr_attrvalue($3);
666                         free($3); $3 = NULL;
667                 }
668         ;
670 object_type:
671         HOST_T { $$ = SDB_HOST; }
672         |
673         SERVICE_T { $$ = SDB_SERVICE; }
674         |
675         METRIC_T { $$ = SDB_METRIC; }
676         ;
678 object_type_plural:
679         HOSTS_T { $$ = SDB_HOST; }
680         |
681         SERVICES_T { $$ = SDB_SERVICE; }
682         |
683         METRICS_T { $$ = SDB_METRIC; }
684         ;
686 iterable:
687         SERVICE_T { $$ = SDB_SERVICE; }
688         |
689         METRIC_T { $$ = SDB_METRIC; }
690         |
691         ATTRIBUTE_T { $$ = SDB_ATTRIBUTE; }
692         |
693         BACKEND_T { $$ = SDB_FIELD_BACKEND; }
694         ;
696 field:
697         NAME_T { $$ = SDB_FIELD_NAME; }
698         |
699         LAST_UPDATE_T { $$ = SDB_FIELD_LAST_UPDATE; }
700         |
701         AGE_T { $$ = SDB_FIELD_AGE; }
702         |
703         INTERVAL_T { $$ = SDB_FIELD_INTERVAL; }
704         |
705         BACKEND_T { $$ = SDB_FIELD_BACKEND; }
706         ;
708 cmp:
709         CMP_EQUAL { $$ = "="; }
710         |
711         CMP_NEQUAL { $$ = "!="; }
712         |
713         CMP_REGEX { $$ = "=~"; }
714         |
715         CMP_NREGEX { $$ = "!~"; }
716         |
717         CMP_LT { $$ = "<"; }
718         |
719         CMP_LE { $$ = "<="; }
720         |
721         CMP_GE { $$ = ">="; }
722         |
723         CMP_GT { $$ = ">"; }
724         ;
726 data:
727         STRING { $$.type = SDB_TYPE_STRING; $$.data.string = $1; }
728         |
729         INTEGER { $$ = $1; }
730         |
731         FLOAT { $$ = $1; }
732         |
733         datetime { $$.type = SDB_TYPE_DATETIME; $$.data.datetime = $1; }
734         |
735         interval { $$ = $1; }
736         |
737         array { $$ = $1; }
738         ;
740 datetime:
741         DATE TIME { $$ = $1 + $2; }
742         |
743         DATE { $$ = $1; }
744         |
745         TIME { $$ = $1; }
746         ;
748 interval:
749         interval interval_elem
750                 {
751                         $$.data.datetime = $1.data.datetime + $2.data.datetime;
752                 }
753         |
754         interval_elem { $$ = $1; }
755         ;
757 interval_elem:
758         INTEGER IDENTIFIER
759                 {
760                         sdb_time_t unit = 1;
762                         unit = sdb_strpunit($2);
763                         if (! unit) {
764                                 sdb_fe_yyerrorf(&yylloc, scanner,
765                                                 YY_("syntax error, invalid time unit %s"), $2);
766                                 free($2); $2 = NULL;
767                                 YYABORT;
768                         }
769                         free($2); $2 = NULL;
771                         $$.type = SDB_TYPE_DATETIME;
772                         $$.data.datetime = (sdb_time_t)$1.data.integer * unit;
774                         if ($1.data.integer < 0) {
775                                 sdb_fe_yyerror(&yylloc, scanner,
776                                                 YY_("syntax error, negative intervals not supported"));
777                                 YYABORT;
778                         }
779                 }
780         ;
782 array:
783         '[' array_elem_list ']'
784                 {
785                         $$ = $2;
786                 }
787         ;
789 array_elem_list:
790         array_elem_list ',' data
791                 {
792                         size_t elem_size;
794                         if (($3.type & SDB_TYPE_ARRAY) || (($1.type & 0xff) != $3.type)) {
795                                 sdb_fe_yyerrorf(&yylloc, scanner, YY_("syntax error, "
796                                                 "cannot use element of type %s in array of type %s"),
797                                                 SDB_TYPE_TO_STRING($3.type),
798                                                 SDB_TYPE_TO_STRING($1.type));
799                                 sdb_data_free_datum(&$1);
800                                 sdb_data_free_datum(&$3);
801                                 YYABORT;
802                         }
804                         elem_size = sdb_data_sizeof($3.type);
805                         $1.data.array.values = realloc($1.data.array.values,
806                                         ($1.data.array.length + 1) * elem_size);
807                         if (! $1.data.array.values) {
808                                 sdb_fe_yyerror(&yylloc, scanner, YY_("out of memory"));
809                                 YYABORT;
810                         }
812                         memcpy((char *)$1.data.array.values
813                                                 + $1.data.array.length * elem_size,
814                                         &$3.data, elem_size);
815                         ++$1.data.array.length;
817                         $$ = $1;
818                 }
819         |
820         data
821                 {
822                         size_t elem_size;
824                         if ($1.type & SDB_TYPE_ARRAY) {
825                                 sdb_fe_yyerrorf(&yylloc, scanner, YY_("syntax error, "
826                                                 "cannot construct array of type %s"),
827                                                 SDB_TYPE_TO_STRING($1.type));
828                                 sdb_data_free_datum(&$1);
829                                 YYABORT;
830                         }
832                         $$ = $1;
833                         $$.type = $1.type | SDB_TYPE_ARRAY;
834                         $$.data.array.length = 1;
835                         elem_size = sdb_data_sizeof($1.type);
836                         $$.data.array.values = malloc(elem_size);
837                         if (! $$.data.array.values ) {
838                                 sdb_fe_yyerror(&yylloc, scanner, YY_("out of memory"));
839                                 YYABORT;
840                         }
841                         memcpy($$.data.array.values, &$1.data, elem_size);
842                 }
843         ;
845 %%
847 void
848 sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg)
850         sdb_log(SDB_LOG_ERR, "frontend: parse error: %s", msg);
851         sdb_strbuf_sprintf(errbuf, "%s", msg);
852 } /* sdb_fe_yyerror */
854 void
855 sdb_fe_yyerrorf(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *fmt, ...)
857         va_list ap, aq;
858         va_start(ap, fmt);
859         va_copy(aq, ap);
860         sdb_vlog(SDB_LOG_ERR, fmt, ap);
861         sdb_strbuf_vsprintf(errbuf, fmt, aq);
862         va_end(ap);
863 } /* sdb_fe_yyerrorf */
865 static sdb_store_matcher_t *
866 name_iter_matcher(int m_type, int type, const char *cmp,
867                 sdb_store_expr_t *expr)
869         sdb_store_matcher_op_cb cb = sdb_store_parse_matcher_op(cmp);
870         sdb_store_expr_t *e;
871         sdb_store_matcher_t *m, *tmp = NULL;
872         assert(cb);
874         /* hosts are never iterable */
875         if (type == SDB_HOST) {
876                 return NULL;
877         }
879         if (type == SDB_FIELD_BACKEND)
880                 e = sdb_store_expr_fieldvalue(type);
881         else
882                 e = sdb_store_expr_fieldvalue(SDB_FIELD_NAME);
883         m = cb(e, expr);
884         if (m_type == MATCHER_ANY)
885                 tmp = sdb_store_any_matcher(type, m);
886         else if (m_type == MATCHER_ALL)
887                 tmp = sdb_store_all_matcher(type, m);
888         sdb_object_deref(SDB_OBJ(m));
889         sdb_object_deref(SDB_OBJ(e));
890         return tmp;
891 } /* name_iter_matcher */
893 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */