]> git.karo-electronics.de Git - karo-tx-linux.git/blob - tools/perf/util/expr.y
Merge tag 'perf-core-for-mingo-4.12-20170503' of git://git.kernel.org/pub/scm/linux...
[karo-tx-linux.git] / tools / perf / util / expr.y
1 /* Simple expression parser */
2 %{
3 #include "util.h"
4 #include "util/debug.h"
5 #define IN_EXPR_Y 1
6 #include "expr.h"
7 #include <string.h>
8
9 #define MAXIDLEN 256
10 %}
11
12 %pure-parser
13 %parse-param { double *final_val }
14 %parse-param { struct parse_ctx *ctx }
15 %parse-param { const char **pp }
16 %lex-param { const char **pp }
17
18 %union {
19         double num;
20         char id[MAXIDLEN+1];
21 }
22
23 %token <num> NUMBER
24 %token <id> ID
25 %left '|'
26 %left '^'
27 %left '&'
28 %left '-' '+'
29 %left '*' '/' '%'
30 %left NEG NOT
31 %type <num> expr
32
33 %{
34 static int expr__lex(YYSTYPE *res, const char **pp);
35
36 static void expr__error(double *final_val __maybe_unused,
37                        struct parse_ctx *ctx __maybe_unused,
38                        const char **pp __maybe_unused,
39                        const char *s)
40 {
41         pr_debug("%s\n", s);
42 }
43
44 static int lookup_id(struct parse_ctx *ctx, char *id, double *val)
45 {
46         int i;
47
48         for (i = 0; i < ctx->num_ids; i++) {
49                 if (!strcasecmp(ctx->ids[i].name, id)) {
50                         *val = ctx->ids[i].val;
51                         return 0;
52                 }
53         }
54         return -1;
55 }
56
57 %}
58 %%
59
60 all_expr: expr                  { *final_val = $1; }
61         ;
62
63 expr:     NUMBER
64         | ID                    { if (lookup_id(ctx, $1, &$$) < 0) {
65                                         pr_debug("%s not found", $1);
66                                         YYABORT;
67                                   }
68                                 }
69         | expr '+' expr         { $$ = $1 + $3; }
70         | expr '-' expr         { $$ = $1 - $3; }
71         | expr '*' expr         { $$ = $1 * $3; }
72         | expr '/' expr         { if ($3 == 0) YYABORT; $$ = $1 / $3; }
73         | expr '%' expr         { if ((long)$3 == 0) YYABORT; $$ = (long)$1 % (long)$3; }
74         | '-' expr %prec NEG    { $$ = -$2; }
75         | '(' expr ')'          { $$ = $2; }
76         ;
77
78 %%
79
80 static int expr__symbol(YYSTYPE *res, const char *p, const char **pp)
81 {
82         char *dst = res->id;
83         const char *s = p;
84
85         while (isalnum(*p) || *p == '_' || *p == '.') {
86                 if (p - s >= MAXIDLEN)
87                         return -1;
88                 *dst++ = *p++;
89         }
90         *dst = 0;
91         *pp = p;
92         return ID;
93 }
94
95 static int expr__lex(YYSTYPE *res, const char **pp)
96 {
97         int tok;
98         const char *s;
99         const char *p = *pp;
100
101         while (isspace(*p))
102                 p++;
103         s = p;
104         switch (*p++) {
105         case 'a' ... 'z':
106         case 'A' ... 'Z':
107                 return expr__symbol(res, p - 1, pp);
108         case '0' ... '9': case '.':
109                 res->num = strtod(s, (char **)&p);
110                 tok = NUMBER;
111                 break;
112         default:
113                 tok = *s;
114                 break;
115         }
116         *pp = p;
117         return tok;
118 }
119
120 /* Caller must make sure id is allocated */
121 void expr__add_id(struct parse_ctx *ctx, const char *name, double val)
122 {
123         int idx;
124         assert(ctx->num_ids < MAX_PARSE_ID);
125         idx = ctx->num_ids++;
126         ctx->ids[idx].name = name;
127         ctx->ids[idx].val = val;
128 }
129
130 void expr__ctx_init(struct parse_ctx *ctx)
131 {
132         ctx->num_ids = 0;
133 }
134
135 int expr__find_other(const char *p, const char *one, const char ***other,
136                      int *num_otherp)
137 {
138         const char *orig = p;
139         int err = -1;
140         int num_other;
141
142         *other = malloc((EXPR_MAX_OTHER + 1) * sizeof(char *));
143         if (!*other)
144                 return -1;
145
146         num_other = 0;
147         for (;;) {
148                 YYSTYPE val;
149                 int tok = expr__lex(&val, &p);
150                 if (tok == 0) {
151                         err = 0;
152                         break;
153                 }
154                 if (tok == ID && strcasecmp(one, val.id)) {
155                         if (num_other >= EXPR_MAX_OTHER - 1) {
156                                 pr_debug("Too many extra events in %s\n", orig);
157                                 break;
158                         }
159                         (*other)[num_other] = strdup(val.id);
160                         if (!(*other)[num_other])
161                                 return -1;
162                         num_other++;
163                 }
164         }
165         (*other)[num_other] = NULL;
166         *num_otherp = num_other;
167         if (err) {
168                 *num_otherp = 0;
169                 free(*other);
170                 *other = NULL;
171         }
172         return err;
173 }