| %option prefix="expr_" |
| %option reentrant |
| %option bison-bridge |
| |
| %{ |
| #include <linux/compiler.h> |
| #include "expr.h" |
| #include "expr-bison.h" |
| #include <math.h> |
| |
| char *expr_get_text(yyscan_t yyscanner); |
| YYSTYPE *expr_get_lval(yyscan_t yyscanner); |
| |
| static double __value(YYSTYPE *yylval, char *str, int token) |
| { |
| double num; |
| |
| errno = 0; |
| num = strtod(str, NULL); |
| if (errno) |
| return EXPR_ERROR; |
| |
| yylval->num = num; |
| return token; |
| } |
| |
| static int value(yyscan_t scanner) |
| { |
| YYSTYPE *yylval = expr_get_lval(scanner); |
| char *text = expr_get_text(scanner); |
| |
| return __value(yylval, text, NUMBER); |
| } |
| |
| /* |
| * Allow @ instead of / to be able to specify pmu/event/ without |
| * conflicts with normal division. |
| */ |
| static char *normalize(char *str, int runtime) |
| { |
| char *ret = str; |
| char *dst = str; |
| |
| while (*str) { |
| if (*str == '\\') { |
| *dst++ = *++str; |
| if (!*str) |
| break; |
| } |
| else if (*str == '?') { |
| char *paramval; |
| int i = 0; |
| int size = asprintf(¶mval, "%d", runtime); |
| |
| if (size < 0) |
| *dst++ = '0'; |
| else { |
| while (i < size) |
| *dst++ = paramval[i++]; |
| free(paramval); |
| } |
| } |
| else |
| *dst++ = *str; |
| str++; |
| } |
| |
| *dst = 0x0; |
| return ret; |
| } |
| |
| static int str(yyscan_t scanner, int token, int runtime) |
| { |
| YYSTYPE *yylval = expr_get_lval(scanner); |
| char *text = expr_get_text(scanner); |
| |
| yylval->str = normalize(strdup(text), runtime); |
| if (!yylval->str) |
| return EXPR_ERROR; |
| |
| yylval->str = normalize(yylval->str, runtime); |
| return token; |
| } |
| |
| static int literal(yyscan_t scanner, const struct expr_scanner_ctx *sctx) |
| { |
| YYSTYPE *yylval = expr_get_lval(scanner); |
| |
| yylval->num = expr__get_literal(expr_get_text(scanner), sctx); |
| if (isnan(yylval->num)) { |
| if (!sctx->is_test) |
| return EXPR_ERROR; |
| yylval->num = 1; |
| } |
| return LITERAL; |
| } |
| |
| static int nan_value(yyscan_t scanner) |
| { |
| YYSTYPE *yylval = expr_get_lval(scanner); |
| |
| yylval->num = NAN; |
| return NUMBER; |
| } |
| %} |
| |
| number ([0-9]+\.?[0-9]*|[0-9]*\.?[0-9]+)(e-?[0-9]+)? |
| |
| sch [-,=] |
| spec \\{sch} |
| sym [0-9a-zA-Z_\.:@?]+ |
| symbol ({spec}|{sym})+ |
| literal #[0-9a-zA-Z_\.\-]+ |
| |
| %% |
| struct expr_scanner_ctx *sctx = expr_get_extra(yyscanner); |
| |
| d_ratio { return D_RATIO; } |
| max { return MAX; } |
| min { return MIN; } |
| if { return IF; } |
| else { return ELSE; } |
| source_count { return SOURCE_COUNT; } |
| has_event { return HAS_EVENT; } |
| strcmp_cpuid_str { return STRCMP_CPUID_STR; } |
| NaN { return nan_value(yyscanner); } |
| {literal} { return literal(yyscanner, sctx); } |
| {number} { return value(yyscanner); } |
| {symbol} { return str(yyscanner, ID, sctx->runtime); } |
| "|" { return '|'; } |
| "^" { return '^'; } |
| "&" { return '&'; } |
| "<" { return '<'; } |
| ">" { return '>'; } |
| "-" { return '-'; } |
| "+" { return '+'; } |
| "*" { return '*'; } |
| "/" { return '/'; } |
| "%" { return '%'; } |
| "(" { return '('; } |
| ")" { return ')'; } |
| "," { return ','; } |
| . { } |
| %% |
| |
| int expr_wrap(void *scanner __maybe_unused) |
| { |
| return 1; |
| } |