%{ #include #include #include #include #include #include #include "evtr.h" #include "tok.h" #include "internal.h" #include "ktrfmt.tab.h" int __ktrfmtlex(YYSTYPE *); #define __ktrfmt_lex __ktrfmtlex void __ktrfmt_error (struct ktrfmt_parse_ctx *, const char *); static void do_parse_err(struct ktrfmt_parse_ctx *, const char *, ...) __printflike(2, 3); static void do_parse_err(struct ktrfmt_parse_ctx *ctx, const char *fmt, ...) { va_list ap; va_start(ap, fmt); vsnprintf(ctx->errbuf, ctx->errbufsz, fmt, ap); va_end(ap); ctx->err = !0; } #define parse_err(fmt, ...) \ do { \ do_parse_err(ctx, fmt, ##__VA_ARGS__); \ YYABORT; \ } while (0) static struct evtr_variable * evtr_var_new(const char *name) { struct evtr_variable *var; var = calloc(1, sizeof(*var)); if (var) { if (!(var->name = strdup(name))) { free(var); return NULL; } var->val.type = EVTR_VAL_NIL; } return var; } /* * XXX: should be reentrant */ static char * uniq_varname(void) { static long serno; static char buf[100]; serno++; snprintf(buf, sizeof(buf), "@%ld", serno); return &buf[0]; } static int index_hash(struct ktrfmt_parse_ctx *ctx, const char *hashname, evtr_variable_value_t val, evtr_var_t *_var) { evtr_var_t hsh, var; uintptr_t ret, key; hsh = symtab_find(ctx->symtab, hashname); if (hsh->val.type == EVTR_VAL_NIL) { /* it's probably the first time we see this "variable" */ printd(PARSE, "creating hash for %s\n", hsh->name); hsh->val.type = EVTR_VAL_HASH; hsh->val.hashtab = hash_new(); } else if (hsh->val.type != EVTR_VAL_HASH) { printd(PARSE, "trying to use type %d as hash\n", hsh->val.type); return !0; } if (val->type == EVTR_VAL_INT) { key = val->num; printd(PARSE, "looking up %s[%jd] in %p\n", hsh->name, val->num, hsh->val.hashtab); } else if (val->type == EVTR_VAL_STR) { key = (uintptr_t)val->str; printd(PARSE, "looking up %s[\"%s\"] in %p\n", hsh->name, val->str, hsh->val.hashtab); } else { do_parse_err(ctx, "trying to index hash '%s' with " "non-supported value", hashname); return !0; } if (hash_find(hsh->val.hashtab, key, &ret)) { printd(PARSE, "didn't find it\n"); var = evtr_var_new(uniq_varname()); if (var) { printd(PARSE, "inserting it as %s\n", var->name); if (!hash_insert(hsh->val.hashtab, key, (uintptr_t)var)) { do_parse_err(ctx, "can't insert temporary " "variable into hash\n"); return !0; } symtab_insert(ctx->symtab, var->name, var); } else { do_parse_err(ctx, "out of memory"); } } else { var = (struct evtr_variable *)ret; } if (!var) { fprintf(stderr, "no var!\n"); return !0; /* XXX */ } *_var = var; return 0; } %} %verbose %error-verbose %debug %name-prefix "__ktrfmt_" %define api.pure %parse-param{struct ktrfmt_parse_ctx *ctx} %union { struct token *tok; struct evtr_variable *var; struct evtr_variable_value *val; void *na; } %token TOK_ID %token TOK_CTOR %token TOK_INT %token TOK_STR %token TOK_EQ %token TOK_LEFT_BRACK %token TOK_RIGHT_BRACK %token TOK_DOT %type constant %type ctor_args %type construct_expr %type primary_expr %type postfix_expr %type unary_expr %type assign_expr %type expr %% input: stmt stmt: unary_expr { ctx->var = $1; } | expr ; constant: TOK_INT { evtr_var_t var; if (!$1->str) parse_err("out of memory"); var = evtr_var_new(uniq_varname()); var->val.type = EVTR_VAL_INT; errno = 0; var->val.num = strtoll($1->str, NULL, 0); if (errno) { parse_err("Can't parse numeric constant '%s'", $1->str); } $$ = var; tok_free($1); } | TOK_STR { evtr_var_t var; if (!$1->str) parse_err("out of memory"); var = evtr_var_new(uniq_varname()); var->val.type = EVTR_VAL_STR; var->val.str = $1->str; if (!var->val.str) { parse_err("out of memory"); } $$ = var; tok_free($1); } ; ctor_args: constant { evtr_var_t ctor; ctor = evtr_var_new(uniq_varname()); ctor->val.type = EVTR_VAL_CTOR; ctor->val.ctor.name = NULL; TAILQ_INIT(&ctor->val.ctor.args); TAILQ_INSERT_HEAD(&ctor->val.ctor.args, &$1->val, link); $$ = ctor; } | constant ctor_args { TAILQ_INSERT_HEAD(&$2->val.ctor.args, &$1->val, link); $$ = $2; } ; construct_expr: TOK_CTOR { evtr_var_t var; if (!$1->str) parse_err("out of memory"); printd(PARSE, "TOK_CTOR\n"); printd(PARSE, "tok: %p, str = %p\n", $1, $1->str); var = evtr_var_new(uniq_varname()); var->val.type = EVTR_VAL_CTOR; var->val.ctor.name = $1->str; TAILQ_INIT(&var->val.ctor.args); tok_free($1); $$ = var; } | TOK_CTOR ctor_args { evtr_variable_value_t val; if (!$1->str) parse_err("out of memory"); printd(PARSE, "TOK_CTOR\n"); printd(PARSE, "tok: %p, str = %p\n", $1, $1->str); $2->val.ctor.name = $1->str; $$ = $2; printd(PARSE, "CTOR: %s\n", $1->str); TAILQ_FOREACH(val, &$2->val.ctor.args, link) { switch (val->type) { case EVTR_VAL_INT: printd(PARSE, "\t%jd\n", val->num); break; case EVTR_VAL_STR: printd(PARSE, "\t\"%s\"\n", val->str); break; case EVTR_VAL_NIL: assert(!"can't get here"); default: ; } } } ; primary_expr: TOK_ID { evtr_var_t var; if (!$1->str) parse_err("out of memory"); printd(PARSE, "TOK_ID\n"); printd(PARSE, "tok: %p, str = %p\n", $1, $1->str); var = symtab_find(ctx->symtab, $1->str); if (!var) { if (!(var = evtr_var_new($1->str))) { tok_free($1); parse_err("out of memory"); } printd(PARSE, "creating var %s\n", $1->str); symtab_insert(ctx->symtab, $1->str, var); } $$ = var; tok_free($1); } | constant { $$ = $1; } ; postfix_expr: postfix_expr TOK_LEFT_BRACK postfix_expr TOK_RIGHT_BRACK { evtr_var_t var; if (index_hash(ctx, $1->name, &$3->val, &var)) YYABORT; $$ = var; } | postfix_expr TOK_DOT TOK_ID { evtr_var_t var, tmp; if (!$3->str) parse_err("out of memory"); tmp = evtr_var_new(uniq_varname()); tmp->val.type = EVTR_VAL_STR; tmp->val.str = $3->str; if (index_hash(ctx, $1->name, &tmp->val, &var)) YYABORT; tok_free($3); $$ = var; } | primary_expr { $$ = $1; } ; unary_expr: postfix_expr { $$ = $1; } ; assign_expr: unary_expr TOK_EQ constant { $1->val = $3->val; ctx->ev->type = EVTR_TYPE_STMT; ctx->ev->stmt.var = $1; ctx->ev->stmt.val = &$3->val; ctx->ev->stmt.op = EVTR_OP_SET; } | unary_expr TOK_EQ construct_expr { $1->val = $3->val; ctx->ev->type = EVTR_TYPE_STMT; ctx->ev->stmt.var = $1; ctx->ev->stmt.val = &$3->val; ctx->ev->stmt.op = EVTR_OP_SET; } ; expr: assign_expr { $$ = $1; } ; %% void * __ktrfmt_scan_string(const char *); void __ktrfmt_delete_buffer(void *); void __ktrfmt_error (struct ktrfmt_parse_ctx *ctx, const char *s) { do_parse_err(ctx, "%s", s); } int parse_string(evtr_event_t ev, struct symtab *symtab, const char *str, char *errbuf, size_t errbufsz) { void *bufstate; int ret; struct ktrfmt_parse_ctx ctx; printd(PARSE, "parsing \"%s\"\n", str); ctx.ev = ev; ctx.symtab = symtab; ctx.errbuf = errbuf; ctx.errbuf[0] = '\0'; ctx.errbufsz = errbufsz; ctx.err = 0; bufstate = __ktrfmt_scan_string(str); ret = __ktrfmt_parse(&ctx); __ktrfmt_delete_buffer(bufstate); return ret; } int parse_var(const char *str, struct symtab *symtab, struct evtr_variable **var, char *errbuf, size_t errbufsz) { void *bufstate; int ret; struct ktrfmt_parse_ctx ctx; printd(PARSE, "parsing \"%s\"\n", str); ctx.ev = NULL; ctx.symtab = symtab; ctx.var = NULL; ctx.errbuf = errbuf; ctx.errbuf[0] = '\0'; ctx.errbufsz = errbufsz; ctx.err = 0; bufstate = __ktrfmt_scan_string(str); ret = __ktrfmt_parse(&ctx); __ktrfmt_delete_buffer(bufstate); *var = ctx.var; return ret; }