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