107516736SAndi Kleen /* Simple expression parser */ 207516736SAndi Kleen %{ 307516736SAndi Kleen #include "util.h" 407516736SAndi Kleen #include "util/debug.h" 507516736SAndi Kleen #define IN_EXPR_Y 1 607516736SAndi Kleen #include "expr.h" 707516736SAndi Kleen #include <string.h> 807516736SAndi Kleen 907516736SAndi Kleen #define MAXIDLEN 256 1007516736SAndi Kleen %} 1107516736SAndi Kleen 1207516736SAndi Kleen %pure-parser 1307516736SAndi Kleen %parse-param { double *final_val } 1407516736SAndi Kleen %parse-param { struct parse_ctx *ctx } 1507516736SAndi Kleen %parse-param { const char **pp } 1607516736SAndi Kleen %lex-param { const char **pp } 1707516736SAndi Kleen 1807516736SAndi Kleen %union { 1907516736SAndi Kleen double num; 2007516736SAndi Kleen char id[MAXIDLEN+1]; 2107516736SAndi Kleen } 2207516736SAndi Kleen 2307516736SAndi Kleen %token <num> NUMBER 2407516736SAndi Kleen %token <id> ID 2507516736SAndi Kleen %left '|' 2607516736SAndi Kleen %left '^' 2707516736SAndi Kleen %left '&' 2807516736SAndi Kleen %left '-' '+' 2907516736SAndi Kleen %left '*' '/' '%' 3007516736SAndi Kleen %left NEG NOT 3107516736SAndi Kleen %type <num> expr 3207516736SAndi Kleen 3307516736SAndi Kleen %{ 3407516736SAndi Kleen static int expr__lex(YYSTYPE *res, const char **pp); 3507516736SAndi Kleen 3607516736SAndi Kleen static void expr__error(double *final_val __maybe_unused, 3707516736SAndi Kleen struct parse_ctx *ctx __maybe_unused, 3807516736SAndi Kleen const char **pp __maybe_unused, 3907516736SAndi Kleen const char *s) 4007516736SAndi Kleen { 4107516736SAndi Kleen pr_debug("%s\n", s); 4207516736SAndi Kleen } 4307516736SAndi Kleen 4407516736SAndi Kleen static int lookup_id(struct parse_ctx *ctx, char *id, double *val) 4507516736SAndi Kleen { 4607516736SAndi Kleen int i; 4707516736SAndi Kleen 4807516736SAndi Kleen for (i = 0; i < ctx->num_ids; i++) { 4907516736SAndi Kleen if (!strcasecmp(ctx->ids[i].name, id)) { 5007516736SAndi Kleen *val = ctx->ids[i].val; 5107516736SAndi Kleen return 0; 5207516736SAndi Kleen } 5307516736SAndi Kleen } 5407516736SAndi Kleen return -1; 5507516736SAndi Kleen } 5607516736SAndi Kleen 5707516736SAndi Kleen %} 5807516736SAndi Kleen %% 5907516736SAndi Kleen 6007516736SAndi Kleen all_expr: expr { *final_val = $1; } 6107516736SAndi Kleen ; 6207516736SAndi Kleen 6307516736SAndi Kleen expr: NUMBER 6407516736SAndi Kleen | ID { if (lookup_id(ctx, $1, &$$) < 0) { 65*c295036bSAndi Kleen pr_debug("%s not found\n", $1); 6607516736SAndi Kleen YYABORT; 6707516736SAndi Kleen } 6807516736SAndi Kleen } 6907516736SAndi Kleen | expr '+' expr { $$ = $1 + $3; } 7007516736SAndi Kleen | expr '-' expr { $$ = $1 - $3; } 7107516736SAndi Kleen | expr '*' expr { $$ = $1 * $3; } 7207516736SAndi Kleen | expr '/' expr { if ($3 == 0) YYABORT; $$ = $1 / $3; } 7307516736SAndi Kleen | expr '%' expr { if ((long)$3 == 0) YYABORT; $$ = (long)$1 % (long)$3; } 7407516736SAndi Kleen | '-' expr %prec NEG { $$ = -$2; } 7507516736SAndi Kleen | '(' expr ')' { $$ = $2; } 7607516736SAndi Kleen ; 7707516736SAndi Kleen 7807516736SAndi Kleen %% 7907516736SAndi Kleen 8007516736SAndi Kleen static int expr__symbol(YYSTYPE *res, const char *p, const char **pp) 8107516736SAndi Kleen { 8207516736SAndi Kleen char *dst = res->id; 8307516736SAndi Kleen const char *s = p; 8407516736SAndi Kleen 8507516736SAndi Kleen while (isalnum(*p) || *p == '_' || *p == '.') { 8607516736SAndi Kleen if (p - s >= MAXIDLEN) 8707516736SAndi Kleen return -1; 8807516736SAndi Kleen *dst++ = *p++; 8907516736SAndi Kleen } 9007516736SAndi Kleen *dst = 0; 9107516736SAndi Kleen *pp = p; 9207516736SAndi Kleen return ID; 9307516736SAndi Kleen } 9407516736SAndi Kleen 9507516736SAndi Kleen static int expr__lex(YYSTYPE *res, const char **pp) 9607516736SAndi Kleen { 9707516736SAndi Kleen int tok; 9807516736SAndi Kleen const char *s; 9907516736SAndi Kleen const char *p = *pp; 10007516736SAndi Kleen 10107516736SAndi Kleen while (isspace(*p)) 10207516736SAndi Kleen p++; 10307516736SAndi Kleen s = p; 10407516736SAndi Kleen switch (*p++) { 10507516736SAndi Kleen case 'a' ... 'z': 10607516736SAndi Kleen case 'A' ... 'Z': 10707516736SAndi Kleen return expr__symbol(res, p - 1, pp); 10807516736SAndi Kleen case '0' ... '9': case '.': 10907516736SAndi Kleen res->num = strtod(s, (char **)&p); 11007516736SAndi Kleen tok = NUMBER; 11107516736SAndi Kleen break; 11207516736SAndi Kleen default: 11307516736SAndi Kleen tok = *s; 11407516736SAndi Kleen break; 11507516736SAndi Kleen } 11607516736SAndi Kleen *pp = p; 11707516736SAndi Kleen return tok; 11807516736SAndi Kleen } 11907516736SAndi Kleen 12007516736SAndi Kleen /* Caller must make sure id is allocated */ 12107516736SAndi Kleen void expr__add_id(struct parse_ctx *ctx, const char *name, double val) 12207516736SAndi Kleen { 12307516736SAndi Kleen int idx; 12407516736SAndi Kleen assert(ctx->num_ids < MAX_PARSE_ID); 12507516736SAndi Kleen idx = ctx->num_ids++; 12607516736SAndi Kleen ctx->ids[idx].name = name; 12707516736SAndi Kleen ctx->ids[idx].val = val; 12807516736SAndi Kleen } 12907516736SAndi Kleen 13007516736SAndi Kleen void expr__ctx_init(struct parse_ctx *ctx) 13107516736SAndi Kleen { 13207516736SAndi Kleen ctx->num_ids = 0; 13307516736SAndi Kleen } 13407516736SAndi Kleen 13507516736SAndi Kleen int expr__find_other(const char *p, const char *one, const char ***other, 13607516736SAndi Kleen int *num_otherp) 13707516736SAndi Kleen { 13807516736SAndi Kleen const char *orig = p; 13907516736SAndi Kleen int err = -1; 14007516736SAndi Kleen int num_other; 14107516736SAndi Kleen 14207516736SAndi Kleen *other = malloc((EXPR_MAX_OTHER + 1) * sizeof(char *)); 14307516736SAndi Kleen if (!*other) 14407516736SAndi Kleen return -1; 14507516736SAndi Kleen 14607516736SAndi Kleen num_other = 0; 14707516736SAndi Kleen for (;;) { 14807516736SAndi Kleen YYSTYPE val; 14907516736SAndi Kleen int tok = expr__lex(&val, &p); 15007516736SAndi Kleen if (tok == 0) { 15107516736SAndi Kleen err = 0; 15207516736SAndi Kleen break; 15307516736SAndi Kleen } 15407516736SAndi Kleen if (tok == ID && strcasecmp(one, val.id)) { 15507516736SAndi Kleen if (num_other >= EXPR_MAX_OTHER - 1) { 15607516736SAndi Kleen pr_debug("Too many extra events in %s\n", orig); 15707516736SAndi Kleen break; 15807516736SAndi Kleen } 15907516736SAndi Kleen (*other)[num_other] = strdup(val.id); 16007516736SAndi Kleen if (!(*other)[num_other]) 16107516736SAndi Kleen return -1; 16207516736SAndi Kleen num_other++; 16307516736SAndi Kleen } 16407516736SAndi Kleen } 16507516736SAndi Kleen (*other)[num_other] = NULL; 16607516736SAndi Kleen *num_otherp = num_other; 16707516736SAndi Kleen if (err) { 16807516736SAndi Kleen *num_otherp = 0; 16907516736SAndi Kleen free(*other); 17007516736SAndi Kleen *other = NULL; 17107516736SAndi Kleen } 17207516736SAndi Kleen return err; 17307516736SAndi Kleen } 174