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