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