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