/* $NetBSD: yacc.y,v 1.7 2006/09/09 14:35:17 tnozaki Exp $ */ %{ /*- * Copyright (c)2003, 2006 Citrus Project, * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if HAVE_NBTOOL_CONFIG_H #include "nbtool_config.h" #endif #include #if !defined(lint) __RCSID("$NetBSD: yacc.y,v 1.7 2006/09/09 14:35:17 tnozaki Exp $"); #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include "ldef.h" #ifndef __packed #define __packed #endif #include "citrus_namespace.h" #include "citrus_types.h" #include "citrus_mapper_std_file.h" #include "citrus_region.h" #include "citrus_db_factory.h" #include "citrus_db_hash.h" #include "citrus_lookup_factory.h" #include "citrus_pivot_factory.h" int debug = 0; static char *output = NULL; static void *table = NULL; static size_t table_size; static char *map_name; static int map_type; static u_int32_t dst_invalid, dst_ilseq, oob_mode, dst_unit_bits; static void (*putfunc)(void *, size_t, u_int32_t) = 0; static u_int32_t src_next; static u_int32_t done_flag = 0; #define DF_TYPE 0x00000001 #define DF_NAME 0x00000002 #define DF_SRC_ZONE 0x00000004 #define DF_DST_INVALID 0x00000008 #define DF_DST_ILSEQ 0x00000010 #define DF_DST_UNIT_BITS 0x00000020 #define DF_OOB_MODE 0x00000040 static linear_zone_t rowcol[_CITRUS_MAPPER_STD_ROWCOL_MAX]; static size_t rowcol_len = 0; static u_int32_t rowcol_bits = 0, rowcol_mask = 0; static void dump_file(void); static void setup_map(void); static void set_type(int); static void set_name(char *); static void set_src_zone(u_int32_t); static void set_dst_invalid(u_int32_t); static void set_dst_ilseq(u_int32_t); static void set_dst_unit_bits(u_int32_t); static void set_oob_mode(u_int32_t); static int check_src(u_int32_t, u_int32_t); static void store(const linear_zone_t *, u_int32_t, int); static void put8(void *, size_t, u_int32_t); static void put16(void *, size_t, u_int32_t); static void put32(void *, size_t, u_int32_t); static void set_range(u_int32_t, u_int32_t); static void set_src(linear_zone_t *, u_int32_t, u_int32_t); %} %union { u_int32_t i_value; char *s_value; linear_zone_t lz_value; } %token R_TYPE R_NAME R_SRC_ZONE R_DST_UNIT_BITS %token R_DST_INVALID R_DST_ILSEQ %token R_BEGIN_MAP R_END_MAP R_INVALID R_ROWCOL %token R_ILSEQ R_OOB_MODE %token R_LN %token L_IMM %token L_STRING %type src %type dst types oob_mode_sel zone %% file : property mapping lns { dump_file(); } property : /* empty */ | property R_LN | property name | property type | property src_zone | property dst_invalid | property dst_ilseq | property dst_unit_bits | property oob_mode name : R_NAME L_STRING { set_name($2); $2 = NULL; } type : R_TYPE types { set_type($2); } types : R_ROWCOL { $$ = R_ROWCOL; } range : L_IMM '-' L_IMM { set_range($1, $3); } ranges : /* empty */ | ranges range '/' src_zone : R_SRC_ZONE zone { set_src_zone($2); } zone : range { $$ = 32; } | range '/' range '/' ranges L_IMM { $$ = $6; } dst_invalid : R_DST_INVALID L_IMM { set_dst_invalid($2); } dst_ilseq : R_DST_ILSEQ L_IMM { set_dst_ilseq($2); } dst_unit_bits : R_DST_UNIT_BITS L_IMM { set_dst_unit_bits($2); } oob_mode : R_OOB_MODE oob_mode_sel { set_oob_mode($2); } oob_mode_sel : R_INVALID { $$ = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL; } | R_ILSEQ { $$ = _CITRUS_MAPPER_STD_OOB_ILSEQ; } mapping : begin_map map_elems R_END_MAP begin_map : R_BEGIN_MAP lns { setup_map(); } map_elems : /* empty */ | map_elems map_elem lns map_elem : src '=' dst { store(&$1, $3, 0); } | src '=' L_IMM '-' { store(&$1, $3, 1); } dst : L_IMM { $$ = $1; } | R_INVALID { $$ = dst_invalid; } | R_ILSEQ { $$ = dst_ilseq; } src : /* empty */ { set_src(&$$, src_next, src_next); } | L_IMM { set_src(&$$, $1, $1); } | L_IMM '-' L_IMM { set_src(&$$, $1, $3); } | '-' L_IMM { set_src(&$$, src_next, $2); } lns : R_LN | lns R_LN %% static void warning(const char *s) { fprintf(stderr, "%s in %d\n", s, line_number); } int yyerror(const char *s) { warning(s); exit(1); } void put8(void *ptr, size_t ofs, u_int32_t val) { *((u_int8_t *)ptr + ofs) = val; } void put16(void *ptr, size_t ofs, u_int32_t val) { u_int16_t oval = htons(val); memcpy((u_int16_t *)ptr + ofs, &oval, 2); } void put32(void *ptr, size_t ofs, u_int32_t val) { u_int32_t oval = htonl(val); memcpy((u_int32_t *)ptr + ofs, &oval, 4); } static void alloc_table(void) { size_t i; u_int32_t val = 0; linear_zone_t *p; i = rowcol_len; p = &rowcol[--i]; table_size = p->width; while (i > 0) { p = &rowcol[--i]; table_size *= p->width; } table = (void *)malloc(table_size * dst_unit_bits / 8); if (table == NULL) { perror("malloc"); exit(1); } switch (oob_mode) { case _CITRUS_MAPPER_STD_OOB_NONIDENTICAL: val = dst_invalid; break; case _CITRUS_MAPPER_STD_OOB_ILSEQ: val = dst_ilseq; break; default: _DIAGASSERT(0); } for (i = 0; i < table_size; i++) (*putfunc)(table, i, val); } static void setup_map(void) { if ((done_flag & DF_SRC_ZONE)==0) { fprintf(stderr, "SRC_ZONE is mandatory.\n"); exit(1); } if ((done_flag & DF_DST_UNIT_BITS)==0) { fprintf(stderr, "DST_UNIT_BITS is mandatory.\n"); exit(1); } if ((done_flag & DF_DST_INVALID) == 0) dst_invalid = 0xFFFFFFFF; if ((done_flag & DF_DST_ILSEQ) == 0) dst_ilseq = 0xFFFFFFFE; if ((done_flag & DF_OOB_MODE) == 0) oob_mode = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL; alloc_table(); } static void create_rowcol_info(struct _region *r) { void *ptr; size_t ofs, i, len; ofs = 0; ptr = malloc(_CITRUS_MAPPER_STD_ROWCOL_INFO_SIZE); if (ptr == NULL) err(EXIT_FAILURE, "malloc"); put32(ptr, ofs, rowcol_bits); ofs++; put32(ptr, ofs, dst_invalid); ofs++; /* XXX: keep backward compatibility */ switch (rowcol_len) { case 1: put32(ptr, ofs, 0); ofs++; put32(ptr, ofs, 0); ofs++; /*FALLTHROUGH*/ case 2: len = 0; break; default: len = rowcol_len; } for (i = 0; i < rowcol_len; ++i) { put32(ptr, ofs, rowcol[i].begin); ofs++; put32(ptr, ofs, rowcol[i].end); ofs++; } put32(ptr, ofs, dst_unit_bits); ofs++; put32(ptr, ofs, len); ofs++; _region_init(r, ptr, ofs * 4); } static void create_rowcol_ext_ilseq_info(struct _region *r) { void *ptr; size_t ofs; ofs = 0; ptr = malloc(_CITRUS_MAPPER_STD_ROWCOL_EXT_ILSEQ_SIZE); if (ptr==NULL) err(EXIT_FAILURE, "malloc"); put32(ptr, ofs, oob_mode); ofs++; put32(ptr, ofs, dst_ilseq); ofs++; _region_init(r, ptr, _CITRUS_MAPPER_STD_ROWCOL_EXT_ILSEQ_SIZE); } #define CHKERR(ret, func, a) \ do { \ ret = func a; \ if (ret) \ errx(EXIT_FAILURE, "%s: %s", #func, strerror(ret)); \ } while (/*CONSTCOND*/0) static void dump_file(void) { FILE *fp; int ret; struct _db_factory *df; struct _region data; void *serialized; size_t size; /* * build database */ CHKERR(ret, _db_factory_create, (&df, _db_hash_std, NULL)); /* store type */ CHKERR(ret, _db_factory_addstr_by_s, (df, _CITRUS_MAPPER_STD_SYM_TYPE, _CITRUS_MAPPER_STD_TYPE_ROWCOL)); /* store info */ create_rowcol_info(&data); CHKERR(ret, _db_factory_add_by_s, (df, _CITRUS_MAPPER_STD_SYM_INFO, &data, 1)); /* ilseq extension */ create_rowcol_ext_ilseq_info(&data); CHKERR(ret, _db_factory_add_by_s, (df, _CITRUS_MAPPER_STD_SYM_ROWCOL_EXT_ILSEQ, &data, 1)); /* store table */ _region_init(&data, table, table_size*dst_unit_bits/8); CHKERR(ret, _db_factory_add_by_s, (df, _CITRUS_MAPPER_STD_SYM_TABLE, &data, 1)); /* * dump database to file */ if (output) fp = fopen(output, "wb"); else fp = stdout; if (fp == NULL) { perror("fopen"); exit(1); } /* dump database body */ size = _db_factory_calc_size(df); serialized = malloc(size); _region_init(&data, serialized, size); CHKERR(ret, _db_factory_serialize, (df, _CITRUS_MAPPER_STD_MAGIC, &data)); if (fwrite(serialized, size, 1, fp) != 1) err(EXIT_FAILURE, "fwrite"); fclose(fp); } static void /*ARGSUSED*/ set_type(int type) { if (done_flag & DF_TYPE) { warning("TYPE is duplicated. ignored this one"); return; } map_type = type; done_flag |= DF_TYPE; } static void /*ARGSUSED*/ set_name(char *str) { if (done_flag & DF_NAME) { warning("NAME is duplicated. ignored this one"); return; } map_name = str; done_flag |= DF_NAME; } static void set_src_zone(u_int32_t val) { size_t i; linear_zone_t *p; if (done_flag & DF_SRC_ZONE) { warning("SRC_ZONE is duplicated. ignored this one"); return; } rowcol_bits = val; /* sanity check */ switch (rowcol_bits) { case 8: case 16: case 32: if (rowcol_len <= 32 / rowcol_bits) break; /*FALLTHROUGH*/ default: goto bad; } rowcol_mask = 1 << (rowcol_bits - 1); rowcol_mask |= rowcol_mask - 1; for (i = 0; i < rowcol_len; ++i) { p = &rowcol[i]; _DIAGASSERT(p->begin <= p->end); if (p->end > rowcol_mask) goto bad; } done_flag |= DF_SRC_ZONE; return; bad: yyerror("Illegal argument for SRC_ZONE"); } static void set_dst_invalid(u_int32_t val) { if (done_flag & DF_DST_INVALID) { warning("DST_INVALID is duplicated. ignored this one"); return; } dst_invalid = val; done_flag |= DF_DST_INVALID; } static void set_dst_ilseq(u_int32_t val) { if (done_flag & DF_DST_ILSEQ) { warning("DST_ILSEQ is duplicated. ignored this one"); return; } dst_ilseq = val; done_flag |= DF_DST_ILSEQ; } static void set_oob_mode(u_int32_t val) { if (done_flag & DF_OOB_MODE) { warning("OOB_MODE is duplicated. ignored this one"); return; } oob_mode = val; done_flag |= DF_OOB_MODE; } static void set_dst_unit_bits(u_int32_t val) { if (done_flag & DF_DST_UNIT_BITS) { warning("DST_UNIT_BITS is duplicated. ignored this one"); return; } switch (val) { case 8: putfunc = &put8; dst_unit_bits = val; break; case 16: putfunc = &put16; dst_unit_bits = val; break; case 32: putfunc = &put32; dst_unit_bits = val; break; default: yyerror("Illegal argument for DST_UNIT_BITS"); } done_flag |= DF_DST_UNIT_BITS; } static int check_src(u_int32_t begin, u_int32_t end) { size_t i; linear_zone_t *p; u_int32_t m, n; if (begin > end) return 1; if (begin < end) { m = begin & ~rowcol_mask; n = end & ~rowcol_mask; if (m != n) return 1; } for (i = rowcol_len * rowcol_bits, p = &rowcol[0]; i > 0; ++p) { i -= rowcol_bits; m = (begin >> i) & rowcol_mask; if (m < p->begin || m > p->end) return 1; } if (begin < end) { n = end & rowcol_mask; _DIAGASSERT(p > rowcol); --p; if (n < p->begin || n > p->end) return 1; } return 0; } static void store(const linear_zone_t *lz, u_int32_t dst, int inc) { size_t i, ofs; linear_zone_t *p; u_int32_t n; ofs = 0; for (i = rowcol_len * rowcol_bits, p = &rowcol[0]; i > 0; ++p) { i -= rowcol_bits; n = ((lz->begin >> i) & rowcol_mask) - p->begin; ofs = (ofs * p->width) + n; } n = lz->width; while (n-- > 0) { (*putfunc)(table, ofs++, dst); if (inc) dst++; } } static void set_range(u_int32_t begin, u_int32_t end) { linear_zone_t *p; if (rowcol_len >= _CITRUS_MAPPER_STD_ROWCOL_MAX) goto bad; p = &rowcol[rowcol_len++]; if (begin > end) goto bad; p->begin = begin, p->end = end; p->width = end - begin + 1; return; bad: yyerror("Illegal argument for SRC_ZONE"); } static void set_src(linear_zone_t *lz, u_int32_t begin, u_int32_t end) { _DIAGASSERT(lz != NULL); if (check_src(begin, end) != 0) yyerror("illegal zone"); lz->begin = begin, lz->end = end; lz->width = end - begin + 1; src_next = end + 1; } static void do_mkdb(FILE *in) { int ret; FILE *out; /* dump DB to file */ if (output) out = fopen(output, "wb"); else out = stdout; if (out==NULL) err(EXIT_FAILURE, "fopen"); ret = _lookup_factory_convert(out, in); fclose(out); if (ret && output) unlink(output); /* dump failure */ } static void do_mkpv(FILE *in) { int ret; FILE *out; /* dump pivot to file */ if (output) out = fopen(output, "wb"); else out = stdout; if (out==NULL) err(EXIT_FAILURE, "fopen"); ret = _pivot_factory_convert(out, in); fclose(out); if (ret && output) unlink(output); /* dump failure */ if (ret) errx(EXIT_FAILURE, "%s\n", strerror(ret)); } static void usage(void) { warnx("usage: \n" "\t%s [-d] [-o outfile] [infile]\n" "\t%s -m [-d] [-o outfile] [infile]\n" "\t%s -p [-d] [-o outfile] [infile]\n", getprogname(), getprogname(), getprogname()); exit(1); } int main(int argc, char **argv) { int ch; extern char *optarg; extern int optind; FILE *in = NULL; int mkdb = 0, mkpv = 0; while ((ch=getopt(argc, argv, "do:mp")) != EOF) { switch (ch) { case 'd': debug=1; break; case 'o': output = strdup(optarg); break; case 'm': mkdb = 1; break; case 'p': mkpv = 1; break; default: usage(); } } argc-=optind; argv+=optind; switch (argc) { case 0: in = stdin; break; case 1: in = fopen(argv[0], "r"); if (!in) err(EXIT_FAILURE, argv[0]); break; default: usage(); } if (mkdb) do_mkdb(in); else if (mkpv) do_mkpv(in); else { yyin = in; yyparse(); } return (0); }