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 <string.h> 8 9 #define MAXIDLEN 256 10 %} 11 12 %pure-parser 13 %parse-param { double *final_val } 14 %parse-param { struct parse_ctx *ctx } 15 %parse-param { const char **pp } 16 %lex-param { const char **pp } 17 18 %union { 19 double num; 20 char id[MAXIDLEN+1]; 21 } 22 23 %token <num> NUMBER 24 %token <id> ID 25 %left '|' 26 %left '^' 27 %left '&' 28 %left '-' '+' 29 %left '*' '/' '%' 30 %left NEG NOT 31 %type <num> expr 32 33 %{ 34 static int expr__lex(YYSTYPE *res, const char **pp); 35 36 static void expr__error(double *final_val __maybe_unused, 37 struct parse_ctx *ctx __maybe_unused, 38 const char **pp __maybe_unused, 39 const char *s) 40 { 41 pr_debug("%s\n", s); 42 } 43 44 static int lookup_id(struct parse_ctx *ctx, char *id, double *val) 45 { 46 int i; 47 48 for (i = 0; i < ctx->num_ids; i++) { 49 if (!strcasecmp(ctx->ids[i].name, id)) { 50 *val = ctx->ids[i].val; 51 return 0; 52 } 53 } 54 return -1; 55 } 56 57 %} 58 %% 59 60 all_expr: expr { *final_val = $1; } 61 ; 62 63 expr: NUMBER 64 | ID { if (lookup_id(ctx, $1, &$$) < 0) { 65 pr_debug("%s not found", $1); 66 YYABORT; 67 } 68 } 69 | expr '+' expr { $$ = $1 + $3; } 70 | expr '-' expr { $$ = $1 - $3; } 71 | expr '*' expr { $$ = $1 * $3; } 72 | expr '/' expr { if ($3 == 0) YYABORT; $$ = $1 / $3; } 73 | expr '%' expr { if ((long)$3 == 0) YYABORT; $$ = (long)$1 % (long)$3; } 74 | '-' expr %prec NEG { $$ = -$2; } 75 | '(' expr ')' { $$ = $2; } 76 ; 77 78 %% 79 80 static int expr__symbol(YYSTYPE *res, const char *p, const char **pp) 81 { 82 char *dst = res->id; 83 const char *s = p; 84 85 while (isalnum(*p) || *p == '_' || *p == '.') { 86 if (p - s >= MAXIDLEN) 87 return -1; 88 *dst++ = *p++; 89 } 90 *dst = 0; 91 *pp = p; 92 return ID; 93 } 94 95 static int expr__lex(YYSTYPE *res, const char **pp) 96 { 97 int tok; 98 const char *s; 99 const char *p = *pp; 100 101 while (isspace(*p)) 102 p++; 103 s = p; 104 switch (*p++) { 105 case 'a' ... 'z': 106 case 'A' ... 'Z': 107 return expr__symbol(res, p - 1, pp); 108 case '0' ... '9': case '.': 109 res->num = strtod(s, (char **)&p); 110 tok = NUMBER; 111 break; 112 default: 113 tok = *s; 114 break; 115 } 116 *pp = p; 117 return tok; 118 } 119 120 /* Caller must make sure id is allocated */ 121 void expr__add_id(struct parse_ctx *ctx, const char *name, double val) 122 { 123 int idx; 124 assert(ctx->num_ids < MAX_PARSE_ID); 125 idx = ctx->num_ids++; 126 ctx->ids[idx].name = name; 127 ctx->ids[idx].val = val; 128 } 129 130 void expr__ctx_init(struct parse_ctx *ctx) 131 { 132 ctx->num_ids = 0; 133 } 134 135 int expr__find_other(const char *p, const char *one, const char ***other, 136 int *num_otherp) 137 { 138 const char *orig = p; 139 int err = -1; 140 int num_other; 141 142 *other = malloc((EXPR_MAX_OTHER + 1) * sizeof(char *)); 143 if (!*other) 144 return -1; 145 146 num_other = 0; 147 for (;;) { 148 YYSTYPE val; 149 int tok = expr__lex(&val, &p); 150 if (tok == 0) { 151 err = 0; 152 break; 153 } 154 if (tok == ID && strcasecmp(one, val.id)) { 155 if (num_other >= EXPR_MAX_OTHER - 1) { 156 pr_debug("Too many extra events in %s\n", orig); 157 break; 158 } 159 (*other)[num_other] = strdup(val.id); 160 if (!(*other)[num_other]) 161 return -1; 162 num_other++; 163 } 164 } 165 (*other)[num_other] = NULL; 166 *num_otherp = num_other; 167 if (err) { 168 *num_otherp = 0; 169 free(*other); 170 *other = NULL; 171 } 172 return err; 173 } 174