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