1 /* $NetBSD: main.c,v 1.6 2010/12/25 23:43:30 christos Exp $ */ 2 /* Id: main.c,v 1.30 2010/11/24 15:13:39 tom Exp */ 3 4 #include "defs.h" 5 6 #include <sys/cdefs.h> 7 __RCSID("$NetBSD: main.c,v 1.6 2010/12/25 23:43:30 christos Exp $"); 8 9 #include <signal.h> 10 #include <unistd.h> /* for _exit() */ 11 12 13 char dflag; 14 char gflag; 15 char lflag; 16 static char oflag; 17 char rflag; 18 char tflag; 19 char vflag; 20 21 const char *symbol_prefix; 22 const char *myname = "yacc"; 23 24 int lineno; 25 int outline; 26 27 static char empty_string[] = ""; 28 static char default_file_prefix[] = "y"; 29 static int explicit_file_name; 30 31 static char *file_prefix = default_file_prefix; 32 33 char *code_file_name; 34 char *input_file_name = empty_string; 35 static char *defines_file_name; 36 static char *graph_file_name; 37 static char *output_file_name; 38 static char *verbose_file_name; 39 40 FILE *action_file; /* a temp file, used to save actions associated */ 41 /* with rules until the parser is written */ 42 FILE *code_file; /* y.code.c (used when the -r option is specified) */ 43 FILE *defines_file; /* y.tab.h */ 44 FILE *input_file; /* the input file */ 45 FILE *output_file; /* y.tab.c */ 46 FILE *text_file; /* a temp file, used to save text until all */ 47 /* symbols have been defined */ 48 FILE *union_file; /* a temp file, used to save the union */ 49 /* definition until all symbol have been */ 50 /* defined */ 51 FILE *verbose_file; /* y.output */ 52 FILE *graph_file; /* y.dot */ 53 54 int nitems; 55 int nrules; 56 int nsyms; 57 int ntokens; 58 int nvars; 59 60 Value_t start_symbol; 61 char **symbol_name; 62 char **symbol_pname; 63 Value_t *symbol_value; 64 short *symbol_prec; 65 char *symbol_assoc; 66 67 int pure_parser; 68 int exit_code; 69 70 Value_t *ritem; 71 Value_t *rlhs; 72 Value_t *rrhs; 73 Value_t *rprec; 74 Assoc_t *rassoc; 75 Value_t **derives; 76 char *nullable; 77 78 /* 79 * Since fclose() is called via the signal handler, it might die. Don't loop 80 * if there is a problem closing a file. 81 */ 82 #define DO_CLOSE(fp) \ 83 if (fp != 0) { \ 84 FILE *use = fp; \ 85 fp = 0; \ 86 fclose(use); \ 87 } 88 89 static int got_intr = 0; 90 91 void 92 done(int k) 93 { 94 DO_CLOSE(input_file); 95 DO_CLOSE(output_file); 96 97 DO_CLOSE(action_file); 98 DO_CLOSE(defines_file); 99 DO_CLOSE(graph_file); 100 DO_CLOSE(text_file); 101 DO_CLOSE(union_file); 102 DO_CLOSE(verbose_file); 103 104 if (got_intr) 105 _exit(EXIT_FAILURE); 106 107 #ifdef NO_LEAKS 108 if (rflag) 109 DO_FREE(code_file_name); 110 111 if (dflag) 112 DO_FREE(defines_file_name); 113 114 if (oflag) 115 DO_FREE(output_file_name); 116 117 if (vflag) 118 DO_FREE(verbose_file_name); 119 120 if (gflag) 121 DO_FREE(graph_file_name); 122 123 lr0_leaks(); 124 lalr_leaks(); 125 mkpar_leaks(); 126 output_leaks(); 127 reader_leaks(); 128 #endif 129 130 if (rflag) 131 DO_CLOSE(code_file); 132 133 exit(k); 134 } 135 136 static void 137 onintr(int sig GCC_UNUSED) 138 { 139 got_intr = 1; 140 done(EXIT_FAILURE); 141 } 142 143 static void 144 set_signals(void) 145 { 146 #ifdef SIGINT 147 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 148 signal(SIGINT, onintr); 149 #endif 150 #ifdef SIGTERM 151 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 152 signal(SIGTERM, onintr); 153 #endif 154 #ifdef SIGHUP 155 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 156 signal(SIGHUP, onintr); 157 #endif 158 } 159 160 static void 161 usage(void) 162 { 163 static const char *msg[] = 164 { 165 "" 166 ,"Options:" 167 ," -b file_prefix set filename prefix (default \"y.\")" 168 ," -d write definitions (y.tab.h)" 169 ," -g write a graphical description" 170 ," -l suppress #line directives" 171 ," -o output_file (default \"y.tab.c\")" 172 ," -p symbol_prefix set symbol prefix (default \"yy\")" 173 ," -P create a reentrant parser, e.g., \"%pure-parser\"" 174 ," -r produce separate code and table files (y.code.c)" 175 ," -t add debugging support" 176 ," -v write description (y.output)" 177 ," -V show version information and exit" 178 }; 179 unsigned n; 180 181 fflush(stdout); 182 fprintf(stderr, "Usage: %s [options] filename\n", myname); 183 for (n = 0; n < sizeof(msg) / sizeof(msg[0]); ++n) 184 fprintf(stderr, "%s\n", msg[n]); 185 186 exit(1); 187 } 188 189 static void 190 setflag(int ch) 191 { 192 switch (ch) 193 { 194 case 'd': 195 dflag = 1; 196 break; 197 198 case 'g': 199 gflag = 1; 200 break; 201 202 case 'l': 203 lflag = 1; 204 break; 205 206 case 'P': 207 pure_parser = 1; 208 break; 209 210 case 'r': 211 rflag = 1; 212 break; 213 214 case 't': 215 tflag = 1; 216 break; 217 218 case 'v': 219 vflag = 1; 220 break; 221 222 case 'V': 223 printf("%s - %s\n", myname, VERSION); 224 exit(EXIT_SUCCESS); 225 226 case 'y': 227 /* noop for bison compatibility. byacc is already designed to be posix 228 * yacc compatible. */ 229 break; 230 231 default: 232 usage(); 233 } 234 } 235 236 static void 237 getargs(int argc, char *argv[]) 238 { 239 int i; 240 char *s; 241 int ch; 242 243 if (argc > 0) 244 myname = argv[0]; 245 246 for (i = 1; i < argc; ++i) 247 { 248 s = argv[i]; 249 if (*s != '-') 250 break; 251 switch (ch = *++s) 252 { 253 case '\0': 254 input_file = stdin; 255 if (i + 1 < argc) 256 usage(); 257 return; 258 259 case '-': 260 ++i; 261 goto no_more_options; 262 263 case 'b': 264 if (*++s) 265 file_prefix = s; 266 else if (++i < argc) 267 file_prefix = argv[i]; 268 else 269 usage(); 270 continue; 271 272 case 'o': 273 if (*++s) 274 output_file_name = s; 275 else if (++i < argc) 276 output_file_name = argv[i]; 277 else 278 usage(); 279 explicit_file_name = 1; 280 continue; 281 282 case 'p': 283 if (*++s) 284 symbol_prefix = s; 285 else if (++i < argc) 286 symbol_prefix = argv[i]; 287 else 288 usage(); 289 continue; 290 291 default: 292 setflag(ch); 293 break; 294 } 295 296 for (;;) 297 { 298 switch (ch = *++s) 299 { 300 case '\0': 301 goto end_of_option; 302 303 default: 304 setflag(ch); 305 break; 306 } 307 } 308 end_of_option:; 309 } 310 311 no_more_options:; 312 if (i + 1 != argc) 313 usage(); 314 input_file_name = argv[i]; 315 } 316 317 char * 318 allocate(size_t n) 319 { 320 char *p; 321 322 p = NULL; 323 if (n) 324 { 325 p = CALLOC(1, n); 326 NO_SPACE(p); 327 } 328 return (p); 329 } 330 331 #define CREATE_FILE_NAME(dest, suffix) \ 332 dest = MALLOC(len + strlen(suffix) + 1); \ 333 NO_SPACE(dest); \ 334 strcpy(dest, file_prefix); \ 335 strcpy(dest + len, suffix) 336 337 static void 338 create_file_names(void) 339 { 340 size_t len; 341 const char *defines_suffix; 342 char *prefix; 343 344 prefix = NULL; 345 defines_suffix = DEFINES_SUFFIX; 346 347 /* compute the file_prefix from the user provided output_file_name */ 348 if (output_file_name != 0) 349 { 350 if (!(prefix = strstr(output_file_name, ".tab.c")) 351 && (prefix = strstr(output_file_name, ".c"))) 352 defines_suffix = ".h"; 353 } 354 355 if (prefix != NULL) 356 { 357 len = (size_t) (prefix - output_file_name); 358 file_prefix = MALLOC(len + 1); 359 NO_SPACE(file_prefix); 360 strncpy(file_prefix, output_file_name, len)[len] = 0; 361 } 362 else 363 len = strlen(file_prefix); 364 365 /* if "-o filename" was not given */ 366 if (output_file_name == 0) 367 { 368 oflag = 1; 369 CREATE_FILE_NAME(output_file_name, OUTPUT_SUFFIX); 370 } 371 372 if (rflag) 373 { 374 CREATE_FILE_NAME(code_file_name, CODE_SUFFIX); 375 } 376 else 377 code_file_name = output_file_name; 378 379 if (dflag) 380 { 381 if (explicit_file_name) 382 { 383 char *suffix; 384 defines_file_name = strdup(output_file_name); 385 if (defines_file_name == 0) 386 no_space(); 387 /* does the output_file_name have a known suffix */ 388 suffix = strrchr(output_file_name, '.'); 389 if (suffix != 0 && 390 (!strcmp(suffix, ".c") || /* good, old-fashioned C */ 391 !strcmp(suffix, ".C") || /* C++, or C on Windows */ 392 !strcmp(suffix, ".cc") || /* C++ */ 393 !strcmp(suffix, ".cxx") || /* C++ */ 394 !strcmp(suffix, ".cpp"))) /* C++ (Windows) */ 395 { 396 strncpy(defines_file_name, output_file_name, 397 suffix - output_file_name + 1); 398 defines_file_name[suffix - output_file_name + 1] = 'h'; 399 defines_file_name[suffix - output_file_name + 2] = 0; 400 } else { 401 fprintf(stderr,"%s: suffix of output file name %s" 402 " not recognized, no -d file generated.\n", 403 myname, output_file_name); 404 dflag = 0; 405 free(defines_file_name); 406 defines_file_name = 0; 407 } 408 } else { 409 CREATE_FILE_NAME(defines_file_name, defines_suffix); 410 } 411 } 412 413 if (vflag) 414 { 415 CREATE_FILE_NAME(verbose_file_name, VERBOSE_SUFFIX); 416 } 417 418 if (gflag) 419 { 420 CREATE_FILE_NAME(graph_file_name, GRAPH_SUFFIX); 421 } 422 423 if (prefix != NULL) 424 { 425 FREE(file_prefix); 426 } 427 } 428 429 static void 430 open_files(void) 431 { 432 create_file_names(); 433 434 if (input_file == 0) 435 { 436 input_file = fopen(input_file_name, "r"); 437 if (input_file == 0) 438 open_error(input_file_name); 439 } 440 441 action_file = tmpfile(); 442 if (action_file == 0) 443 open_error("action_file"); 444 445 text_file = tmpfile(); 446 if (text_file == 0) 447 open_error("text_file"); 448 449 if (vflag) 450 { 451 verbose_file = fopen(verbose_file_name, "w"); 452 if (verbose_file == 0) 453 open_error(verbose_file_name); 454 } 455 456 if (gflag) 457 { 458 graph_file = fopen(graph_file_name, "w"); 459 if (graph_file == 0) 460 open_error(graph_file_name); 461 fprintf(graph_file, "digraph %s {\n", file_prefix); 462 fprintf(graph_file, "\tedge [fontsize=10];\n"); 463 fprintf(graph_file, "\tnode [shape=box,fontsize=10];\n"); 464 fprintf(graph_file, "\torientation=landscape;\n"); 465 fprintf(graph_file, "\trankdir=LR;\n"); 466 fprintf(graph_file, "\t/*\n"); 467 fprintf(graph_file, "\tmargin=0.2;\n"); 468 fprintf(graph_file, "\tpage=\"8.27,11.69\"; // for A4 printing\n"); 469 fprintf(graph_file, "\tratio=auto;\n"); 470 fprintf(graph_file, "\t*/\n"); 471 } 472 473 if (dflag) 474 { 475 defines_file = fopen(defines_file_name, "w"); 476 if (defines_file == 0) 477 open_error(defines_file_name); 478 union_file = tmpfile(); 479 if (union_file == 0) 480 open_error("union_file"); 481 } 482 483 output_file = fopen(output_file_name, "w"); 484 if (output_file == 0) 485 open_error(output_file_name); 486 487 if (rflag) 488 { 489 code_file = fopen(code_file_name, "w"); 490 if (code_file == 0) 491 open_error(code_file_name); 492 } 493 else 494 code_file = output_file; 495 } 496 497 int 498 main(int argc, char *argv[]) 499 { 500 SRexpect = -1; 501 RRexpect = -1; 502 exit_code = EXIT_SUCCESS; 503 504 set_signals(); 505 getargs(argc, argv); 506 open_files(); 507 reader(); 508 lr0(); 509 lalr(); 510 make_parser(); 511 graph(); 512 finalize_closure(); 513 verbose(); 514 output(); 515 done(exit_code); 516 /*NOTREACHED */ 517 } 518