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