15ecf0be157fab21571c5143972ca200fdcc24d8
[dragonfly.git] / lib / libevtr / ktrfmt.y
1 %{
2
3 #include <assert.h>
4 #include <errno.h>
5 #include <stdarg.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/queue.h>
9
10 #include "evtr.h"
11 #include "tok.h"
12 #include "ktrfmt.tab.h"
13 #include "internal.h"
14
15 struct ktrfmt_parse_ctx {
16         struct symtab *symtab;
17         struct evtr_variable *var;
18         struct evtr_variable_value *val;
19         evtr_event_t ev;
20         char *errbuf;
21         size_t errbufsz;
22         int err;
23 };
24
25 int __ktrfmtlex(YYSTYPE *);
26 #define __ktrfmt_lex __ktrfmtlex
27
28 void __ktrfmt_error (struct ktrfmt_parse_ctx *, const char *);
29
30 static
31 void
32 do_parse_err(struct ktrfmt_parse_ctx *ctx, const char *fmt, ...)
33 {
34         va_list ap;
35
36         va_start(ap, fmt);
37         vsnprintf(ctx->errbuf, ctx->errbufsz, fmt, ap);
38         va_end(ap);
39         ctx->err = !0;
40 }
41
42 #define parse_err(fmt, ...)                     \
43         do {                                    \
44                 do_parse_err(ctx, fmt, ##__VA_ARGS__);  \
45                 YYABORT;                                \
46         } while (0)
47
48 static
49 struct evtr_variable *
50 evtr_var_new(const char *name)
51 {
52         struct evtr_variable *var;
53
54         var = calloc(1, sizeof(*var));
55         if (var) {
56                 if (!(var->name = strdup(name))) {
57                         free(var);
58                         return NULL;
59                 }
60                 var->val.type = EVTR_VAL_NIL;
61         }
62         return var;
63 }
64
65 /*
66  * XXX: should be reentrant
67  */
68 static
69 char *
70 uniq_varname(void)
71 {
72         static long serno;
73         static char buf[100];
74
75         serno++;
76         snprintf(buf, sizeof(buf), "@%ld", serno);
77         return &buf[0];
78 }
79
80 static
81 int
82 index_hash(struct ktrfmt_parse_ctx *ctx, const char *hashname,
83            evtr_variable_value_t val, evtr_var_t *_var)
84 {
85         evtr_var_t hsh, var;
86         uintptr_t ret, key;
87         hsh = symtab_find(ctx->symtab, hashname);
88         if (hsh->val.type == EVTR_VAL_NIL) {
89                 /* it's probably the first time we see this "variable" */
90                 printd(PARSE, "creating hash for %s\n", hsh->name);
91                 hsh->val.type = EVTR_VAL_HASH;
92                 hsh->val.hashtab = hash_new();
93         } else if (hsh->val.type != EVTR_VAL_HASH) {
94                 printd(PARSE, "trying to use type %d as hash\n", hsh->val.type);
95                 return !0;
96         }
97         if (val->type == EVTR_VAL_INT) {
98                 key = val->num;
99                 printd(PARSE, "looking up %s[%jd] in %p\n", hsh->name,
100                        val->num, hsh->val.hashtab);
101         } else if (val->type == EVTR_VAL_STR) {
102                 key = (uintptr_t)val->str;
103                 printd(PARSE, "looking up %s[\"%s\"] in %p\n", hsh->name,
104                        val->str, hsh->val.hashtab);
105         } else {
106                 do_parse_err(ctx, "trying to index hash '%s' with "
107                              "non-supported value", hashname);
108                 return !0;
109         }
110
111         if (hash_find(hsh->val.hashtab, key, &ret)) {
112                 printd(PARSE, "didn't find it\n");
113                 var = evtr_var_new(uniq_varname());
114                 if (var) {
115                         printd(PARSE, "inserting it as %s\n", var->name);
116                         if (!hash_insert(hsh->val.hashtab, key,
117                                          (uintptr_t)var)) {
118                                 do_parse_err(ctx, "can't insert temporary "
119                                         "variable into hash\n");
120                                 return !0;
121                         }
122                         symtab_insert(ctx->symtab, var->name, var);
123                 } else {
124                         do_parse_err(ctx, "out of memory");
125                 }
126         } else {
127                 var = (struct evtr_variable *)ret;
128         }
129         if (!var) {
130                 fprintf(stderr, "no var!\n");
131                 return !0;
132                 /* XXX */
133         }
134         *_var = var;
135         return 0;
136 }
137
138 %}
139
140 %verbose
141 %error-verbose
142 %debug
143 %name-prefix "__ktrfmt_"
144 %define api.pure
145 %parse-param{struct ktrfmt_parse_ctx *ctx}
146
147 %union {
148         struct token *tok;
149         struct evtr_variable *var;
150         struct evtr_variable_value *val;
151         void *na;
152 }
153
154 %token<tok> TOK_ID
155 %token<tok> TOK_CTOR
156 %token<tok> TOK_INT
157 %token<tok> TOK_STR
158
159 %token<na> TOK_EQ
160 %token<na> TOK_LEFT_BRACK
161 %token<na> TOK_RIGHT_BRACK
162 %token<na> TOK_DOT
163
164 %type<var> constant
165 %type<var> ctor_args
166 %type<var> construct_expr
167 %type<var> primary_expr
168 %type<var> postfix_expr
169 %type<var> unary_expr
170 %type<na> assign_expr
171 %type<na> expr
172
173 %%
174
175 input: stmt
176
177 stmt: unary_expr {
178         ctx->var = $1;
179  }
180      | expr
181      ;
182 constant: TOK_INT {
183         evtr_var_t var;
184         if (!$1->str)
185                 parse_err("out of memory");
186         var = evtr_var_new(uniq_varname());
187         var->val.type = EVTR_VAL_INT;
188         errno = 0;
189         var->val.num = strtoll($1->str, NULL, 0);
190         if (errno) {
191                 parse_err("Can't parse numeric constant '%s'", $1->str);
192         }
193         $$ = var;
194         tok_free($1);
195         }
196         | TOK_STR {
197         evtr_var_t var;
198         if (!$1->str)
199                 parse_err("out of memory");
200         var = evtr_var_new(uniq_varname());
201         var->val.type = EVTR_VAL_STR;
202         var->val.str = $1->str;
203         if (!var->val.str) {
204                 parse_err("out of memory");
205         }
206         $$ = var;
207         tok_free($1);
208         }
209         ;
210 ctor_args: constant {
211         evtr_var_t ctor;
212         ctor = evtr_var_new(uniq_varname());
213         ctor->val.type = EVTR_VAL_CTOR;
214         ctor->val.ctor.name = NULL;
215         TAILQ_INIT(&ctor->val.ctor.args);
216         TAILQ_INSERT_HEAD(&ctor->val.ctor.args, &$1->val, link);
217         $$ = ctor;
218  }
219 | constant ctor_args {
220         TAILQ_INSERT_HEAD(&$2->val.ctor.args, &$1->val, link);
221         $$ = $2;
222  }
223 ;
224 construct_expr: TOK_CTOR {
225         evtr_var_t var;
226         if (!$1->str)
227                 parse_err("out of memory");
228         printd(PARSE, "TOK_CTOR\n");
229         printd(PARSE, "tok: %p, str = %p\n", $1, $1->str);
230         var = evtr_var_new(uniq_varname());
231         var->val.type = EVTR_VAL_CTOR;
232         var->val.ctor.name = $1->str;
233         TAILQ_INIT(&var->val.ctor.args);
234         tok_free($1);
235         $$ = var;
236  }
237 | TOK_CTOR ctor_args {
238         evtr_variable_value_t val;
239         if (!$1->str)
240                 parse_err("out of memory");
241         printd(PARSE, "TOK_CTOR\n");
242         printd(PARSE, "tok: %p, str = %p\n", $1, $1->str);
243         $2->val.ctor.name = $1->str;
244         $$ = $2;
245         printd(PARSE, "CTOR: %s\n", $1->str);
246         TAILQ_FOREACH(val, &$2->val.ctor.args, link) {
247                 switch (val->type) {
248                 case EVTR_VAL_INT:
249                         printd(PARSE, "\t%jd\n", val->num);
250                         break;
251                 case EVTR_VAL_STR:
252                         printd(PARSE, "\t\"%s\"\n", val->str);
253                         break;
254                 case EVTR_VAL_NIL:
255                         assert(!"can't get here");
256                 default:
257                         ;
258                 }
259         }
260  }
261 ;
262 primary_expr: TOK_ID {
263         evtr_var_t var;
264         if (!$1->str)
265                 parse_err("out of memory");
266         printd(PARSE, "TOK_ID\n");
267         printd(PARSE, "tok: %p, str = %p\n", $1, $1->str);
268         var = symtab_find(ctx->symtab, $1->str);
269         if (!var) {
270                 if (!(var = evtr_var_new($1->str))) {
271                         tok_free($1);
272                         parse_err("out of memory");
273                 }
274                 printd(PARSE, "creating var %s\n", $1->str);
275                 symtab_insert(ctx->symtab, $1->str, var);
276         }
277         $$ = var;
278         tok_free($1);
279  }
280 | constant {
281         $$ = $1;
282   }
283 ;
284 postfix_expr: postfix_expr TOK_LEFT_BRACK postfix_expr TOK_RIGHT_BRACK {
285         evtr_var_t var;
286
287         if (index_hash(ctx, $1->name, &$3->val, &var))
288                 YYABORT;
289         $$ = var;
290  }
291 | postfix_expr TOK_DOT TOK_ID {
292         evtr_var_t var, tmp;
293         if (!$3->str)
294                 parse_err("out of memory");
295         tmp = evtr_var_new(uniq_varname());
296         tmp->val.type = EVTR_VAL_STR;
297         tmp->val.str = $3->str;
298
299         if (index_hash(ctx, $1->name, &tmp->val, &var))
300                 YYABORT;
301         tok_free($3);
302         $$ = var;
303  }
304             | primary_expr {
305         $$ = $1;
306  }
307 ;
308 unary_expr: postfix_expr {
309         $$ = $1;
310  }
311 ;
312 assign_expr: unary_expr TOK_EQ constant {
313         $1->val = $3->val;
314         ctx->ev->type = EVTR_TYPE_STMT;
315         ctx->ev->stmt.var = $1;
316         ctx->ev->stmt.val = &$3->val;
317         ctx->ev->stmt.op = EVTR_OP_SET;
318  }
319 | unary_expr TOK_EQ construct_expr {
320         $1->val = $3->val;
321         ctx->ev->type = EVTR_TYPE_STMT;
322         ctx->ev->stmt.var = $1;
323         ctx->ev->stmt.val = &$3->val;
324         ctx->ev->stmt.op = EVTR_OP_SET;
325  }
326 ;
327 expr: assign_expr {
328         $$ = $1;
329  }
330 ;
331
332 %%
333
334 void * __ktrfmt_scan_string(const char *);
335 void __ktrfmt_delete_buffer(void *);
336
337 void
338 __ktrfmt_error (struct ktrfmt_parse_ctx *ctx, const char *s)
339 {
340         do_parse_err(ctx, s);
341 }
342
343 int
344 parse_string(evtr_event_t ev, struct symtab *symtab, const char *str,
345              char *errbuf, size_t errbufsz)
346 {
347         void *bufstate;
348         int ret;
349         struct ktrfmt_parse_ctx ctx;
350
351         printd(PARSE, "parsing \"%s\"\n", str);
352         ctx.ev = ev;
353         ctx.symtab = symtab;
354         ctx.errbuf = errbuf;
355         ctx.errbuf[0] = '\0';
356         ctx.errbufsz = errbufsz;
357         ctx.err = 0;
358         bufstate = __ktrfmt_scan_string(str);
359         ret = __ktrfmt_parse(&ctx);
360         __ktrfmt_delete_buffer(bufstate);
361
362         return ret;
363 }
364
365 int
366 parse_var(const char *str, struct symtab *symtab, struct evtr_variable **var,
367           char *errbuf, size_t errbufsz)
368 {
369         void *bufstate;
370         int ret;
371         struct ktrfmt_parse_ctx ctx;
372
373         printd(PARSE, "parsing \"%s\"\n", str);
374         ctx.ev = NULL;
375         ctx.symtab = symtab;
376         ctx.var = NULL;
377         ctx.errbuf = errbuf;
378         ctx.errbuf[0] = '\0';
379         ctx.errbufsz = errbufsz;
380         ctx.err = 0;
381         bufstate = __ktrfmt_scan_string(str);
382         ret = __ktrfmt_parse(&ctx);
383         __ktrfmt_delete_buffer(bufstate);
384
385         *var = ctx.var;
386         return ret;
387 }