1 /* $Id: main.c,v 1.56 2016/03/25 00:16:28 Jung-uk.Kim Exp $ */ 2 3 #include <signal.h> 4 #ifndef _WIN32 5 #include <unistd.h> /* for _exit() */ 6 #else 7 #include <stdlib.h> /* for _exit() */ 8 #endif 9 10 #include "defs.h" 11 12 #ifdef HAVE_MKSTEMP 13 # define USE_MKSTEMP 1 14 #elif defined(HAVE_FCNTL_H) 15 # define USE_MKSTEMP 1 16 # include <fcntl.h> /* for open(), O_EXCL, etc. */ 17 #else 18 # define USE_MKSTEMP 0 19 #endif 20 21 #if USE_MKSTEMP 22 #include <sys/types.h> 23 #include <sys/stat.h> 24 25 typedef struct _my_tmpfiles 26 { 27 struct _my_tmpfiles *next; 28 char *name; 29 } 30 MY_TMPFILES; 31 32 static MY_TMPFILES *my_tmpfiles; 33 #endif /* USE_MKSTEMP */ 34 35 char dflag; 36 char gflag; 37 char iflag; 38 char lflag; 39 static char oflag; 40 char rflag; 41 char sflag; 42 char tflag; 43 char vflag; 44 45 const char *symbol_prefix; 46 const char *myname = "yacc"; 47 48 int lineno; 49 int outline; 50 51 static char empty_string[] = ""; 52 static char default_file_prefix[] = "y"; 53 54 static char *file_prefix = default_file_prefix; 55 56 char *code_file_name; 57 char *input_file_name = empty_string; 58 char *defines_file_name; 59 char *externs_file_name; 60 61 static char *graph_file_name; 62 static char *output_file_name; 63 static char *verbose_file_name; 64 65 FILE *action_file; /* a temp file, used to save actions associated */ 66 /* with rules until the parser is written */ 67 FILE *code_file; /* y.code.c (used when the -r option is specified) */ 68 FILE *defines_file; /* y.tab.h */ 69 FILE *externs_file; /* y.tab.i */ 70 FILE *input_file; /* the input file */ 71 FILE *output_file; /* y.tab.c */ 72 FILE *text_file; /* a temp file, used to save text until all */ 73 /* symbols have been defined */ 74 FILE *union_file; /* a temp file, used to save the union */ 75 /* definition until all symbol have been */ 76 /* defined */ 77 FILE *verbose_file; /* y.output */ 78 FILE *graph_file; /* y.dot */ 79 80 Value_t nitems; 81 Value_t nrules; 82 Value_t nsyms; 83 Value_t ntokens; 84 Value_t nvars; 85 86 Value_t start_symbol; 87 char **symbol_name; 88 char **symbol_pname; 89 Value_t *symbol_value; 90 Value_t *symbol_prec; 91 char *symbol_assoc; 92 93 int pure_parser; 94 int token_table; 95 96 #if defined(YYBTYACC) 97 Value_t *symbol_pval; 98 char **symbol_destructor; 99 char **symbol_type_tag; 100 int locations = 0; /* default to no position processing */ 101 int backtrack = 0; /* default is no backtracking */ 102 #endif 103 104 int exit_code; 105 106 Value_t *ritem; 107 Value_t *rlhs; 108 Value_t *rrhs; 109 Value_t *rprec; 110 Assoc_t *rassoc; 111 Value_t **derives; 112 char *nullable; 113 114 /* 115 * Since fclose() is called via the signal handler, it might die. Don't loop 116 * if there is a problem closing a file. 117 */ 118 #define DO_CLOSE(fp) \ 119 if (fp != 0) { \ 120 FILE *use = fp; \ 121 fp = 0; \ 122 fclose(use); \ 123 } 124 125 static int got_intr = 0; 126 127 void 128 done(int k) 129 { 130 DO_CLOSE(input_file); 131 DO_CLOSE(output_file); 132 if (iflag) 133 DO_CLOSE(externs_file); 134 if (rflag) 135 DO_CLOSE(code_file); 136 137 DO_CLOSE(action_file); 138 DO_CLOSE(defines_file); 139 DO_CLOSE(graph_file); 140 DO_CLOSE(text_file); 141 DO_CLOSE(union_file); 142 DO_CLOSE(verbose_file); 143 144 if (got_intr) 145 _exit(EXIT_FAILURE); 146 147 #ifdef NO_LEAKS 148 if (rflag) 149 DO_FREE(code_file_name); 150 151 if (dflag) 152 DO_FREE(defines_file_name); 153 154 if (iflag) 155 DO_FREE(externs_file_name); 156 157 if (oflag) 158 DO_FREE(output_file_name); 159 160 if (vflag) 161 DO_FREE(verbose_file_name); 162 163 if (gflag) 164 DO_FREE(graph_file_name); 165 166 lr0_leaks(); 167 lalr_leaks(); 168 mkpar_leaks(); 169 mstring_leaks(); 170 output_leaks(); 171 reader_leaks(); 172 #endif 173 174 exit(k); 175 } 176 177 static void 178 onintr(int sig GCC_UNUSED) 179 { 180 got_intr = 1; 181 done(EXIT_FAILURE); 182 } 183 184 static void 185 set_signals(void) 186 { 187 #ifdef SIGINT 188 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 189 signal(SIGINT, onintr); 190 #endif 191 #ifdef SIGTERM 192 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 193 signal(SIGTERM, onintr); 194 #endif 195 #ifdef SIGHUP 196 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 197 signal(SIGHUP, onintr); 198 #endif 199 } 200 201 static void 202 usage(void) 203 { 204 static const char *msg[] = 205 { 206 "" 207 ,"Options:" 208 ," -b file_prefix set filename prefix (default \"y.\")" 209 ," -B create a backtracking parser" 210 ," -d write definitions (" DEFINES_SUFFIX ")" 211 ," -i write interface (y.tab.i)" 212 ," -g write a graphical description" 213 ," -l suppress #line directives" 214 ," -L enable position processing, e.g., \"%locations\"" 215 ," -o output_file (default \"" OUTPUT_SUFFIX "\")" 216 ," -p symbol_prefix set symbol prefix (default \"yy\")" 217 ," -P create a reentrant parser, e.g., \"%pure-parser\"" 218 ," -r produce separate code and table files (y.code.c)" 219 ," -s suppress #define's for quoted names in %token lines" 220 ," -t add debugging support" 221 ," -v write description (y.output)" 222 ," -V show version information and exit" 223 }; 224 unsigned n; 225 226 fflush(stdout); 227 fprintf(stderr, "Usage: %s [options] filename\n", myname); 228 for (n = 0; n < sizeof(msg) / sizeof(msg[0]); ++n) 229 fprintf(stderr, "%s\n", msg[n]); 230 231 exit(1); 232 } 233 234 static void 235 setflag(int ch) 236 { 237 switch (ch) 238 { 239 case 'B': 240 #if defined(YYBTYACC) 241 backtrack = 1; 242 #else 243 unsupported_flag_warning("-B", "reconfigure with --enable-btyacc"); 244 #endif 245 break; 246 247 case 'd': 248 dflag = 1; 249 break; 250 251 case 'g': 252 gflag = 1; 253 break; 254 255 case 'i': 256 iflag = 1; 257 break; 258 259 case 'l': 260 lflag = 1; 261 break; 262 263 case 'L': 264 #if defined(YYBTYACC) 265 locations = 1; 266 #else 267 unsupported_flag_warning("-B", "reconfigure with --enable-btyacc"); 268 #endif 269 break; 270 271 case 'P': 272 pure_parser = 1; 273 break; 274 275 case 'r': 276 rflag = 1; 277 break; 278 279 case 's': 280 sflag = 1; 281 break; 282 283 case 't': 284 tflag = 1; 285 break; 286 287 case 'v': 288 vflag = 1; 289 break; 290 291 case 'V': 292 printf("%s - %s\n", myname, VERSION); 293 exit(EXIT_SUCCESS); 294 295 case 'y': 296 /* noop for bison compatibility. byacc is already designed to be posix 297 * yacc compatible. */ 298 break; 299 300 default: 301 usage(); 302 } 303 } 304 305 static void 306 getargs(int argc, char *argv[]) 307 { 308 int i; 309 char *s; 310 int ch; 311 312 if (argc > 0) 313 myname = argv[0]; 314 315 for (i = 1; i < argc; ++i) 316 { 317 s = argv[i]; 318 if (*s != '-') 319 break; 320 switch (ch = *++s) 321 { 322 case '\0': 323 input_file = stdin; 324 if (i + 1 < argc) 325 usage(); 326 return; 327 328 case '-': 329 ++i; 330 goto no_more_options; 331 332 case 'b': 333 if (*++s) 334 file_prefix = s; 335 else if (++i < argc) 336 file_prefix = argv[i]; 337 else 338 usage(); 339 continue; 340 341 case 'o': 342 if (*++s) 343 output_file_name = s; 344 else if (++i < argc) 345 output_file_name = argv[i]; 346 else 347 usage(); 348 continue; 349 350 case 'p': 351 if (*++s) 352 symbol_prefix = s; 353 else if (++i < argc) 354 symbol_prefix = argv[i]; 355 else 356 usage(); 357 continue; 358 359 default: 360 setflag(ch); 361 break; 362 } 363 364 for (;;) 365 { 366 switch (ch = *++s) 367 { 368 case '\0': 369 goto end_of_option; 370 371 default: 372 setflag(ch); 373 break; 374 } 375 } 376 end_of_option:; 377 } 378 379 no_more_options:; 380 if (i + 1 != argc) 381 usage(); 382 input_file_name = argv[i]; 383 } 384 385 void * 386 allocate(size_t n) 387 { 388 void *p; 389 390 p = NULL; 391 if (n) 392 { 393 p = CALLOC(1, n); 394 NO_SPACE(p); 395 } 396 return (p); 397 } 398 399 #define CREATE_FILE_NAME(dest, suffix) \ 400 dest = alloc_file_name(len, suffix) 401 402 static char * 403 alloc_file_name(size_t len, const char *suffix) 404 { 405 char *result = TMALLOC(char, len + strlen(suffix) + 1); 406 if (result == 0) 407 no_space(); 408 strcpy(result, file_prefix); 409 strcpy(result + len, suffix); 410 return result; 411 } 412 413 static char * 414 find_suffix(char *name, const char *suffix) 415 { 416 size_t len = strlen(name); 417 size_t slen = strlen(suffix); 418 if (len >= slen) 419 { 420 name += len - slen; 421 if (strcmp(name, suffix) == 0) 422 return name; 423 } 424 return NULL; 425 } 426 427 static void 428 create_file_names(void) 429 { 430 size_t len; 431 const char *defines_suffix; 432 const char *externs_suffix; 433 char *suffix; 434 435 suffix = NULL; 436 defines_suffix = DEFINES_SUFFIX; 437 externs_suffix = EXTERNS_SUFFIX; 438 439 /* compute the file_prefix from the user provided output_file_name */ 440 if (output_file_name != 0) 441 { 442 if (!(suffix = find_suffix(output_file_name, OUTPUT_SUFFIX)) 443 && (suffix = find_suffix(output_file_name, ".c"))) 444 { 445 defines_suffix = ".h"; 446 externs_suffix = ".i"; 447 } 448 } 449 450 if (suffix != NULL) 451 { 452 len = (size_t) (suffix - output_file_name); 453 file_prefix = TMALLOC(char, len + 1); 454 NO_SPACE(file_prefix); 455 strncpy(file_prefix, output_file_name, len)[len] = 0; 456 } 457 else 458 len = strlen(file_prefix); 459 460 /* if "-o filename" was not given */ 461 if (output_file_name == 0) 462 { 463 oflag = 1; 464 CREATE_FILE_NAME(output_file_name, OUTPUT_SUFFIX); 465 } 466 467 if (rflag) 468 { 469 CREATE_FILE_NAME(code_file_name, CODE_SUFFIX); 470 } 471 else 472 code_file_name = output_file_name; 473 474 if (dflag) 475 { 476 CREATE_FILE_NAME(defines_file_name, defines_suffix); 477 } 478 479 if (iflag) 480 { 481 CREATE_FILE_NAME(externs_file_name, externs_suffix); 482 } 483 484 if (vflag) 485 { 486 CREATE_FILE_NAME(verbose_file_name, VERBOSE_SUFFIX); 487 } 488 489 if (gflag) 490 { 491 CREATE_FILE_NAME(graph_file_name, GRAPH_SUFFIX); 492 } 493 494 if (suffix != NULL) 495 { 496 FREE(file_prefix); 497 } 498 } 499 500 #if USE_MKSTEMP 501 static void 502 close_tmpfiles(void) 503 { 504 while (my_tmpfiles != 0) 505 { 506 MY_TMPFILES *next = my_tmpfiles->next; 507 508 (void)chmod(my_tmpfiles->name, 0644); 509 (void)unlink(my_tmpfiles->name); 510 511 free(my_tmpfiles->name); 512 free(my_tmpfiles); 513 514 my_tmpfiles = next; 515 } 516 } 517 518 #ifndef HAVE_MKSTEMP 519 static int 520 my_mkstemp(char *temp) 521 { 522 int fd; 523 char *dname; 524 char *fname; 525 char *name; 526 527 /* 528 * Split-up to use tempnam, rather than tmpnam; the latter (like 529 * mkstemp) is unusable on Windows. 530 */ 531 if ((fname = strrchr(temp, '/')) != 0) 532 { 533 dname = strdup(temp); 534 dname[++fname - temp] = '\0'; 535 } 536 else 537 { 538 dname = 0; 539 fname = temp; 540 } 541 if ((name = tempnam(dname, fname)) != 0) 542 { 543 fd = open(name, O_CREAT | O_EXCL | O_RDWR); 544 strcpy(temp, name); 545 } 546 else 547 { 548 fd = -1; 549 } 550 551 if (dname != 0) 552 free(dname); 553 554 return fd; 555 } 556 #define mkstemp(s) my_mkstemp(s) 557 #endif 558 559 #endif 560 561 /* 562 * tmpfile() should be adequate, except that it may require special privileges 563 * to use, e.g., MinGW and Windows 7 where it tries to use the root directory. 564 */ 565 static FILE * 566 open_tmpfile(const char *label) 567 { 568 #define MY_FMT "%s/%.*sXXXXXX" 569 FILE *result; 570 #if USE_MKSTEMP 571 int fd; 572 const char *tmpdir; 573 char *name; 574 const char *mark; 575 576 if ((tmpdir = getenv("TMPDIR")) == 0 || access(tmpdir, W_OK) != 0) 577 { 578 #ifdef P_tmpdir 579 tmpdir = P_tmpdir; 580 #else 581 tmpdir = "/tmp"; 582 #endif 583 if (access(tmpdir, W_OK) != 0) 584 tmpdir = "."; 585 } 586 587 /* The size of the format is guaranteed to be longer than the result from 588 * printing empty strings with it; this calculation accounts for the 589 * string-lengths as well. 590 */ 591 name = malloc(strlen(tmpdir) + sizeof(MY_FMT) + strlen(label)); 592 593 result = 0; 594 if (name != 0) 595 { 596 mode_t save_umask = umask(0177); 597 598 if ((mark = strrchr(label, '_')) == 0) 599 mark = label + strlen(label); 600 601 sprintf(name, MY_FMT, tmpdir, (int)(mark - label), label); 602 fd = mkstemp(name); 603 if (fd >= 0) 604 { 605 result = fdopen(fd, "w+"); 606 if (result != 0) 607 { 608 MY_TMPFILES *item; 609 610 if (my_tmpfiles == 0) 611 { 612 atexit(close_tmpfiles); 613 } 614 615 item = NEW(MY_TMPFILES); 616 NO_SPACE(item); 617 618 item->name = name; 619 NO_SPACE(item->name); 620 621 item->next = my_tmpfiles; 622 my_tmpfiles = item; 623 } 624 } 625 (void)umask(save_umask); 626 } 627 #else 628 result = tmpfile(); 629 #endif 630 631 if (result == 0) 632 open_error(label); 633 return result; 634 #undef MY_FMT 635 } 636 637 static void 638 open_files(void) 639 { 640 create_file_names(); 641 642 if (input_file == 0) 643 { 644 input_file = fopen(input_file_name, "r"); 645 if (input_file == 0) 646 open_error(input_file_name); 647 } 648 649 action_file = open_tmpfile("action_file"); 650 text_file = open_tmpfile("text_file"); 651 652 if (vflag) 653 { 654 verbose_file = fopen(verbose_file_name, "w"); 655 if (verbose_file == 0) 656 open_error(verbose_file_name); 657 } 658 659 if (gflag) 660 { 661 graph_file = fopen(graph_file_name, "w"); 662 if (graph_file == 0) 663 open_error(graph_file_name); 664 fprintf(graph_file, "digraph %s {\n", file_prefix); 665 fprintf(graph_file, "\tedge [fontsize=10];\n"); 666 fprintf(graph_file, "\tnode [shape=box,fontsize=10];\n"); 667 fprintf(graph_file, "\torientation=landscape;\n"); 668 fprintf(graph_file, "\trankdir=LR;\n"); 669 fprintf(graph_file, "\t/*\n"); 670 fprintf(graph_file, "\tmargin=0.2;\n"); 671 fprintf(graph_file, "\tpage=\"8.27,11.69\"; // for A4 printing\n"); 672 fprintf(graph_file, "\tratio=auto;\n"); 673 fprintf(graph_file, "\t*/\n"); 674 } 675 676 if (dflag) 677 { 678 defines_file = fopen(defines_file_name, "w"); 679 if (defines_file == 0) 680 open_error(defines_file_name); 681 union_file = open_tmpfile("union_file"); 682 } 683 684 if (iflag) 685 { 686 externs_file = fopen(externs_file_name, "w"); 687 if (externs_file == 0) 688 open_error(externs_file_name); 689 } 690 691 output_file = fopen(output_file_name, "w"); 692 if (output_file == 0) 693 open_error(output_file_name); 694 695 if (rflag) 696 { 697 code_file = fopen(code_file_name, "w"); 698 if (code_file == 0) 699 open_error(code_file_name); 700 } 701 else 702 code_file = output_file; 703 } 704 705 int 706 main(int argc, char *argv[]) 707 { 708 SRexpect = -1; 709 RRexpect = -1; 710 exit_code = EXIT_SUCCESS; 711 712 set_signals(); 713 getargs(argc, argv); 714 open_files(); 715 reader(); 716 lr0(); 717 lalr(); 718 make_parser(); 719 graph(); 720 finalize_closure(); 721 verbose(); 722 output(); 723 done(exit_code); 724 /*NOTREACHED */ 725 } 726