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