1 /*
2 * SysDB - src/parser/grammar.y
3 * Copyright (C) 2013-2015 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 /*
29 * Grammar for the SysDB Query Language (SysQL).
30 */
32 %{
34 #include "core/store.h"
35 #include "core/time.h"
37 #include "parser/ast.h"
38 #include "parser/parser.h"
39 #include "parser/grammar.h"
41 #include "utils/error.h"
42 #include "utils/llist.h"
44 #include <assert.h>
46 #include <stdio.h>
47 #include <string.h>
49 /*
50 * public API
51 */
53 int
54 sdb_parser_yylex(YYSTYPE *yylval, YYLTYPE *yylloc, sdb_parser_yyscan_t yyscanner);
56 sdb_parser_yyextra_t *
57 sdb_parser_yyget_extra(sdb_parser_yyscan_t scanner);
59 void
60 sdb_parser_yyerror(YYLTYPE *lval, sdb_parser_yyscan_t scanner, const char *msg);
61 void
62 sdb_parser_yyerrorf(YYLTYPE *lval, sdb_parser_yyscan_t scanner, const char *fmt, ...);
64 /* quick access to the current parse tree */
65 #define pt sdb_parser_yyget_extra(scanner)->parsetree
67 /* quick access to the parser mode */
68 #define parser_mode sdb_parser_yyget_extra(scanner)->mode
70 /* quick access to the parser's error buffer */
71 #define errbuf sdb_parser_yyget_extra(scanner)->errbuf
73 #define CK_OOM(p) \
74 do { \
75 if (! (p)) { \
76 sdb_parser_yyerror(&yylloc, scanner, YY_("out of memory")); \
77 YYABORT; \
78 } \
79 } while (0)
81 #define MODE_TO_STRING(m) \
82 (((m) == SDB_PARSE_DEFAULT) ? "statement" \
83 : ((m) == SDB_PARSE_COND) ? "condition" \
84 : ((m) == SDB_PARSE_ARITH) ? "arithmetic expression" \
85 : "UNKNOWN")
87 %}
89 %pure-parser
90 %lex-param {sdb_parser_yyscan_t scanner}
91 %parse-param {sdb_parser_yyscan_t scanner}
92 %locations
93 %error-verbose
94 %expect 0
95 %name-prefix "sdb_parser_yy"
97 %union {
98 char *str;
99 int integer;
101 sdb_data_t data;
102 sdb_time_t datetime;
104 sdb_llist_t *list;
105 sdb_ast_node_t *node;
107 struct { char *type; char *id; sdb_time_t last_update; } metric_store;
108 }
110 %start statements
112 %token SCANNER_ERROR
114 %token AND OR IS NOT MATCHING FILTER
115 %token CMP_EQUAL CMP_NEQUAL CMP_REGEX CMP_NREGEX
116 %token CMP_LT CMP_LE CMP_GE CMP_GT ALL ANY IN
117 %token CONCAT
119 %token HOST_T HOSTS_T SERVICE_T SERVICES_T METRIC_T METRICS_T
120 %token ATTRIBUTE_T ATTRIBUTES_T
121 %token NAME_T LAST_UPDATE_T AGE_T INTERVAL_T BACKEND_T VALUE_T
123 %token LAST UPDATE
125 %token START END
127 /* NULL token */
128 %token NULL_T
130 %token TRUE FALSE
132 %token FETCH LIST LOOKUP STORE TIMESERIES
134 %token <str> IDENTIFIER STRING
136 %token <data> INTEGER FLOAT
138 %token <datetime> DATE TIME
140 /* Precedence (lowest first): */
141 %left OR
142 %left AND
143 %right NOT
144 %left CMP_EQUAL CMP_NEQUAL
145 %left CMP_LT CMP_LE CMP_GE CMP_GT
146 %nonassoc CMP_REGEX CMP_NREGEX
147 %nonassoc IN
148 %left CONCAT
149 %nonassoc IS
150 %left '+' '-'
151 %left '*' '/' '%'
152 %left '[' ']'
153 %left '(' ')'
154 %left '.'
156 %type <list> statements
157 %type <node> statement
158 fetch_statement
159 list_statement
160 lookup_statement
161 store_statement
162 timeseries_statement
163 matching_clause
164 filter_clause
165 condition comparison
166 expression object_expression
168 %type <integer> object_type object_type_plural
169 %type <integer> field
170 %type <integer> cmp
172 %type <data> data
173 interval interval_elem
174 array array_elem_list
176 %type <datetime> datetime
177 start_clause end_clause
178 last_update_clause
180 %type <metric_store> metric_store_clause
182 %destructor { free($$); } <str>
183 %destructor { sdb_object_deref(SDB_OBJ($$)); } <node>
184 %destructor { sdb_data_free_datum(&$$); } <data>
186 %%
188 statements:
189 statements ';' statement
190 {
191 /* only accepted in default parse mode */
192 if (parser_mode != SDB_PARSE_DEFAULT) {
193 sdb_parser_yyerrorf(&yylloc, scanner,
194 YY_("syntax error, unexpected statement, "
195 "expecting %s"), MODE_TO_STRING(parser_mode));
196 sdb_object_deref(SDB_OBJ($3));
197 YYABORT;
198 }
200 if ($3) {
201 sdb_llist_append(pt, SDB_OBJ($3));
202 sdb_object_deref(SDB_OBJ($3));
203 }
204 }
205 |
206 statement
207 {
208 /* only accepted in default parse mode */
209 if (parser_mode != SDB_PARSE_DEFAULT) {
210 sdb_parser_yyerrorf(&yylloc, scanner,
211 YY_("syntax error, unexpected statement, "
212 "expecting %s"), MODE_TO_STRING(parser_mode));
213 sdb_object_deref(SDB_OBJ($1));
214 YYABORT;
215 }
217 if ($1) {
218 sdb_llist_append(pt, SDB_OBJ($1));
219 sdb_object_deref(SDB_OBJ($1));
220 }
221 }
222 |
223 condition
224 {
225 /* only accepted in condition parse mode */
226 if (! (parser_mode & SDB_PARSE_COND)) {
227 sdb_parser_yyerrorf(&yylloc, scanner,
228 YY_("syntax error, unexpected condition, "
229 "expecting %s"), MODE_TO_STRING(parser_mode));
230 sdb_object_deref(SDB_OBJ($1));
231 YYABORT;
232 }
234 if ($1) {
235 sdb_llist_append(pt, SDB_OBJ($1));
236 sdb_object_deref(SDB_OBJ($1));
237 }
238 }
239 |
240 expression
241 {
242 /* only accepted in expression parse mode */
243 if (! (parser_mode & SDB_PARSE_ARITH)) {
244 sdb_parser_yyerrorf(&yylloc, scanner,
245 YY_("syntax error, unexpected expression, "
246 "expecting %s"), MODE_TO_STRING(parser_mode));
247 sdb_object_deref(SDB_OBJ($1));
248 YYABORT;
249 }
251 if ($1) {
252 sdb_llist_append(pt, SDB_OBJ($1));
253 sdb_object_deref(SDB_OBJ($1));
254 }
255 }
256 ;
258 statement:
259 fetch_statement
260 |
261 list_statement
262 |
263 lookup_statement
264 |
265 store_statement
266 |
267 timeseries_statement
268 |
269 /* empty */
270 {
271 $$ = NULL;
272 }
273 ;
275 /*
276 * FETCH host <hostname> [FILTER <condition>];
277 * FETCH <type> <hostname>.<name> [FILTER <condition>];
278 *
279 * Retrieve detailed information about a single object.
280 */
281 fetch_statement:
282 FETCH object_type STRING filter_clause
283 {
284 $$ = sdb_ast_fetch_create($2, NULL, -1, NULL, $3, 1, $4);
285 CK_OOM($$);
286 }
287 |
288 FETCH object_type STRING '.' STRING filter_clause
289 {
290 $$ = sdb_ast_fetch_create($2, $3, -1, NULL, $5, 1, $6);
291 CK_OOM($$);
292 }
293 ;
295 /*
296 * LIST <type> [FILTER <condition>];
297 *
298 * Returns a list of all objects in the store.
299 */
300 list_statement:
301 LIST object_type_plural filter_clause
302 {
303 $$ = sdb_ast_list_create($2, $3);
304 CK_OOM($$);
305 }
306 ;
308 /*
309 * LOOKUP <type> [MATCHING <condition>] [FILTER <condition>];
310 *
311 * Returns detailed information about objects matching a condition.
312 */
313 lookup_statement:
314 LOOKUP object_type_plural matching_clause filter_clause
315 {
316 $$ = sdb_ast_lookup_create($2, $3, $4);
317 CK_OOM($$);
318 }
319 ;
321 matching_clause:
322 MATCHING condition { $$ = $2; }
323 |
324 /* empty */ { $$ = NULL; }
326 filter_clause:
327 FILTER condition { $$ = $2; }
328 |
329 /* empty */ { $$ = NULL; }
331 /*
332 * STORE <type> <name>|<host>.<name> [LAST UPDATE <datetime>];
333 * STORE METRIC <host>.<name> STORE <type> <id> [LAST UPDATE <datetime>];
334 * STORE <type> ATTRIBUTE <parent>.<key> <datum> [LAST UPDATE <datetime>];
335 *
336 * Store or update an object in the database.
337 */
338 store_statement:
339 STORE HOST_T STRING last_update_clause
340 {
341 $$ = sdb_ast_store_create(SDB_HOST, NULL, 0, NULL,
342 $3, $4, NULL, NULL, 0, SDB_DATA_NULL);
343 CK_OOM($$);
344 }
345 |
346 STORE SERVICE_T STRING '.' STRING last_update_clause
347 {
348 $$ = sdb_ast_store_create(SDB_SERVICE, $3, 0, NULL,
349 $5, $6, NULL, NULL, 0, SDB_DATA_NULL);
350 CK_OOM($$);
351 }
352 |
353 STORE METRIC_T STRING '.' STRING metric_store_clause last_update_clause
354 {
355 $$ = sdb_ast_store_create(SDB_METRIC, $3, 0, NULL,
356 $5, $7, $6.type, $6.id, $6.last_update, SDB_DATA_NULL);
357 CK_OOM($$);
358 }
359 |
360 STORE HOST_T ATTRIBUTE_T STRING '.' STRING data last_update_clause
361 {
362 $$ = sdb_ast_store_create(SDB_ATTRIBUTE, $4, 0, NULL,
363 $6, $8, NULL, NULL, 0, $7);
364 CK_OOM($$);
365 }
366 |
367 STORE SERVICE_T ATTRIBUTE_T STRING '.' STRING '.' STRING data last_update_clause
368 {
369 $$ = sdb_ast_store_create(SDB_ATTRIBUTE, $4, SDB_SERVICE, $6,
370 $8, $10, NULL, NULL, 0, $9);
371 CK_OOM($$);
372 }
373 |
374 STORE METRIC_T ATTRIBUTE_T STRING '.' STRING '.' STRING data last_update_clause
375 {
376 $$ = sdb_ast_store_create(SDB_ATTRIBUTE, $4, SDB_METRIC, $6,
377 $8, $10, NULL, NULL, 0, $9);
378 CK_OOM($$);
379 }
380 ;
382 last_update_clause:
383 LAST UPDATE datetime { $$ = $3; }
384 |
385 /* empty */ { $$ = sdb_gettime(); }
387 metric_store_clause:
388 STORE STRING STRING datetime { $$.type = $2; $$.id = $3; $$.last_update = $4; }
389 |
390 STORE STRING STRING { $$.type = $2; $$.id = $3; $$.last_update = 0; }
391 |
392 /* empty */ { $$.type = $$.id = NULL; $$.last_update = 0; }
394 /*
395 * TIMESERIES <host>.<metric>[<data-source>...] [START <datetime>] [END <datetime>];
396 *
397 * Returns a time-series for the specified host's metric.
398 */
399 timeseries_statement:
400 TIMESERIES STRING '.' STRING start_clause end_clause
401 {
402 $$ = sdb_ast_timeseries_create($2, $4, NULL, 0, $5, $6);
403 CK_OOM($$);
404 }
405 |
406 TIMESERIES STRING '.' STRING array start_clause end_clause
407 {
408 char **ds;
409 size_t ds_num;
411 if ($5.type != (SDB_TYPE_ARRAY | SDB_TYPE_STRING)) {
412 sdb_parser_yyerrorf(&yylloc, scanner, YY_("syntax error, "
413 "unexpected array of type %s; expected STRING"),
414 SDB_TYPE_TO_STRING($5.type));
415 sdb_data_free_datum(&$5);
416 free($2);
417 free($4);
418 YYABORT;
419 }
421 ds = $5.data.array.values;
422 ds_num = $5.data.array.length;
424 $$ = sdb_ast_timeseries_create($2, $4, ds, ds_num, $6, $7);
425 CK_OOM($$);
426 }
427 ;
429 start_clause:
430 START datetime { $$ = $2; }
431 |
432 /* empty */ { $$ = sdb_gettime() - SDB_INTERVAL_HOUR; }
434 end_clause:
435 END datetime { $$ = $2; }
436 |
437 /* empty */ { $$ = sdb_gettime(); }
439 /*
440 * Basic expressions.
441 */
443 condition:
444 '(' condition ')'
445 {
446 $$ = $2;
447 }
448 |
449 condition AND condition
450 {
451 $$ = sdb_ast_op_create(SDB_AST_AND, $1, $3);
452 CK_OOM($$);
453 }
454 |
455 condition OR condition
456 {
457 $$ = sdb_ast_op_create(SDB_AST_OR, $1, $3);
458 CK_OOM($$);
459 }
460 |
461 NOT condition
462 {
463 $$ = sdb_ast_op_create(SDB_AST_NOT, NULL, $2);
464 CK_OOM($$);
465 }
466 |
467 comparison
468 {
469 $$ = $1;
470 }
471 ;
473 comparison:
474 expression cmp expression
475 {
476 $$ = sdb_ast_op_create($2, $1, $3);
477 CK_OOM($$);
478 }
479 |
480 ANY expression cmp expression
481 {
482 sdb_ast_node_t *n = sdb_ast_op_create($3, NULL, $4);
483 CK_OOM(n);
484 $$ = sdb_ast_iter_create(SDB_AST_ANY, $2, n);
485 CK_OOM($$);
486 }
487 |
488 ALL expression cmp expression
489 {
490 sdb_ast_node_t *n = sdb_ast_op_create($3, NULL, $4);
491 CK_OOM(n);
492 $$ = sdb_ast_iter_create(SDB_AST_ALL, $2, n);
493 CK_OOM($$);
494 }
495 |
496 expression IS NULL_T
497 {
498 $$ = sdb_ast_op_create(SDB_AST_ISNULL, NULL, $1);
499 CK_OOM($$);
500 }
501 |
502 expression IS NOT NULL_T
503 {
504 $$ = sdb_ast_op_create(SDB_AST_ISNULL, NULL, $1);
505 CK_OOM($$);
506 $$ = sdb_ast_op_create(SDB_AST_NOT, NULL, $$);
507 CK_OOM($$);
508 }
509 |
510 expression IS TRUE
511 {
512 $$ = sdb_ast_op_create(SDB_AST_ISTRUE, NULL, $1);
513 CK_OOM($$);
514 }
515 |
516 expression IS NOT TRUE
517 {
518 $$ = sdb_ast_op_create(SDB_AST_ISTRUE, NULL, $1);
519 CK_OOM($$);
520 $$ = sdb_ast_op_create(SDB_AST_NOT, NULL, $$);
521 CK_OOM($$);
522 }
523 |
524 expression IS FALSE
525 {
526 $$ = sdb_ast_op_create(SDB_AST_ISFALSE, NULL, $1);
527 CK_OOM($$);
528 }
529 |
530 expression IS NOT FALSE
531 {
532 $$ = sdb_ast_op_create(SDB_AST_ISFALSE, NULL, $1);
533 CK_OOM($$);
534 $$ = sdb_ast_op_create(SDB_AST_NOT, NULL, $$);
535 CK_OOM($$);
536 }
537 |
538 expression IN expression
539 {
540 $$ = sdb_ast_op_create(SDB_AST_IN, $1, $3);
541 CK_OOM($$);
542 }
543 |
544 expression NOT IN expression
545 {
546 $$ = sdb_ast_op_create(SDB_AST_IN, $1, $4);
547 CK_OOM($$);
548 $$ = sdb_ast_op_create(SDB_AST_NOT, NULL, $$);
549 CK_OOM($$);
550 }
551 ;
553 expression:
554 '(' expression ')'
555 {
556 $$ = $2;
557 }
558 |
559 expression '+' expression
560 {
561 $$ = sdb_ast_op_create(SDB_AST_ADD, $1, $3);
562 CK_OOM($$);
563 }
564 |
565 expression '-' expression
566 {
567 $$ = sdb_ast_op_create(SDB_AST_SUB, $1, $3);
568 CK_OOM($$);
569 }
570 |
571 expression '*' expression
572 {
573 $$ = sdb_ast_op_create(SDB_AST_MUL, $1, $3);
574 CK_OOM($$);
575 }
576 |
577 expression '/' expression
578 {
579 $$ = sdb_ast_op_create(SDB_AST_DIV, $1, $3);
580 CK_OOM($$);
581 }
582 |
583 expression '%' expression
584 {
585 $$ = sdb_ast_op_create(SDB_AST_MOD, $1, $3);
586 CK_OOM($$);
587 }
588 |
589 expression CONCAT expression
590 {
591 $$ = sdb_ast_op_create(SDB_AST_CONCAT, $1, $3);
592 CK_OOM($$);
593 }
594 |
595 object_expression
596 {
597 $$ = $1;
598 }
599 |
600 data
601 {
602 $$ = sdb_ast_const_create($1);
603 CK_OOM($$);
604 }
605 ;
607 object_expression:
608 object_type '.' object_expression
609 {
610 $$ = sdb_ast_typed_create($1, $3);
611 CK_OOM($$);
612 }
613 |
614 ATTRIBUTE_T '.' object_expression
615 {
616 $$ = sdb_ast_typed_create(SDB_ATTRIBUTE, $3);
617 CK_OOM($$);
618 }
619 |
620 field
621 {
622 $$ = sdb_ast_value_create($1, NULL);
623 CK_OOM($$);
624 }
625 |
626 ATTRIBUTE_T '[' STRING ']'
627 {
628 $$ = sdb_ast_value_create(SDB_ATTRIBUTE, $3);
629 CK_OOM($$);
630 }
631 ;
633 object_type:
634 HOST_T { $$ = SDB_HOST; }
635 |
636 SERVICE_T { $$ = SDB_SERVICE; }
637 |
638 METRIC_T { $$ = SDB_METRIC; }
639 ;
641 object_type_plural:
642 HOSTS_T { $$ = SDB_HOST; }
643 |
644 SERVICES_T { $$ = SDB_SERVICE; }
645 |
646 METRICS_T { $$ = SDB_METRIC; }
647 ;
649 field:
650 NAME_T { $$ = SDB_FIELD_NAME; }
651 |
652 LAST_UPDATE_T { $$ = SDB_FIELD_LAST_UPDATE; }
653 |
654 AGE_T { $$ = SDB_FIELD_AGE; }
655 |
656 INTERVAL_T { $$ = SDB_FIELD_INTERVAL; }
657 |
658 BACKEND_T { $$ = SDB_FIELD_BACKEND; }
659 |
660 VALUE_T { $$ = SDB_FIELD_VALUE; }
661 |
662 TIMESERIES { $$ = SDB_FIELD_TIMESERIES; }
663 ;
665 cmp:
666 CMP_EQUAL { $$ = SDB_AST_EQ; }
667 |
668 CMP_NEQUAL { $$ = SDB_AST_NE; }
669 |
670 CMP_REGEX { $$ = SDB_AST_REGEX; }
671 |
672 CMP_NREGEX { $$ = SDB_AST_NREGEX; }
673 |
674 CMP_LT { $$ = SDB_AST_LT; }
675 |
676 CMP_LE { $$ = SDB_AST_LE; }
677 |
678 CMP_GE { $$ = SDB_AST_GE; }
679 |
680 CMP_GT { $$ = SDB_AST_GT; }
681 ;
683 data:
684 STRING { $$.type = SDB_TYPE_STRING; $$.data.string = $1; }
685 |
686 INTEGER { $$ = $1; }
687 |
688 FLOAT { $$ = $1; }
689 |
690 datetime { $$.type = SDB_TYPE_DATETIME; $$.data.datetime = $1; }
691 |
692 interval { $$ = $1; }
693 |
694 array { $$ = $1; }
695 ;
697 datetime:
698 DATE TIME { $$ = $1 + $2; }
699 |
700 DATE { $$ = $1; }
701 |
702 TIME { $$ = $1; }
703 ;
705 interval:
706 interval interval_elem
707 {
708 $$.data.datetime = $1.data.datetime + $2.data.datetime;
709 }
710 |
711 interval_elem { $$ = $1; }
712 ;
714 interval_elem:
715 INTEGER IDENTIFIER
716 {
717 sdb_time_t unit = sdb_strpunit($2);
718 if (! unit) {
719 sdb_parser_yyerrorf(&yylloc, scanner,
720 YY_("syntax error, invalid time unit %s"), $2);
721 free($2); $2 = NULL;
722 YYABORT;
723 }
724 free($2); $2 = NULL;
726 if ($1.data.integer < 0) {
727 sdb_parser_yyerror(&yylloc, scanner,
728 YY_("syntax error, negative intervals not supported"));
729 YYABORT;
730 }
732 $$.type = SDB_TYPE_DATETIME;
733 $$.data.datetime = (sdb_time_t)$1.data.integer * unit;
734 }
735 ;
737 array:
738 '[' array_elem_list ']'
739 {
740 $$ = $2;
741 }
742 ;
744 array_elem_list:
745 array_elem_list ',' data
746 {
747 size_t elem_size = sdb_data_sizeof($3.type);
749 if (($3.type & SDB_TYPE_ARRAY) || (($1.type & 0xff) != $3.type)) {
750 sdb_parser_yyerrorf(&yylloc, scanner, YY_("syntax error, "
751 "cannot use element of type %s in array of type %s"),
752 SDB_TYPE_TO_STRING($3.type),
753 SDB_TYPE_TO_STRING($1.type));
754 sdb_data_free_datum(&$1);
755 sdb_data_free_datum(&$3);
756 YYABORT;
757 }
759 $$ = $1;
760 $$.data.array.values = realloc($$.data.array.values,
761 ($$.data.array.length + 1) * elem_size);
762 CK_OOM($$.data.array.values);
764 memcpy((char *)$$.data.array.values + $$.data.array.length * elem_size,
765 &$3.data, elem_size);
766 ++$$.data.array.length;
767 }
768 |
769 data
770 {
771 size_t elem_size = sdb_data_sizeof($1.type);
773 if ($1.type & SDB_TYPE_ARRAY) {
774 sdb_parser_yyerrorf(&yylloc, scanner, YY_("syntax error, "
775 "cannot construct array of type %s"),
776 SDB_TYPE_TO_STRING($1.type));
777 sdb_data_free_datum(&$1);
778 YYABORT;
779 }
781 $$ = $1;
782 $$.type |= SDB_TYPE_ARRAY;
783 $$.data.array.values = malloc(elem_size);
784 CK_OOM($$.data.array.values);
786 memcpy($$.data.array.values, &$1.data, elem_size);
787 $$.data.array.length = 1;
788 }
789 ;
791 %%
793 void
794 sdb_parser_yyerror(YYLTYPE *lval, sdb_parser_yyscan_t scanner, const char *msg)
795 {
796 sdb_log(SDB_LOG_ERR, "parser: parse error: %s", msg);
797 sdb_strbuf_sprintf(errbuf, "%s", msg);
798 } /* sdb_parser_yyerror */
800 void
801 sdb_parser_yyerrorf(YYLTYPE *lval, sdb_parser_yyscan_t scanner, const char *fmt, ...)
802 {
803 va_list ap, aq;
804 va_start(ap, fmt);
805 va_copy(aq, ap);
806 sdb_vlog(SDB_LOG_ERR, fmt, ap);
807 sdb_strbuf_vsprintf(errbuf, fmt, aq);
808 va_end(ap);
809 } /* sdb_parser_yyerrorf */
811 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */