NetBSD/usr.bin/mkcsmapper/yacc.y
2011-09-16 15:39:25 +00:00

738 lines
14 KiB
Plaintext

/* $NetBSD: yacc.y,v 1.9 2011/09/16 15:39:27 joerg 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 <sys/cdefs.h>
#if !defined(lint)
__RCSID("$NetBSD: yacc.y,v 1.9 2011/09/16 15:39:27 joerg Exp $");
#endif /* not lint */
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#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 <i_value> L_IMM
%token <s_value> L_STRING
%type <lz_value> src
%type <i_value> 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));
}
__dead 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, "%s", argv[0]);
break;
default:
usage();
}
if (mkdb)
do_mkdb(in);
else if (mkpv)
do_mkpv(in);
else {
yyin = in;
yyparse();
}
return (0);
}