| 1 | %option prefix="expr_"
|
| 2 | %option reentrant
|
| 3 | %option bison-bridge
|
| 4 |
|
| 5 | %{
|
| 6 | #include <linux/compiler.h>
|
| 7 | #include "expr.h"
|
| 8 | #include "expr-bison.h"
|
| 9 | #include <math.h>
|
| 10 |
|
| 11 | char *expr_get_text(yyscan_t yyscanner) |
| 12 | YYSTYPE *expr_get_lval(yyscan_t yyscanner) |
| 13 |
|
| 14 | static double __value(YYSTYPE *yylval, char *str, int token)
|
| 15 | {
|
| 16 | double num |
| 17 |
|
| 18 | errno = 0 |
| 19 | num = strtod(str, NULL) |
| 20 | if (errno)
|
| 21 | return EXPR_ERROR |
| 22 |
|
| 23 | yylval->num = num |
| 24 | return token |
| 25 | }
|
| 26 |
|
| 27 | static int value(yyscan_t scanner)
|
| 28 | {
|
| 29 | YYSTYPE *yylval = expr_get_lval(scanner) |
| 30 | char *text = expr_get_text(scanner) |
| 31 |
|
| 32 | return __value(yylval, text, NUMBER) |
| 33 | }
|
| 34 |
|
| 35 | /*
|
| 36 | * Allow @ instead of / to be able to specify pmu/event/ without
|
| 37 | * conflicts with normal division.
|
| 38 | */
|
| 39 | static char *normalize(char *str, int runtime)
|
| 40 | {
|
| 41 | char *ret = str |
| 42 | char *dst = str |
| 43 |
|
| 44 | while (*str) {
|
| 45 | if (*str == '\\') {
|
| 46 | *dst++ = *++str |
| 47 | if (!*str)
|
| 48 | break |
| 49 | }
|
| 50 | else if (*str == '?') {
|
| 51 | char *paramval |
| 52 | int i = 0 |
| 53 | int size = asprintf(¶mval, "%d", runtime) |
| 54 |
|
| 55 | if (size < 0)
|
| 56 | *dst++ = '0' |
| 57 | else {
|
| 58 | while (i < size)
|
| 59 | *dst++ = paramval[i++] |
| 60 | free(paramval) |
| 61 | }
|
| 62 | }
|
| 63 | else
|
| 64 | *dst++ = *str |
| 65 | str++ |
| 66 | }
|
| 67 |
|
| 68 | *dst = 0x0 |
| 69 | return ret |
| 70 | }
|
| 71 |
|
| 72 | static int str(yyscan_t scanner, int token, int runtime)
|
| 73 | {
|
| 74 | YYSTYPE *yylval = expr_get_lval(scanner) |
| 75 | char *text = expr_get_text(scanner) |
| 76 |
|
| 77 | yylval->str = normalize(strdup(text), runtime) |
| 78 | if (!yylval->str)
|
| 79 | return EXPR_ERROR |
| 80 |
|
| 81 | yylval->str = normalize(yylval->str, runtime) |
| 82 | return token |
| 83 | }
|
| 84 |
|
| 85 | static int literal(yyscan_t scanner, const struct expr_scanner_ctx *sctx)
|
| 86 | {
|
| 87 | YYSTYPE *yylval = expr_get_lval(scanner) |
| 88 |
|
| 89 | yylval->num = expr__get_literal(expr_get_text(scanner), sctx) |
| 90 | if (isnan(yylval->num)) {
|
| 91 | if (!sctx->is_test)
|
| 92 | return EXPR_ERROR |
| 93 | yylval->num = 1 |
| 94 | }
|
| 95 | return LITERAL |
| 96 | }
|
| 97 |
|
| 98 | static int nan_value(yyscan_t scanner)
|
| 99 | {
|
| 100 | YYSTYPE *yylval = expr_get_lval(scanner) |
| 101 |
|
| 102 | yylval->num = NAN |
| 103 | return NUMBER |
| 104 | }
|
| 105 | %}
|
| 106 |
|
| 107 | number ([0-9]+\.?[0-9]*|[0-9]*\.?[0-9]+)(e-?[0-9]+)?
|
| 108 |
|
| 109 | sch [-,=]
|
| 110 | spec \\{sch}
|
| 111 | sym [0-9a-zA-Z_\.:@?]+
|
| 112 | symbol ({spec}|{sym})+
|
| 113 | literal #[0-9a-zA-Z_\.\-]+
|
| 114 |
|
| 115 | %%
|
| 116 | struct expr_scanner_ctx *sctx = expr_get_extra(yyscanner) |
| 117 |
|
| 118 | d_ratio { return D_RATIO |
| 119 | max { return MAX |
| 120 | min { return MIN |
| 121 | if { return IF |
| 122 | else { return ELSE |
| 123 | source_count { return SOURCE_COUNT |
| 124 | aggr_nr { return AGGR_NR |
| 125 | has_event { return HAS_EVENT |
| 126 | strcmp_cpuid_str { return STRCMP_CPUID_STR |
| 127 | NaN { return nan_value(yyscanner) |
| 128 | {literal} { return literal(yyscanner, sctx) |
| 129 | {number} { return value(yyscanner) |
| 130 | {symbol} { return str(yyscanner, ID, sctx->runtime) |
| 131 | "|" { return '|' |
| 132 | "^" { return '^' |
| 133 | "&" { return '&' |
| 134 | "<" { return '<' |
| 135 | ">" { return '>' |
| 136 | "-" { return '-' |
| 137 | "+" { return '+' |
| 138 | "*" { return '*' |
| 139 | "/" { return '/' |
| 140 | "%" { return '%' |
| 141 | "(" { return '('; }
|
| 142 | ")" { return ')' |
| 143 | "," { return ',' |
| 144 | . { }
|
| 145 | %%
|
| 146 |
|
| 147 | int expr_wrap(void *scanner __maybe_unused)
|
| 148 | {
|
| 149 | return 1 |
| 150 | }
|