perf expr: Move expr lexer to flex
[linux-2.6-microblaze.git] / tools / perf / util / expr.l
diff --git a/tools/perf/util/expr.l b/tools/perf/util/expr.l
new file mode 100644 (file)
index 0000000..1928f2a
--- /dev/null
@@ -0,0 +1,114 @@
+%option prefix="expr_"
+%option reentrant
+%option bison-bridge
+
+%{
+#include <linux/compiler.h>
+#include "expr.h"
+#include "expr-bison.h"
+
+char *expr_get_text(yyscan_t yyscanner);
+YYSTYPE *expr_get_lval(yyscan_t yyscanner);
+
+static int __value(YYSTYPE *yylval, char *str, int base, int token)
+{
+       u64 num;
+
+       errno = 0;
+       num = strtoull(str, NULL, base);
+       if (errno)
+               return EXPR_ERROR;
+
+       yylval->num = num;
+       return token;
+}
+
+static int value(yyscan_t scanner, int base)
+{
+       YYSTYPE *yylval = expr_get_lval(scanner);
+       char *text = expr_get_text(scanner);
+
+       return __value(yylval, text, base, NUMBER);
+}
+
+/*
+ * Allow @ instead of / to be able to specify pmu/event/ without
+ * conflicts with normal division.
+ */
+static char *normalize(char *str)
+{
+       char *ret = str;
+       char *dst = str;
+
+       while (*str) {
+               if (*str == '@')
+                       *dst++ = '/';
+               else if (*str == '\\')
+                       *dst++ = *++str;
+               else
+                       *dst++ = *str;
+               str++;
+       }
+
+       *dst = 0x0;
+       return ret;
+}
+
+static int str(yyscan_t scanner, int token)
+{
+       YYSTYPE *yylval = expr_get_lval(scanner);
+       char *text = expr_get_text(scanner);
+
+       yylval->str = normalize(strdup(text));
+       if (!yylval->str)
+               return EXPR_ERROR;
+
+       yylval->str = normalize(yylval->str);
+       return token;
+}
+%}
+
+number         [0-9]+
+
+sch            [-,=]
+spec           \\{sch}
+sym            [0-9a-zA-Z_\.:@]+
+symbol         {spec}*{sym}*{spec}*{sym}*
+
+%%
+       {
+               int start_token;
+
+               start_token = parse_events_get_extra(yyscanner);
+
+               if (start_token) {
+                       parse_events_set_extra(NULL, yyscanner);
+                       return start_token;
+               }
+       }
+
+max            { return MAX; }
+min            { return MIN; }
+if             { return IF; }
+else           { return ELSE; }
+#smt_on                { return SMT_ON; }
+{number}       { return value(yyscanner, 10); }
+{symbol}       { return str(yyscanner, ID); }
+"|"            { return '|'; }
+"^"            { return '^'; }
+"&"            { return '&'; }
+"-"            { return '-'; }
+"+"            { return '+'; }
+"*"            { return '*'; }
+"/"            { return '/'; }
+"%"            { return '%'; }
+"("            { return '('; }
+")"            { return ')'; }
+","            { return ','; }
+.              { }
+%%
+
+int expr_wrap(void *scanner __maybe_unused)
+{
+       return 1;
+}