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