]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - tools/perf/util/expr.y
Merge branch 'work.uaccess-unaligned' of git://git.kernel.org/pub/scm/linux/kernel...
[mirror_ubuntu-bionic-kernel.git] / tools / perf / util / expr.y
CommitLineData
07516736
AK
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%{
34static int expr__lex(YYSTYPE *res, const char **pp);
35
36static 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
44static 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
60all_expr: expr { *final_val = $1; }
61 ;
62
63expr: 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
80static 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
95static 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 */
121void 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
130void expr__ctx_init(struct parse_ctx *ctx)
131{
132 ctx->num_ids = 0;
133}
134
135int 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}