ac899e3708212fe78b928fe6977fb86c6d5cfb2b
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, sdb_store_expr_t *iter, 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> field
174 %type <sstr> cmp
176 %type <data> data
177 interval interval_elem
178 array array_elem_list
180 %type <datetime> datetime
181 start_clause end_clause
182 last_update_clause
184 %type <metric_store> metric_store_clause
186 %destructor { free($$); } <str>
187 %destructor { sdb_object_deref(SDB_OBJ($$)); } <node> <m> <expr>
188 %destructor { sdb_data_free_datum(&$$); } <data>
190 %%
192 statements:
193 statements ';' statement
194 {
195 /* only accepted in default parse mode */
196 if (parser_mode != SDB_PARSE_DEFAULT) {
197 sdb_fe_yyerrorf(&yylloc, scanner,
198 YY_("syntax error, unexpected statement, "
199 "expecting %s"), MODE_TO_STRING(parser_mode));
200 sdb_object_deref(SDB_OBJ($3));
201 YYABORT;
202 }
204 if ($3) {
205 sdb_llist_append(pt, SDB_OBJ($3));
206 sdb_object_deref(SDB_OBJ($3));
207 }
208 }
209 |
210 statement
211 {
212 /* only accepted in default parse mode */
213 if (parser_mode != SDB_PARSE_DEFAULT) {
214 sdb_fe_yyerrorf(&yylloc, scanner,
215 YY_("syntax error, unexpected statement, "
216 "expecting %s"), MODE_TO_STRING(parser_mode));
217 sdb_object_deref(SDB_OBJ($1));
218 YYABORT;
219 }
221 if ($1) {
222 sdb_llist_append(pt, SDB_OBJ($1));
223 sdb_object_deref(SDB_OBJ($1));
224 }
225 }
226 |
227 condition
228 {
229 /* only accepted in condition parse mode */
230 if (! (parser_mode & SDB_PARSE_COND)) {
231 sdb_fe_yyerrorf(&yylloc, scanner,
232 YY_("syntax error, unexpected condition, "
233 "expecting %s"), MODE_TO_STRING(parser_mode));
234 sdb_object_deref(SDB_OBJ($1));
235 YYABORT;
236 }
238 if ($1) {
239 sdb_llist_append(pt, SDB_OBJ($1));
240 sdb_object_deref(SDB_OBJ($1));
241 }
242 }
243 |
244 expression
245 {
246 /* only accepted in expression parse mode */
247 if (! (parser_mode & SDB_PARSE_EXPR)) {
248 sdb_fe_yyerrorf(&yylloc, scanner,
249 YY_("syntax error, unexpected expression, "
250 "expecting %s"), MODE_TO_STRING(parser_mode));
251 sdb_object_deref(SDB_OBJ($1));
252 YYABORT;
253 }
255 if ($1) {
256 sdb_conn_node_t *n;
257 n = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
258 conn_expr_t, conn_expr_destroy));
259 n->cmd = SDB_CONNECTION_EXPR;
260 CONN_EXPR(n)->expr = $1;
262 sdb_llist_append(pt, SDB_OBJ(n));
263 sdb_object_deref(SDB_OBJ(n));
264 }
265 }
266 ;
268 statement:
269 fetch_statement
270 |
271 list_statement
272 |
273 lookup_statement
274 |
275 store_statement
276 |
277 timeseries_statement
278 |
279 /* empty */
280 {
281 $$ = NULL;
282 }
283 ;
285 /*
286 * FETCH <type> <hostname> [FILTER <condition>];
287 *
288 * Retrieve detailed information about a single host.
289 */
290 fetch_statement:
291 FETCH object_type STRING filter_clause
292 {
293 $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
294 conn_fetch_t, conn_fetch_destroy));
295 CONN_FETCH($$)->type = $2;
296 CONN_FETCH($$)->host = $3;
297 CONN_FETCH($$)->name = NULL;
298 CONN_FETCH($$)->filter = CONN_MATCHER($4);
299 $$->cmd = SDB_CONNECTION_FETCH;
300 }
301 |
302 FETCH object_type STRING '.' STRING filter_clause
303 {
304 $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
305 conn_fetch_t, conn_fetch_destroy));
306 CONN_FETCH($$)->type = $2;
307 CONN_FETCH($$)->host = $3;
308 CONN_FETCH($$)->name = $5;
309 CONN_FETCH($$)->filter = CONN_MATCHER($6);
310 $$->cmd = SDB_CONNECTION_FETCH;
311 }
312 ;
314 /*
315 * LIST <type> [FILTER <condition>];
316 *
317 * Returns a list of all hosts in the store.
318 */
319 list_statement:
320 LIST object_type_plural filter_clause
321 {
322 $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
323 conn_list_t, conn_list_destroy));
324 CONN_LIST($$)->type = $2;
325 CONN_LIST($$)->filter = CONN_MATCHER($3);
326 $$->cmd = SDB_CONNECTION_LIST;
327 }
328 ;
330 /*
331 * LOOKUP <type> MATCHING <condition> [FILTER <condition>];
332 *
333 * Returns detailed information about <type> matching condition.
334 */
335 lookup_statement:
336 LOOKUP object_type_plural matching_clause filter_clause
337 {
338 $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
339 conn_lookup_t, conn_lookup_destroy));
340 CONN_LOOKUP($$)->type = $2;
341 CONN_LOOKUP($$)->matcher = CONN_MATCHER($3);
342 CONN_LOOKUP($$)->filter = CONN_MATCHER($4);
343 $$->cmd = SDB_CONNECTION_LOOKUP;
344 }
345 ;
347 matching_clause:
348 MATCHING condition { $$ = $2; }
349 |
350 /* empty */ { $$ = NULL; }
352 filter_clause:
353 FILTER condition { $$ = $2; }
354 |
355 /* empty */ { $$ = NULL; }
357 /*
358 * STORE <type> <name>|<host>.<name> [LAST UPDATE <datetime>];
359 * STORE METRIC <host>.<name> STORE <type> <id> [LAST UPDATE <datetime>];
360 * STORE <type> ATTRIBUTE <parent>.<key> <datum> [LAST UPDATE <datetime>];
361 *
362 * Store or update an object in the database.
363 */
364 store_statement:
365 STORE HOST_T STRING last_update_clause
366 {
367 $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
368 conn_store_host_t, conn_store_host_destroy));
369 CONN_STORE_HOST($$)->name = $3;
370 CONN_STORE_HOST($$)->last_update = $4;
371 $$->cmd = SDB_CONNECTION_STORE_HOST;
372 }
373 |
374 STORE SERVICE_T STRING '.' STRING last_update_clause
375 {
376 $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
377 conn_store_svc_t, conn_store_svc_destroy));
378 CONN_STORE_SVC($$)->hostname = $3;
379 CONN_STORE_SVC($$)->name = $5;
380 CONN_STORE_SVC($$)->last_update = $6;
381 $$->cmd = SDB_CONNECTION_STORE_SERVICE;
382 }
383 |
384 STORE METRIC_T STRING '.' STRING metric_store_clause last_update_clause
385 {
386 $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
387 conn_store_metric_t, conn_store_metric_destroy));
388 CONN_STORE_METRIC($$)->hostname = $3;
389 CONN_STORE_METRIC($$)->name = $5;
390 CONN_STORE_METRIC($$)->store_type = $6.type;
391 CONN_STORE_METRIC($$)->store_id = $6.id;
392 CONN_STORE_METRIC($$)->last_update = $7;
393 $$->cmd = SDB_CONNECTION_STORE_METRIC;
394 }
395 |
396 STORE HOST_T ATTRIBUTE_T STRING '.' STRING data last_update_clause
397 {
398 $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
399 conn_store_attr_t, conn_store_attr_destroy));
400 CONN_STORE_ATTR($$)->parent_type = SDB_HOST;
401 CONN_STORE_ATTR($$)->hostname = NULL;
402 CONN_STORE_ATTR($$)->parent = $4;
403 CONN_STORE_ATTR($$)->key = $6;
404 CONN_STORE_ATTR($$)->value = $7;
405 CONN_STORE_ATTR($$)->last_update = $8;
406 $$->cmd = SDB_CONNECTION_STORE_ATTRIBUTE;
407 }
408 |
409 STORE SERVICE_T ATTRIBUTE_T STRING '.' STRING '.' STRING data last_update_clause
410 {
411 $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
412 conn_store_attr_t, conn_store_attr_destroy));
413 CONN_STORE_ATTR($$)->parent_type = SDB_SERVICE;
414 CONN_STORE_ATTR($$)->hostname = $4;
415 CONN_STORE_ATTR($$)->parent = $6;
416 CONN_STORE_ATTR($$)->key = $8;
417 CONN_STORE_ATTR($$)->value = $9;
418 CONN_STORE_ATTR($$)->last_update = $10;
419 $$->cmd = SDB_CONNECTION_STORE_ATTRIBUTE;
420 }
421 |
422 STORE METRIC_T ATTRIBUTE_T STRING '.' STRING '.' STRING data last_update_clause
423 {
424 $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
425 conn_store_attr_t, conn_store_attr_destroy));
426 CONN_STORE_ATTR($$)->parent_type = SDB_METRIC;
427 CONN_STORE_ATTR($$)->hostname = $4;
428 CONN_STORE_ATTR($$)->parent = $6;
429 CONN_STORE_ATTR($$)->key = $8;
430 CONN_STORE_ATTR($$)->value = $9;
431 CONN_STORE_ATTR($$)->last_update = $10;
432 $$->cmd = SDB_CONNECTION_STORE_ATTRIBUTE;
433 }
434 ;
436 last_update_clause:
437 LAST UPDATE datetime { $$ = $3; }
438 |
439 /* empty */ { $$ = sdb_gettime(); }
441 metric_store_clause:
442 STORE STRING STRING { $$.type = $2; $$.id = $3; }
443 |
444 /* empty */ { $$.type = $$.id = NULL; }
446 /*
447 * TIMESERIES <host>.<metric> [START <datetime>] [END <datetime>];
448 *
449 * Returns a time-series for the specified host's metric.
450 */
451 timeseries_statement:
452 TIMESERIES STRING '.' STRING start_clause end_clause
453 {
454 $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
455 conn_ts_t, conn_ts_destroy));
456 CONN_TS($$)->hostname = $2;
457 CONN_TS($$)->metric = $4;
458 CONN_TS($$)->opts.start = $5;
459 CONN_TS($$)->opts.end = $6;
460 $$->cmd = SDB_CONNECTION_TIMESERIES;
461 }
462 ;
464 start_clause:
465 START datetime { $$ = $2; }
466 |
467 /* empty */ { $$ = sdb_gettime() - SDB_INTERVAL_HOUR; }
469 end_clause:
470 END datetime { $$ = $2; }
471 |
472 /* empty */ { $$ = sdb_gettime(); }
474 /*
475 * Basic expressions.
476 */
478 condition:
479 matcher
480 {
481 if (! $1) {
482 /* TODO: improve error reporting */
483 sdb_fe_yyerror(&yylloc, scanner,
484 YY_("syntax error, invalid condition"));
485 YYABORT;
486 }
488 $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
489 conn_matcher_t, conn_matcher_destroy));
490 $$->cmd = SDB_CONNECTION_MATCHER;
491 CONN_MATCHER($$)->matcher = $1;
492 }
493 ;
495 matcher:
496 '(' matcher ')'
497 {
498 $$ = $2;
499 }
500 |
501 matcher AND matcher
502 {
503 $$ = sdb_store_con_matcher($1, $3);
504 sdb_object_deref(SDB_OBJ($1));
505 sdb_object_deref(SDB_OBJ($3));
506 }
507 |
508 matcher OR matcher
509 {
510 $$ = sdb_store_dis_matcher($1, $3);
511 sdb_object_deref(SDB_OBJ($1));
512 sdb_object_deref(SDB_OBJ($3));
513 }
514 |
515 NOT matcher
516 {
517 $$ = sdb_store_inv_matcher($2);
518 sdb_object_deref(SDB_OBJ($2));
519 }
520 |
521 compare_matcher
522 {
523 $$ = $1;
524 }
525 ;
527 compare_matcher:
528 expression cmp expression
529 {
530 sdb_store_matcher_op_cb cb = sdb_store_parse_matcher_op($2);
531 assert(cb); /* else, the grammar accepts invalid 'cmp' */
532 $$ = cb($1, $3);
533 sdb_object_deref(SDB_OBJ($1));
534 sdb_object_deref(SDB_OBJ($3));
535 }
536 |
537 ANY expression cmp expression
538 {
539 $$ = name_iter_matcher(MATCHER_ANY, $2, $3, $4);
540 sdb_object_deref(SDB_OBJ($2));
541 sdb_object_deref(SDB_OBJ($4));
542 }
543 |
544 ALL expression cmp expression
545 {
546 $$ = name_iter_matcher(MATCHER_ALL, $2, $3, $4);
547 sdb_object_deref(SDB_OBJ($2));
548 sdb_object_deref(SDB_OBJ($4));
549 }
550 |
551 expression IS NULL_T
552 {
553 $$ = sdb_store_isnull_matcher($1);
554 sdb_object_deref(SDB_OBJ($1));
555 }
556 |
557 expression IS NOT NULL_T
558 {
559 $$ = sdb_store_isnnull_matcher($1);
560 sdb_object_deref(SDB_OBJ($1));
561 }
562 |
563 expression IN expression
564 {
565 $$ = sdb_store_in_matcher($1, $3);
566 sdb_object_deref(SDB_OBJ($1));
567 sdb_object_deref(SDB_OBJ($3));
568 }
569 |
570 expression NOT IN expression
571 {
572 $$ = sdb_store_nin_matcher($1, $4);
573 sdb_object_deref(SDB_OBJ($1));
574 sdb_object_deref(SDB_OBJ($4));
575 }
576 ;
578 expression:
579 arithmetic_expression
580 {
581 if (! $1) {
582 /* we should have better error messages here
583 * TODO: maybe let the analyzer handle this instead */
584 sdb_fe_yyerror(&yylloc, scanner,
585 YY_("syntax error, invalid arithmetic expression"));
586 YYABORT;
587 }
588 $$ = $1;
589 }
590 |
591 object_expression
592 {
593 $$ = $1;
594 }
595 |
596 data
597 {
598 $$ = sdb_store_expr_constvalue(&$1);
599 sdb_data_free_datum(&$1);
600 }
601 ;
603 arithmetic_expression:
604 '(' expression ')'
605 {
606 $$ = $2;
607 }
608 |
609 expression '+' expression
610 {
611 $$ = sdb_store_expr_create(SDB_DATA_ADD, $1, $3);
612 sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
613 sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
614 }
615 |
616 expression '-' expression
617 {
618 $$ = sdb_store_expr_create(SDB_DATA_SUB, $1, $3);
619 sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
620 sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
621 }
622 |
623 expression '*' expression
624 {
625 $$ = sdb_store_expr_create(SDB_DATA_MUL, $1, $3);
626 sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
627 sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
628 }
629 |
630 expression '/' expression
631 {
632 $$ = sdb_store_expr_create(SDB_DATA_DIV, $1, $3);
633 sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
634 sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
635 }
636 |
637 expression '%' expression
638 {
639 $$ = sdb_store_expr_create(SDB_DATA_MOD, $1, $3);
640 sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
641 sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
642 }
643 |
644 expression CONCAT expression
645 {
646 $$ = sdb_store_expr_create(SDB_DATA_CONCAT, $1, $3);
647 sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
648 sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
649 }
650 ;
652 object_expression:
653 object_type '.' object_expression
654 {
655 $$ = sdb_store_expr_typed($1, $3);
656 sdb_object_deref(SDB_OBJ($3));
657 }
658 |
659 ATTRIBUTE_T '.' object_expression
660 {
661 $$ = sdb_store_expr_typed(SDB_ATTRIBUTE, $3);
662 sdb_object_deref(SDB_OBJ($3));
663 }
664 |
665 field
666 {
667 $$ = sdb_store_expr_fieldvalue($1);
668 }
669 |
670 ATTRIBUTE_T '[' STRING ']'
671 {
672 $$ = sdb_store_expr_attrvalue($3);
673 free($3); $3 = NULL;
674 }
675 ;
677 object_type:
678 HOST_T { $$ = SDB_HOST; }
679 |
680 SERVICE_T { $$ = SDB_SERVICE; }
681 |
682 METRIC_T { $$ = SDB_METRIC; }
683 ;
685 object_type_plural:
686 HOSTS_T { $$ = SDB_HOST; }
687 |
688 SERVICES_T { $$ = SDB_SERVICE; }
689 |
690 METRICS_T { $$ = SDB_METRIC; }
691 ;
693 field:
694 NAME_T { $$ = SDB_FIELD_NAME; }
695 |
696 LAST_UPDATE_T { $$ = SDB_FIELD_LAST_UPDATE; }
697 |
698 AGE_T { $$ = SDB_FIELD_AGE; }
699 |
700 INTERVAL_T { $$ = SDB_FIELD_INTERVAL; }
701 |
702 BACKEND_T { $$ = SDB_FIELD_BACKEND; }
703 ;
705 cmp:
706 CMP_EQUAL { $$ = "="; }
707 |
708 CMP_NEQUAL { $$ = "!="; }
709 |
710 CMP_REGEX { $$ = "=~"; }
711 |
712 CMP_NREGEX { $$ = "!~"; }
713 |
714 CMP_LT { $$ = "<"; }
715 |
716 CMP_LE { $$ = "<="; }
717 |
718 CMP_GE { $$ = ">="; }
719 |
720 CMP_GT { $$ = ">"; }
721 ;
723 data:
724 STRING { $$.type = SDB_TYPE_STRING; $$.data.string = $1; }
725 |
726 INTEGER { $$ = $1; }
727 |
728 FLOAT { $$ = $1; }
729 |
730 datetime { $$.type = SDB_TYPE_DATETIME; $$.data.datetime = $1; }
731 |
732 interval { $$ = $1; }
733 |
734 array { $$ = $1; }
735 ;
737 datetime:
738 DATE TIME { $$ = $1 + $2; }
739 |
740 DATE { $$ = $1; }
741 |
742 TIME { $$ = $1; }
743 ;
745 interval:
746 interval interval_elem
747 {
748 $$.data.datetime = $1.data.datetime + $2.data.datetime;
749 }
750 |
751 interval_elem { $$ = $1; }
752 ;
754 interval_elem:
755 INTEGER IDENTIFIER
756 {
757 sdb_time_t unit = 1;
759 unit = sdb_strpunit($2);
760 if (! unit) {
761 sdb_fe_yyerrorf(&yylloc, scanner,
762 YY_("syntax error, invalid time unit %s"), $2);
763 free($2); $2 = NULL;
764 YYABORT;
765 }
766 free($2); $2 = NULL;
768 $$.type = SDB_TYPE_DATETIME;
769 $$.data.datetime = (sdb_time_t)$1.data.integer * unit;
771 if ($1.data.integer < 0) {
772 sdb_fe_yyerror(&yylloc, scanner,
773 YY_("syntax error, negative intervals not supported"));
774 YYABORT;
775 }
776 }
777 ;
779 array:
780 '[' array_elem_list ']'
781 {
782 $$ = $2;
783 }
784 ;
786 array_elem_list:
787 array_elem_list ',' data
788 {
789 size_t elem_size;
791 if (($3.type & SDB_TYPE_ARRAY) || (($1.type & 0xff) != $3.type)) {
792 sdb_fe_yyerrorf(&yylloc, scanner, YY_("syntax error, "
793 "cannot use element of type %s in array of type %s"),
794 SDB_TYPE_TO_STRING($3.type),
795 SDB_TYPE_TO_STRING($1.type));
796 sdb_data_free_datum(&$1);
797 sdb_data_free_datum(&$3);
798 YYABORT;
799 }
801 elem_size = sdb_data_sizeof($3.type);
802 $1.data.array.values = realloc($1.data.array.values,
803 ($1.data.array.length + 1) * elem_size);
804 if (! $1.data.array.values) {
805 sdb_fe_yyerror(&yylloc, scanner, YY_("out of memory"));
806 YYABORT;
807 }
809 memcpy((char *)$1.data.array.values
810 + $1.data.array.length * elem_size,
811 &$3.data, elem_size);
812 ++$1.data.array.length;
814 $$ = $1;
815 }
816 |
817 data
818 {
819 size_t elem_size;
821 if ($1.type & SDB_TYPE_ARRAY) {
822 sdb_fe_yyerrorf(&yylloc, scanner, YY_("syntax error, "
823 "cannot construct array of type %s"),
824 SDB_TYPE_TO_STRING($1.type));
825 sdb_data_free_datum(&$1);
826 YYABORT;
827 }
829 $$ = $1;
830 $$.type = $1.type | SDB_TYPE_ARRAY;
831 $$.data.array.length = 1;
832 elem_size = sdb_data_sizeof($1.type);
833 $$.data.array.values = malloc(elem_size);
834 if (! $$.data.array.values ) {
835 sdb_fe_yyerror(&yylloc, scanner, YY_("out of memory"));
836 YYABORT;
837 }
838 memcpy($$.data.array.values, &$1.data, elem_size);
839 }
840 ;
842 %%
844 void
845 sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg)
846 {
847 sdb_log(SDB_LOG_ERR, "frontend: parse error: %s", msg);
848 sdb_strbuf_sprintf(errbuf, "%s", msg);
849 } /* sdb_fe_yyerror */
851 void
852 sdb_fe_yyerrorf(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *fmt, ...)
853 {
854 va_list ap, aq;
855 va_start(ap, fmt);
856 va_copy(aq, ap);
857 sdb_vlog(SDB_LOG_ERR, fmt, ap);
858 sdb_strbuf_vsprintf(errbuf, fmt, aq);
859 va_end(ap);
860 } /* sdb_fe_yyerrorf */
862 static sdb_store_matcher_t *
863 name_iter_matcher(int type, sdb_store_expr_t *iter, const char *cmp,
864 sdb_store_expr_t *expr)
865 {
866 sdb_store_matcher_op_cb cb = sdb_store_parse_matcher_op(cmp);
867 sdb_store_matcher_t *m, *tmp = NULL;
868 assert(cb);
870 m = cb(iter, expr);
871 if (type == MATCHER_ANY)
872 tmp = sdb_store_any_matcher(iter, m);
873 else if (type == MATCHER_ALL)
874 tmp = sdb_store_all_matcher(iter, m);
875 sdb_object_deref(SDB_OBJ(m));
876 return tmp;
877 } /* name_iter_matcher */
879 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */