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