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