1 /* Parse command line arguments for Bison. 2 3 Copyright (C) 1984, 1986, 1989, 1992, 2000-2012 Free Software 4 Foundation, Inc. 5 6 This file is part of Bison, the GNU Compiler Compiler. 7 8 This program is free software: you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation, either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 20 21 #include <config.h> 22 #include "system.h" 23 #include "output.h" 24 25 #include <argmatch.h> 26 #include <c-strcase.h> 27 #include <configmake.h> 28 #include <error.h> 29 30 /* Hack to get <getopt.h> to declare getopt with a prototype. */ 31 #if lint && ! defined __GNU_LIBRARY__ 32 # define __GNU_LIBRARY__ 33 # define HACK_FOR___GNU_LIBRARY___PROTOTYPE 1 34 #endif 35 36 #include <getopt.h> 37 38 #ifdef HACK_FOR___GNU_LIBRARY___PROTOTYPE 39 # undef __GNU_LIBRARY__ 40 # undef HACK_FOR___GNU_LIBRARY___PROTOTYPE 41 #endif 42 43 #include <progname.h> 44 45 #include "complain.h" 46 #include "files.h" 47 #include "getargs.h" 48 #include "muscle-tab.h" 49 #include "quote.h" 50 #include "uniqstr.h" 51 52 bool debug; 53 bool defines_flag; 54 bool graph_flag; 55 bool xml_flag; 56 bool locations_flag; 57 bool no_lines_flag; 58 bool token_table_flag; 59 bool yacc_flag; /* for -y */ 60 61 bool error_verbose = false; 62 63 bool nondeterministic_parser = false; 64 bool glr_parser = false; 65 66 int feature_flag = feature_none; 67 int report_flag = report_none; 68 int trace_flag = trace_none; 69 int warnings_flag = warnings_conflicts_sr | warnings_conflicts_rr 70 | warnings_other; 71 72 static struct bison_language const valid_languages[] = { 73 { "c", "c-skel.m4", ".c", ".h", true }, 74 { "c++", "c++-skel.m4", ".cc", ".hh", true }, 75 { "java", "java-skel.m4", ".java", ".java", false }, 76 { "", "", "", "", false } 77 }; 78 79 int skeleton_prio = default_prio; 80 const char *skeleton = NULL; 81 int language_prio = default_prio; 82 struct bison_language const *language = &valid_languages[0]; 83 const char *include = NULL; 84 85 86 /** Decode an option's set of keys. 87 * 88 * \param option option being decoded. 89 * \param keys array of valid subarguments. 90 * \param values array of corresponding (int) values. 91 * \param all the all value. 92 * \param flags the flags to update 93 * \param args comma separated list of effective subarguments to decode. 94 * If 0, then activate all the flags. 95 * 96 * If VALUE != 0 then KEY sets flags and no-KEY clears them. 97 * If VALUE == 0 then KEY clears all flags from \c all and no-KEY sets all 98 * flags from \c all. Thus no-none = all and no-all = none. 99 */ 100 static void 101 flags_argmatch (const char *option, 102 const char * const keys[], const int values[], 103 int all, int *flags, char *args) 104 { 105 if (args) 106 { 107 args = strtok (args, ","); 108 while (args) 109 { 110 int no = strncmp (args, "no-", 3) == 0 ? 3 : 0; 111 int value = XARGMATCH (option, args + no, keys, values); 112 if (value == 0) 113 { 114 if (no) 115 *flags |= all; 116 else 117 *flags &= ~all; 118 } 119 else 120 { 121 if (no) 122 *flags &= ~value; 123 else 124 *flags |= value; 125 } 126 args = strtok (NULL, ","); 127 } 128 } 129 else 130 *flags |= all; 131 } 132 133 /** Decode a set of sub arguments. 134 * 135 * \param FlagName the flag familly to update. 136 * \param Args the effective sub arguments to decode. 137 * 138 * \arg FlagName_args the list of keys. 139 * \arg FlagName_types the list of values. 140 * \arg FlagName_all the all value. 141 * \arg FlagName_flag the flag to update. 142 */ 143 #define FLAGS_ARGMATCH(FlagName, Args) \ 144 flags_argmatch ("--" #FlagName, FlagName ## _args, FlagName ## _types, \ 145 FlagName ## _all, &FlagName ## _flag, Args) 146 147 148 /*----------------------. 149 | --report's handling. | 150 `----------------------*/ 151 152 static const char * const report_args[] = 153 { 154 /* In a series of synonyms, present the most meaningful first, so 155 that argmatch_valid be more readable. */ 156 "none", 157 "state", "states", 158 "itemset", "itemsets", 159 "lookahead", "lookaheads", "look-ahead", 160 "solved", 161 "all", 162 0 163 }; 164 165 static const int report_types[] = 166 { 167 report_none, 168 report_states, report_states, 169 report_states | report_itemsets, report_states | report_itemsets, 170 report_states | report_lookahead_tokens, 171 report_states | report_lookahead_tokens, 172 report_states | report_lookahead_tokens, 173 report_states | report_solved_conflicts, 174 report_all 175 }; 176 177 ARGMATCH_VERIFY (report_args, report_types); 178 179 180 /*---------------------. 181 | --trace's handling. | 182 `---------------------*/ 183 184 static const char * const trace_args[] = 185 { 186 /* In a series of synonyms, present the most meaningful first, so 187 that argmatch_valid be more readable. */ 188 "none - no traces", 189 "scan - grammar scanner traces", 190 "parse - grammar parser traces", 191 "automaton - construction of the automaton", 192 "bitsets - use of bitsets", 193 "grammar - reading, reducing the grammar", 194 "resource - memory consumption (where available)", 195 "sets - grammar sets: firsts, nullable etc.", 196 "muscles - m4 definitions passed to the skeleton", 197 "tools - m4 invocation", 198 "m4 - m4 traces", 199 "skeleton - skeleton postprocessing", 200 "time - time consumption", 201 "ielr - IELR conversion", 202 "all - all of the above", 203 0 204 }; 205 206 static const int trace_types[] = 207 { 208 trace_none, 209 trace_scan, 210 trace_parse, 211 trace_automaton, 212 trace_bitsets, 213 trace_grammar, 214 trace_resource, 215 trace_sets, 216 trace_muscles, 217 trace_tools, 218 trace_m4, 219 trace_skeleton, 220 trace_time, 221 trace_ielr, 222 trace_all 223 }; 224 225 ARGMATCH_VERIFY (trace_args, trace_types); 226 227 228 /*------------------------. 229 | --warnings's handling. | 230 `------------------------*/ 231 232 static const char * const warnings_args[] = 233 { 234 /* In a series of synonyms, present the most meaningful first, so 235 that argmatch_valid be more readable. */ 236 "none - no warnings", 237 "midrule-values - unset or unused midrule values", 238 "yacc - incompatibilities with POSIX Yacc", 239 "conflicts-sr - S/R conflicts", 240 "conflicts-rr - R/R conflicts", 241 "other - all other warnings", 242 "all - all of the above", 243 "error - warnings are errors", 244 0 245 }; 246 247 static const int warnings_types[] = 248 { 249 warnings_none, 250 warnings_midrule_values, 251 warnings_yacc, 252 warnings_conflicts_sr, 253 warnings_conflicts_rr, 254 warnings_other, 255 warnings_all, 256 warnings_error 257 }; 258 259 ARGMATCH_VERIFY (warnings_args, warnings_types); 260 261 /*-----------------------. 262 | --feature's handling. | 263 `-----------------------*/ 264 265 static const char * const feature_args[] = 266 { 267 "none", 268 "caret", "diagnostics-show-caret", 269 "all", 270 0 271 }; 272 273 static const int feature_types[] = 274 { 275 feature_none, 276 feature_caret, feature_caret, 277 feature_all 278 }; 279 280 ARGMATCH_VERIFY (feature_args, feature_types); 281 282 /*-------------------------------------------. 283 | Display the help message and exit STATUS. | 284 `-------------------------------------------*/ 285 286 static void usage (int) ATTRIBUTE_NORETURN; 287 288 static void 289 usage (int status) 290 { 291 if (status != 0) 292 fprintf (stderr, _("Try `%s --help' for more information.\n"), 293 program_name); 294 else 295 { 296 /* For ../build-aux/cross-options.pl to work, use the format: 297 ^ -S, --long[=ARGS] (whitespace) 298 A --long option is required. 299 Otherwise, add exceptions to ../build-aux/cross-options.pl. */ 300 301 printf (_("Usage: %s [OPTION]... FILE\n"), program_name); 302 fputs (_("\ 303 Generate a deterministic LR or generalized LR (GLR) parser employing\n\ 304 LALR(1), IELR(1), or canonical LR(1) parser tables. IELR(1) and\n\ 305 canonical LR(1) support is experimental.\n\ 306 \n\ 307 "), stdout); 308 309 fputs (_("\ 310 Mandatory arguments to long options are mandatory for short options too.\n\ 311 "), stdout); 312 fputs (_("\ 313 The same is true for optional arguments.\n\ 314 "), stdout); 315 316 fputs (_("\ 317 \n\ 318 Operation modes:\n\ 319 -h, --help display this help and exit\n\ 320 -V, --version output version information and exit\n\ 321 --print-localedir output directory containing locale-dependent data\n\ 322 --print-datadir output directory containing skeletons and XSLT\n\ 323 -y, --yacc emulate POSIX Yacc\n\ 324 -W, --warnings[=CATEGORY] report the warnings falling in CATEGORY\n\ 325 -f, --feature[=FEATURE] activate miscellaneous features\n\ 326 \n\ 327 "), stdout); 328 329 fputs (_("\ 330 Parser:\n\ 331 -L, --language=LANGUAGE specify the output programming language\n\ 332 -S, --skeleton=FILE specify the skeleton to use\n\ 333 -t, --debug instrument the parser for debugging\n\ 334 --locations enable location support\n\ 335 -D, --define=NAME[=VALUE] similar to '%define NAME \"VALUE\"'\n\ 336 -F, --force-define=NAME[=VALUE] override '%define NAME \"VALUE\"'\n\ 337 -p, --name-prefix=PREFIX prepend PREFIX to the external symbols\n\ 338 deprecated by '-Dapi.prefix=PREFIX'\n\ 339 -l, --no-lines don't generate '#line' directives\n\ 340 -k, --token-table include a table of token names\n\ 341 "), stdout); 342 putc ('\n', stdout); 343 344 /* Keep -d and --defines separate so that ../build-aux/cross-options.pl 345 * won't assume that -d also takes an argument. */ 346 fputs (_("\ 347 Output:\n\ 348 --defines[=FILE] also produce a header file\n\ 349 -d likewise but cannot specify FILE (for POSIX Yacc)\n\ 350 -r, --report=THINGS also produce details on the automaton\n\ 351 --report-file=FILE write report to FILE\n\ 352 -v, --verbose same as `--report=state'\n\ 353 -b, --file-prefix=PREFIX specify a PREFIX for output files\n\ 354 -o, --output=FILE leave output to FILE\n\ 355 -g, --graph[=FILE] also output a graph of the automaton\n\ 356 -x, --xml[=FILE] also output an XML report of the automaton\n\ 357 (the XML schema is experimental)\n\ 358 "), stdout); 359 putc ('\n', stdout); 360 361 fputs (_("\ 362 Warning categories include:\n\ 363 `midrule-values' unset or unused midrule values\n\ 364 `yacc' incompatibilities with POSIX Yacc\n\ 365 `conflicts-sr' S/R conflicts (enabled by default)\n\ 366 `conflicts-rr' R/R conflicts (enabled by default)\n\ 367 `deprecated' obsolete constructs\n\ 368 `other' all other warnings (enabled by default)\n\ 369 `all' all the warnings\n\ 370 `no-CATEGORY' turn off warnings in CATEGORY\n\ 371 `none' turn off all the warnings\n\ 372 `error' treat warnings as errors\n\ 373 "), stdout); 374 putc ('\n', stdout); 375 376 fputs (_("\ 377 THINGS is a list of comma separated words that can include:\n\ 378 `state' describe the states\n\ 379 `itemset' complete the core item sets with their closure\n\ 380 `lookahead' explicitly associate lookahead tokens to items\n\ 381 `solved' describe shift/reduce conflicts solving\n\ 382 `all' include all the above information\n\ 383 `none' disable the report\n\ 384 "), stdout); 385 putc ('\n', stdout); 386 387 fputs (_("\ 388 FEATURE is a list of comma separated words that can include:\n\ 389 `caret' show errors with carets\n\ 390 `all' all of the above\n\ 391 `none' disable all of the above\n\ 392 "), stdout); 393 394 putc ('\n', stdout); 395 printf (_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT); 396 printf (_("%s home page: <%s>.\n"), PACKAGE_NAME, PACKAGE_URL); 397 fputs (_("General help using GNU software: " 398 "<http://www.gnu.org/gethelp/>.\n"), 399 stdout); 400 /* Don't output this redundant message for English locales. 401 Note we still output for 'C' so that it gets included in the 402 man page. */ 403 const char *lc_messages = setlocale (LC_MESSAGES, NULL); 404 if (lc_messages && strcmp (lc_messages, "en_")) 405 /* TRANSLATORS: Replace LANG_CODE in this URL with your language 406 code <http://translationproject.org/team/LANG_CODE.html> to 407 form one of the URLs at http://translationproject.org/team/. 408 Otherwise, replace the entire URL with your translation team's 409 email address. */ 410 fputs (_("Report translation bugs to " 411 "<http://translationproject.org/team/>.\n"), stdout); 412 fputs (_("For complete documentation, run: info bison.\n"), stdout); 413 } 414 415 exit (status); 416 } 417 418 419 /*------------------------------. 420 | Display the version message. | 421 `------------------------------*/ 422 423 static void 424 version (void) 425 { 426 /* Some efforts were made to ease the translators' task, please 427 continue. */ 428 printf (_("bison (GNU Bison) %s"), VERSION); 429 putc ('\n', stdout); 430 fputs (_("Written by Robert Corbett and Richard Stallman.\n"), stdout); 431 putc ('\n', stdout); 432 433 fprintf (stdout, 434 _("Copyright (C) %d Free Software Foundation, Inc.\n"), 435 PACKAGE_COPYRIGHT_YEAR); 436 437 fputs (_("\ 438 This is free software; see the source for copying conditions. There is NO\n\ 439 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ 440 "), 441 stdout); 442 } 443 444 445 /*-------------------------------------. 446 | --skeleton and --language handling. | 447 `--------------------------------------*/ 448 449 void 450 skeleton_arg (char const *arg, int prio, location loc) 451 { 452 if (prio < skeleton_prio) 453 { 454 skeleton_prio = prio; 455 skeleton = arg; 456 } 457 else if (prio == skeleton_prio) 458 complain_at (loc, _("multiple skeleton declarations are invalid")); 459 } 460 461 void 462 language_argmatch (char const *arg, int prio, location loc) 463 { 464 char const *msg; 465 466 if (prio < language_prio) 467 { 468 int i; 469 for (i = 0; valid_languages[i].language[0]; i++) 470 if (c_strcasecmp (arg, valid_languages[i].language) == 0) 471 { 472 language_prio = prio; 473 language = &valid_languages[i]; 474 return; 475 } 476 msg = _("%s: invalid language"); 477 } 478 else if (language_prio == prio) 479 msg = _("multiple language declarations are invalid"); 480 else 481 return; 482 483 complain_at (loc, msg, quotearg_colon (arg)); 484 } 485 486 /*----------------------. 487 | Process the options. | 488 `----------------------*/ 489 490 /* Shorts options. 491 Should be computed from long_options. */ 492 static char const short_options[] = 493 "D:" 494 "F:" 495 "L:" 496 "S:" 497 "T::" 498 "V" 499 "W::" 500 "b:" 501 "d" 502 "f::" 503 "e" 504 "g::" 505 "h" 506 "k" 507 "l" 508 "n" 509 "o:" 510 "p:" 511 "r:" 512 "t" 513 "v" 514 "x::" 515 "y" 516 ; 517 518 /* Values for long options that do not have single-letter equivalents. */ 519 enum 520 { 521 LOCATIONS_OPTION = CHAR_MAX + 1, 522 PRINT_LOCALEDIR_OPTION, 523 PRINT_DATADIR_OPTION, 524 REPORT_FILE_OPTION 525 }; 526 527 static struct option const long_options[] = 528 { 529 /* Operation modes. */ 530 { "help", no_argument, 0, 'h' }, 531 { "version", no_argument, 0, 'V' }, 532 { "print-localedir", no_argument, 0, PRINT_LOCALEDIR_OPTION }, 533 { "print-datadir", no_argument, 0, PRINT_DATADIR_OPTION }, 534 { "warnings", optional_argument, 0, 'W' }, 535 536 /* Parser. */ 537 { "name-prefix", required_argument, 0, 'p' }, 538 { "include", required_argument, 0, 'I' }, 539 540 /* Output. */ 541 { "file-prefix", required_argument, 0, 'b' }, 542 { "output", required_argument, 0, 'o' }, 543 { "output-file", required_argument, 0, 'o' }, 544 { "graph", optional_argument, 0, 'g' }, 545 { "xml", optional_argument, 0, 'x' }, 546 { "report", required_argument, 0, 'r' }, 547 { "report-file", required_argument, 0, REPORT_FILE_OPTION }, 548 { "verbose", no_argument, 0, 'v' }, 549 550 /* Hidden. */ 551 { "trace", optional_argument, 0, 'T' }, 552 553 /* Output. */ 554 { "defines", optional_argument, 0, 'd' }, 555 { "feature", optional_argument, 0, 'f' }, 556 557 /* Operation modes. */ 558 { "fixed-output-files", no_argument, 0, 'y' }, 559 { "yacc", no_argument, 0, 'y' }, 560 561 /* Parser. */ 562 { "debug", no_argument, 0, 't' }, 563 { "define", required_argument, 0, 'D' }, 564 { "force-define", required_argument, 0, 'F' }, 565 { "locations", no_argument, 0, LOCATIONS_OPTION }, 566 { "no-lines", no_argument, 0, 'l' }, 567 { "raw", no_argument, 0, 0 }, 568 { "skeleton", required_argument, 0, 'S' }, 569 { "language", required_argument, 0, 'L' }, 570 { "token-table", no_argument, 0, 'k' }, 571 572 {0, 0, 0, 0} 573 }; 574 575 /* Under DOS, there is no difference on the case. This can be 576 troublesome when looking for `.tab' etc. */ 577 #ifdef MSDOS 578 # define AS_FILE_NAME(File) (strlwr (File), (File)) 579 #else 580 # define AS_FILE_NAME(File) (File) 581 #endif 582 583 /* Build a location for the current command line argument. */ 584 static 585 location 586 command_line_location (void) 587 { 588 location res; 589 /* "<command line>" is used in GCC's messages about -D. */ 590 boundary_set (&res.start, uniqstr_new ("<command line>"), optind - 1, -1); 591 res.end = res.start; 592 return res; 593 } 594 595 596 void 597 getargs (int argc, char *argv[]) 598 { 599 int c; 600 601 while ((c = getopt_long (argc, argv, short_options, long_options, NULL)) 602 != -1) 603 switch (c) 604 { 605 /* ASCII Sorting for short options (i.e., upper case then 606 lower case), and then long-only options. */ 607 608 case 0: 609 /* Certain long options cause getopt_long to return 0. */ 610 break; 611 612 case 'D': /* -DNAME[=VALUE]. */ 613 case 'F': /* -FNAME[=VALUE]. */ 614 { 615 char* name = optarg; 616 char* value = mbschr (optarg, '='); 617 if (value) 618 *value++ = 0; 619 muscle_percent_define_insert (name, command_line_location (), 620 value ? value : "", 621 c == 'D' ? MUSCLE_PERCENT_DEFINE_D 622 : MUSCLE_PERCENT_DEFINE_F); 623 } 624 break; 625 626 case 'I': 627 include = AS_FILE_NAME (optarg); 628 break; 629 630 case 'L': 631 language_argmatch (optarg, command_line_prio, 632 command_line_location ()); 633 break; 634 635 case 'S': 636 skeleton_arg (AS_FILE_NAME (optarg), command_line_prio, 637 command_line_location ()); 638 break; 639 640 case 'T': 641 FLAGS_ARGMATCH (trace, optarg); 642 break; 643 644 case 'V': 645 version (); 646 exit (EXIT_SUCCESS); 647 648 case 'f': 649 FLAGS_ARGMATCH (feature, optarg); 650 break; 651 652 case 'W': 653 FLAGS_ARGMATCH (warnings, optarg); 654 break; 655 656 case 'b': 657 spec_file_prefix = AS_FILE_NAME (optarg); 658 break; 659 660 case 'd': 661 /* Here, the -d and --defines options are differentiated. */ 662 defines_flag = true; 663 if (optarg) 664 { 665 free (spec_defines_file); 666 spec_defines_file = xstrdup (AS_FILE_NAME (optarg)); 667 } 668 break; 669 670 case 'g': 671 graph_flag = true; 672 if (optarg) 673 { 674 free (spec_graph_file); 675 spec_graph_file = xstrdup (AS_FILE_NAME (optarg)); 676 } 677 break; 678 679 case 'h': 680 usage (EXIT_SUCCESS); 681 682 case 'k': 683 token_table_flag = true; 684 break; 685 686 case 'l': 687 no_lines_flag = true; 688 break; 689 690 case 'o': 691 spec_outfile = AS_FILE_NAME (optarg); 692 break; 693 694 case 'p': 695 spec_name_prefix = optarg; 696 break; 697 698 case 'r': 699 FLAGS_ARGMATCH (report, optarg); 700 break; 701 702 case 't': 703 debug = true; 704 break; 705 706 case 'v': 707 report_flag |= report_states; 708 break; 709 710 case 'x': 711 xml_flag = true; 712 if (optarg) 713 { 714 free (spec_xml_file); 715 spec_xml_file = xstrdup (AS_FILE_NAME (optarg)); 716 } 717 break; 718 719 case 'y': 720 yacc_flag = true; 721 break; 722 723 case LOCATIONS_OPTION: 724 locations_flag = true; 725 break; 726 727 case PRINT_LOCALEDIR_OPTION: 728 printf ("%s\n", LOCALEDIR); 729 exit (EXIT_SUCCESS); 730 731 case PRINT_DATADIR_OPTION: 732 printf ("%s\n", compute_pkgdatadir ()); 733 exit (EXIT_SUCCESS); 734 735 case REPORT_FILE_OPTION: 736 free (spec_verbose_file); 737 spec_verbose_file = xstrdup (AS_FILE_NAME (optarg)); 738 break; 739 740 default: 741 usage (EXIT_FAILURE); 742 } 743 744 if (argc - optind != 1) 745 { 746 if (argc - optind < 1) 747 error (0, 0, _("%s: missing operand"), quotearg_colon (argv[argc - 1])); 748 else 749 error (0, 0, _("extra operand %s"), quote (argv[optind + 1])); 750 usage (EXIT_FAILURE); 751 } 752 753 current_file = grammar_file = uniqstr_new (argv[optind]); 754 MUSCLE_INSERT_C_STRING ("file_name", grammar_file); 755 } 756 757 void 758 tr (char *s, char from, char to) 759 { 760 for (; *s; s++) 761 if (*s == from) 762 *s = to; 763 } 764