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