perf expr: Move expr lexer to flex
Adding expr flex code instead of the manual parser code. So it's easily extensible in upcoming changes. The new flex code is in flex.l object and gets compiled like all the other flexers we use. It's defined as flex reentrant parser. It's used by both expr__parse and expr__find_other interfaces by separating the starting point. There's no intended change of functionality ;-) the test expr is passing. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Reviewed-by: Andi Kleen <ak@linux.intel.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: John Garry <john.garry@huawei.com> Cc: Kajol Jain <kjain@linux.ibm.com> Cc: Michael Petlan <mpetlan@redhat.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Ravi Bangoria <ravi.bangoria@linux.ibm.com> Link: http://lore.kernel.org/lkml/20200228093616.67125-3-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:

committed by
Arnaldo Carvalho de Melo

parent
576a65b697
commit
26226a9772
@@ -1,5 +1,7 @@
|
||||
/* Simple expression parser */
|
||||
%{
|
||||
#define YYDEBUG 1
|
||||
#include <stdio.h>
|
||||
#include "util.h"
|
||||
#include "util/debug.h"
|
||||
#include <stdlib.h> // strtod()
|
||||
@@ -8,23 +10,23 @@
|
||||
#include "smt.h"
|
||||
#include <string.h>
|
||||
|
||||
#define MAXIDLEN 256
|
||||
%}
|
||||
|
||||
%define api.pure full
|
||||
|
||||
%parse-param { double *final_val }
|
||||
%parse-param { struct parse_ctx *ctx }
|
||||
%parse-param { const char **pp }
|
||||
%lex-param { const char **pp }
|
||||
%parse-param {void *scanner}
|
||||
%lex-param {void* scanner}
|
||||
|
||||
%union {
|
||||
double num;
|
||||
char id[MAXIDLEN+1];
|
||||
double num;
|
||||
char *str;
|
||||
}
|
||||
|
||||
%token EXPR_PARSE EXPR_OTHER EXPR_ERROR
|
||||
%token <num> NUMBER
|
||||
%token <id> ID
|
||||
%token <str> ID
|
||||
%token MIN MAX IF ELSE SMT_ON
|
||||
%left MIN MAX IF
|
||||
%left '|'
|
||||
@@ -36,11 +38,9 @@
|
||||
%type <num> expr if_expr
|
||||
|
||||
%{
|
||||
static int expr__lex(YYSTYPE *res, const char **pp);
|
||||
|
||||
static void expr__error(double *final_val __maybe_unused,
|
||||
static void expr_error(double *final_val __maybe_unused,
|
||||
struct parse_ctx *ctx __maybe_unused,
|
||||
const char **pp __maybe_unused,
|
||||
void *scanner,
|
||||
const char *s)
|
||||
{
|
||||
pr_debug("%s\n", s);
|
||||
@@ -62,6 +62,27 @@ static int lookup_id(struct parse_ctx *ctx, char *id, double *val)
|
||||
%}
|
||||
%%
|
||||
|
||||
start:
|
||||
EXPR_PARSE all_expr
|
||||
|
|
||||
EXPR_OTHER all_other
|
||||
|
||||
all_other: all_other other
|
||||
|
|
||||
|
||||
other: ID
|
||||
{
|
||||
if (ctx->num_ids + 1 >= EXPR_MAX_OTHER) {
|
||||
pr_err("failed: way too many variables");
|
||||
YYABORT;
|
||||
}
|
||||
|
||||
ctx->ids[ctx->num_ids++].name = $1;
|
||||
}
|
||||
|
|
||||
MIN | MAX | IF | ELSE | SMT_ON | NUMBER | '|' | '^' | '&' | '-' | '+' | '*' | '/' | '%' | '(' | ')'
|
||||
|
||||
|
||||
all_expr: if_expr { *final_val = $1; }
|
||||
;
|
||||
|
||||
@@ -92,131 +113,3 @@ expr: NUMBER
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
static int expr__symbol(YYSTYPE *res, const char *p, const char **pp)
|
||||
{
|
||||
char *dst = res->id;
|
||||
const char *s = p;
|
||||
|
||||
if (*p == '#')
|
||||
*dst++ = *p++;
|
||||
|
||||
while (isalnum(*p) || *p == '_' || *p == '.' || *p == ':' || *p == '@' || *p == '\\') {
|
||||
if (p - s >= MAXIDLEN)
|
||||
return -1;
|
||||
/*
|
||||
* Allow @ instead of / to be able to specify pmu/event/ without
|
||||
* conflicts with normal division.
|
||||
*/
|
||||
if (*p == '@')
|
||||
*dst++ = '/';
|
||||
else if (*p == '\\')
|
||||
*dst++ = *++p;
|
||||
else
|
||||
*dst++ = *p;
|
||||
p++;
|
||||
}
|
||||
*dst = 0;
|
||||
*pp = p;
|
||||
dst = res->id;
|
||||
switch (dst[0]) {
|
||||
case 'm':
|
||||
if (!strcmp(dst, "min"))
|
||||
return MIN;
|
||||
if (!strcmp(dst, "max"))
|
||||
return MAX;
|
||||
break;
|
||||
case 'i':
|
||||
if (!strcmp(dst, "if"))
|
||||
return IF;
|
||||
break;
|
||||
case 'e':
|
||||
if (!strcmp(dst, "else"))
|
||||
return ELSE;
|
||||
break;
|
||||
case '#':
|
||||
if (!strcasecmp(dst, "#smt_on"))
|
||||
return SMT_ON;
|
||||
break;
|
||||
}
|
||||
return ID;
|
||||
}
|
||||
|
||||
static int expr__lex(YYSTYPE *res, const char **pp)
|
||||
{
|
||||
int tok;
|
||||
const char *s;
|
||||
const char *p = *pp;
|
||||
|
||||
while (isspace(*p))
|
||||
p++;
|
||||
s = p;
|
||||
switch (*p++) {
|
||||
case '#':
|
||||
case 'a' ... 'z':
|
||||
case 'A' ... 'Z':
|
||||
return expr__symbol(res, p - 1, pp);
|
||||
case '0' ... '9': case '.':
|
||||
res->num = strtod(s, (char **)&p);
|
||||
tok = NUMBER;
|
||||
break;
|
||||
default:
|
||||
tok = *s;
|
||||
break;
|
||||
}
|
||||
*pp = p;
|
||||
return tok;
|
||||
}
|
||||
|
||||
static bool already_seen(const char *val, const char *one, const char **other,
|
||||
int num_other)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (one && !strcasecmp(one, val))
|
||||
return true;
|
||||
for (i = 0; i < num_other; i++)
|
||||
if (!strcasecmp(other[i], val))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int expr__find_other(const char *p, const char *one, const char ***other,
|
||||
int *num_otherp)
|
||||
{
|
||||
const char *orig = p;
|
||||
int err = -1;
|
||||
int num_other;
|
||||
|
||||
*other = malloc((EXPR_MAX_OTHER + 1) * sizeof(char *));
|
||||
if (!*other)
|
||||
return -1;
|
||||
|
||||
num_other = 0;
|
||||
for (;;) {
|
||||
YYSTYPE val;
|
||||
int tok = expr__lex(&val, &p);
|
||||
if (tok == 0) {
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
if (tok == ID && !already_seen(val.id, one, *other, num_other)) {
|
||||
if (num_other >= EXPR_MAX_OTHER - 1) {
|
||||
pr_debug("Too many extra events in %s\n", orig);
|
||||
break;
|
||||
}
|
||||
(*other)[num_other] = strdup(val.id);
|
||||
if (!(*other)[num_other])
|
||||
return -1;
|
||||
num_other++;
|
||||
}
|
||||
}
|
||||
(*other)[num_other] = NULL;
|
||||
*num_otherp = num_other;
|
||||
if (err) {
|
||||
*num_otherp = 0;
|
||||
free(*other);
|
||||
*other = NULL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
Reference in New Issue
Block a user