evtr: initial implementation of a DSL
[dragonfly.git] / lib / libevtr / ktrfmt.y
1 %{
2
3 #include <assert.h>
4 #include <stdlib.h>
5 #include <string.h>
6
7 #include "evtr.h"
8 #include "tok.h"
9 #include "ktrfmt.tab.h"
10 #include "internal.h"
11
12 struct ktrfmt_parse_ctx {
13         struct symtab *symtab;
14         struct evtr_variable *var;
15         struct evtr_variable_value *val;
16         evtr_event_t ev;
17 };
18
19 int __ktrfmtlex(YYSTYPE *);
20 #define __ktrfmt_lex __ktrfmtlex
21
22 void __ktrfmt_error (struct ktrfmt_parse_ctx *, const char *);
23
24 static
25 struct evtr_variable *
26 evtr_var_new(const char *name)
27 {
28         struct evtr_variable *var;
29
30         var = calloc(1, sizeof(*var));
31         if (var) {
32                 var->name = strdup(name);
33                 /* XXX: oom */
34                 var->val.type = EVTR_VAL_NIL;
35         }
36         return var;
37 }
38
39 /*
40  * XXX: should be reentrant
41  */
42 static
43 char *
44 uniq_varname(void)
45 {
46         static long serno;
47         static char buf[100];
48
49         serno++;
50         snprintf(buf, sizeof(buf), "@%ld", serno);
51         return &buf[0];
52 }
53
54 %}
55
56 %verbose
57 %error-verbose
58 %debug
59 %name-prefix "__ktrfmt_"
60 %define api.pure
61 %parse-param{struct ktrfmt_parse_ctx *ctx}
62
63 %union {
64         struct token *tok;
65         struct evtr_variable *var;
66         struct evtr_variable_value *val;
67         void *na;
68 }
69
70 %token<tok> TOK_ID
71 %token<tok> TOK_INT
72 %token<tok> TOK_STR
73
74 %token<na> TOK_EQ
75 %token<na> TOK_LEFT_BRACK
76 %token<na> TOK_RIGHT_BRACK
77 %token<na> TOK_DOT
78
79 %type<var> constant
80 %type<var> primary_expr
81 %type<var> postfix_expr
82 %type<var> unary_expr
83 %type<na> assign_expr
84 %type<na> expr
85
86 %%
87
88 input: stmt
89
90 stmt: unary_expr {
91         ctx->var = $1;
92  }
93      | expr
94      ;
95 constant: TOK_INT {
96         evtr_var_t var;
97         var = evtr_var_new(uniq_varname());
98         var->val.type = EVTR_VAL_INT;
99         var->val.num =
100                 atoll($1->str); /* XXX */
101         $$ = var;
102         tok_free($1);
103         }
104         | TOK_STR {
105         evtr_var_t var;
106         var = evtr_var_new(uniq_varname());
107         var->val.type = EVTR_VAL_INT;
108         var->val.str = strdup($1->str);
109         if (!var->val.str) {
110                 fprintf(stderr, "oom\n");
111                 YYABORT;
112         }
113         $$ = var;
114         tok_free($1);
115         }
116         ;
117
118 primary_expr: TOK_ID {
119         evtr_var_t var;
120         printd(PARSE, "TOK_ID\n");
121         printd(PARSE, "tok: %p, str = %p\n", $1, $1->str);
122         var = symtab_find(ctx->symtab, $1->str);
123         if (!var) {
124                 var = evtr_var_new($1->str); /* XXX: oom */
125                 printd(PARSE, "creating var %s\n", $1->str);
126                 symtab_insert(ctx->symtab, $1->str, var);
127         }
128         $$ = var;
129         tok_free($1);
130  }
131 | constant {
132         $$ = $1;
133   }
134 ;
135 postfix_expr: TOK_ID TOK_LEFT_BRACK postfix_expr TOK_RIGHT_BRACK {
136         evtr_var_t hsh, var;
137         evtr_variable_value_t val;
138         hsh = symtab_find(ctx->symtab, $1->str);
139         if (!hsh) {
140                 printd(PARSE, "creating hash: %s\n", $1->str);
141                 hsh = evtr_var_new($1->str);
142                 hsh->val.type = EVTR_VAL_HASH;
143                 hsh->val.hashtab = hash_new();
144                 symtab_insert(ctx->symtab, $1->str, hsh);
145         }
146         if (hsh->val.type != EVTR_VAL_HASH) {
147                 printd(PARSE, "variable %s does not contain a hash\n", hsh->name);
148                 YYABORT;
149         }
150         val = &$3->val;
151         if (val->type == EVTR_VAL_INT) {
152                 uintptr_t ret;
153                 uintptr_t key = val->num;
154                 printd(PARSE, "looking up %s[%jd] in %p\n", $1->str, val->num, hsh->val.hashtab);
155                 /* XXX: should definitely be using uintptr_t for keys/values */
156                 if (hash_find(hsh->val.hashtab, key, &ret)) {
157                         printd(PARSE, "didn't find it\n");
158                         var = evtr_var_new(uniq_varname());
159                         if (var) {
160                                 printd(PARSE, "inserting it as %s\n", var->name);
161                                 if (!hash_insert(hsh->val.hashtab, key, (uintptr_t)var)) {
162                                         fprintf(stderr, "can't insert tmp "
163                                                 "variable into hash\n");
164                                         YYABORT;
165                                 }
166                         }
167                 } else {
168                         var = (struct evtr_variable *)ret;
169                 }
170         } else {
171                 fprintf(stderr, "trying to index hash w/ non-integral value\n");
172                 YYABORT;
173         }
174         if (!var) {
175                 fprintf(stderr, "no var!\n");
176                 YYABORT;
177                 /* XXX */
178         }
179         tok_free($1);
180         $$ = var;
181  }
182             | primary_expr {
183         $$ = $1;
184  }
185 ;
186 unary_expr: postfix_expr {
187         $$ = $1;
188  }
189 ;
190 assign_expr: unary_expr TOK_EQ constant {
191         $1->val = $3->val;
192         ctx->ev->type = EVTR_TYPE_STMT;
193         ctx->ev->stmt.var = $1;
194         ctx->ev->stmt.val = &$3->val;
195         ctx->ev->stmt.op = EVTR_OP_SET;
196  }
197 ;
198 expr: assign_expr {
199         $$ = $1;
200  }
201 ;
202
203 %%
204
205 void * __ktrfmt_scan_string(const char *);
206 void __ktrfmt_delete_buffer(void *);
207
208 void
209 __ktrfmt_error (struct ktrfmt_parse_ctx *ctx, const char *s)
210 {
211         (void)ctx;
212         fprintf(stderr, "%s\n", s);
213 }
214
215 int
216 parse_string(evtr_event_t ev, struct symtab *symtab, const char *str)
217 {
218         void *bufstate;
219         int ret;
220         struct ktrfmt_parse_ctx ctx;
221
222         printd(PARSE, "parsing \"%s\"\n", str);
223         ctx.ev = ev;
224         ctx.symtab = symtab;
225         bufstate = __ktrfmt_scan_string(str);
226         ret = __ktrfmt_parse(&ctx);
227         __ktrfmt_delete_buffer(bufstate);
228
229         return ret;
230 }
231
232 int
233 parse_var(const char *str, struct symtab *symtab, struct evtr_variable **var)
234 {
235         void *bufstate;
236         int ret;
237         struct ktrfmt_parse_ctx ctx;
238
239         ctx.ev = NULL;
240         ctx.symtab = symtab;
241         ctx.var = NULL;
242         bufstate = __ktrfmt_scan_string(str);
243         ret = __ktrfmt_parse(&ctx);
244         __ktrfmt_delete_buffer(bufstate);
245
246         *var = ctx.var;
247         return ret;
248 }