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