%parse-param {struct list_head *expr_head} %define parse.error verbose %{ #ifndef NDEBUG #define YYDEBUG 1 #endif #include #include #include #include #include "bpf-filter.h" #include "cgroup.h" int perf_bpf_filter_lex(void); /* To indicate if the current term needs a pathname or not */ int perf_bpf_filter_needs_path; static void perf_bpf_filter_error(struct list_head *expr __maybe_unused, char const *msg) { printf("perf_bpf_filter: %s\n", msg); } %} %union { unsigned long num; char *path; struct { enum perf_bpf_filter_term term; int part; } sample; enum perf_bpf_filter_op op; struct perf_bpf_filter_expr *expr; } %token BFT_SAMPLE BFT_SAMPLE_PATH BFT_OP BFT_ERROR BFT_NUM BFT_LOGICAL_OR BFT_PATH %type filter_term filter_expr %destructor { free ($$); } %type BFT_SAMPLE BFT_SAMPLE_PATH %type BFT_OP %type BFT_NUM %type BFT_PATH %% filter: filter ',' filter_term { list_add_tail(&$3->list, expr_head); } | filter_term { list_add_tail(&$1->list, expr_head); } filter_term: filter_term BFT_LOGICAL_OR filter_expr { struct perf_bpf_filter_expr *expr; if ($1->op == PBF_OP_GROUP_BEGIN) { expr = $1; } else { expr = perf_bpf_filter_expr__new(PBF_TERM_NONE, /*part=*/0, PBF_OP_GROUP_BEGIN, /*val=*/1); list_add_tail(&$1->list, &expr->groups); } expr->val++; list_add_tail(&$3->list, &expr->groups); $$ = expr; } | filter_expr { $$ = $1; } filter_expr: BFT_SAMPLE BFT_OP BFT_NUM { $$ = perf_bpf_filter_expr__new($1.term, $1.part, $2, $3); } | BFT_SAMPLE_PATH BFT_OP BFT_PATH { struct cgroup *cgrp; unsigned long cgroup_id = 0; if ($2 != PBF_OP_EQ && $2 != PBF_OP_NEQ) { printf("perf_bpf_filter: cgroup accepts '==' or '!=' only\n"); YYERROR; } cgrp = cgroup__new($3, /*do_open=*/false); if (cgrp && read_cgroup_id(cgrp) == 0) cgroup_id = cgrp->id; $$ = perf_bpf_filter_expr__new($1.term, $1.part, $2, cgroup_id); cgroup__put(cgrp); } %%