Fix: miscellaneous memory handling fixes
[lttng-tools.git] / src / lib / lttng-ctl / filter / filter-parser.y
CommitLineData
953192ba
MD
1%{
2/*
3 * filter-parser.y
4 *
5 * LTTng filter expression parser
6 *
7 * Copyright 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 *
9 * This library is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License, version 2.1 only,
11 * as published by the Free Software Foundation.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 *
22 * Grammar inspired from http://www.quut.com/c/ANSI-C-grammar-y.html
23 */
24
25#include <stdio.h>
26#include <unistd.h>
27#include <string.h>
28#include <stdlib.h>
29#include <assert.h>
30#include <errno.h>
31#include <inttypes.h>
953192ba 32#include "filter-ast.h"
95b9bd90 33#include "filter-parser.h"
953192ba 34
a187da1a
DG
35#include <common/macros.h>
36
37LTTNG_HIDDEN
953192ba 38int yydebug;
a187da1a 39LTTNG_HIDDEN
953192ba
MD
40int filter_parser_debug = 0;
41
a187da1a 42LTTNG_HIDDEN
9039edd4 43int yyparse(struct filter_parser_ctx *parser_ctx, yyscan_t scanner);
a187da1a 44LTTNG_HIDDEN
9039edd4 45int yylex(union YYSTYPE *yyval, yyscan_t scanner);
a187da1a 46LTTNG_HIDDEN
953192ba 47int yylex_init_extra(struct filter_parser_ctx *parser_ctx, yyscan_t * ptr_yy_globals);
a187da1a 48LTTNG_HIDDEN
953192ba 49int yylex_destroy(yyscan_t yyparser_ctx);
a187da1a 50LTTNG_HIDDEN
953192ba
MD
51void yyrestart(FILE * in_str, yyscan_t parser_ctx);
52
53struct gc_string {
54 struct cds_list_head gc;
55 size_t alloclen;
56 char s[];
57};
58
59static const char *node_type_to_str[] = {
60 [ NODE_UNKNOWN ] = "NODE_UNKNOWN",
61 [ NODE_ROOT ] = "NODE_ROOT",
62 [ NODE_EXPRESSION ] = "NODE_EXPRESSION",
63 [ NODE_OP ] = "NODE_OP",
64 [ NODE_UNARY_OP ] = "NODE_UNARY_OP",
65};
66
a187da1a 67LTTNG_HIDDEN
953192ba
MD
68const char *node_type(struct filter_node *node)
69{
70 if (node->type < NR_NODE_TYPES)
71 return node_type_to_str[node->type];
72 else
73 return NULL;
74}
75
76static struct gc_string *gc_string_alloc(struct filter_parser_ctx *parser_ctx,
77 size_t len)
78{
79 struct gc_string *gstr;
80 size_t alloclen;
81
82 /* TODO: could be faster with find first bit or glib Gstring */
83 /* sizeof long to account for malloc header (int or long ?) */
84 for (alloclen = 8; alloclen < sizeof(long) + sizeof(*gstr) + len;
85 alloclen *= 2);
86
87 gstr = malloc(alloclen);
88 cds_list_add(&gstr->gc, &parser_ctx->allocated_strings);
89 gstr->alloclen = alloclen;
90 return gstr;
91}
92
93/*
94 * note: never use gc_string_append on a string that has external references.
95 * gsrc will be garbage collected immediately, and gstr might be.
96 * Should only be used to append characters to a string literal or constant.
97 */
a187da1a 98LTTNG_HIDDEN
953192ba
MD
99struct gc_string *gc_string_append(struct filter_parser_ctx *parser_ctx,
100 struct gc_string *gstr,
101 struct gc_string *gsrc)
102{
103 size_t newlen = strlen(gsrc->s) + strlen(gstr->s) + 1;
104 size_t alloclen;
105
106 /* TODO: could be faster with find first bit or glib Gstring */
107 /* sizeof long to account for malloc header (int or long ?) */
108 for (alloclen = 8; alloclen < sizeof(long) + sizeof(*gstr) + newlen;
109 alloclen *= 2);
110
111 if (alloclen > gstr->alloclen) {
112 struct gc_string *newgstr;
113
114 newgstr = gc_string_alloc(parser_ctx, newlen);
115 strcpy(newgstr->s, gstr->s);
116 strcat(newgstr->s, gsrc->s);
117 cds_list_del(&gstr->gc);
118 free(gstr);
119 gstr = newgstr;
120 } else {
121 strcat(gstr->s, gsrc->s);
122 }
123 cds_list_del(&gsrc->gc);
124 free(gsrc);
125 return gstr;
126}
127
a187da1a 128LTTNG_HIDDEN
953192ba
MD
129void setstring(struct filter_parser_ctx *parser_ctx, YYSTYPE *lvalp, const char *src)
130{
131 lvalp->gs = gc_string_alloc(parser_ctx, strlen(src) + 1);
132 strcpy(lvalp->gs->s, src);
133}
134
135static struct filter_node *make_node(struct filter_parser_ctx *scanner,
136 enum node_type type)
137{
138 struct filter_ast *ast = filter_parser_get_ast(scanner);
139 struct filter_node *node;
140
141 node = malloc(sizeof(*node));
142 if (!node)
143 return NULL;
144 memset(node, 0, sizeof(*node));
145 node->type = type;
146 cds_list_add(&node->gc, &ast->allocated_nodes);
147
148 switch (type) {
149 case NODE_ROOT:
150 fprintf(stderr, "[error] %s: trying to create root node\n", __func__);
151 break;
152
153 case NODE_EXPRESSION:
154 break;
155 case NODE_OP:
156 break;
157 case NODE_UNARY_OP:
158 break;
159
160 case NODE_UNKNOWN:
161 default:
162 fprintf(stderr, "[error] %s: unknown node type %d\n", __func__,
163 (int) type);
164 break;
165 }
166
167 return node;
168}
169
170static struct filter_node *make_op_node(struct filter_parser_ctx *scanner,
171 enum op_type type,
172 struct filter_node *lchild,
173 struct filter_node *rchild)
174{
175 struct filter_ast *ast = filter_parser_get_ast(scanner);
176 struct filter_node *node;
177
178 node = malloc(sizeof(*node));
179 if (!node)
180 return NULL;
181 memset(node, 0, sizeof(*node));
182 node->type = NODE_OP;
183 cds_list_add(&node->gc, &ast->allocated_nodes);
184 node->u.op.type = type;
185 node->u.op.lchild = lchild;
186 node->u.op.rchild = rchild;
187 return node;
188}
189
a187da1a 190LTTNG_HIDDEN
9039edd4 191void yyerror(struct filter_parser_ctx *parser_ctx, yyscan_t scanner, const char *str)
953192ba
MD
192{
193 fprintf(stderr, "error %s\n", str);
194}
195
a187da1a 196LTTNG_HIDDEN
953192ba
MD
197int yywrap(void)
198{
199 return 1;
200}
201
202#define parse_error(parser_ctx, str) \
203do { \
9039edd4 204 yyerror(parser_ctx, parser_ctx->scanner, YY_("parse error: " str "\n")); \
953192ba
MD
205 YYERROR; \
206} while (0)
207
208static void free_strings(struct cds_list_head *list)
209{
210 struct gc_string *gstr, *tmp;
211
212 cds_list_for_each_entry_safe(gstr, tmp, list, gc)
213 free(gstr);
214}
215
216static struct filter_ast *filter_ast_alloc(void)
217{
218 struct filter_ast *ast;
219
220 ast = malloc(sizeof(*ast));
221 if (!ast)
222 return NULL;
223 memset(ast, 0, sizeof(*ast));
224 CDS_INIT_LIST_HEAD(&ast->allocated_nodes);
225 ast->root.type = NODE_ROOT;
226 return ast;
227}
228
229static void filter_ast_free(struct filter_ast *ast)
230{
231 struct filter_node *node, *tmp;
232
233 cds_list_for_each_entry_safe(node, tmp, &ast->allocated_nodes, gc)
234 free(node);
37600d79 235 free(ast);
953192ba
MD
236}
237
a187da1a 238LTTNG_HIDDEN
953192ba
MD
239int filter_parser_ctx_append_ast(struct filter_parser_ctx *parser_ctx)
240{
9039edd4 241 return yyparse(parser_ctx, parser_ctx->scanner);
953192ba
MD
242}
243
a187da1a 244LTTNG_HIDDEN
953192ba
MD
245struct filter_parser_ctx *filter_parser_ctx_alloc(FILE *input)
246{
247 struct filter_parser_ctx *parser_ctx;
248 int ret;
249
250 yydebug = filter_parser_debug;
251
252 parser_ctx = malloc(sizeof(*parser_ctx));
253 if (!parser_ctx)
254 return NULL;
255 memset(parser_ctx, 0, sizeof(*parser_ctx));
256
257 ret = yylex_init_extra(parser_ctx, &parser_ctx->scanner);
258 if (ret) {
259 fprintf(stderr, "yylex_init error\n");
260 goto cleanup_parser_ctx;
261 }
262 /* Start processing new stream */
263 yyrestart(input, parser_ctx->scanner);
264
265 parser_ctx->ast = filter_ast_alloc();
266 if (!parser_ctx->ast)
267 goto cleanup_lexer;
268 CDS_INIT_LIST_HEAD(&parser_ctx->allocated_strings);
269
270 if (yydebug)
271 fprintf(stdout, "parser_ctx input is a%s.\n",
272 isatty(fileno(input)) ? "n interactive tty" :
273 " noninteractive file");
274
275 return parser_ctx;
276
277cleanup_lexer:
278 ret = yylex_destroy(parser_ctx->scanner);
279 if (!ret)
280 fprintf(stderr, "yylex_destroy error\n");
281cleanup_parser_ctx:
282 free(parser_ctx);
283 return NULL;
284}
285
a187da1a 286LTTNG_HIDDEN
953192ba
MD
287void filter_parser_ctx_free(struct filter_parser_ctx *parser_ctx)
288{
289 int ret;
290
291 free_strings(&parser_ctx->allocated_strings);
292 filter_ast_free(parser_ctx->ast);
293 ret = yylex_destroy(parser_ctx->scanner);
294 if (ret)
295 fprintf(stderr, "yylex_destroy error\n");
296 free(parser_ctx);
297}
298
299%}
300
301%define api.pure
302 /* %locations */
303%parse-param {struct filter_parser_ctx *parser_ctx}
9039edd4
ZT
304%parse-param {yyscan_t scanner}
305%lex-param {yyscan_t scanner}
953192ba
MD
306%start translation_unit
307%token CHARACTER_CONSTANT_START SQUOTE STRING_LITERAL_START DQUOTE
308%token ESCSEQ CHAR_STRING_TOKEN
e90d8561 309%token DECIMAL_CONSTANT OCTAL_CONSTANT HEXADECIMAL_CONSTANT FLOAT_CONSTANT
953192ba
MD
310%token LSBRAC RSBRAC LPAREN RPAREN LBRAC RBRAC RARROW
311%token STAR PLUS MINUS
312%token MOD_OP DIV_OP RIGHT_OP LEFT_OP
313%token EQ_OP NE_OP LE_OP GE_OP LT_OP GT_OP AND_OP OR_OP NOT_OP
314%token ASSIGN COLON SEMICOLON DOTDOTDOT DOT EQUAL COMMA
315%token XOR_BIN AND_BIN OR_BIN NOT_BIN
316
586dc72f 317%token <gs> IDENTIFIER GLOBAL_IDENTIFIER
953192ba
MD
318%token ERROR
319%union
320{
321 long long ll;
322 char c;
323 struct gc_string *gs;
324 struct filter_node *n;
325}
326
327%type <gs> s_char s_char_sequence c_char c_char_sequence
328
329%type <n> primary_expression
330%type <n> postfix_expression
331%type <n> unary_expression
332%type <n> unary_operator
333%type <n> multiplicative_expression
334%type <n> additive_expression
335%type <n> shift_expression
336%type <n> relational_expression
337%type <n> equality_expression
338%type <n> and_expression
339%type <n> exclusive_or_expression
340%type <n> inclusive_or_expression
341%type <n> logical_and_expression
342%type <n> logical_or_expression
343%type <n> expression
344
345%%
346
347
348/* 1.5 Constants */
349
350c_char_sequence:
351 c_char
352 { $$ = $1; }
353 | c_char_sequence c_char
354 { $$ = gc_string_append(parser_ctx, $1, $2); }
355 ;
356
357c_char:
358 CHAR_STRING_TOKEN
359 { $$ = yylval.gs; }
360 | ESCSEQ
361 {
362 parse_error(parser_ctx, "escape sequences not supported yet");
363 }
364 ;
365
366/* 1.6 String literals */
367
368s_char_sequence:
369 s_char
370 { $$ = $1; }
371 | s_char_sequence s_char
372 { $$ = gc_string_append(parser_ctx, $1, $2); }
373 ;
374
375s_char:
376 CHAR_STRING_TOKEN
377 { $$ = yylval.gs; }
378 | ESCSEQ
379 {
380 parse_error(parser_ctx, "escape sequences not supported yet");
381 }
382 ;
383
384primary_expression
385 : IDENTIFIER
386 {
387 $$ = make_node(parser_ctx, NODE_EXPRESSION);
388 $$->u.expression.type = AST_EXP_IDENTIFIER;
389 $$->u.expression.u.identifier = yylval.gs->s;
390 }
586dc72f
MD
391 | GLOBAL_IDENTIFIER
392 {
393 $$ = make_node(parser_ctx, NODE_EXPRESSION);
394 $$->u.expression.type = AST_EXP_GLOBAL_IDENTIFIER;
395 $$->u.expression.u.identifier = yylval.gs->s;
396 }
397
953192ba
MD
398 | DECIMAL_CONSTANT
399 {
400 $$ = make_node(parser_ctx, NODE_EXPRESSION);
401 $$->u.expression.type = AST_EXP_CONSTANT;
402 sscanf(yylval.gs->s, "%" PRIu64,
403 &$$->u.expression.u.constant);
404 }
405 | OCTAL_CONSTANT
406 {
407 $$ = make_node(parser_ctx, NODE_EXPRESSION);
408 $$->u.expression.type = AST_EXP_CONSTANT;
409 sscanf(yylval.gs->s, "0%" PRIo64,
410 &$$->u.expression.u.constant);
411 }
412 | HEXADECIMAL_CONSTANT
413 {
414 $$ = make_node(parser_ctx, NODE_EXPRESSION);
415 $$->u.expression.type = AST_EXP_CONSTANT;
416 sscanf(yylval.gs->s, "0x%" PRIx64,
417 &$$->u.expression.u.constant);
418 }
e90d8561
MD
419 | FLOAT_CONSTANT
420 {
421 $$ = make_node(parser_ctx, NODE_EXPRESSION);
422 $$->u.expression.type = AST_EXP_FLOAT_CONSTANT;
423 sscanf(yylval.gs->s, "%lg",
424 &$$->u.expression.u.float_constant);
425 }
953192ba
MD
426 | STRING_LITERAL_START DQUOTE
427 {
428 $$ = make_node(parser_ctx, NODE_EXPRESSION);
429 $$->u.expression.type = AST_EXP_STRING;
430 $$->u.expression.u.string = "";
431 }
432 | STRING_LITERAL_START s_char_sequence DQUOTE
433 {
434 $$ = make_node(parser_ctx, NODE_EXPRESSION);
435 $$->u.expression.type = AST_EXP_STRING;
436 $$->u.expression.u.string = $2->s;
437 }
438 | CHARACTER_CONSTANT_START c_char_sequence SQUOTE
439 {
440 $$ = make_node(parser_ctx, NODE_EXPRESSION);
441 $$->u.expression.type = AST_EXP_STRING;
442 $$->u.expression.u.string = $2->s;
443 }
444 | LPAREN expression RPAREN
445 {
446 $$ = make_node(parser_ctx, NODE_EXPRESSION);
447 $$->u.expression.type = AST_EXP_NESTED;
448 $$->u.expression.u.child = $2;
449 }
450 ;
451
452postfix_expression
453 : primary_expression
454 { $$ = $1; }
455 | postfix_expression DOT IDENTIFIER
456 {
457 $$ = make_node(parser_ctx, NODE_EXPRESSION);
458 $$->u.expression.type = AST_EXP_IDENTIFIER;
459 $$->u.expression.post_op = AST_LINK_DOT;
460 $$->u.expression.u.identifier = $3->s;
461 $$->u.expression.prev = $1;
462 }
463 | postfix_expression RARROW IDENTIFIER
464 {
465 $$ = make_node(parser_ctx, NODE_EXPRESSION);
466 $$->u.expression.type = AST_EXP_IDENTIFIER;
467 $$->u.expression.post_op = AST_LINK_RARROW;
468 $$->u.expression.u.identifier = $3->s;
469 $$->u.expression.prev = $1;
470 }
471 ;
472
473unary_expression
474 : postfix_expression
475 { $$ = $1; }
476 | unary_operator unary_expression
477 {
478 $$ = $1;
479 $$->u.unary_op.child = $2;
480 }
481 ;
482
483unary_operator
484 : PLUS
485 {
486 $$ = make_node(parser_ctx, NODE_UNARY_OP);
487 $$->u.unary_op.type = AST_UNARY_PLUS;
488 }
489 | MINUS
490 {
491 $$ = make_node(parser_ctx, NODE_UNARY_OP);
492 $$->u.unary_op.type = AST_UNARY_MINUS;
493 }
494 | NOT_OP
495 {
496 $$ = make_node(parser_ctx, NODE_UNARY_OP);
497 $$->u.unary_op.type = AST_UNARY_NOT;
498 }
ab78f161
CB
499 | NOT_BIN
500 {
501 $$ = make_node(parser_ctx, NODE_UNARY_OP);
502 $$->u.unary_op.type = AST_UNARY_BIN_NOT;
503 }
953192ba
MD
504 ;
505
506multiplicative_expression
507 : unary_expression
508 { $$ = $1; }
509 | multiplicative_expression STAR unary_expression
510 {
511 $$ = make_op_node(parser_ctx, AST_OP_MUL, $1, $3);
512 }
513 | multiplicative_expression DIV_OP unary_expression
514 {
515 $$ = make_op_node(parser_ctx, AST_OP_DIV, $1, $3);
516 }
517 | multiplicative_expression MOD_OP unary_expression
518 {
519 $$ = make_op_node(parser_ctx, AST_OP_MOD, $1, $3);
520 }
521 ;
522
523additive_expression
524 : multiplicative_expression
525 { $$ = $1; }
526 | additive_expression PLUS multiplicative_expression
527 {
528 $$ = make_op_node(parser_ctx, AST_OP_PLUS, $1, $3);
529 }
530 | additive_expression MINUS multiplicative_expression
531 {
532 $$ = make_op_node(parser_ctx, AST_OP_MINUS, $1, $3);
533 }
534 ;
535
536shift_expression
537 : additive_expression
538 { $$ = $1; }
539 | shift_expression LEFT_OP additive_expression
540 {
541 $$ = make_op_node(parser_ctx, AST_OP_LSHIFT, $1, $3);
542 }
543 | shift_expression RIGHT_OP additive_expression
544 {
545 $$ = make_op_node(parser_ctx, AST_OP_RSHIFT, $1, $3);
546 }
547 ;
548
549relational_expression
550 : shift_expression
551 { $$ = $1; }
552 | relational_expression LT_OP shift_expression
553 {
554 $$ = make_op_node(parser_ctx, AST_OP_LT, $1, $3);
555 }
556 | relational_expression GT_OP shift_expression
557 {
558 $$ = make_op_node(parser_ctx, AST_OP_GT, $1, $3);
559 }
560 | relational_expression LE_OP shift_expression
561 {
562 $$ = make_op_node(parser_ctx, AST_OP_LE, $1, $3);
563 }
564 | relational_expression GE_OP shift_expression
565 {
566 $$ = make_op_node(parser_ctx, AST_OP_GE, $1, $3);
567 }
568 ;
569
570equality_expression
571 : relational_expression
572 { $$ = $1; }
573 | equality_expression EQ_OP relational_expression
574 {
575 $$ = make_op_node(parser_ctx, AST_OP_EQ, $1, $3);
576 }
577 | equality_expression NE_OP relational_expression
578 {
579 $$ = make_op_node(parser_ctx, AST_OP_NE, $1, $3);
580 }
581 ;
582
583and_expression
584 : equality_expression
585 { $$ = $1; }
586 | and_expression AND_BIN equality_expression
587 {
588 $$ = make_op_node(parser_ctx, AST_OP_BIN_AND, $1, $3);
589 }
590 ;
591
592exclusive_or_expression
593 : and_expression
594 { $$ = $1; }
595 | exclusive_or_expression XOR_BIN and_expression
596 {
597 $$ = make_op_node(parser_ctx, AST_OP_BIN_XOR, $1, $3);
598 }
599 ;
600
601inclusive_or_expression
602 : exclusive_or_expression
603 { $$ = $1; }
604 | inclusive_or_expression OR_BIN exclusive_or_expression
605 {
606 $$ = make_op_node(parser_ctx, AST_OP_BIN_OR, $1, $3);
607 }
608 ;
609
610logical_and_expression
611 : inclusive_or_expression
612 { $$ = $1; }
613 | logical_and_expression AND_OP inclusive_or_expression
614 {
615 $$ = make_op_node(parser_ctx, AST_OP_AND, $1, $3);
616 }
617 ;
618
619logical_or_expression
620 : logical_and_expression
621 { $$ = $1; }
622 | logical_or_expression OR_OP logical_and_expression
623 {
624 $$ = make_op_node(parser_ctx, AST_OP_OR, $1, $3);
625 }
626 ;
627
628expression
629 : logical_or_expression
630 { $$ = $1; }
631 ;
632
633translation_unit
634 : expression
635 {
636 parser_ctx->ast->root.u.root.child = $1;
637 }
638 ;
This page took 0.093012 seconds and 5 git commands to generate.