xref: /dragonfly/usr.bin/mkcsmapper/yacc.y (revision 36a3d1d6)
1 /*	$NetBSD: yacc.y,v 1.7 2006/09/09 14:35:17 tnozaki Exp $	*/
2 /*	$DragonFly: src/usr.bin/mkcsmapper/yacc.y,v 1.3 2008/07/10 18:29:51 swildner Exp $	*/
3 
4 %{
5 /*-
6  * Copyright (c)2003, 2006 Citrus Project,
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #include <sys/types.h>
32 #include <assert.h>
33 #include <err.h>
34 #include <errno.h>
35 #include <limits.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 
41 #include <netinet/in.h>
42 
43 #include "ldef.h"
44 
45 #include "citrus_namespace.h"
46 #include "citrus_types.h"
47 #include "citrus_mapper_std_file.h"
48 #include "citrus_region.h"
49 #include "citrus_db_factory.h"
50 #include "citrus_db_hash.h"
51 #include "citrus_lookup_factory.h"
52 #include "citrus_pivot_factory.h"
53 
54 extern FILE *	yyin;
55 
56 int			debug = 0;
57 static char		*output = NULL;
58 static void		*table = NULL;
59 static size_t		table_size;
60 static char		*map_name;
61 static int		map_type;
62 static u_int32_t	dst_invalid, dst_ilseq, oob_mode, dst_unit_bits;
63 static void		(*putfunc)(void *, size_t, u_int32_t) = 0;
64 
65 static u_int32_t	src_next;
66 
67 static u_int32_t	done_flag = 0;
68 #define DF_TYPE			0x00000001
69 #define DF_NAME			0x00000002
70 #define DF_SRC_ZONE		0x00000004
71 #define DF_DST_INVALID		0x00000008
72 #define DF_DST_ILSEQ		0x00000010
73 #define DF_DST_UNIT_BITS	0x00000020
74 #define DF_OOB_MODE		0x00000040
75 
76 static linear_zone_t	rowcol[_CITRUS_MAPPER_STD_ROWCOL_MAX];
77 static size_t		rowcol_len = 0;
78 static u_int32_t	rowcol_bits = 0, rowcol_mask = 0;
79 
80 static void	dump_file(void);
81 static void	setup_map(void);
82 static void	set_type(int);
83 static void	set_name(char *);
84 static void	set_src_zone(u_int32_t);
85 static void	set_dst_invalid(u_int32_t);
86 static void	set_dst_ilseq(u_int32_t);
87 static void	set_dst_unit_bits(u_int32_t);
88 static void	set_oob_mode(u_int32_t);
89 static int	check_src(u_int32_t, u_int32_t);
90 static void	store(const linear_zone_t *, u_int32_t, int);
91 static void	put8(void *, size_t, u_int32_t);
92 static void	put16(void *, size_t, u_int32_t);
93 static void	put32(void *, size_t, u_int32_t);
94 static void	set_range(u_int32_t, u_int32_t);
95 static void	set_src(linear_zone_t *, u_int32_t, u_int32_t);
96 %}
97 
98 %union {
99 	u_int32_t	i_value;
100 	char		*s_value;
101 	linear_zone_t	lz_value;
102 }
103 
104 %token			R_TYPE R_NAME R_SRC_ZONE R_DST_UNIT_BITS
105 %token			R_DST_INVALID R_DST_ILSEQ
106 %token			R_BEGIN_MAP R_END_MAP R_INVALID R_ROWCOL
107 %token			R_ILSEQ R_OOB_MODE
108 %token			R_LN
109 %token <i_value>	L_IMM
110 %token <s_value>	L_STRING
111 
112 %type <lz_value>	src
113 %type <i_value>		dst types oob_mode_sel zone
114 
115 %%
116 
117 file		: property mapping lns
118 		{ dump_file(); }
119 
120 property	: /* empty */
121 		| property R_LN
122 		| property name
123 		| property type
124 		| property src_zone
125 		| property dst_invalid
126 		| property dst_ilseq
127 		| property dst_unit_bits
128 		| property oob_mode
129 
130 name		: R_NAME L_STRING { set_name($2); $2 = NULL; }
131 type		: R_TYPE types { set_type($2); }
132 types		: R_ROWCOL { $$ = R_ROWCOL; }
133 range		: L_IMM '-' L_IMM { set_range($1, $3); }
134 
135 ranges		: /* empty */
136 		| ranges range '/'
137 
138 src_zone	: R_SRC_ZONE zone { set_src_zone($2); }
139 zone		: range {
140 			$$ = 32;
141 		}
142 		| range '/' range '/' ranges L_IMM {
143 			$$ = $6;
144 		}
145 
146 dst_invalid	: R_DST_INVALID L_IMM { set_dst_invalid($2); }
147 dst_ilseq	: R_DST_ILSEQ L_IMM { set_dst_ilseq($2); }
148 dst_unit_bits	: R_DST_UNIT_BITS L_IMM { set_dst_unit_bits($2); }
149 oob_mode	: R_OOB_MODE oob_mode_sel { set_oob_mode($2); }
150 
151 oob_mode_sel	: R_INVALID { $$ = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL; }
152 		| R_ILSEQ { $$ = _CITRUS_MAPPER_STD_OOB_ILSEQ; }
153 
154 mapping		: begin_map map_elems R_END_MAP
155 begin_map	: R_BEGIN_MAP lns { setup_map(); }
156 
157 map_elems	: /* empty */
158 		| map_elems map_elem lns
159 
160 map_elem	: src '=' dst
161 		{ store(&$1, $3, 0); }
162 		| src '=' L_IMM '-'
163 		{ store(&$1, $3, 1); }
164 dst		: L_IMM
165 		{
166 			$$ = $1;
167 		}
168 		| R_INVALID
169 		{
170 			$$ = dst_invalid;
171 		}
172 		| R_ILSEQ
173 		{
174 			$$ = dst_ilseq;
175 		}
176 
177 src		: /* empty */
178 		{
179 			set_src(&$$, src_next, src_next);
180 		}
181 		| L_IMM
182 		{
183 			set_src(&$$, $1, $1);
184 		}
185 		| L_IMM '-' L_IMM
186 		{
187 			set_src(&$$, $1, $3);
188 		}
189 		| '-' L_IMM
190 		{
191 			set_src(&$$, src_next, $2);
192 		}
193 lns		: R_LN
194 		| lns R_LN
195 
196 %%
197 
198 static void
199 warning(const char *s)
200 {
201 	fprintf(stderr, "%s in %d\n", s, line_number);
202 }
203 
204 int
205 yyerror(const char *s)
206 {
207 	warning(s);
208 	exit(1);
209 }
210 
211 void
212 put8(void *ptr, size_t ofs, u_int32_t val)
213 {
214 	*((u_int8_t *)ptr + ofs) = val;
215 }
216 
217 void
218 put16(void *ptr, size_t ofs, u_int32_t val)
219 {
220 	u_int16_t oval = htons(val);
221 	memcpy((u_int16_t *)ptr + ofs, &oval, 2);
222 }
223 
224 void
225 put32(void *ptr, size_t ofs, u_int32_t val)
226 {
227 	u_int32_t oval = htonl(val);
228 	memcpy((u_int32_t *)ptr + ofs, &oval, 4);
229 }
230 
231 static void
232 alloc_table(void)
233 {
234 	size_t i;
235 	u_int32_t val = 0;
236 	linear_zone_t *p;
237 
238 	i = rowcol_len;
239 	p = &rowcol[--i];
240 	table_size = p->width;
241 	while (i > 0) {
242 		p = &rowcol[--i];
243 		table_size *= p->width;
244 	}
245 	table = (void *)malloc(table_size * dst_unit_bits / 8);
246 	if (table == NULL) {
247 		perror("malloc");
248 		exit(1);
249 	}
250 
251 	switch (oob_mode) {
252 	case _CITRUS_MAPPER_STD_OOB_NONIDENTICAL:
253 		val = dst_invalid;
254 		break;
255 	case _CITRUS_MAPPER_STD_OOB_ILSEQ:
256 		val = dst_ilseq;
257 		break;
258 	default:
259 		;
260 	}
261 	for (i = 0; i < table_size; i++)
262 		(*putfunc)(table, i, val);
263 }
264 
265 static void
266 setup_map(void)
267 {
268 
269 	if ((done_flag & DF_SRC_ZONE)==0) {
270 		fprintf(stderr, "SRC_ZONE is mandatory.\n");
271 		exit(1);
272 	}
273 	if ((done_flag & DF_DST_UNIT_BITS)==0) {
274 		fprintf(stderr, "DST_UNIT_BITS is mandatory.\n");
275 		exit(1);
276 	}
277 
278 	if ((done_flag & DF_DST_INVALID) == 0)
279 		dst_invalid = 0xFFFFFFFF;
280 	if ((done_flag & DF_DST_ILSEQ) == 0)
281 		dst_ilseq = 0xFFFFFFFE;
282 	if ((done_flag & DF_OOB_MODE) == 0)
283 		oob_mode = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL;
284 
285 	alloc_table();
286 }
287 
288 static void
289 create_rowcol_info(struct _region *r)
290 {
291 	void *ptr;
292 	size_t ofs, i, len;
293 
294 	ofs = 0;
295 	ptr = malloc(_CITRUS_MAPPER_STD_ROWCOL_INFO_SIZE);
296 	if (ptr == NULL)
297 		err(EXIT_FAILURE, "malloc");
298 	put32(ptr, ofs, rowcol_bits); ofs++;
299 	put32(ptr, ofs, dst_invalid); ofs++;
300 
301 	/* XXX: keep backward compatibility */
302 	switch (rowcol_len) {
303 	case 1:
304 		put32(ptr, ofs, 0); ofs++;
305 		put32(ptr, ofs, 0); ofs++;
306 	/*FALLTHROUGH*/
307 	case 2:
308 		len = 0;
309 		break;
310 	default:
311 		len = rowcol_len;
312 	}
313 	for (i = 0; i < rowcol_len; ++i) {
314 		put32(ptr, ofs, rowcol[i].begin); ofs++;
315 		put32(ptr, ofs, rowcol[i].end); ofs++;
316 	}
317 	put32(ptr, ofs, dst_unit_bits); ofs++;
318 	put32(ptr, ofs, len); ofs++;
319 
320 	_region_init(r, ptr, ofs * 4);
321 }
322 
323 
324 static void
325 create_rowcol_ext_ilseq_info(struct _region *r)
326 {
327 	void *ptr;
328 	size_t ofs;
329 
330 	ofs = 0;
331 	ptr = malloc(_CITRUS_MAPPER_STD_ROWCOL_EXT_ILSEQ_SIZE);
332 	if (ptr==NULL)
333 		err(EXIT_FAILURE, "malloc");
334 
335 	put32(ptr, ofs, oob_mode); ofs++;
336 	put32(ptr, ofs, dst_ilseq); ofs++;
337 
338 	_region_init(r, ptr, _CITRUS_MAPPER_STD_ROWCOL_EXT_ILSEQ_SIZE);
339 }
340 
341 #define CHKERR(ret, func, a)						\
342 do {									\
343 	ret = func a;							\
344 	if (ret)							\
345 		errx(EXIT_FAILURE, "%s: %s", #func, strerror(ret));	\
346 } while (/*CONSTCOND*/0)
347 
348 static void
349 dump_file(void)
350 {
351 	FILE *fp;
352 	int ret;
353 	struct _db_factory *df;
354 	struct _region data;
355 	void *serialized;
356 	size_t size;
357 
358 	/*
359 	 * build database
360 	 */
361 	CHKERR(ret, _db_factory_create, (&df, _db_hash_std, NULL));
362 
363 	/* store type */
364 	CHKERR(ret, _db_factory_addstr_by_s,
365 	       (df, _CITRUS_MAPPER_STD_SYM_TYPE,
366 		_CITRUS_MAPPER_STD_TYPE_ROWCOL));
367 
368 	/* store info */
369 	create_rowcol_info(&data);
370 	CHKERR(ret, _db_factory_add_by_s,
371 	       (df, _CITRUS_MAPPER_STD_SYM_INFO, &data, 1));
372 
373 	/* ilseq extension */
374 	create_rowcol_ext_ilseq_info(&data);
375 	CHKERR(ret, _db_factory_add_by_s,
376 	       (df, _CITRUS_MAPPER_STD_SYM_ROWCOL_EXT_ILSEQ, &data, 1));
377 
378 	/* store table */
379 	_region_init(&data, table, table_size*dst_unit_bits/8);
380 	CHKERR(ret, _db_factory_add_by_s,
381 	       (df, _CITRUS_MAPPER_STD_SYM_TABLE, &data, 1));
382 
383 	/*
384 	 * dump database to file
385 	 */
386 	if (output)
387 		fp = fopen(output, "wb");
388 	else
389 		fp = stdout;
390 
391 	if (fp == NULL) {
392 		perror("fopen");
393 		exit(1);
394 	}
395 
396 	/* dump database body */
397 	size = _db_factory_calc_size(df);
398 	serialized = malloc(size);
399 	_region_init(&data, serialized, size);
400 	CHKERR(ret, _db_factory_serialize,
401 	       (df, _CITRUS_MAPPER_STD_MAGIC, &data));
402 	if (fwrite(serialized, size, 1, fp) != 1)
403 		err(EXIT_FAILURE, "fwrite");
404 
405 	fclose(fp);
406 }
407 
408 static void
409 /*ARGSUSED*/
410 set_type(int type)
411 {
412 
413 	if (done_flag & DF_TYPE) {
414 		warning("TYPE is duplicated. ignored this one");
415 		return;
416 	}
417 
418 	map_type = type;
419 
420 	done_flag |= DF_TYPE;
421 }
422 static void
423 /*ARGSUSED*/
424 set_name(char *str)
425 {
426 
427 	if (done_flag & DF_NAME) {
428 		warning("NAME is duplicated. ignored this one");
429 		return;
430 	}
431 
432 	map_name = str;
433 
434 	done_flag |= DF_NAME;
435 }
436 static void
437 set_src_zone(u_int32_t val)
438 {
439 	size_t i;
440 	linear_zone_t *p;
441 
442 	if (done_flag & DF_SRC_ZONE) {
443 		warning("SRC_ZONE is duplicated. ignored this one");
444 		return;
445 	}
446 	rowcol_bits = val;
447 
448 	/* sanity check */
449 	switch (rowcol_bits) {
450 	case 8: case 16: case 32:
451 		if (rowcol_len <= 32 / rowcol_bits)
452 			break;
453 	/*FALLTHROUGH*/
454 	default:
455 		goto bad;
456 	}
457 	rowcol_mask = 1 << (rowcol_bits - 1);
458 	rowcol_mask |= rowcol_mask - 1;
459 	for (i = 0; i < rowcol_len; ++i) {
460 		p = &rowcol[i];
461 		_DIAGASSERT(p->begin <= p->end);
462 		if (p->end > rowcol_mask)
463 			goto bad;
464 	}
465 	done_flag |= DF_SRC_ZONE;
466 	return;
467 
468 bad:
469 	yyerror("Illegal argument for SRC_ZONE");
470 }
471 static void
472 set_dst_invalid(u_int32_t val)
473 {
474 
475 	if (done_flag & DF_DST_INVALID) {
476 		warning("DST_INVALID is duplicated. ignored this one");
477 		return;
478 	}
479 
480 	dst_invalid = val;
481 
482 	done_flag |= DF_DST_INVALID;
483 }
484 static void
485 set_dst_ilseq(u_int32_t val)
486 {
487 
488 	if (done_flag & DF_DST_ILSEQ) {
489 		warning("DST_ILSEQ is duplicated. ignored this one");
490 		return;
491 	}
492 
493 	dst_ilseq = val;
494 
495 	done_flag |= DF_DST_ILSEQ;
496 }
497 static void
498 set_oob_mode(u_int32_t val)
499 {
500 
501 	if (done_flag & DF_OOB_MODE) {
502 		warning("OOB_MODE is duplicated. ignored this one");
503 		return;
504 	}
505 
506 	oob_mode = val;
507 
508 	done_flag |= DF_OOB_MODE;
509 }
510 static void
511 set_dst_unit_bits(u_int32_t val)
512 {
513 
514 	if (done_flag & DF_DST_UNIT_BITS) {
515 		warning("DST_UNIT_BITS is duplicated. ignored this one");
516 		return;
517 	}
518 
519 	switch (val) {
520 	case 8:
521 		putfunc = &put8;
522 		dst_unit_bits = val;
523 		break;
524 	case 16:
525 		putfunc = &put16;
526 		dst_unit_bits = val;
527 		break;
528 	case 32:
529 		putfunc = &put32;
530 		dst_unit_bits = val;
531 		break;
532 	default:
533 		yyerror("Illegal argument for DST_UNIT_BITS");
534 	}
535 	done_flag |= DF_DST_UNIT_BITS;
536 }
537 static int
538 check_src(u_int32_t begin, u_int32_t end)
539 {
540 	size_t i;
541 	linear_zone_t *p;
542 	u_int32_t m, n;
543 
544 	if (begin > end)
545 		return 1;
546 	if (begin < end) {
547 		m = begin & ~rowcol_mask;
548 		n = end & ~rowcol_mask;
549 		if (m != n)
550 			return 1;
551 	}
552 	for (i = rowcol_len * rowcol_bits, p = &rowcol[0]; i > 0; ++p) {
553 		i -= rowcol_bits;
554 		m = (begin >> i) & rowcol_mask;
555 		if (m < p->begin || m > p->end)
556 			return 1;
557 	}
558 	if (begin < end) {
559 		n = end & rowcol_mask;
560 		_DIAGASSERT(p > rowcol);
561 		--p;
562 		if (n < p->begin || n > p->end)
563 			return 1;
564 	}
565 	return 0;
566 }
567 static void
568 store(const linear_zone_t *lz, u_int32_t dst, int inc)
569 {
570 	size_t i, ofs;
571 	linear_zone_t *p;
572 	u_int32_t n;
573 
574 	ofs = 0;
575 	for (i = rowcol_len * rowcol_bits, p = &rowcol[0]; i > 0; ++p) {
576 		i -= rowcol_bits;
577 		n = ((lz->begin >> i) & rowcol_mask) - p->begin;
578 		ofs = (ofs * p->width) + n;
579 	}
580 	n = lz->width;
581 	while (n-- > 0) {
582 		(*putfunc)(table, ofs++, dst);
583 		if (inc)
584 			dst++;
585 	}
586 }
587 static void
588 set_range(u_int32_t begin, u_int32_t end)
589 {
590 	linear_zone_t *p;
591 
592 	if (rowcol_len >= _CITRUS_MAPPER_STD_ROWCOL_MAX)
593 		goto bad;
594 	p = &rowcol[rowcol_len++];
595 
596 	if (begin > end)
597 		goto bad;
598 	p->begin = begin, p->end = end;
599 	p->width = end - begin + 1;
600 
601 	return;
602 
603 bad:
604 	yyerror("Illegal argument for SRC_ZONE");
605 }
606 static void
607 set_src(linear_zone_t *lz, u_int32_t begin, u_int32_t end)
608 {
609 	_DIAGASSERT(lz != NULL);
610 
611 	if (check_src(begin, end) != 0)
612 		yyerror("illegal zone");
613 
614 	lz->begin = begin, lz->end = end;
615 	lz->width = end - begin + 1;
616 
617 	src_next = end + 1;
618 }
619 
620 static void
621 do_mkdb(FILE *in)
622 {
623 	int ret;
624 	FILE *out;
625 
626         /* dump DB to file */
627 	if (output)
628 		out = fopen(output, "wb");
629 	else
630 		out = stdout;
631 
632 	if (out==NULL)
633 		err(EXIT_FAILURE, "fopen");
634 
635 	ret = _lookup_factory_convert(out, in);
636 	fclose(out);
637 	if (ret && output)
638 		unlink(output); /* dump failure */
639 }
640 
641 static void
642 do_mkpv(FILE *in)
643 {
644 	int ret;
645 	FILE *out;
646 
647         /* dump pivot to file */
648 	if (output)
649 		out = fopen(output, "wb");
650 	else
651 		out = stdout;
652 
653 	if (out==NULL)
654 		err(EXIT_FAILURE, "fopen");
655 
656 	ret = _pivot_factory_convert(out, in);
657 	fclose(out);
658 	if (ret && output)
659 		unlink(output); /* dump failure */
660 	if (ret)
661 		errx(EXIT_FAILURE, "%s\n", strerror(ret));
662 }
663 
664 static void
665 usage(void)
666 {
667 	warnx("usage: \n"
668 	      "\t%s [-d] [-o outfile] [infile]\n"
669 	      "\t%s -m [-d] [-o outfile] [infile]\n"
670 	      "\t%s -p [-d] [-o outfile] [infile]\n",
671 	      getprogname(), getprogname(), getprogname());
672 	exit(1);
673 }
674 
675 int
676 main(int argc, char **argv)
677 {
678 	int ch;
679 	FILE *in = NULL;
680 	int mkdb = 0, mkpv = 0;
681 
682 	while ((ch = getopt(argc, argv, "do:mp")) != -1) {
683 		switch (ch) {
684 		case 'd':
685 			debug=1;
686 			break;
687 		case 'o':
688 			output = strdup(optarg);
689 			break;
690 		case 'm':
691 			mkdb = 1;
692 			break;
693 		case 'p':
694 			mkpv = 1;
695 			break;
696 		default:
697 			usage();
698 		}
699 	}
700 
701 	argc-=optind;
702 	argv+=optind;
703 	switch (argc) {
704 	case 0:
705 		in = stdin;
706 		break;
707 	case 1:
708 		in = fopen(argv[0], "r");
709 		if (!in)
710 			err(EXIT_FAILURE, argv[0]);
711 		break;
712 	default:
713 		usage();
714 	}
715 
716 	if (mkdb)
717 		do_mkdb(in);
718 	else if (mkpv)
719 		do_mkpv(in);
720 	else {
721 		yyin = in;
722 		yyparse();
723 	}
724 
725 	return (0);
726 }
727