xref: /dragonfly/lib/libevtr/ktrfmt.y (revision dcd37f7d)
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 }
388