1 /* $NetBSD: main.c,v 1.23 2026/05/03 15:29:19 christos Exp $ */ 2 3 #include "defs.h" 4 5 #include <sys/cdefs.h> 6 __RCSID("$NetBSD: main.c,v 1.23 2026/05/03 15:29:19 christos Exp $"); 7 /* Id: main.c,v 1.81 2025/10/08 00:23:02 tom Exp */ 8 9 #include <signal.h> 10 #if !defined(_WIN32) || defined(__MINGW32__) 11 #include <unistd.h> /* for _exit() */ 12 #else 13 #include <stdlib.h> /* for _exit() */ 14 #endif 15 16 17 #ifdef HAVE_MKSTEMP 18 # define USE_MKSTEMP 1 19 #elif defined(HAVE_FCNTL_H) 20 # define USE_MKSTEMP 1 21 # include <fcntl.h> /* for open(), O_EXCL, etc. */ 22 #else 23 # define USE_MKSTEMP 0 24 #endif 25 26 #ifndef W_OK 27 #define W_OK 02 28 #endif 29 30 #if USE_MKSTEMP 31 #include <sys/types.h> 32 #include <sys/stat.h> 33 34 typedef struct _my_tmpfiles 35 { 36 struct _my_tmpfiles *next; 37 char *name; 38 } 39 MY_TMPFILES; 40 41 static MY_TMPFILES *my_tmpfiles; 42 #endif /* USE_MKSTEMP */ 43 44 char dflag; 45 char dflag2; 46 char gflag; 47 char iflag; 48 char lflag; 49 static char oflag; 50 char rflag; 51 char sflag; 52 char tflag; 53 char vflag; 54 55 const char *symbol_prefix; 56 const char *myname = "yacc"; 57 58 int lineno; 59 int outline; 60 61 static char default_file_prefix[] = "y"; 62 static int explicit_file_name; 63 64 static char *file_prefix = default_file_prefix; 65 66 char *code_file_name; 67 char *input_file_name; 68 size_t input_file_name_len = 0; 69 char *defines_file_name; 70 char *externs_file_name; 71 72 static char *graph_file_name; 73 static char *output_file_name; 74 static char *verbose_file_name; 75 76 FILE *action_file; /* a temp file, used to save actions associated */ 77 /* with rules until the parser is written */ 78 FILE *code_file; /* y.code.c (used when the -r option is specified) */ 79 FILE *defines_file; /* y.tab.h */ 80 FILE *externs_file; /* y.tab.i */ 81 FILE *input_file; /* the input file */ 82 FILE *output_file; /* y.tab.c */ 83 FILE *text_file; /* a temp file, used to save text until all */ 84 /* symbols have been defined */ 85 FILE *union_file; /* a temp file, used to save the union */ 86 /* definition until all symbol have been */ 87 /* defined */ 88 FILE *verbose_file; /* y.output */ 89 FILE *graph_file; /* y.dot */ 90 91 Value_t nitems; 92 Value_t nrules; 93 Value_t nsyms; 94 Value_t ntokens; 95 Value_t nvars; 96 97 Value_t start_symbol; 98 char **symbol_name; 99 char **symbol_pname; 100 Value_t *symbol_value; 101 Value_t *symbol_prec; 102 char *symbol_assoc; 103 104 int pure_parser; 105 int token_table; 106 int error_verbose; 107 108 #if defined(YYBTYACC) 109 Value_t *symbol_pval; 110 char **symbol_destructor; 111 char **symbol_type_tag; 112 int locations = 0; /* default to no position processing */ 113 int backtrack = 0; /* default is no backtracking */ 114 char *initial_action = NULL; 115 #endif 116 117 int exit_code; 118 119 Value_t *ritem; 120 Value_t *rlhs; 121 Value_t *rrhs; 122 Value_t *rprec; 123 Assoc_t *rassoc; 124 Value_t **derives; 125 char *nullable; 126 127 /* 128 * Since fclose() is called via the signal handler, it might die. Don't loop 129 * if there is a problem closing a file. 130 */ 131 #define DO_CLOSE(fp) \ 132 if (fp != NULL) { \ 133 FILE *use = fp; \ 134 fp = NULL; \ 135 fclose(use); \ 136 } 137 138 static int got_intr = 0; 139 140 void 141 done(int k) 142 { 143 DO_CLOSE(input_file); 144 DO_CLOSE(output_file); 145 if (iflag) 146 DO_CLOSE(externs_file); 147 if (rflag) 148 DO_CLOSE(code_file); 149 150 DO_CLOSE(action_file); 151 DO_CLOSE(defines_file); 152 DO_CLOSE(graph_file); 153 DO_CLOSE(text_file); 154 DO_CLOSE(union_file); 155 DO_CLOSE(verbose_file); 156 157 if (got_intr) 158 _exit(EXIT_FAILURE); 159 160 #ifdef NO_LEAKS 161 DO_FREE(input_file_name); 162 163 if (rflag) 164 DO_FREE(code_file_name); 165 166 if (dflag && !dflag2) 167 DO_FREE(defines_file_name); 168 169 if (iflag) 170 DO_FREE(externs_file_name); 171 172 if (oflag) 173 DO_FREE(output_file_name); 174 175 if (vflag) 176 DO_FREE(verbose_file_name); 177 178 if (gflag) 179 DO_FREE(graph_file_name); 180 181 lr0_leaks(); 182 lalr_leaks(); 183 mkpar_leaks(); 184 mstring_leaks(); 185 output_leaks(); 186 reader_leaks(); 187 #endif 188 189 exit(k); 190 } 191 192 static void 193 onintr(int sig GCC_UNUSED) 194 { 195 got_intr = 1; 196 done(EXIT_FAILURE); 197 } 198 199 static void 200 set_signals(void) 201 { 202 #ifdef SIGINT 203 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 204 signal(SIGINT, onintr); 205 #endif 206 #ifdef SIGTERM 207 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 208 signal(SIGTERM, onintr); 209 #endif 210 #ifdef SIGHUP 211 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 212 signal(SIGHUP, onintr); 213 #endif 214 } 215 216 #define SIZEOF(v) (sizeof(v) / sizeof((v)[0])) 217 218 /* 219 * Long options are provided only as a compatibility aid for scripters. 220 */ 221 /* *INDENT-OFF* */ 222 static const struct { 223 const char long_opt[16]; 224 const char yacc_arg; 225 const char yacc_opt; 226 } long_opts[] = { 227 { "defines", 1, 'H' }, 228 { "file-prefix", 1, 'b' }, 229 { "graph", 0, 'g' }, 230 { "help", 0, 'h' }, 231 { "name-prefix", 1, 'p' }, 232 { "no-lines", 0, 'l' }, 233 { "output", 1, 'o' }, 234 { "version", 0, 'V' } 235 }; 236 /* *INDENT-ON* */ 237 238 /* 239 * Usage-message is designed for 80 columns, with some unknowns. Account for 240 * those in the maximum width so that the usage message uses no relocatable 241 * pointers. 242 */ 243 #define USAGE_COLS (80 + sizeof(DEFINES_SUFFIX) + sizeof(OUTPUT_SUFFIX)) 244 245 static void 246 usage(void) 247 { 248 /* *INDENT-OFF* */ 249 static const char msg[][USAGE_COLS] = 250 { 251 { " -b file_prefix set filename prefix (default \"y.\")" }, 252 { " -B create a backtracking parser" }, 253 { " -d write definitions (" DEFINES_SUFFIX ")" }, 254 { " -h print this help-message" }, 255 { " -H defines_file write definitions to defines_file" }, 256 { " -i write interface (y.tab.i)" }, 257 { " -g write a graphical description" }, 258 { " -l suppress #line directives" }, 259 { " -L enable position processing, e.g., \"%locations\"" }, 260 { " -o output_file (default \"" OUTPUT_SUFFIX "\")" }, 261 { " -p symbol_prefix set symbol prefix (default \"yy\")" }, 262 { " -P create a reentrant parser, e.g., \"%pure-parser\"" }, 263 { " -r produce separate code and table files (y.code.c)" }, 264 { " -s suppress #define's for quoted names in %token lines" }, 265 { " -t add debugging support" }, 266 { " -v write description (y.output)" }, 267 { " -V show version information and exit" }, 268 }; 269 /* *INDENT-ON* */ 270 unsigned n; 271 272 fflush(stdout); 273 fprintf(stderr, "Usage: %s [options] filename\n", myname); 274 275 fprintf(stderr, "\nOptions:\n"); 276 for (n = 0; n < SIZEOF(msg); ++n) 277 { 278 fprintf(stderr, "%s\n", msg[n]); 279 } 280 281 fprintf(stderr, "\nLong options:\n"); 282 for (n = 0; n < SIZEOF(long_opts); ++n) 283 { 284 fprintf(stderr, " --%-20s-%c\n", 285 long_opts[n].long_opt, 286 long_opts[n].yacc_opt); 287 } 288 289 exit(EXIT_FAILURE); 290 } 291 292 static void 293 invalid_option(const char *option) 294 { 295 fprintf(stderr, "invalid option: %s\n", option); 296 usage(); 297 } 298 299 static void 300 setflag(int ch) 301 { 302 switch (ch) 303 { 304 case 'B': 305 #if defined(YYBTYACC) 306 backtrack = 1; 307 #else 308 unsupported_flag_warning("-B", "reconfigure with --enable-btyacc"); 309 #endif 310 break; 311 312 case 'd': 313 dflag = 1; 314 dflag2 = 0; 315 break; 316 317 case 'g': 318 gflag = 1; 319 break; 320 321 case 'i': 322 iflag = 1; 323 break; 324 325 case 'l': 326 lflag = 1; 327 break; 328 329 case 'L': 330 #if defined(YYBTYACC) 331 locations = 1; 332 #else 333 unsupported_flag_warning("-L", "reconfigure with --enable-btyacc"); 334 #endif 335 break; 336 337 case 'P': 338 pure_parser = 1; 339 break; 340 341 case 'r': 342 rflag = 1; 343 break; 344 345 case 's': 346 sflag = 1; 347 break; 348 349 case 't': 350 tflag = 1; 351 break; 352 353 case 'v': 354 vflag = 1; 355 break; 356 357 case 'V': 358 printf("%s - %s\n", myname, VERSION); 359 exit(EXIT_SUCCESS); 360 361 case 'y': 362 /* noop for bison compatibility. byacc is already designed to be posix 363 * yacc compatible. */ 364 break; 365 366 default: 367 usage(); 368 } 369 } 370 371 static void 372 getargs(int argc, char *argv[]) 373 { 374 int i; 375 #ifdef HAVE_GETOPT 376 int ch; 377 #endif 378 379 /* 380 * Map bison's long-options into yacc short options. 381 */ 382 for (i = 1; i < argc; ++i) 383 { 384 char *a = argv[i]; 385 386 if (!strncmp(a, "--", 2)) 387 { 388 const char *eqls; 389 size_t lc; 390 size_t len; 391 392 if ((len = strlen(a)) == 2) 393 break; 394 395 if ((eqls = strchr(a, '=')) != NULL) 396 { 397 len = (size_t)(eqls - a); 398 if (len == 0 || eqls[1] == '\0') 399 invalid_option(a); 400 } 401 402 for (lc = 0; lc < SIZEOF(long_opts); ++lc) 403 { 404 if (!strncmp(long_opts[lc].long_opt, a + 2, len - 2)) 405 { 406 if (eqls != NULL && !long_opts[lc].yacc_arg) 407 invalid_option(a); 408 *a++ = '-'; 409 *a++ = long_opts[lc].yacc_opt; 410 *a = '\0'; 411 if (eqls) 412 { 413 while ((*a++ = *++eqls) != '\0') /* empty */ ; 414 } 415 break; 416 } 417 } 418 if (!strncmp(a, "--", 2)) 419 invalid_option(a); 420 } 421 } 422 423 #ifdef HAVE_GETOPT 424 if (argc > 0) 425 myname = argv[0]; 426 427 while ((ch = getopt(argc, argv, "Bb:dghH:ilLo:Pp:rstVvy")) != -1) 428 { 429 switch (ch) 430 { 431 case 'b': 432 file_prefix = optarg; 433 break; 434 case 'h': 435 usage(); 436 break; 437 case 'H': 438 dflag = dflag2 = 1; 439 defines_file_name = optarg; 440 break; 441 case 'o': 442 output_file_name = optarg; 443 explicit_file_name = 1; 444 break; 445 case 'p': 446 symbol_prefix = optarg; 447 break; 448 default: 449 setflag(ch); 450 break; 451 } 452 } 453 if ((i = optind) < argc) 454 { 455 /* getopt handles "--" specially, while we handle "-" specially */ 456 if (!strcmp(argv[i], "-")) 457 { 458 if ((i + 1) < argc) 459 usage(); 460 input_file = stdin; 461 return; 462 } 463 } 464 #else 465 char *s; 466 int ch; 467 468 if (argc > 0) 469 myname = argv[0]; 470 471 for (i = 1; i < argc; ++i) 472 { 473 s = argv[i]; 474 if (*s != '-') 475 break; 476 switch (ch = *++s) 477 { 478 case '\0': 479 input_file = stdin; 480 if (i + 1 < argc) 481 usage(); 482 return; 483 484 case '-': 485 ++i; 486 goto no_more_options; 487 488 case 'b': 489 if (*++s) 490 file_prefix = s; 491 else if (++i < argc) 492 file_prefix = argv[i]; 493 else 494 usage(); 495 continue; 496 497 case 'H': 498 dflag = dflag2 = 1; 499 if (*++s) 500 defines_file_name = s; 501 else if (++i < argc) 502 defines_file_name = argv[i]; 503 else 504 usage(); 505 continue; 506 507 case 'o': 508 if (*++s) 509 output_file_name = s; 510 else if (++i < argc) 511 output_file_name = argv[i]; 512 else 513 usage(); 514 explicit_file_name = 1; 515 continue; 516 517 case 'p': 518 if (*++s) 519 symbol_prefix = s; 520 else if (++i < argc) 521 symbol_prefix = argv[i]; 522 else 523 usage(); 524 continue; 525 526 default: 527 setflag(ch); 528 break; 529 } 530 531 for (;;) 532 { 533 switch (ch = *++s) 534 { 535 case '\0': 536 goto end_of_option; 537 538 default: 539 setflag(ch); 540 break; 541 } 542 } 543 end_of_option:; 544 } 545 546 no_more_options: 547 548 #endif /* HAVE_GETOPT */ 549 if (i + 1 != argc) 550 usage(); 551 input_file_name_len = strlen(argv[i]); 552 input_file_name = TMALLOC(char, input_file_name_len + 1); 553 NO_SPACE(input_file_name); 554 strcpy(input_file_name, argv[i]); 555 } 556 557 void * 558 allocate(size_t n) 559 { 560 void *p; 561 562 p = NULL; 563 if (n) 564 { 565 p = CALLOC(1, n); 566 NO_SPACE(p); 567 } 568 return (p); 569 } 570 571 #define CREATE_FILE_NAME(dest, suffix) \ 572 dest = alloc_file_name(len, suffix) 573 574 static char * 575 alloc_file_name(size_t len, const char *suffix) 576 { 577 char *result = TMALLOC(char, len + strlen(suffix) + 1); 578 if (result == NULL) 579 on_error(); 580 strcpy(result, file_prefix); 581 strcpy(result + len, suffix); 582 return result; 583 } 584 585 static char * 586 find_suffix(char *name, const char *suffix) 587 { 588 size_t len = strlen(name); 589 size_t slen = strlen(suffix); 590 if (len >= slen) 591 { 592 name += len - slen; 593 if (strcmp(name, suffix) == 0) 594 return name; 595 } 596 return NULL; 597 } 598 599 static void 600 create_file_names(void) 601 { 602 size_t len; 603 const char *defines_suffix; 604 const char *externs_suffix; 605 const char *suffix; 606 607 suffix = NULL; 608 defines_suffix = DEFINES_SUFFIX; 609 externs_suffix = EXTERNS_SUFFIX; 610 611 /* compute the file_prefix from the user provided output_file_name */ 612 if (output_file_name != NULL) 613 { 614 if (!(suffix = find_suffix(output_file_name, OUTPUT_SUFFIX)) 615 && (suffix = find_suffix(output_file_name, ".c"))) 616 { 617 defines_suffix = ".h"; 618 externs_suffix = ".i"; 619 } 620 } 621 622 if (suffix != NULL) 623 { 624 len = (size_t)(suffix - output_file_name); 625 file_prefix = TMALLOC(char, len + 1); 626 NO_SPACE(file_prefix); 627 strncpy(file_prefix, output_file_name, len)[len] = 0; 628 } 629 else 630 len = strlen(file_prefix); 631 632 /* if "-o filename" was not given */ 633 if (output_file_name == NULL) 634 { 635 oflag = 1; 636 CREATE_FILE_NAME(output_file_name, OUTPUT_SUFFIX); 637 } 638 639 if (rflag) 640 { 641 CREATE_FILE_NAME(code_file_name, CODE_SUFFIX); 642 } 643 else 644 code_file_name = output_file_name; 645 646 if (dflag && !dflag2) 647 { 648 if (explicit_file_name) 649 { 650 const char *xsuffix; 651 defines_file_name = strdup(output_file_name); 652 if (defines_file_name == NULL) 653 on_error(); 654 /* does the output_file_name have a known suffix */ 655 xsuffix = strrchr(output_file_name, '.'); 656 if (xsuffix != NULL && 657 (!strcmp(xsuffix, ".c") || /* good, old-fashioned C */ 658 !strcmp(xsuffix, ".C") || /* C++, or C on Windows */ 659 !strcmp(xsuffix, ".cc") || /* C++ */ 660 !strcmp(xsuffix, ".cxx") || /* C++ */ 661 !strcmp(xsuffix, ".cpp"))) /* C++ (Windows) */ 662 { 663 strncpy(defines_file_name, output_file_name, 664 (size_t)(xsuffix - output_file_name + 1)); 665 defines_file_name[xsuffix - output_file_name + 1] = 'h'; 666 defines_file_name[xsuffix - output_file_name + 2] = 0; 667 } 668 else 669 { 670 fprintf(stderr, "%s: suffix of output file name %s" 671 " not recognized, no -d file generated.\n", 672 myname, output_file_name); 673 dflag = 0; 674 free(defines_file_name); 675 defines_file_name = NULL; 676 } 677 } 678 else 679 { 680 CREATE_FILE_NAME(defines_file_name, defines_suffix); 681 } 682 } 683 684 if (iflag) 685 { 686 CREATE_FILE_NAME(externs_file_name, externs_suffix); 687 } 688 689 if (vflag) 690 { 691 CREATE_FILE_NAME(verbose_file_name, VERBOSE_SUFFIX); 692 } 693 694 if (gflag) 695 { 696 CREATE_FILE_NAME(graph_file_name, GRAPH_SUFFIX); 697 } 698 699 if (suffix != NULL) 700 { 701 FREE(file_prefix); 702 } 703 } 704 705 #if USE_MKSTEMP 706 static void 707 close_tmpfiles(void) 708 { 709 while (my_tmpfiles != NULL) 710 { 711 MY_TMPFILES *next = my_tmpfiles->next; 712 713 (void)chmod(my_tmpfiles->name, 0644); 714 (void)unlink(my_tmpfiles->name); 715 716 free(my_tmpfiles->name); 717 free(my_tmpfiles); 718 719 my_tmpfiles = next; 720 } 721 } 722 723 #ifndef HAVE_MKSTEMP 724 static int 725 my_mkstemp(char *temp) 726 { 727 int fd; 728 char *dname; 729 char *fname; 730 char *name; 731 732 /* 733 * Split-up to use tempnam, rather than tmpnam; the latter (like 734 * mkstemp) is unusable on Windows. 735 */ 736 if ((fname = strrchr(temp, '/')) != 0) 737 { 738 dname = strdup(temp); 739 dname[++fname - temp] = '\0'; 740 } 741 else 742 { 743 dname = 0; 744 fname = temp; 745 } 746 if ((name = tempnam(dname, fname)) != 0) 747 { 748 fd = open(name, O_CREAT | O_EXCL | O_RDWR); 749 strcpy(temp, name); 750 } 751 else 752 { 753 fd = -1; 754 } 755 756 if (dname != 0) 757 free(dname); 758 759 return fd; 760 } 761 #define mkstemp(s) my_mkstemp(s) 762 #endif 763 764 #endif 765 766 /* 767 * tmpfile() should be adequate, except that it may require special privileges 768 * to use, e.g., MinGW and Windows 7 where it tries to use the root directory. 769 */ 770 static FILE * 771 open_tmpfile(const char *label) 772 { 773 #define MY_FMT "%s/%.*sXXXXXX" 774 FILE *result; 775 #if USE_MKSTEMP 776 const char *tmpdir; 777 char *name; 778 779 if (((tmpdir = getenv("TMPDIR")) == NULL || access(tmpdir, W_OK) != 0) && 780 ((tmpdir = getenv("TEMP")) == NULL || access(tmpdir, W_OK) != 0)) 781 { 782 #ifdef P_tmpdir 783 tmpdir = P_tmpdir; 784 #else 785 tmpdir = "/tmp"; 786 #endif 787 if (access(tmpdir, W_OK) != 0) 788 tmpdir = "."; 789 } 790 791 /* The size of the format is guaranteed to be longer than the result from 792 * printing empty strings with it; this calculation accounts for the 793 * string-lengths as well. 794 */ 795 name = malloc(strlen(tmpdir) + sizeof(MY_FMT) + strlen(label)); 796 797 result = NULL; 798 if (name != NULL) 799 { 800 int fd; 801 const char *mark; 802 803 mode_t save_umask = umask(0177); 804 805 if ((mark = strrchr(label, '_')) == NULL) 806 mark = label + strlen(label); 807 808 sprintf(name, MY_FMT, tmpdir, (int)(mark - label), label); 809 fd = mkstemp(name); 810 if (fd >= 0 811 && (result = fdopen(fd, "w+")) != NULL) 812 { 813 MY_TMPFILES *item; 814 815 if (my_tmpfiles == NULL) 816 { 817 atexit(close_tmpfiles); 818 } 819 820 item = NEW(MY_TMPFILES); 821 NO_SPACE(item); 822 823 item->name = name; 824 NO_SPACE(item->name); 825 826 item->next = my_tmpfiles; 827 my_tmpfiles = item; 828 } 829 else 830 { 831 FREE(name); 832 } 833 (void)umask(save_umask); 834 } 835 #else 836 result = tmpfile(); 837 #endif 838 839 if (result == NULL) 840 open_error(label); 841 return result; 842 #undef MY_FMT 843 } 844 845 static void 846 open_files(void) 847 { 848 create_file_names(); 849 850 if (input_file == NULL) 851 { 852 input_file = fopen(input_file_name, "r"); 853 if (input_file == NULL) 854 open_error(input_file_name); 855 } 856 857 action_file = open_tmpfile("action_file"); 858 text_file = open_tmpfile("text_file"); 859 860 if (vflag) 861 { 862 verbose_file = fopen(verbose_file_name, "w"); 863 if (verbose_file == NULL) 864 open_error(verbose_file_name); 865 } 866 867 if (gflag) 868 { 869 graph_file = fopen(graph_file_name, "w"); 870 if (graph_file == NULL) 871 open_error(graph_file_name); 872 fprintf(graph_file, "digraph %s {\n", file_prefix); 873 fprintf(graph_file, "\tedge [fontsize=10];\n"); 874 fprintf(graph_file, "\tnode [shape=box,fontsize=10];\n"); 875 fprintf(graph_file, "\torientation=landscape;\n"); 876 fprintf(graph_file, "\trankdir=LR;\n"); 877 fprintf(graph_file, "\t/*\n"); 878 fprintf(graph_file, "\tmargin=0.2;\n"); 879 fprintf(graph_file, "\tpage=\"8.27,11.69\"; // for A4 printing\n"); 880 fprintf(graph_file, "\tratio=auto;\n"); 881 fprintf(graph_file, "\t*/\n"); 882 } 883 884 if (dflag || dflag2) 885 { 886 defines_file = fopen(defines_file_name, "w"); 887 if (defines_file == NULL) 888 open_error(defines_file_name); 889 union_file = open_tmpfile("union_file"); 890 } 891 892 if (iflag) 893 { 894 externs_file = fopen(externs_file_name, "w"); 895 if (externs_file == NULL) 896 open_error(externs_file_name); 897 } 898 899 output_file = fopen(output_file_name, "w"); 900 if (output_file == NULL) 901 open_error(output_file_name); 902 903 if (rflag) 904 { 905 code_file = fopen(code_file_name, "w"); 906 if (code_file == NULL) 907 open_error(code_file_name); 908 } 909 else 910 code_file = output_file; 911 } 912 913 int 914 main(int argc, char *argv[]) 915 { 916 SRexpect = -1; 917 RRexpect = -1; 918 exit_code = EXIT_SUCCESS; 919 920 set_signals(); 921 getargs(argc, argv); 922 open_files(); 923 reader(); 924 lr0(); 925 lalr(); 926 make_parser(); 927 graph(); 928 finalize_closure(); 929 verbose(); 930 output(); 931 done(exit_code); 932 /*NOTREACHED */ 933 } 934