1 /* Simple expression parser */ 2 %{ 3 #include "util.h" 4 #include "util/debug.h" 5 #define IN_EXPR_Y 1 6 #include "expr.h" 7 #include "smt.h" 8 #include <string.h> 9 10 #define MAXIDLEN 256 11 %} 12 13 %pure-parser 14 %parse-param { double *final_val } 15 %parse-param { struct parse_ctx *ctx } 16 %parse-param { const char **pp } 17 %lex-param { const char **pp } 18 19 %union { 20 double num; 21 char id[MAXIDLEN+1]; 22 } 23 24 %token <num> NUMBER 25 %token <id> ID 26 %token MIN MAX IF ELSE SMT_ON 27 %left MIN MAX IF 28 %left '|' 29 %left '^' 30 %left '&' 31 %left '-' '+' 32 %left '*' '/' '%' 33 %left NEG NOT 34 %type <num> expr if_expr 35 36 %{ 37 static int expr__lex(YYSTYPE *res, const char **pp); 38 39 static void expr__error(double *final_val __maybe_unused, 40 struct parse_ctx *ctx __maybe_unused, 41 const char **pp __maybe_unused, 42 const char *s) 43 { 44 pr_debug("%s\n", s); 45 } 46 47 static int lookup_id(struct parse_ctx *ctx, char *id, double *val) 48 { 49 int i; 50 51 for (i = 0; i < ctx->num_ids; i++) { 52 if (!strcasecmp(ctx->ids[i].name, id)) { 53 *val = ctx->ids[i].val; 54 return 0; 55 } 56 } 57 return -1; 58 } 59 60 %} 61 %% 62 63 all_expr: if_expr { *final_val = $1; } 64 ; 65 66 if_expr: 67 expr IF expr ELSE expr { $$ = $3 ? $1 : $5; } 68 | expr 69 ; 70 71 expr: NUMBER 72 | ID { if (lookup_id(ctx, $1, &$$) < 0) { 73 pr_debug("%s not found\n", $1); 74 YYABORT; 75 } 76 } 77 | expr '|' expr { $$ = (long)$1 | (long)$3; } 78 | expr '&' expr { $$ = (long)$1 & (long)$3; } 79 | expr '^' expr { $$ = (long)$1 ^ (long)$3; } 80 | expr '+' expr { $$ = $1 + $3; } 81 | expr '-' expr { $$ = $1 - $3; } 82 | expr '*' expr { $$ = $1 * $3; } 83 | expr '/' expr { if ($3 == 0) YYABORT; $$ = $1 / $3; } 84 | expr '%' expr { if ((long)$3 == 0) YYABORT; $$ = (long)$1 % (long)$3; } 85 | '-' expr %prec NEG { $$ = -$2; } 86 | '(' if_expr ')' { $$ = $2; } 87 | MIN '(' expr ',' expr ')' { $$ = $3 < $5 ? $3 : $5; } 88 | MAX '(' expr ',' expr ')' { $$ = $3 > $5 ? $3 : $5; } 89 | SMT_ON { $$ = smt_on() > 0; } 90 ; 91 92 %% 93 94 static int expr__symbol(YYSTYPE *res, const char *p, const char **pp) 95 { 96 char *dst = res->id; 97 const char *s = p; 98 99 if (*p == '#') 100 *dst++ = *p++; 101 102 while (isalnum(*p) || *p == '_' || *p == '.' || *p == ':' || *p == '@' || *p == '\\') { 103 if (p - s >= MAXIDLEN) 104 return -1; 105 /* 106 * Allow @ instead of / to be able to specify pmu/event/ without 107 * conflicts with normal division. 108 */ 109 if (*p == '@') 110 *dst++ = '/'; 111 else if (*p == '\\') 112 *dst++ = *++p; 113 else 114 *dst++ = *p; 115 p++; 116 } 117 *dst = 0; 118 *pp = p; 119 dst = res->id; 120 switch (dst[0]) { 121 case 'm': 122 if (!strcmp(dst, "min")) 123 return MIN; 124 if (!strcmp(dst, "max")) 125 return MAX; 126 break; 127 case 'i': 128 if (!strcmp(dst, "if")) 129 return IF; 130 break; 131 case 'e': 132 if (!strcmp(dst, "else")) 133 return ELSE; 134 break; 135 case '#': 136 if (!strcasecmp(dst, "#smt_on")) 137 return SMT_ON; 138 break; 139 } 140 return ID; 141 } 142 143 static int expr__lex(YYSTYPE *res, const char **pp) 144 { 145 int tok; 146 const char *s; 147 const char *p = *pp; 148 149 while (isspace(*p)) 150 p++; 151 s = p; 152 switch (*p++) { 153 case '#': 154 case 'a' ... 'z': 155 case 'A' ... 'Z': 156 return expr__symbol(res, p - 1, pp); 157 case '0' ... '9': case '.': 158 res->num = strtod(s, (char **)&p); 159 tok = NUMBER; 160 break; 161 default: 162 tok = *s; 163 break; 164 } 165 *pp = p; 166 return tok; 167 } 168 169 /* Caller must make sure id is allocated */ 170 void expr__add_id(struct parse_ctx *ctx, const char *name, double val) 171 { 172 int idx; 173 assert(ctx->num_ids < MAX_PARSE_ID); 174 idx = ctx->num_ids++; 175 ctx->ids[idx].name = name; 176 ctx->ids[idx].val = val; 177 } 178 179 void expr__ctx_init(struct parse_ctx *ctx) 180 { 181 ctx->num_ids = 0; 182 } 183 184 static bool already_seen(const char *val, const char *one, const char **other, 185 int num_other) 186 { 187 int i; 188 189 if (one && !strcasecmp(one, val)) 190 return true; 191 for (i = 0; i < num_other; i++) 192 if (!strcasecmp(other[i], val)) 193 return true; 194 return false; 195 } 196 197 int expr__find_other(const char *p, const char *one, const char ***other, 198 int *num_otherp) 199 { 200 const char *orig = p; 201 int err = -1; 202 int num_other; 203 204 *other = malloc((EXPR_MAX_OTHER + 1) * sizeof(char *)); 205 if (!*other) 206 return -1; 207 208 num_other = 0; 209 for (;;) { 210 YYSTYPE val; 211 int tok = expr__lex(&val, &p); 212 if (tok == 0) { 213 err = 0; 214 break; 215 } 216 if (tok == ID && !already_seen(val.id, one, *other, num_other)) { 217 if (num_other >= EXPR_MAX_OTHER - 1) { 218 pr_debug("Too many extra events in %s\n", orig); 219 break; 220 } 221 (*other)[num_other] = strdup(val.id); 222 if (!(*other)[num_other]) 223 return -1; 224 num_other++; 225 } 226 } 227 (*other)[num_other] = NULL; 228 *num_otherp = num_other; 229 if (err) { 230 *num_otherp = 0; 231 free(*other); 232 *other = NULL; 233 } 234 return err; 235 } 236