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