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 |
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)
835 {
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, ...)
842 {
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)
854 {
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 : */