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