1 /* Simple expression parser */ 2 %{ 3 #define YYDEBUG 1 4 #include <stdio.h> 5 #include "util.h" 6 #include "util/debug.h" 7 #include <stdlib.h> // strtod() 8 #define IN_EXPR_Y 1 9 #include "expr.h" 10 #include "smt.h" 11 #include <string.h> 12 13 %} 14 15 %define api.pure full 16 17 %parse-param { double *final_val } 18 %parse-param { struct expr_parse_ctx *ctx } 19 %parse-param {void *scanner} 20 %lex-param {void* scanner} 21 22 %union { 23 double num; 24 char *str; 25 } 26 27 %token EXPR_PARSE EXPR_OTHER EXPR_ERROR 28 %token <num> NUMBER 29 %token <str> ID 30 %destructor { free ($$); } <str> 31 %token MIN MAX IF ELSE SMT_ON 32 %left MIN MAX IF 33 %left '|' 34 %left '^' 35 %left '&' 36 %left '-' '+' 37 %left '*' '/' '%' 38 %left NEG NOT 39 %type <num> expr if_expr 40 41 %{ 42 static void expr_error(double *final_val __maybe_unused, 43 struct expr_parse_ctx *ctx __maybe_unused, 44 void *scanner, 45 const char *s) 46 { 47 pr_debug("%s\n", s); 48 } 49 50 static int lookup_id(struct expr_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 start: 67 EXPR_PARSE all_expr 68 | 69 EXPR_OTHER all_other 70 71 all_other: all_other other 72 | 73 74 other: ID 75 { 76 if (ctx->num_ids + 1 >= EXPR_MAX_OTHER) { 77 pr_err("failed: way too many variables"); 78 YYABORT; 79 } 80 81 ctx->ids[ctx->num_ids++].name = $1; 82 } 83 | 84 MIN | MAX | IF | ELSE | SMT_ON | NUMBER | '|' | '^' | '&' | '-' | '+' | '*' | '/' | '%' | '(' | ')' | ',' 85 86 87 all_expr: if_expr { *final_val = $1; } 88 ; 89 90 if_expr: 91 expr IF expr ELSE expr { $$ = $3 ? $1 : $5; } 92 | expr 93 ; 94 95 expr: NUMBER 96 | ID { if (lookup_id(ctx, $1, &$$) < 0) { 97 pr_debug("%s not found\n", $1); 98 free($1); 99 YYABORT; 100 } 101 free($1); 102 } 103 | expr '|' expr { $$ = (long)$1 | (long)$3; } 104 | expr '&' expr { $$ = (long)$1 & (long)$3; } 105 | expr '^' expr { $$ = (long)$1 ^ (long)$3; } 106 | expr '+' expr { $$ = $1 + $3; } 107 | expr '-' expr { $$ = $1 - $3; } 108 | expr '*' expr { $$ = $1 * $3; } 109 | expr '/' expr { if ($3 == 0) { 110 pr_debug("division by zero\n"); 111 YYABORT; 112 } 113 $$ = $1 / $3; 114 } 115 | expr '%' expr { if ((long)$3 == 0) { 116 pr_debug("division by zero\n"); 117 YYABORT; 118 } 119 $$ = (long)$1 % (long)$3; 120 } 121 | '-' expr %prec NEG { $$ = -$2; } 122 | '(' if_expr ')' { $$ = $2; } 123 | MIN '(' expr ',' expr ')' { $$ = $3 < $5 ? $3 : $5; } 124 | MAX '(' expr ',' expr ')' { $$ = $3 > $5 ? $3 : $5; } 125 | SMT_ON { $$ = smt_on() > 0; } 126 ; 127 128 %% 129