libevtr: add support for string literals
[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_STR;
108         var->val.str = $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: primary_expr TOK_LEFT_BRACK postfix_expr TOK_RIGHT_BRACK {
136         evtr_var_t hsh, var;
137         evtr_variable_value_t val;
138         uintptr_t ret, key;
139         hsh = symtab_find(ctx->symtab, $1->name);
140 #if 0
141         if (!hsh) {
142                 printd(PARSE, "creating hash: %s\n", $1->name);
143                 hsh = evtr_var_new($1->name);
144                 hsh->val.type = EVTR_VAL_HASH;
145                 hsh->val.hashtab = hash_new();
146                 symtab_insert(ctx->symtab, $1->str, hsh);
147         }
148 #endif
149         if (hsh->val.type == EVTR_VAL_NIL) {
150                 /* it's probably the first time we see this "variable" */
151                 printd(PARSE, "creating hash for %s\n", hsh->name);
152                 hsh->val.type = EVTR_VAL_HASH;
153                 hsh->val.hashtab = hash_new();
154         } else if (hsh->val.type != EVTR_VAL_HASH) {
155                 printd(PARSE, "trying to use type %d as hash\n", hsh->val.type);
156                 YYABORT;
157         }
158         val = &$3->val;
159         if (val->type == EVTR_VAL_INT) {
160                 key = val->num;
161                 printd(PARSE, "looking up %s[%jd] in %p\n", hsh->name, val->num, hsh->val.hashtab);
162         } else if (val->type == EVTR_VAL_STR) {
163                 key = (uintptr_t)val->str;
164                 printd(PARSE, "looking up %s[\"%s\"] in %p\n", hsh->name, val->str, hsh->val.hashtab);
165         } else {
166                 fprintf(stderr, "trying to index hash w/ non-supported value\n");
167                 YYABORT;
168         }
169
170         if (hash_find(hsh->val.hashtab, key, &ret)) {
171                 printd(PARSE, "didn't find it\n");
172                 var = evtr_var_new(uniq_varname());
173                 if (var) {
174                         printd(PARSE, "inserting it as %s\n", var->name);
175                         if (!hash_insert(hsh->val.hashtab, key, (uintptr_t)var)) {
176                                 fprintf(stderr, "can't insert tmp "
177                                         "variable into hash\n");
178                                 YYABORT;
179                         }
180                 } else {
181                         /* XXX: oom */
182                 }
183         } else {
184                 var = (struct evtr_variable *)ret;
185         }
186         if (!var) {
187                 fprintf(stderr, "no var!\n");
188                 YYABORT;
189                 /* XXX */
190         }
191         $$ = var;
192  }
193 | primary_expr TOK_DOT TOK_ID {
194         /* XXX */
195  }
196             | primary_expr {
197         $$ = $1;
198  }
199 ;
200 unary_expr: postfix_expr {
201         $$ = $1;
202  }
203 ;
204 assign_expr: unary_expr TOK_EQ constant {
205         $1->val = $3->val;
206         ctx->ev->type = EVTR_TYPE_STMT;
207         ctx->ev->stmt.var = $1;
208         ctx->ev->stmt.val = &$3->val;
209         ctx->ev->stmt.op = EVTR_OP_SET;
210  }
211 ;
212 expr: assign_expr {
213         $$ = $1;
214  }
215 ;
216
217 %%
218
219 void * __ktrfmt_scan_string(const char *);
220 void __ktrfmt_delete_buffer(void *);
221
222 void
223 __ktrfmt_error (struct ktrfmt_parse_ctx *ctx, const char *s)
224 {
225         (void)ctx;
226         fprintf(stderr, "%s\n", s);
227 }
228
229 int
230 parse_string(evtr_event_t ev, struct symtab *symtab, const char *str)
231 {
232         void *bufstate;
233         int ret;
234         struct ktrfmt_parse_ctx ctx;
235
236         printd(PARSE, "parsing \"%s\"\n", str);
237         ctx.ev = ev;
238         ctx.symtab = symtab;
239         bufstate = __ktrfmt_scan_string(str);
240         ret = __ktrfmt_parse(&ctx);
241         __ktrfmt_delete_buffer(bufstate);
242
243         return ret;
244 }
245
246 int
247 parse_var(const char *str, struct symtab *symtab, struct evtr_variable **var)
248 {
249         void *bufstate;
250         int ret;
251         struct ktrfmt_parse_ctx ctx;
252
253         ctx.ev = NULL;
254         ctx.symtab = symtab;
255         ctx.var = NULL;
256         bufstate = __ktrfmt_scan_string(str);
257         ret = __ktrfmt_parse(&ctx);
258         __ktrfmt_delete_buffer(bufstate);
259
260         *var = ctx.var;
261         return ret;
262 }