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