summaryrefslogtreecommitdiffstats
path: root/tools/perf/util/expr.y
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/expr.y')
-rw-r--r--tools/perf/util/expr.y127
1 files changed, 127 insertions, 0 deletions
diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y
new file mode 100644
index 000000000..d34b37039
--- /dev/null
+++ b/tools/perf/util/expr.y
@@ -0,0 +1,127 @@
+/* Simple expression parser */
+%{
+#define YYDEBUG 1
+#include <stdio.h>
+#include "util.h"
+#include "util/debug.h"
+#include <stdlib.h> // strtod()
+#define IN_EXPR_Y 1
+#include "expr.h"
+#include "smt.h"
+#include <string.h>
+
+static double d_ratio(double val0, double val1)
+{
+ if (val1 == 0) {
+ return 0;
+ }
+ return val0 / val1;
+}
+
+%}
+
+%define api.pure full
+
+%parse-param { double *final_val }
+%parse-param { struct expr_parse_ctx *ctx }
+%parse-param {void *scanner}
+%lex-param {void* scanner}
+
+%union {
+ double num;
+ char *str;
+}
+
+%token EXPR_PARSE EXPR_OTHER EXPR_ERROR
+%token <num> NUMBER
+%token <str> ID
+%destructor { free ($$); } <str>
+%token MIN MAX IF ELSE SMT_ON D_RATIO
+%left MIN MAX IF
+%left '|'
+%left '^'
+%left '&'
+%left '<' '>'
+%left '-' '+'
+%left '*' '/' '%'
+%left NEG NOT
+%type <num> expr if_expr
+
+%{
+static void expr_error(double *final_val __maybe_unused,
+ struct expr_parse_ctx *ctx __maybe_unused,
+ void *scanner,
+ const char *s)
+{
+ pr_debug("%s\n", s);
+}
+
+%}
+%%
+
+start:
+EXPR_PARSE all_expr
+|
+EXPR_OTHER all_other
+
+all_other: all_other other
+|
+
+other: ID
+{
+ expr__add_id(ctx, $1);
+}
+|
+MIN | MAX | IF | ELSE | SMT_ON | NUMBER | '|' | '^' | '&' | '-' | '+' | '*' | '/' | '%' | '(' | ')' | ','
+|
+'<' | '>' | D_RATIO
+
+all_expr: if_expr { *final_val = $1; }
+ ;
+
+if_expr:
+ expr IF expr ELSE expr { $$ = $3 ? $1 : $5; }
+ | expr
+ ;
+
+expr: NUMBER
+ | ID {
+ struct expr_id_data *data;
+
+ if (expr__resolve_id(ctx, $1, &data)) {
+ free($1);
+ YYABORT;
+ }
+
+ $$ = data->val;
+ free($1);
+ }
+ | expr '|' expr { $$ = (long)$1 | (long)$3; }
+ | expr '&' expr { $$ = (long)$1 & (long)$3; }
+ | expr '^' expr { $$ = (long)$1 ^ (long)$3; }
+ | expr '<' expr { $$ = $1 < $3; }
+ | expr '>' expr { $$ = $1 > $3; }
+ | expr '+' expr { $$ = $1 + $3; }
+ | expr '-' expr { $$ = $1 - $3; }
+ | expr '*' expr { $$ = $1 * $3; }
+ | expr '/' expr { if ($3 == 0) {
+ pr_debug("division by zero\n");
+ YYABORT;
+ }
+ $$ = $1 / $3;
+ }
+ | expr '%' expr { if ((long)$3 == 0) {
+ pr_debug("division by zero\n");
+ YYABORT;
+ }
+ $$ = (long)$1 % (long)$3;
+ }
+ | '-' expr %prec NEG { $$ = -$2; }
+ | '(' if_expr ')' { $$ = $2; }
+ | MIN '(' expr ',' expr ')' { $$ = $3 < $5 ? $3 : $5; }
+ | MAX '(' expr ',' expr ')' { $$ = $3 > $5 ? $3 : $5; }
+ | SMT_ON { $$ = smt_on() > 0; }
+ | D_RATIO '(' expr ',' expr ')' { $$ = d_ratio($3,$5); }
+ ;
+
+%%