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