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