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