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