1 /* Simple expression parser */ 1 /* Simple expression parser */ 2 %{ 2 %{ 3 #ifndef NDEBUG << 4 #define YYDEBUG 1 3 #define YYDEBUG 1 5 #endif !! 4 #include <stdio.h> 6 #include <assert.h> !! 5 #include "util.h" 7 #include <math.h> << 8 #include <stdlib.h> << 9 #include "util/debug.h" 6 #include "util/debug.h" >> 7 #include <stdlib.h> // strtod() 10 #define IN_EXPR_Y 1 8 #define IN_EXPR_Y 1 11 #include "expr.h" 9 #include "expr.h" 12 #include "expr-bison.h" !! 10 #include "smt.h" 13 int expr_lex(YYSTYPE * yylval_param , void *yy !! 11 #include <string.h> >> 12 >> 13 static double d_ratio(double val0, double val1) >> 14 { >> 15 if (val1 == 0) { >> 16 return 0; >> 17 } >> 18 return val0 / val1; >> 19 } >> 20 14 %} 21 %} 15 22 16 %define api.pure full 23 %define api.pure full 17 24 18 %parse-param { double *final_val } 25 %parse-param { double *final_val } 19 %parse-param { struct expr_parse_ctx *ctx } 26 %parse-param { struct expr_parse_ctx *ctx } 20 %parse-param { bool compute_ids } << 21 %parse-param {void *scanner} 27 %parse-param {void *scanner} 22 %lex-param {void* scanner} 28 %lex-param {void* scanner} 23 29 24 %union { 30 %union { 25 double num; 31 double num; 26 char *str; 32 char *str; 27 struct ids { << 28 /* << 29 * When creating ids, holds th << 30 * implies the set is empty. << 31 */ << 32 struct hashmap *ids; << 33 /* << 34 * The metric value. When not << 35 * read from a counter, a cons << 36 * creating ids the value is e << 37 * used as the special BOTTOM << 38 * values" case. << 39 */ << 40 double val; << 41 } ids; << 42 } 33 } 43 34 44 %token ID NUMBER MIN MAX IF ELSE LITERAL D_RAT !! 35 %token EXPR_PARSE EXPR_OTHER EXPR_ERROR >> 36 %token <num> NUMBER >> 37 %token <str> ID >> 38 %destructor { free ($$); } <str> >> 39 %token MIN MAX IF ELSE SMT_ON D_RATIO 45 %left MIN MAX IF 40 %left MIN MAX IF 46 %left '|' 41 %left '|' 47 %left '^' 42 %left '^' 48 %left '&' 43 %left '&' 49 %left '<' '>' 44 %left '<' '>' 50 %left '-' '+' 45 %left '-' '+' 51 %left '*' '/' '%' 46 %left '*' '/' '%' 52 %left NEG NOT 47 %left NEG NOT 53 %type <num> NUMBER LITERAL !! 48 %type <num> expr if_expr 54 %type <str> ID << 55 %destructor { free ($$); } <str> << 56 %type <ids> expr if_expr << 57 %destructor { ids__free($$.ids); } <ids> << 58 49 59 %{ 50 %{ 60 static void expr_error(double *final_val __may 51 static void expr_error(double *final_val __maybe_unused, 61 struct expr_parse_ctx * 52 struct expr_parse_ctx *ctx __maybe_unused, 62 bool compute_ids __mayb !! 53 void *scanner, 63 void *scanner __maybe_u << 64 const char *s) 54 const char *s) 65 { 55 { 66 pr_debug("%s\n", s); 56 pr_debug("%s\n", s); 67 } 57 } 68 58 69 /* << 70 * During compute ids, the special "bottom" va << 71 * of all values. NAN is selected as it isn't << 72 */ << 73 #define BOTTOM NAN << 74 << 75 /* During computing ids, does val represent a << 76 static bool is_const(double val) << 77 { << 78 return isfinite(val); << 79 } << 80 << 81 static struct ids union_expr(struct ids ids1, << 82 { << 83 struct ids result = { << 84 .val = BOTTOM, << 85 .ids = ids__union(ids1.ids, id << 86 }; << 87 return result; << 88 } << 89 << 90 static struct ids handle_id(struct expr_parse_ << 91 bool compute_ids, << 92 { << 93 struct ids result; << 94 << 95 if (!compute_ids) { << 96 /* << 97 * Compute the event's value f << 98 * it isn't used to compute th << 99 */ << 100 struct expr_id_data *data; << 101 << 102 result.val = NAN; << 103 if (expr__resolve_id(ctx, id, << 104 result.val = source_co << 105 ? expr_id_data << 106 : expr_id_data << 107 } << 108 result.ids = NULL; << 109 free(id); << 110 } else { << 111 /* << 112 * Set the value to BOTTOM to << 113 * when the event is computed. << 114 */ << 115 result.val = BOTTOM; << 116 result.ids = ids__new(); << 117 if (!result.ids || ids__insert << 118 pr_err("Error creating << 119 free(id); << 120 } << 121 } << 122 return result; << 123 } << 124 << 125 /* << 126 * If we're not computing ids or $1 and $3 are << 127 * constant value using OP. Its invariant that << 128 * ids for non-constants union the set of IDs << 129 */ << 130 #define BINARY_OP(RESULT, OP, LHS, RHS) << 131 if (!compute_ids || (is_const(LHS.val) << 132 assert(LHS.ids == NULL); << 133 assert(RHS.ids == NULL); << 134 if (isnan(LHS.val) || isnan(RH << 135 RESULT.val = NAN; << 136 } else { << 137 RESULT.val = LHS.val O << 138 } << 139 RESULT.ids = NULL; << 140 } else { << 141 RESULT = union_expr(LHS, RHS); << 142 } << 143 << 144 %} 59 %} 145 %% 60 %% 146 61 147 start: if_expr !! 62 start: 148 { !! 63 EXPR_PARSE all_expr 149 if (compute_ids) !! 64 | 150 ctx->ids = ids__union($1.ids, !! 65 EXPR_OTHER all_other 151 !! 66 152 if (final_val) !! 67 all_other: all_other other 153 *final_val = $1.val; !! 68 | 154 } !! 69 155 ; !! 70 other: ID 156 !! 71 { 157 if_expr: expr IF expr ELSE if_expr !! 72 expr__add_id(ctx, $1); 158 { !! 73 } 159 if (fpclassify($3.val) == FP_ZERO) { !! 74 | 160 /* !! 75 MIN | MAX | IF | ELSE | SMT_ON | NUMBER | '|' | '^' | '&' | '-' | '+' | '*' | '/' | '%' | '(' | ')' | ',' 161 * The IF expression evaluated !! 76 | 162 * ELSE and discard everything !! 77 '<' | '>' | D_RATIO 163 */ !! 78 164 $$.val = $5.val; !! 79 all_expr: if_expr { *final_val = $1; } 165 $$.ids = $5.ids; !! 80 ; 166 ids__free($1.ids); !! 81 167 ids__free($3.ids); !! 82 if_expr: 168 } else if (!compute_ids || is_const($3 !! 83 expr IF expr ELSE expr { $$ = $3 ? $1 : $5; } 169 /* !! 84 | expr 170 * If ids aren't computed then !! 85 ; 171 * ids are being computed and !! 86 172 * constant, then also evaluat !! 87 expr: NUMBER 173 */ !! 88 | ID { 174 $$.val = $1.val; !! 89 struct expr_id_data *data; 175 $$.ids = $1.ids; !! 90 176 ids__free($3.ids); !! 91 if (expr__resolve_id(ctx, $1, &data)) { 177 ids__free($5.ids); !! 92 free($1); 178 } else if ($1.val == $5.val) { !! 93 YYABORT; 179 /* !! 94 } 180 * LHS == RHS, so both are an !! 95 181 * evaluate any events. !! 96 $$ = expr_id_data__value(data); 182 */ !! 97 free($1); 183 $$.val = $1.val; !! 98 } 184 $$.ids = NULL; !! 99 | expr '|' expr { $$ = (long)$1 | (long)$3; } 185 ids__free($1.ids); !! 100 | expr '&' expr { $$ = (long)$1 & (long)$3; } 186 ids__free($3.ids); !! 101 | expr '^' expr { $$ = (long)$1 ^ (long)$3; } 187 ids__free($5.ids); !! 102 | expr '<' expr { $$ = $1 < $3; } 188 } else { !! 103 | expr '>' expr { $$ = $1 > $3; } 189 /* !! 104 | expr '+' expr { $$ = $1 + $3; } 190 * Value is either the LHS or !! 105 | expr '-' expr { $$ = $1 - $3; } 191 * to compute it. !! 106 | expr '*' expr { $$ = $1 * $3; } 192 */ !! 107 | expr '/' expr { if ($3 == 0) { 193 $$ = union_expr($1, union_expr !! 108 pr_debug("division by zero\n"); 194 } !! 109 YYABORT; 195 } !! 110 } 196 | expr !! 111 $$ = $1 / $3; 197 ; !! 112 } 198 !! 113 | expr '%' expr { if ((long)$3 == 0) { 199 expr: NUMBER !! 114 pr_debug("division by zero\n"); 200 { !! 115 YYABORT; 201 $$.val = $1; !! 116 } 202 $$.ids = NULL; !! 117 $$ = (long)$1 % (long)$3; 203 } !! 118 } 204 | ID { $$ = handle_ !! 119 | '-' expr %prec NEG { $$ = -$2; } 205 | SOURCE_COUNT '(' ID ')' { $$ = handle_ !! 120 | '(' if_expr ')' { $$ = $2; } 206 | HAS_EVENT '(' ID ')' !! 121 | MIN '(' expr ',' expr ')' { $$ = $3 < $5 ? $3 : $5; } 207 { !! 122 | MAX '(' expr ',' expr ')' { $$ = $3 > $5 ? $3 : $5; } 208 $$.val = expr__has_event(ctx, compute_ !! 123 | SMT_ON { $$ = smt_on() > 0; } 209 $$.ids = NULL; !! 124 | D_RATIO '(' expr ',' expr ')' { $$ = d_ratio($3,$5); } 210 free($3); !! 125 ; 211 } << 212 | STRCMP_CPUID_STR '(' ID ')' << 213 { << 214 $$.val = expr__strcmp_cpuid_str(ctx, c << 215 $$.ids = NULL; << 216 free($3); << 217 } << 218 | expr '|' expr << 219 { << 220 if (is_const($1.val) && is_const($3.va << 221 assert($1.ids == NULL); << 222 assert($3.ids == NULL); << 223 $$.ids = NULL; << 224 $$.val = (fpclassify($1.val) = << 225 } else if (is_const($1.val)) { << 226 assert($1.ids == NULL); << 227 if (fpclassify($1.val) == FP_Z << 228 $$ = $3; << 229 } else { << 230 $$.val = 1; << 231 $$.ids = NULL; << 232 ids__free($3.ids); << 233 } << 234 } else if (is_const($3.val)) { << 235 assert($3.ids == NULL); << 236 if (fpclassify($3.val) == FP_Z << 237 $$ = $1; << 238 } else { << 239 $$.val = 1; << 240 $$.ids = NULL; << 241 ids__free($1.ids); << 242 } << 243 } else { << 244 $$ = union_expr($1, $3); << 245 } << 246 } << 247 | expr '&' expr << 248 { << 249 if (is_const($1.val) && is_const($3.va << 250 assert($1.ids == NULL); << 251 assert($3.ids == NULL); << 252 $$.val = (fpclassify($1.val) ! << 253 $$.ids = NULL; << 254 } else if (is_const($1.val)) { << 255 assert($1.ids == NULL); << 256 if (fpclassify($1.val) != FP_Z << 257 $$ = $3; << 258 } else { << 259 $$.val = 0; << 260 $$.ids = NULL; << 261 ids__free($3.ids); << 262 } << 263 } else if (is_const($3.val)) { << 264 assert($3.ids == NULL); << 265 if (fpclassify($3.val) != FP_Z << 266 $$ = $1; << 267 } else { << 268 $$.val = 0; << 269 $$.ids = NULL; << 270 ids__free($1.ids); << 271 } << 272 } else { << 273 $$ = union_expr($1, $3); << 274 } << 275 } << 276 | expr '^' expr << 277 { << 278 if (is_const($1.val) && is_const($3.va << 279 assert($1.ids == NULL); << 280 assert($3.ids == NULL); << 281 $$.val = (fpclassify($1.val) = << 282 $$.ids = NULL; << 283 } else { << 284 $$ = union_expr($1, $3); << 285 } << 286 } << 287 | expr '<' expr { BINARY_OP($$, <, $1, $3); } << 288 | expr '>' expr { BINARY_OP($$, >, $1, $3); } << 289 | expr '+' expr { BINARY_OP($$, +, $1, $3); } << 290 | expr '-' expr { BINARY_OP($$, -, $1, $3); } << 291 | expr '*' expr { BINARY_OP($$, *, $1, $3); } << 292 | expr '/' expr << 293 { << 294 if (fpclassify($3.val) == FP_ZERO) { << 295 pr_debug("division by zero\n") << 296 assert($3.ids == NULL); << 297 if (compute_ids) << 298 ids__free($1.ids); << 299 $$.val = NAN; << 300 $$.ids = NULL; << 301 } else if (!compute_ids || (is_const($ << 302 assert($1.ids == NULL); << 303 assert($3.ids == NULL); << 304 $$.val = $1.val / $3.val; << 305 $$.ids = NULL; << 306 } else { << 307 /* LHS and/or RHS need computi << 308 $$ = union_expr($1, $3); << 309 } << 310 } << 311 | expr '%' expr << 312 { << 313 if (fpclassify($3.val) == FP_ZERO) { << 314 pr_debug("division by zero\n") << 315 YYABORT; << 316 } else if (!compute_ids || (is_const($ << 317 assert($1.ids == NULL); << 318 assert($3.ids == NULL); << 319 $$.val = (long)$1.val % (long) << 320 $$.ids = NULL; << 321 } else { << 322 /* LHS and/or RHS need computi << 323 $$ = union_expr($1, $3); << 324 } << 325 } << 326 | D_RATIO '(' expr ',' expr ')' << 327 { << 328 if (fpclassify($5.val) == FP_ZERO) { << 329 /* << 330 * Division by constant zero a << 331 * are necessary. << 332 */ << 333 assert($5.ids == NULL); << 334 $$.val = 0.0; << 335 $$.ids = NULL; << 336 ids__free($3.ids); << 337 } else if (!compute_ids || (is_const($ << 338 assert($3.ids == NULL); << 339 assert($5.ids == NULL); << 340 $$.val = $3.val / $5.val; << 341 $$.ids = NULL; << 342 } else { << 343 /* LHS and/or RHS need computi << 344 $$ = union_expr($3, $5); << 345 } << 346 } << 347 | '-' expr %prec NEG << 348 { << 349 $$.val = -$2.val; << 350 $$.ids = $2.ids; << 351 } << 352 | '(' if_expr ')' << 353 { << 354 $$ = $2; << 355 } << 356 | MIN '(' expr ',' expr ')' << 357 { << 358 if (!compute_ids) { << 359 $$.val = $3.val < $5.val ? $3. << 360 $$.ids = NULL; << 361 } else { << 362 $$ = union_expr($3, $5); << 363 } << 364 } << 365 | MAX '(' expr ',' expr ')' << 366 { << 367 if (!compute_ids) { << 368 $$.val = $3.val > $5.val ? $3. << 369 $$.ids = NULL; << 370 } else { << 371 $$ = union_expr($3, $5); << 372 } << 373 } << 374 | LITERAL << 375 { << 376 $$.val = $1; << 377 $$.ids = NULL; << 378 } << 379 ; << 380 126 381 %% 127 %%
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.