xref: /linux/tools/perf/util/expr.y (revision 9be27a5d416925aef4ff816379c31b8cd18ff55d)
107516736SAndi Kleen /* Simple expression parser */
207516736SAndi Kleen %{
326226a97SJiri Olsa #define YYDEBUG 1
426226a97SJiri Olsa #include <stdio.h>
507516736SAndi Kleen #include "util.h"
607516736SAndi Kleen #include "util/debug.h"
78520a98dSArnaldo Carvalho de Melo #include <stdlib.h> // strtod()
807516736SAndi Kleen #define IN_EXPR_Y 1
907516736SAndi Kleen #include "expr.h"
10d73bad06SAndi Kleen #include "smt.h"
1107516736SAndi Kleen #include <string.h>
1207516736SAndi Kleen 
1307516736SAndi Kleen %}
1407516736SAndi Kleen 
15fc8c0a99SJiri Olsa %define api.pure full
16fc8c0a99SJiri Olsa 
1707516736SAndi Kleen %parse-param { double *final_val }
18aecce63eSJiri Olsa %parse-param { struct expr_parse_ctx *ctx }
1926226a97SJiri Olsa %parse-param {void *scanner}
2026226a97SJiri Olsa %lex-param {void* scanner}
2107516736SAndi Kleen 
2207516736SAndi Kleen %union {
2307516736SAndi Kleen 	double	 num;
2426226a97SJiri Olsa 	char	*str;
2507516736SAndi Kleen }
2607516736SAndi Kleen 
2726226a97SJiri Olsa %token EXPR_PARSE EXPR_OTHER EXPR_ERROR
2807516736SAndi Kleen %token <num> NUMBER
2926226a97SJiri Olsa %token <str> ID
30d73bad06SAndi Kleen %token MIN MAX IF ELSE SMT_ON
31d73bad06SAndi Kleen %left MIN MAX IF
3207516736SAndi Kleen %left '|'
3307516736SAndi Kleen %left '^'
3407516736SAndi Kleen %left '&'
3507516736SAndi Kleen %left '-' '+'
3607516736SAndi Kleen %left '*' '/' '%'
3707516736SAndi Kleen %left NEG NOT
38d73bad06SAndi Kleen %type <num> expr if_expr
3907516736SAndi Kleen 
4007516736SAndi Kleen %{
4126226a97SJiri Olsa static void expr_error(double *final_val __maybe_unused,
42aecce63eSJiri Olsa 		       struct expr_parse_ctx *ctx __maybe_unused,
4326226a97SJiri Olsa 		       void *scanner,
4407516736SAndi Kleen 		       const char *s)
4507516736SAndi Kleen {
4607516736SAndi Kleen 	pr_debug("%s\n", s);
4707516736SAndi Kleen }
4807516736SAndi Kleen 
49aecce63eSJiri Olsa static int lookup_id(struct expr_parse_ctx *ctx, char *id, double *val)
5007516736SAndi Kleen {
5107516736SAndi Kleen 	int i;
5207516736SAndi Kleen 
5307516736SAndi Kleen 	for (i = 0; i < ctx->num_ids; i++) {
5407516736SAndi Kleen 		if (!strcasecmp(ctx->ids[i].name, id)) {
5507516736SAndi Kleen 			*val = ctx->ids[i].val;
5607516736SAndi Kleen 			return 0;
5707516736SAndi Kleen 		}
5807516736SAndi Kleen 	}
5907516736SAndi Kleen 	return -1;
6007516736SAndi Kleen }
6107516736SAndi Kleen 
6207516736SAndi Kleen %}
6307516736SAndi Kleen %%
6407516736SAndi Kleen 
6526226a97SJiri Olsa start:
6626226a97SJiri Olsa EXPR_PARSE all_expr
6726226a97SJiri Olsa |
6826226a97SJiri Olsa EXPR_OTHER all_other
6926226a97SJiri Olsa 
7026226a97SJiri Olsa all_other: all_other other
7126226a97SJiri Olsa |
7226226a97SJiri Olsa 
7326226a97SJiri Olsa other: ID
7426226a97SJiri Olsa {
7526226a97SJiri Olsa 	if (ctx->num_ids + 1 >= EXPR_MAX_OTHER) {
7626226a97SJiri Olsa 		pr_err("failed: way too many variables");
7726226a97SJiri Olsa 		YYABORT;
7826226a97SJiri Olsa 	}
7926226a97SJiri Olsa 
8026226a97SJiri Olsa 	ctx->ids[ctx->num_ids++].name = $1;
8126226a97SJiri Olsa }
8226226a97SJiri Olsa |
83cb59fa79SIan Rogers MIN | MAX | IF | ELSE | SMT_ON | NUMBER | '|' | '^' | '&' | '-' | '+' | '*' | '/' | '%' | '(' | ')' | ','
8426226a97SJiri Olsa 
8526226a97SJiri Olsa 
86d73bad06SAndi Kleen all_expr: if_expr			{ *final_val = $1; }
87d73bad06SAndi Kleen 	;
88d73bad06SAndi Kleen 
89d73bad06SAndi Kleen if_expr:
90d73bad06SAndi Kleen 	expr IF expr ELSE expr { $$ = $3 ? $1 : $5; }
91d73bad06SAndi Kleen 	| expr
9207516736SAndi Kleen 	;
9307516736SAndi Kleen 
9407516736SAndi Kleen expr:	  NUMBER
9507516736SAndi Kleen 	| ID			{ if (lookup_id(ctx, $1, &$$) < 0) {
96c295036bSAndi Kleen 					pr_debug("%s not found\n", $1);
9707516736SAndi Kleen 					YYABORT;
9807516736SAndi Kleen 				  }
9907516736SAndi Kleen 				}
100d73bad06SAndi Kleen 	| expr '|' expr		{ $$ = (long)$1 | (long)$3; }
101d73bad06SAndi Kleen 	| expr '&' expr		{ $$ = (long)$1 & (long)$3; }
102d73bad06SAndi Kleen 	| expr '^' expr		{ $$ = (long)$1 ^ (long)$3; }
10307516736SAndi Kleen 	| expr '+' expr		{ $$ = $1 + $3; }
10407516736SAndi Kleen 	| expr '-' expr		{ $$ = $1 - $3; }
10507516736SAndi Kleen 	| expr '*' expr		{ $$ = $1 * $3; }
106*9be27a5dSIan Rogers 	| expr '/' expr		{ if ($3 == 0) {
107*9be27a5dSIan Rogers 					pr_debug("division by zero\n");
108*9be27a5dSIan Rogers 					YYABORT;
109*9be27a5dSIan Rogers 				  }
110*9be27a5dSIan Rogers 				  $$ = $1 / $3;
111*9be27a5dSIan Rogers 	                        }
112*9be27a5dSIan Rogers 	| expr '%' expr		{ if ((long)$3 == 0) {
113*9be27a5dSIan Rogers 					pr_debug("division by zero\n");
114*9be27a5dSIan Rogers 					YYABORT;
115*9be27a5dSIan Rogers 				  }
116*9be27a5dSIan Rogers 				  $$ = (long)$1 % (long)$3;
117*9be27a5dSIan Rogers 	                        }
11807516736SAndi Kleen 	| '-' expr %prec NEG	{ $$ = -$2; }
119d73bad06SAndi Kleen 	| '(' if_expr ')'	{ $$ = $2; }
120d73bad06SAndi Kleen 	| MIN '(' expr ',' expr ')' { $$ = $3 < $5 ? $3 : $5; }
121d73bad06SAndi Kleen 	| MAX '(' expr ',' expr ')' { $$ = $3 > $5 ? $3 : $5; }
122d73bad06SAndi Kleen 	| SMT_ON		 { $$ = smt_on() > 0; }
12307516736SAndi Kleen 	;
12407516736SAndi Kleen 
12507516736SAndi Kleen %%
126