1 /* Simple expression parser */
4 #include "util/debug.h"
14 %parse
-param
{ double *final_val
}
15 %parse
-param
{ struct parse_ctx
*ctx
}
16 %parse
-param
{ const char **pp
}
17 %lex
-param
{ const char **pp
}
26 %token MIN MAX IF ELSE SMT_ON
34 %type
<num
> expr if_expr
37 static int expr__lex
(YYSTYPE *res
, const char **pp
);
39 static void expr__error
(double *final_val __maybe_unused
,
40 struct parse_ctx
*ctx __maybe_unused
,
41 const char **pp __maybe_unused
,
47 static int lookup_id
(struct parse_ctx
*ctx
, char *id
, double *val
)
51 for
(i
= 0; i
< ctx
->num_ids
; i
++) {
52 if
(!strcasecmp
(ctx
->ids
[i
].name
, id
)) {
53 *val
= ctx
->ids
[i
].val
;
63 all_expr: if_expr
{ *final_val
= $1; }
67 expr IF expr ELSE expr
{ $$
= $3 ?
$1 : $5; }
72 | ID
{ if
(lookup_id
(ctx
, $1, &$$
) < 0) {
73 pr_debug
("%s not found\n", $1);
77 | expr
'|' expr
{ $$
= (long)$1 |
(long)$3; }
78 | expr
'&' expr
{ $$
= (long)$1 & (long)$3; }
79 | expr
'^' expr
{ $$
= (long)$1 ^
(long)$3; }
80 | expr
'+' expr
{ $$
= $1 + $3; }
81 | expr
'-' expr
{ $$
= $1 - $3; }
82 | expr
'*' expr
{ $$
= $1 * $3; }
83 | expr
'/' expr
{ if
($3 == 0) YYABORT; $$
= $1 / $3; }
84 | expr
'%' expr
{ if
((long)$3 == 0) YYABORT; $$
= (long)$1 %
(long)$3; }
85 |
'-' expr %prec NEG
{ $$
= -$2; }
86 |
'(' if_expr
')' { $$
= $2; }
87 | MIN
'(' expr
',' expr
')' { $$
= $3 < $5 ?
$3 : $5; }
88 | MAX
'(' expr
',' expr
')' { $$
= $3 > $5 ?
$3 : $5; }
89 | SMT_ON
{ $$
= smt_on
() > 0; }
94 static int expr__symbol
(YYSTYPE *res
, const char *p
, const char **pp
)
102 while
(isalnum
(*p
) ||
*p
== '_' ||
*p
== '.' ||
*p
== ':' ||
*p
== '@' ||
*p
== '\\') {
103 if
(p
- s
>= MAXIDLEN
)
106 * Allow @ instead of / to be able to specify pmu/event/ without
107 * conflicts with normal division.
122 if
(!strcmp
(dst
, "min"))
124 if
(!strcmp
(dst
, "max"))
128 if
(!strcmp
(dst
, "if"))
132 if
(!strcmp
(dst
, "else"))
136 if
(!strcasecmp
(dst
, "#smt_on"))
143 static int expr__lex
(YYSTYPE *res
, const char **pp
)
156 return expr__symbol
(res
, p
- 1, pp
);
157 case
'0' ...
'9': case
'.':
158 res
->num
= strtod
(s
, (char **)&p
);
169 /* Caller must make sure id is allocated */
170 void expr__add_id
(struct parse_ctx
*ctx
, const char *name
, double val
)
173 assert
(ctx
->num_ids
< MAX_PARSE_ID
);
174 idx
= ctx
->num_ids
++;
175 ctx
->ids
[idx
].name
= name
;
176 ctx
->ids
[idx
].val
= val
;
179 void expr__ctx_init
(struct parse_ctx
*ctx
)
184 static bool already_seen
(const char *val
, const char *one
, const char **other
,
189 if
(one
&& !strcasecmp
(one
, val
))
191 for
(i
= 0; i
< num_other
; i
++)
192 if
(!strcasecmp
(other
[i
], val
))
197 int expr__find_other
(const char *p
, const char *one
, const char ***other
,
200 const char *orig
= p
;
204 *other
= malloc
((EXPR_MAX_OTHER
+ 1) * sizeof
(char *));
211 int tok
= expr__lex
(&val
, &p
);
216 if
(tok
== ID
&& !already_seen
(val.id
, one
, *other
, num_other
)) {
217 if
(num_other
>= EXPR_MAX_OTHER
- 1) {
218 pr_debug
("Too many extra events in %s\n", orig
);
221 (*other
)[num_other
] = strdup
(val.id
);
222 if
(!(*other
)[num_other
])
227 (*other
)[num_other
] = NULL
;
228 *num_otherp
= num_other
;