xref: /linux/tools/perf/util/expr.y (revision c295036b6a2cf968ceac76d16d5fac43e22369f7)
107516736SAndi Kleen /* Simple expression parser */
207516736SAndi Kleen %{
307516736SAndi Kleen #include "util.h"
407516736SAndi Kleen #include "util/debug.h"
507516736SAndi Kleen #define IN_EXPR_Y 1
607516736SAndi Kleen #include "expr.h"
707516736SAndi Kleen #include <string.h>
807516736SAndi Kleen 
907516736SAndi Kleen #define MAXIDLEN 256
1007516736SAndi Kleen %}
1107516736SAndi Kleen 
1207516736SAndi Kleen %pure-parser
1307516736SAndi Kleen %parse-param { double *final_val }
1407516736SAndi Kleen %parse-param { struct parse_ctx *ctx }
1507516736SAndi Kleen %parse-param { const char **pp }
1607516736SAndi Kleen %lex-param { const char **pp }
1707516736SAndi Kleen 
1807516736SAndi Kleen %union {
1907516736SAndi Kleen 	double num;
2007516736SAndi Kleen 	char id[MAXIDLEN+1];
2107516736SAndi Kleen }
2207516736SAndi Kleen 
2307516736SAndi Kleen %token <num> NUMBER
2407516736SAndi Kleen %token <id> ID
2507516736SAndi Kleen %left '|'
2607516736SAndi Kleen %left '^'
2707516736SAndi Kleen %left '&'
2807516736SAndi Kleen %left '-' '+'
2907516736SAndi Kleen %left '*' '/' '%'
3007516736SAndi Kleen %left NEG NOT
3107516736SAndi Kleen %type <num> expr
3207516736SAndi Kleen 
3307516736SAndi Kleen %{
3407516736SAndi Kleen static int expr__lex(YYSTYPE *res, const char **pp);
3507516736SAndi Kleen 
3607516736SAndi Kleen static void expr__error(double *final_val __maybe_unused,
3707516736SAndi Kleen 		       struct parse_ctx *ctx __maybe_unused,
3807516736SAndi Kleen 		       const char **pp __maybe_unused,
3907516736SAndi Kleen 		       const char *s)
4007516736SAndi Kleen {
4107516736SAndi Kleen 	pr_debug("%s\n", s);
4207516736SAndi Kleen }
4307516736SAndi Kleen 
4407516736SAndi Kleen static int lookup_id(struct parse_ctx *ctx, char *id, double *val)
4507516736SAndi Kleen {
4607516736SAndi Kleen 	int i;
4707516736SAndi Kleen 
4807516736SAndi Kleen 	for (i = 0; i < ctx->num_ids; i++) {
4907516736SAndi Kleen 		if (!strcasecmp(ctx->ids[i].name, id)) {
5007516736SAndi Kleen 			*val = ctx->ids[i].val;
5107516736SAndi Kleen 			return 0;
5207516736SAndi Kleen 		}
5307516736SAndi Kleen 	}
5407516736SAndi Kleen 	return -1;
5507516736SAndi Kleen }
5607516736SAndi Kleen 
5707516736SAndi Kleen %}
5807516736SAndi Kleen %%
5907516736SAndi Kleen 
6007516736SAndi Kleen all_expr: expr			{ *final_val = $1; }
6107516736SAndi Kleen 	;
6207516736SAndi Kleen 
6307516736SAndi Kleen expr:	  NUMBER
6407516736SAndi Kleen 	| ID			{ if (lookup_id(ctx, $1, &$$) < 0) {
65*c295036bSAndi Kleen 					pr_debug("%s not found\n", $1);
6607516736SAndi Kleen 					YYABORT;
6707516736SAndi Kleen 				  }
6807516736SAndi Kleen 				}
6907516736SAndi Kleen 	| expr '+' expr		{ $$ = $1 + $3; }
7007516736SAndi Kleen 	| expr '-' expr		{ $$ = $1 - $3; }
7107516736SAndi Kleen 	| expr '*' expr		{ $$ = $1 * $3; }
7207516736SAndi Kleen 	| expr '/' expr		{ if ($3 == 0) YYABORT; $$ = $1 / $3; }
7307516736SAndi Kleen 	| expr '%' expr		{ if ((long)$3 == 0) YYABORT; $$ = (long)$1 % (long)$3; }
7407516736SAndi Kleen 	| '-' expr %prec NEG	{ $$ = -$2; }
7507516736SAndi Kleen 	| '(' expr ')'		{ $$ = $2; }
7607516736SAndi Kleen 	;
7707516736SAndi Kleen 
7807516736SAndi Kleen %%
7907516736SAndi Kleen 
8007516736SAndi Kleen static int expr__symbol(YYSTYPE *res, const char *p, const char **pp)
8107516736SAndi Kleen {
8207516736SAndi Kleen 	char *dst = res->id;
8307516736SAndi Kleen 	const char *s = p;
8407516736SAndi Kleen 
8507516736SAndi Kleen 	while (isalnum(*p) || *p == '_' || *p == '.') {
8607516736SAndi Kleen 		if (p - s >= MAXIDLEN)
8707516736SAndi Kleen 			return -1;
8807516736SAndi Kleen 		*dst++ = *p++;
8907516736SAndi Kleen 	}
9007516736SAndi Kleen 	*dst = 0;
9107516736SAndi Kleen 	*pp = p;
9207516736SAndi Kleen 	return ID;
9307516736SAndi Kleen }
9407516736SAndi Kleen 
9507516736SAndi Kleen static int expr__lex(YYSTYPE *res, const char **pp)
9607516736SAndi Kleen {
9707516736SAndi Kleen 	int tok;
9807516736SAndi Kleen 	const char *s;
9907516736SAndi Kleen 	const char *p = *pp;
10007516736SAndi Kleen 
10107516736SAndi Kleen 	while (isspace(*p))
10207516736SAndi Kleen 		p++;
10307516736SAndi Kleen 	s = p;
10407516736SAndi Kleen 	switch (*p++) {
10507516736SAndi Kleen 	case 'a' ... 'z':
10607516736SAndi Kleen 	case 'A' ... 'Z':
10707516736SAndi Kleen 		return expr__symbol(res, p - 1, pp);
10807516736SAndi Kleen 	case '0' ... '9': case '.':
10907516736SAndi Kleen 		res->num = strtod(s, (char **)&p);
11007516736SAndi Kleen 		tok = NUMBER;
11107516736SAndi Kleen 		break;
11207516736SAndi Kleen 	default:
11307516736SAndi Kleen 		tok = *s;
11407516736SAndi Kleen 		break;
11507516736SAndi Kleen 	}
11607516736SAndi Kleen 	*pp = p;
11707516736SAndi Kleen 	return tok;
11807516736SAndi Kleen }
11907516736SAndi Kleen 
12007516736SAndi Kleen /* Caller must make sure id is allocated */
12107516736SAndi Kleen void expr__add_id(struct parse_ctx *ctx, const char *name, double val)
12207516736SAndi Kleen {
12307516736SAndi Kleen 	int idx;
12407516736SAndi Kleen 	assert(ctx->num_ids < MAX_PARSE_ID);
12507516736SAndi Kleen 	idx = ctx->num_ids++;
12607516736SAndi Kleen 	ctx->ids[idx].name = name;
12707516736SAndi Kleen 	ctx->ids[idx].val = val;
12807516736SAndi Kleen }
12907516736SAndi Kleen 
13007516736SAndi Kleen void expr__ctx_init(struct parse_ctx *ctx)
13107516736SAndi Kleen {
13207516736SAndi Kleen 	ctx->num_ids = 0;
13307516736SAndi Kleen }
13407516736SAndi Kleen 
13507516736SAndi Kleen int expr__find_other(const char *p, const char *one, const char ***other,
13607516736SAndi Kleen 		     int *num_otherp)
13707516736SAndi Kleen {
13807516736SAndi Kleen 	const char *orig = p;
13907516736SAndi Kleen 	int err = -1;
14007516736SAndi Kleen 	int num_other;
14107516736SAndi Kleen 
14207516736SAndi Kleen 	*other = malloc((EXPR_MAX_OTHER + 1) * sizeof(char *));
14307516736SAndi Kleen 	if (!*other)
14407516736SAndi Kleen 		return -1;
14507516736SAndi Kleen 
14607516736SAndi Kleen 	num_other = 0;
14707516736SAndi Kleen 	for (;;) {
14807516736SAndi Kleen 		YYSTYPE val;
14907516736SAndi Kleen 		int tok = expr__lex(&val, &p);
15007516736SAndi Kleen 		if (tok == 0) {
15107516736SAndi Kleen 			err = 0;
15207516736SAndi Kleen 			break;
15307516736SAndi Kleen 		}
15407516736SAndi Kleen 		if (tok == ID && strcasecmp(one, val.id)) {
15507516736SAndi Kleen 			if (num_other >= EXPR_MAX_OTHER - 1) {
15607516736SAndi Kleen 				pr_debug("Too many extra events in %s\n", orig);
15707516736SAndi Kleen 				break;
15807516736SAndi Kleen 			}
15907516736SAndi Kleen 			(*other)[num_other] = strdup(val.id);
16007516736SAndi Kleen 			if (!(*other)[num_other])
16107516736SAndi Kleen 				return -1;
16207516736SAndi Kleen 			num_other++;
16307516736SAndi Kleen 		}
16407516736SAndi Kleen 	}
16507516736SAndi Kleen 	(*other)[num_other] = NULL;
16607516736SAndi Kleen 	*num_otherp = num_other;
16707516736SAndi Kleen 	if (err) {
16807516736SAndi Kleen 		*num_otherp = 0;
16907516736SAndi Kleen 		free(*other);
17007516736SAndi Kleen 		*other = NULL;
17107516736SAndi Kleen 	}
17207516736SAndi Kleen 	return err;
17307516736SAndi Kleen }
174