db3df642d3525c9ec729159eb45e4fd4034079bc
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;
109 }
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_yyerrorf(&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)
849 {
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, ...)
856 {
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, "%s", 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)
868 {
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 : */