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 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 ;
570 expression:
571 '(' expression ')'
572 {
573 $$ = $2;
574 }
575 |
576 expression '+' expression
577 {
578 $$ = sdb_store_expr_create(SDB_DATA_ADD, $1, $3);
579 sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
580 sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
581 }
582 |
583 expression '-' expression
584 {
585 $$ = sdb_store_expr_create(SDB_DATA_SUB, $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_MUL, $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_DIV, $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_MOD, $1, $3);
607 sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
608 sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
609 }
610 |
611 expression CONCAT expression
612 {
613 $$ = sdb_store_expr_create(SDB_DATA_CONCAT, $1, $3);
614 sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
615 sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
616 }
617 |
618 object_expression
619 {
620 $$ = $1;
621 }
622 |
623 data
624 {
625 $$ = sdb_store_expr_constvalue(&$1);
626 sdb_data_free_datum(&$1);
627 }
628 ;
630 object_expression:
631 object_type '.' object_expression
632 {
633 $$ = sdb_store_expr_typed($1, $3);
634 sdb_object_deref(SDB_OBJ($3));
635 }
636 |
637 field
638 {
639 $$ = sdb_store_expr_fieldvalue($1);
640 }
641 |
642 ATTRIBUTE_T '[' STRING ']'
643 {
644 $$ = sdb_store_expr_attrvalue($3);
645 free($3); $3 = NULL;
646 }
647 ;
649 object_type:
650 HOST_T { $$ = SDB_HOST; }
651 |
652 SERVICE_T { $$ = SDB_SERVICE; }
653 |
654 METRIC_T { $$ = SDB_METRIC; }
655 ;
657 object_type_plural:
658 HOSTS_T { $$ = SDB_HOST; }
659 |
660 SERVICES_T { $$ = SDB_SERVICE; }
661 |
662 METRICS_T { $$ = SDB_METRIC; }
663 ;
665 iterable:
666 SERVICE_T { $$ = SDB_SERVICE; }
667 |
668 METRIC_T { $$ = SDB_METRIC; }
669 |
670 ATTRIBUTE_T { $$ = SDB_ATTRIBUTE; }
671 |
672 BACKEND_T { $$ = SDB_FIELD_BACKEND; }
673 ;
675 field:
676 NAME_T { $$ = SDB_FIELD_NAME; }
677 |
678 LAST_UPDATE_T { $$ = SDB_FIELD_LAST_UPDATE; }
679 |
680 AGE_T { $$ = SDB_FIELD_AGE; }
681 |
682 INTERVAL_T { $$ = SDB_FIELD_INTERVAL; }
683 |
684 BACKEND_T { $$ = SDB_FIELD_BACKEND; }
685 ;
687 cmp:
688 CMP_EQUAL { $$ = "="; }
689 |
690 CMP_NEQUAL { $$ = "!="; }
691 |
692 CMP_REGEX { $$ = "=~"; }
693 |
694 CMP_NREGEX { $$ = "!~"; }
695 |
696 CMP_LT { $$ = "<"; }
697 |
698 CMP_LE { $$ = "<="; }
699 |
700 CMP_GE { $$ = ">="; }
701 |
702 CMP_GT { $$ = ">"; }
703 ;
705 data:
706 STRING { $$.type = SDB_TYPE_STRING; $$.data.string = $1; }
707 |
708 INTEGER { $$ = $1; }
709 |
710 FLOAT { $$ = $1; }
711 |
712 datetime { $$.type = SDB_TYPE_DATETIME; $$.data.datetime = $1; }
713 |
714 interval { $$ = $1; }
715 |
716 array { $$ = $1; }
717 ;
719 datetime:
720 DATE TIME { $$ = $1 + $2; }
721 |
722 DATE { $$ = $1; }
723 |
724 TIME { $$ = $1; }
725 ;
727 interval:
728 interval interval_elem
729 {
730 $$.data.datetime = $1.data.datetime + $2.data.datetime;
731 }
732 |
733 interval_elem { $$ = $1; }
734 ;
736 interval_elem:
737 INTEGER IDENTIFIER
738 {
739 sdb_time_t unit = 1;
741 unit = sdb_strpunit($2);
742 if (! unit) {
743 sdb_fe_yyerrorf(&yylloc, scanner,
744 YY_("syntax error, invalid time unit %s"), $2);
745 free($2); $2 = NULL;
746 YYABORT;
747 }
748 free($2); $2 = NULL;
750 $$.type = SDB_TYPE_DATETIME;
751 $$.data.datetime = (sdb_time_t)$1.data.integer * unit;
753 if ($1.data.integer < 0) {
754 sdb_fe_yyerror(&yylloc, scanner,
755 YY_("syntax error, negative intervals not supported"));
756 YYABORT;
757 }
758 }
759 ;
761 array:
762 '[' array_elem_list ']'
763 {
764 $$ = $2;
765 }
766 ;
768 array_elem_list:
769 array_elem_list ',' data
770 {
771 size_t elem_size;
773 if (($3.type & SDB_TYPE_ARRAY) || (($1.type & 0xff) != $3.type)) {
774 sdb_fe_yyerrorf(&yylloc, scanner, YY_("syntax error, "
775 "cannot use element of type %s in array of type %s"),
776 SDB_TYPE_TO_STRING($3.type),
777 SDB_TYPE_TO_STRING($1.type));
778 sdb_data_free_datum(&$1);
779 sdb_data_free_datum(&$3);
780 YYABORT;
781 }
783 elem_size = sdb_data_sizeof($3.type);
784 $1.data.array.values = realloc($1.data.array.values,
785 ($1.data.array.length + 1) * elem_size);
786 if (! $1.data.array.values) {
787 sdb_fe_yyerror(&yylloc, scanner, YY_("out of memory"));
788 YYABORT;
789 }
791 memcpy((char *)$1.data.array.values
792 + $1.data.array.length * elem_size,
793 &$3.data, elem_size);
794 ++$1.data.array.length;
796 $$ = $1;
797 }
798 |
799 data
800 {
801 size_t elem_size;
803 if ($1.type & SDB_TYPE_ARRAY) {
804 sdb_fe_yyerrorf(&yylloc, scanner, YY_("syntax error, "
805 "cannot construct array of type %s"),
806 SDB_TYPE_TO_STRING($1.type));
807 sdb_data_free_datum(&$1);
808 YYABORT;
809 }
811 $$ = $1;
812 $$.type = $1.type | SDB_TYPE_ARRAY;
813 $$.data.array.length = 1;
814 elem_size = sdb_data_sizeof($1.type);
815 $$.data.array.values = malloc(elem_size);
816 if (! $$.data.array.values ) {
817 sdb_fe_yyerror(&yylloc, scanner, YY_("out of memory"));
818 YYABORT;
819 }
820 memcpy($$.data.array.values, &$1.data, elem_size);
821 }
822 ;
824 %%
826 void
827 sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg)
828 {
829 sdb_log(SDB_LOG_ERR, "frontend: parse error: %s", msg);
830 sdb_strbuf_sprintf(errbuf, "%s", msg);
831 } /* sdb_fe_yyerror */
833 void
834 sdb_fe_yyerrorf(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *fmt, ...)
835 {
836 va_list ap, aq;
837 va_start(ap, fmt);
838 va_copy(aq, ap);
839 sdb_vlog(SDB_LOG_ERR, fmt, ap);
840 sdb_strbuf_vsprintf(errbuf, "%s", aq);
841 va_end(ap);
842 } /* sdb_fe_yyerrorf */
844 static sdb_store_matcher_t *
845 name_iter_matcher(int m_type, int type, const char *cmp,
846 sdb_store_expr_t *expr)
847 {
848 sdb_store_matcher_op_cb cb = sdb_store_parse_matcher_op(cmp);
849 sdb_store_expr_t *e;
850 sdb_store_matcher_t *m, *tmp = NULL;
851 assert(cb);
853 /* hosts are never iterable */
854 if (type == SDB_HOST) {
855 return NULL;
856 }
858 if (type == SDB_FIELD_BACKEND)
859 e = sdb_store_expr_fieldvalue(type);
860 else
861 e = sdb_store_expr_fieldvalue(SDB_FIELD_NAME);
862 m = cb(e, expr);
863 if (m_type == MATCHER_ANY)
864 tmp = sdb_store_any_matcher(type, m);
865 else if (m_type == MATCHER_ALL)
866 tmp = sdb_store_all_matcher(type, m);
867 sdb_object_deref(SDB_OBJ(m));
868 sdb_object_deref(SDB_OBJ(e));
869 return tmp;
870 } /* name_iter_matcher */
872 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */