1 /* Simple expression parser */
4 #include "util/debug.h"
5 #include <stdlib.h> // strtod()
17 %parse
-param
{ double *final_val
}
18 %parse
-param
{ struct parse_ctx
*ctx
}
19 %parse
-param
{ const char **pp
}
20 %lex
-param
{ const char **pp
}
29 %token MIN MAX IF ELSE SMT_ON
37 %type
<num
> expr if_expr
40 static int expr__lex
(YYSTYPE *res
, const char **pp
);
42 static void expr__error
(double *final_val __maybe_unused
,
43 struct parse_ctx
*ctx __maybe_unused
,
44 const char **pp __maybe_unused
,
50 static int lookup_id
(struct parse_ctx
*ctx
, char *id
, double *val
)
54 for
(i
= 0; i
< ctx
->num_ids
; i
++) {
55 if
(!strcasecmp
(ctx
->ids
[i
].name
, id
)) {
56 *val
= ctx
->ids
[i
].val
;
66 all_expr: if_expr
{ *final_val
= $1; }
70 expr IF expr ELSE expr
{ $$
= $3 ?
$1 : $5; }
75 | ID
{ if
(lookup_id
(ctx
, $1, &$$
) < 0) {
76 pr_debug
("%s not found\n", $1);
80 | expr
'|' expr
{ $$
= (long)$1 |
(long)$3; }
81 | expr
'&' expr
{ $$
= (long)$1 & (long)$3; }
82 | expr
'^' expr
{ $$
= (long)$1 ^
(long)$3; }
83 | expr
'+' expr
{ $$
= $1 + $3; }
84 | expr
'-' expr
{ $$
= $1 - $3; }
85 | expr
'*' expr
{ $$
= $1 * $3; }
86 | expr
'/' expr
{ if
($3 == 0) YYABORT; $$
= $1 / $3; }
87 | expr
'%' expr
{ if
((long)$3 == 0) YYABORT; $$
= (long)$1 %
(long)$3; }
88 |
'-' expr %prec NEG
{ $$
= -$2; }
89 |
'(' if_expr
')' { $$
= $2; }
90 | MIN
'(' expr
',' expr
')' { $$
= $3 < $5 ?
$3 : $5; }
91 | MAX
'(' expr
',' expr
')' { $$
= $3 > $5 ?
$3 : $5; }
92 | SMT_ON
{ $$
= smt_on
() > 0; }
97 static int expr__symbol
(YYSTYPE *res
, const char *p
, const char **pp
)
105 while
(isalnum
(*p
) ||
*p
== '_' ||
*p
== '.' ||
*p
== ':' ||
*p
== '@' ||
*p
== '\\') {
106 if
(p
- s
>= MAXIDLEN
)
109 * Allow @ instead of / to be able to specify pmu/event/ without
110 * conflicts with normal division.
125 if
(!strcmp
(dst
, "min"))
127 if
(!strcmp
(dst
, "max"))
131 if
(!strcmp
(dst
, "if"))
135 if
(!strcmp
(dst
, "else"))
139 if
(!strcasecmp
(dst
, "#smt_on"))
146 static int expr__lex
(YYSTYPE *res
, const char **pp
)
159 return expr__symbol
(res
, p
- 1, pp
);
160 case
'0' ...
'9': case
'.':
161 res
->num
= strtod
(s
, (char **)&p
);
172 /* Caller must make sure id is allocated */
173 void expr__add_id
(struct parse_ctx
*ctx
, const char *name
, double val
)
176 assert
(ctx
->num_ids
< MAX_PARSE_ID
);
177 idx
= ctx
->num_ids
++;
178 ctx
->ids
[idx
].name
= name
;
179 ctx
->ids
[idx
].val
= val
;
182 void expr__ctx_init
(struct parse_ctx
*ctx
)
187 static bool already_seen
(const char *val
, const char *one
, const char **other
,
192 if
(one
&& !strcasecmp
(one
, val
))
194 for
(i
= 0; i
< num_other
; i
++)
195 if
(!strcasecmp
(other
[i
], val
))
200 int expr__find_other
(const char *p
, const char *one
, const char ***other
,
203 const char *orig
= p
;
207 *other
= malloc
((EXPR_MAX_OTHER
+ 1) * sizeof
(char *));
214 int tok
= expr__lex
(&val
, &p
);
219 if
(tok
== ID
&& !already_seen
(val.id
, one
, *other
, num_other
)) {
220 if
(num_other
>= EXPR_MAX_OTHER
- 1) {
221 pr_debug
("Too many extra events in %s\n", orig
);
224 (*other
)[num_other
] = strdup
(val.id
);
225 if
(!(*other
)[num_other
])
230 (*other
)[num_other
] = NULL
;
231 *num_otherp
= num_other
;