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