xref: /openbmc/linux/tools/perf/util/parse-events.y (revision 3e8bd1ba)
1 %define api.pure full
2 %parse-param {void *_parse_state}
3 %parse-param {void *scanner}
4 %lex-param {void* scanner}
5 %locations
6 
7 %{
8 
9 #define YYDEBUG 1
10 
11 #include <errno.h>
12 #include <fnmatch.h>
13 #include <stdio.h>
14 #include <linux/compiler.h>
15 #include <linux/types.h>
16 #include <linux/zalloc.h>
17 #include "pmu.h"
18 #include "pmus.h"
19 #include "evsel.h"
20 #include "parse-events.h"
21 #include "parse-events-bison.h"
22 
23 int parse_events_lex(YYSTYPE * yylval_param, YYLTYPE * yylloc_param , void *yyscanner);
24 void parse_events_error(YYLTYPE *loc, void *parse_state, void *scanner, char const *msg);
25 
26 #define PE_ABORT(val) \
27 do { \
28 	if (val == -ENOMEM) \
29 		YYNOMEM; \
30 	YYABORT; \
31 } while (0)
32 
33 static struct list_head* alloc_list(void)
34 {
35 	struct list_head *list;
36 
37 	list = malloc(sizeof(*list));
38 	if (!list)
39 		return NULL;
40 
41 	INIT_LIST_HEAD(list);
42 	return list;
43 }
44 
45 static void free_list_evsel(struct list_head* list_evsel)
46 {
47 	struct evsel *evsel, *tmp;
48 
49 	list_for_each_entry_safe(evsel, tmp, list_evsel, core.node) {
50 		list_del_init(&evsel->core.node);
51 		evsel__delete(evsel);
52 	}
53 	free(list_evsel);
54 }
55 
56 %}
57 
58 %token PE_START_EVENTS PE_START_TERMS
59 %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_TERM
60 %token PE_VALUE_SYM_TOOL
61 %token PE_EVENT_NAME
62 %token PE_RAW PE_NAME
63 %token PE_MODIFIER_EVENT PE_MODIFIER_BP PE_BP_COLON PE_BP_SLASH
64 %token PE_LEGACY_CACHE
65 %token PE_PREFIX_MEM
66 %token PE_ERROR
67 %token PE_DRV_CFG_TERM
68 %token PE_TERM_HW
69 %type <num> PE_VALUE
70 %type <num> PE_VALUE_SYM_HW
71 %type <num> PE_VALUE_SYM_SW
72 %type <num> PE_VALUE_SYM_TOOL
73 %type <num> PE_TERM
74 %type <num> value_sym
75 %type <str> PE_RAW
76 %type <str> PE_NAME
77 %type <str> PE_LEGACY_CACHE
78 %type <str> PE_MODIFIER_EVENT
79 %type <str> PE_MODIFIER_BP
80 %type <str> PE_EVENT_NAME
81 %type <str> PE_DRV_CFG_TERM
82 %type <str> name_or_raw name_or_legacy
83 %destructor { free ($$); } <str>
84 %type <term> event_term
85 %destructor { parse_events_term__delete ($$); } <term>
86 %type <list_terms> event_config
87 %type <list_terms> opt_event_config
88 %type <list_terms> opt_pmu_config
89 %destructor { parse_events_terms__delete ($$); } <list_terms>
90 %type <list_evsel> event_pmu
91 %type <list_evsel> event_legacy_symbol
92 %type <list_evsel> event_legacy_cache
93 %type <list_evsel> event_legacy_mem
94 %type <list_evsel> event_legacy_tracepoint
95 %type <list_evsel> event_legacy_numeric
96 %type <list_evsel> event_legacy_raw
97 %type <list_evsel> event_def
98 %type <list_evsel> event_mod
99 %type <list_evsel> event_name
100 %type <list_evsel> event
101 %type <list_evsel> events
102 %type <list_evsel> group_def
103 %type <list_evsel> group
104 %type <list_evsel> groups
105 %destructor { free_list_evsel ($$); } <list_evsel>
106 %type <tracepoint_name> tracepoint_name
107 %type <hardware_term> PE_TERM_HW
108 %destructor { free ($$.str); } <hardware_term>
109 
110 %union
111 {
112 	char *str;
113 	u64 num;
114 	struct list_head *list_evsel;
115 	struct list_head *list_terms;
116 	struct parse_events_term *term;
117 	struct tracepoint_name {
118 		char *sys;
119 		char *event;
120 	} tracepoint_name;
121 	struct hardware_term {
122 		char *str;
123 		u64 num;
124 	} hardware_term;
125 }
126 %%
127 
128 start:
129 PE_START_EVENTS start_events
130 |
131 PE_START_TERMS  start_terms
132 
133 start_events: groups
134 {
135 	struct parse_events_state *parse_state = _parse_state;
136 
137 	/* frees $1 */
138 	parse_events_update_lists($1, &parse_state->list);
139 }
140 
141 groups:
142 groups ',' group
143 {
144 	struct list_head *list  = $1;
145 	struct list_head *group = $3;
146 
147 	/* frees $3 */
148 	parse_events_update_lists(group, list);
149 	$$ = list;
150 }
151 |
152 groups ',' event
153 {
154 	struct list_head *list  = $1;
155 	struct list_head *event = $3;
156 
157 	/* frees $3 */
158 	parse_events_update_lists(event, list);
159 	$$ = list;
160 }
161 |
162 group
163 |
164 event
165 
166 group:
167 group_def ':' PE_MODIFIER_EVENT
168 {
169 	struct list_head *list = $1;
170 	int err;
171 
172 	err = parse_events__modifier_group(list, $3);
173 	free($3);
174 	if (err) {
175 		struct parse_events_state *parse_state = _parse_state;
176 		struct parse_events_error *error = parse_state->error;
177 
178 		parse_events_error__handle(error, @3.first_column,
179 					   strdup("Bad modifier"), NULL);
180 		free_list_evsel(list);
181 		YYABORT;
182 	}
183 	$$ = list;
184 }
185 |
186 group_def
187 
188 group_def:
189 PE_NAME '{' events '}'
190 {
191 	struct list_head *list = $3;
192 
193 	/* Takes ownership of $1. */
194 	parse_events__set_leader($1, list);
195 	$$ = list;
196 }
197 |
198 '{' events '}'
199 {
200 	struct list_head *list = $2;
201 
202 	parse_events__set_leader(NULL, list);
203 	$$ = list;
204 }
205 
206 events:
207 events ',' event
208 {
209 	struct list_head *event = $3;
210 	struct list_head *list  = $1;
211 
212 	/* frees $3 */
213 	parse_events_update_lists(event, list);
214 	$$ = list;
215 }
216 |
217 event
218 
219 event: event_mod
220 
221 event_mod:
222 event_name PE_MODIFIER_EVENT
223 {
224 	struct list_head *list = $1;
225 	int err;
226 
227 	/*
228 	 * Apply modifier on all events added by single event definition
229 	 * (there could be more events added for multiple tracepoint
230 	 * definitions via '*?'.
231 	 */
232 	err = parse_events__modifier_event(list, $2, false);
233 	free($2);
234 	if (err) {
235 		struct parse_events_state *parse_state = _parse_state;
236 		struct parse_events_error *error = parse_state->error;
237 
238 		parse_events_error__handle(error, @2.first_column,
239 					   strdup("Bad modifier"), NULL);
240 		free_list_evsel(list);
241 		YYABORT;
242 	}
243 	$$ = list;
244 }
245 |
246 event_name
247 
248 event_name:
249 PE_EVENT_NAME event_def
250 {
251 	int err;
252 
253 	err = parse_events_name($2, $1);
254 	free($1);
255 	if (err) {
256 		free_list_evsel($2);
257 		YYNOMEM;
258 	}
259 	$$ = $2;
260 }
261 |
262 event_def
263 
264 event_def: event_pmu |
265 	   event_legacy_symbol |
266 	   event_legacy_cache sep_dc |
267 	   event_legacy_mem sep_dc |
268 	   event_legacy_tracepoint sep_dc |
269 	   event_legacy_numeric sep_dc |
270 	   event_legacy_raw sep_dc
271 
272 event_pmu:
273 PE_NAME opt_pmu_config
274 {
275 	struct parse_events_state *parse_state = _parse_state;
276 	struct list_head *list = NULL, *orig_terms = NULL, *terms= NULL;
277 	char *pattern = NULL;
278 
279 #define CLEANUP						\
280 	do {						\
281 		parse_events_terms__delete($2);		\
282 		parse_events_terms__delete(orig_terms);	\
283 		free(list);				\
284 		free($1);				\
285 		free(pattern);				\
286 	} while(0)
287 
288 	if (parse_events_copy_term_list($2, &orig_terms)) {
289 		CLEANUP;
290 		YYNOMEM;
291 	}
292 
293 	list = alloc_list();
294 	if (!list) {
295 		CLEANUP;
296 		YYNOMEM;
297 	}
298 	/* Attempt to add to list assuming $1 is a PMU name. */
299 	if (parse_events_add_pmu(parse_state, list, $1, $2, /*auto_merge_stats=*/false, &@1)) {
300 		struct perf_pmu *pmu = NULL;
301 		int ok = 0;
302 
303 		/* Failure to add, try wildcard expansion of $1 as a PMU name. */
304 		if (asprintf(&pattern, "%s*", $1) < 0) {
305 			CLEANUP;
306 			YYNOMEM;
307 		}
308 
309 		while ((pmu = perf_pmus__scan(pmu)) != NULL) {
310 			const char *name = pmu->name;
311 
312 			if (parse_events__filter_pmu(parse_state, pmu))
313 				continue;
314 
315 			if (!strncmp(name, "uncore_", 7) &&
316 			    strncmp($1, "uncore_", 7))
317 				name += 7;
318 			if (!perf_pmu__match(pattern, name, $1) ||
319 			    !perf_pmu__match(pattern, pmu->alias_name, $1)) {
320 				bool auto_merge_stats = perf_pmu__auto_merge_stats(pmu);
321 
322 				if (parse_events_copy_term_list(orig_terms, &terms)) {
323 					CLEANUP;
324 					YYNOMEM;
325 				}
326 				if (!parse_events_add_pmu(parse_state, list, pmu->name, terms,
327 							  auto_merge_stats, &@1)) {
328 					ok++;
329 					parse_state->wild_card_pmus = true;
330 				}
331 				parse_events_terms__delete(terms);
332 			}
333 		}
334 
335 		if (!ok) {
336 			/* Failure to add, assume $1 is an event name. */
337 			zfree(&list);
338 			ok = !parse_events_multi_pmu_add(parse_state, $1, $2, &list, &@1);
339 			$2 = NULL;
340 		}
341 		if (!ok) {
342 			struct parse_events_error *error = parse_state->error;
343 			char *help;
344 
345 			if (asprintf(&help, "Unable to find PMU or event on a PMU of '%s'", $1) < 0)
346 				help = NULL;
347 			parse_events_error__handle(error, @1.first_column,
348 						   strdup("Bad event or PMU"),
349 						   help);
350 			CLEANUP;
351 			YYABORT;
352 		}
353 	}
354 	$$ = list;
355 	list = NULL;
356 	CLEANUP;
357 #undef CLEANUP
358 }
359 |
360 PE_NAME sep_dc
361 {
362 	struct list_head *list;
363 	int err;
364 
365 	err = parse_events_multi_pmu_add(_parse_state, $1, NULL, &list, &@1);
366 	if (err < 0) {
367 		struct parse_events_state *parse_state = _parse_state;
368 		struct parse_events_error *error = parse_state->error;
369 		char *help;
370 
371 		if (asprintf(&help, "Unable to find event on a PMU of '%s'", $1) < 0)
372 			help = NULL;
373 		parse_events_error__handle(error, @1.first_column, strdup("Bad event name"), help);
374 		free($1);
375 		PE_ABORT(err);
376 	}
377 	free($1);
378 	$$ = list;
379 }
380 
381 value_sym:
382 PE_VALUE_SYM_HW
383 |
384 PE_VALUE_SYM_SW
385 
386 event_legacy_symbol:
387 value_sym '/' event_config '/'
388 {
389 	struct list_head *list;
390 	int type = $1 >> 16;
391 	int config = $1 & 255;
392 	int err;
393 	bool wildcard = (type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE);
394 
395 	list = alloc_list();
396 	if (!list)
397 		YYNOMEM;
398 	err = parse_events_add_numeric(_parse_state, list, type, config, $3, wildcard);
399 	parse_events_terms__delete($3);
400 	if (err) {
401 		free_list_evsel(list);
402 		PE_ABORT(err);
403 	}
404 	$$ = list;
405 }
406 |
407 value_sym sep_slash_slash_dc
408 {
409 	struct list_head *list;
410 	int type = $1 >> 16;
411 	int config = $1 & 255;
412 	bool wildcard = (type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE);
413 	int err;
414 
415 	list = alloc_list();
416 	if (!list)
417 		YYNOMEM;
418 	err = parse_events_add_numeric(_parse_state, list, type, config, /*head_config=*/NULL, wildcard);
419 	if (err)
420 		PE_ABORT(err);
421 	$$ = list;
422 }
423 |
424 PE_VALUE_SYM_TOOL sep_slash_slash_dc
425 {
426 	struct list_head *list;
427 	int err;
428 
429 	list = alloc_list();
430 	if (!list)
431 		YYNOMEM;
432 	err = parse_events_add_tool(_parse_state, list, $1);
433 	if (err)
434 		YYNOMEM;
435 	$$ = list;
436 }
437 
438 event_legacy_cache:
439 PE_LEGACY_CACHE opt_event_config
440 {
441 	struct parse_events_state *parse_state = _parse_state;
442 	struct list_head *list;
443 	int err;
444 
445 	list = alloc_list();
446 	if (!list)
447 		YYNOMEM;
448 
449 	err = parse_events_add_cache(list, &parse_state->idx, $1, parse_state, $2);
450 
451 	parse_events_terms__delete($2);
452 	free($1);
453 	if (err) {
454 		free_list_evsel(list);
455 		PE_ABORT(err);
456 	}
457 	$$ = list;
458 }
459 
460 event_legacy_mem:
461 PE_PREFIX_MEM PE_VALUE PE_BP_SLASH PE_VALUE PE_BP_COLON PE_MODIFIER_BP opt_event_config
462 {
463 	struct list_head *list;
464 	int err;
465 
466 	list = alloc_list();
467 	if (!list)
468 		YYNOMEM;
469 
470 	err = parse_events_add_breakpoint(_parse_state, list,
471 					  $2, $6, $4, $7);
472 	parse_events_terms__delete($7);
473 	free($6);
474 	if (err) {
475 		free(list);
476 		PE_ABORT(err);
477 	}
478 	$$ = list;
479 }
480 |
481 PE_PREFIX_MEM PE_VALUE PE_BP_SLASH PE_VALUE opt_event_config
482 {
483 	struct list_head *list;
484 	int err;
485 
486 	list = alloc_list();
487 	if (!list)
488 		YYNOMEM;
489 
490 	err = parse_events_add_breakpoint(_parse_state, list,
491 					  $2, NULL, $4, $5);
492 	parse_events_terms__delete($5);
493 	if (err) {
494 		free(list);
495 		PE_ABORT(err);
496 	}
497 	$$ = list;
498 }
499 |
500 PE_PREFIX_MEM PE_VALUE PE_BP_COLON PE_MODIFIER_BP opt_event_config
501 {
502 	struct list_head *list;
503 	int err;
504 
505 	list = alloc_list();
506 	if (!list)
507 		YYNOMEM;
508 
509 	err = parse_events_add_breakpoint(_parse_state, list,
510 					  $2, $4, 0, $5);
511 	parse_events_terms__delete($5);
512 	free($4);
513 	if (err) {
514 		free(list);
515 		PE_ABORT(err);
516 	}
517 	$$ = list;
518 }
519 |
520 PE_PREFIX_MEM PE_VALUE opt_event_config
521 {
522 	struct list_head *list;
523 	int err;
524 
525 	list = alloc_list();
526 	if (!list)
527 		YYNOMEM;
528 	err = parse_events_add_breakpoint(_parse_state, list,
529 					  $2, NULL, 0, $3);
530 	parse_events_terms__delete($3);
531 	if (err) {
532 		free(list);
533 		PE_ABORT(err);
534 	}
535 	$$ = list;
536 }
537 
538 event_legacy_tracepoint:
539 tracepoint_name opt_event_config
540 {
541 	struct parse_events_state *parse_state = _parse_state;
542 	struct parse_events_error *error = parse_state->error;
543 	struct list_head *list;
544 	int err;
545 
546 	list = alloc_list();
547 	if (!list)
548 		YYNOMEM;
549 	if (error)
550 		error->idx = @1.first_column;
551 
552 	err = parse_events_add_tracepoint(list, &parse_state->idx, $1.sys, $1.event,
553 					error, $2, &@1);
554 
555 	parse_events_terms__delete($2);
556 	free($1.sys);
557 	free($1.event);
558 	if (err) {
559 		free(list);
560 		PE_ABORT(err);
561 	}
562 	$$ = list;
563 }
564 
565 tracepoint_name:
566 PE_NAME ':' PE_NAME
567 {
568 	struct tracepoint_name tracepoint = {$1, $3};
569 
570 	$$ = tracepoint;
571 }
572 
573 event_legacy_numeric:
574 PE_VALUE ':' PE_VALUE opt_event_config
575 {
576 	struct list_head *list;
577 	int err;
578 
579 	list = alloc_list();
580 	if (!list)
581 		YYNOMEM;
582 	err = parse_events_add_numeric(_parse_state, list, (u32)$1, $3, $4,
583 				       /*wildcard=*/false);
584 	parse_events_terms__delete($4);
585 	if (err) {
586 		free(list);
587 		PE_ABORT(err);
588 	}
589 	$$ = list;
590 }
591 
592 event_legacy_raw:
593 PE_RAW opt_event_config
594 {
595 	struct list_head *list;
596 	int err;
597 	u64 num;
598 
599 	list = alloc_list();
600 	if (!list)
601 		YYNOMEM;
602 	errno = 0;
603 	num = strtoull($1 + 1, NULL, 16);
604 	/* Given the lexer will only give [a-fA-F0-9]+ a failure here should be impossible. */
605 	if (errno)
606 		YYABORT;
607 	free($1);
608 	err = parse_events_add_numeric(_parse_state, list, PERF_TYPE_RAW, num, $2,
609 				       /*wildcard=*/false);
610 	parse_events_terms__delete($2);
611 	if (err) {
612 		free(list);
613 		PE_ABORT(err);
614 	}
615 	$$ = list;
616 }
617 
618 opt_event_config:
619 '/' event_config '/'
620 {
621 	$$ = $2;
622 }
623 |
624 '/' '/'
625 {
626 	$$ = NULL;
627 }
628 |
629 {
630 	$$ = NULL;
631 }
632 
633 opt_pmu_config:
634 '/' event_config '/'
635 {
636 	$$ = $2;
637 }
638 |
639 '/' '/'
640 {
641 	$$ = NULL;
642 }
643 
644 start_terms: event_config
645 {
646 	struct parse_events_state *parse_state = _parse_state;
647 	if (parse_state->terms) {
648 		parse_events_terms__delete ($1);
649 		YYABORT;
650 	}
651 	parse_state->terms = $1;
652 }
653 
654 event_config:
655 event_config ',' event_term
656 {
657 	struct list_head *head = $1;
658 	struct parse_events_term *term = $3;
659 
660 	if (!head) {
661 		parse_events_term__delete(term);
662 		YYABORT;
663 	}
664 	list_add_tail(&term->list, head);
665 	$$ = $1;
666 }
667 |
668 event_term
669 {
670 	struct list_head *head = malloc(sizeof(*head));
671 	struct parse_events_term *term = $1;
672 
673 	if (!head)
674 		YYNOMEM;
675 	INIT_LIST_HEAD(head);
676 	list_add_tail(&term->list, head);
677 	$$ = head;
678 }
679 
680 name_or_raw: PE_RAW | PE_NAME | PE_LEGACY_CACHE
681 
682 name_or_legacy: PE_NAME | PE_LEGACY_CACHE
683 
684 event_term:
685 PE_RAW
686 {
687 	struct parse_events_term *term;
688 	int err = parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_RAW,
689 					 strdup("raw"), $1, &@1, &@1);
690 
691 	if (err) {
692 		free($1);
693 		PE_ABORT(err);
694 	}
695 	$$ = term;
696 }
697 |
698 name_or_raw '=' name_or_legacy
699 {
700 	struct parse_events_term *term;
701 	int err = parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER, $1, $3, &@1, &@3);
702 
703 	if (err) {
704 		free($1);
705 		free($3);
706 		PE_ABORT(err);
707 	}
708 	$$ = term;
709 }
710 |
711 name_or_raw '=' PE_VALUE
712 {
713 	struct parse_events_term *term;
714 	int err = parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
715 					 $1, $3, /*novalue=*/false, &@1, &@3);
716 
717 	if (err) {
718 		free($1);
719 		PE_ABORT(err);
720 	}
721 	$$ = term;
722 }
723 |
724 name_or_raw '=' PE_TERM_HW
725 {
726 	struct parse_events_term *term;
727 	int err = parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER,
728 					 $1, $3.str, &@1, &@3);
729 
730 	if (err) {
731 		free($1);
732 		free($3.str);
733 		PE_ABORT(err);
734 	}
735 	$$ = term;
736 }
737 |
738 PE_LEGACY_CACHE
739 {
740 	struct parse_events_term *term;
741 	int err = parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE,
742 					 $1, /*num=*/1, /*novalue=*/true, &@1, /*loc_val=*/NULL);
743 
744 	if (err) {
745 		free($1);
746 		PE_ABORT(err);
747 	}
748 	$$ = term;
749 }
750 |
751 PE_NAME
752 {
753 	struct parse_events_term *term;
754 	int err = parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
755 					 $1, /*num=*/1, /*novalue=*/true, &@1, /*loc_val=*/NULL);
756 
757 	if (err) {
758 		free($1);
759 		PE_ABORT(err);
760 	}
761 	$$ = term;
762 }
763 |
764 PE_TERM_HW
765 {
766 	struct parse_events_term *term;
767 	int err = parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_HARDWARE,
768 					 $1.str, $1.num & 255, /*novalue=*/false,
769 					 &@1, /*loc_val=*/NULL);
770 
771 	if (err) {
772 		free($1.str);
773 		PE_ABORT(err);
774 	}
775 	$$ = term;
776 }
777 |
778 PE_TERM '=' name_or_legacy
779 {
780 	struct parse_events_term *term;
781 	int err = parse_events_term__str(&term, (enum parse_events__term_type)$1,
782 					/*config=*/NULL, $3, &@1, &@3);
783 
784 	if (err) {
785 		free($3);
786 		PE_ABORT(err);
787 	}
788 	$$ = term;
789 }
790 |
791 PE_TERM '=' PE_TERM_HW
792 {
793 	struct parse_events_term *term;
794 	int err = parse_events_term__str(&term, (enum parse_events__term_type)$1,
795 					 /*config=*/NULL, $3.str, &@1, &@3);
796 
797 	if (err) {
798 		free($3.str);
799 		PE_ABORT(err);
800 	}
801 	$$ = term;
802 }
803 |
804 PE_TERM '=' PE_TERM
805 {
806 	struct parse_events_term *term;
807 	int err = parse_events_term__term(&term,
808 					  (enum parse_events__term_type)$1,
809 					  (enum parse_events__term_type)$3,
810 					  &@1, &@3);
811 
812 	if (err)
813 		PE_ABORT(err);
814 
815 	$$ = term;
816 }
817 |
818 PE_TERM '=' PE_VALUE
819 {
820 	struct parse_events_term *term;
821 	int err = parse_events_term__num(&term, (enum parse_events__term_type)$1,
822 					 /*config=*/NULL, $3, /*novalue=*/false, &@1, &@3);
823 
824 	if (err)
825 		PE_ABORT(err);
826 
827 	$$ = term;
828 }
829 |
830 PE_TERM
831 {
832 	struct parse_events_term *term;
833 	int err = parse_events_term__num(&term, (enum parse_events__term_type)$1,
834 					/*config=*/NULL, /*num=*/1, /*novalue=*/true,
835 					&@1, /*loc_val=*/NULL);
836 
837 	if (err)
838 		PE_ABORT(err);
839 
840 	$$ = term;
841 }
842 |
843 PE_DRV_CFG_TERM
844 {
845 	struct parse_events_term *term;
846 	char *config = strdup($1);
847 	int err;
848 
849 	if (!config)
850 		YYNOMEM;
851 	err = parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_DRV_CFG, config, $1, &@1, NULL);
852 	if (err) {
853 		free($1);
854 		free(config);
855 		PE_ABORT(err);
856 	}
857 	$$ = term;
858 }
859 
860 sep_dc: ':' |
861 
862 sep_slash_slash_dc: '/' '/' | ':' |
863 
864 %%
865 
866 void parse_events_error(YYLTYPE *loc, void *parse_state,
867 			void *scanner __maybe_unused,
868 			char const *msg __maybe_unused)
869 {
870 	parse_events_evlist_error(parse_state, loc->last_column, "parser error");
871 }
872