(root)/
bison-3.8.2/
src/
getargs.c
       1  /* Parse command line arguments for Bison.
       2  
       3     Copyright (C) 1984, 1986, 1989, 1992, 2000-2015, 2018-2021 Free
       4     Software 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 <https://www.gnu.org/licenses/>.  */
      20  
      21  #include <config.h>
      22  #include "getargs.h"
      23  
      24  #include "system.h"
      25  
      26  #include <argmatch.h>
      27  #include <c-strcase.h>
      28  #include <configmake.h>
      29  #include <error.h>
      30  #include <getopt.h>
      31  #include <progname.h>
      32  #include <quote.h>
      33  #include <textstyle.h>
      34  
      35  #include "complain.h"
      36  #include "files.h"
      37  #include "muscle-tab.h"
      38  #include "output.h"
      39  #include "uniqstr.h"
      40  
      41  bool header_flag = false;
      42  bool graph_flag = false;
      43  bool html_flag = false;
      44  bool xml_flag = false;
      45  bool no_lines_flag = false;
      46  bool token_table_flag = false;
      47  location yacc_loc = EMPTY_LOCATION_INIT;
      48  bool update_flag = false; /* for -u */
      49  bool color_debug = false;
      50  
      51  bool nondeterministic_parser = false;
      52  bool glr_parser = false;
      53  
      54  int feature_flag = feature_caret;
      55  int report_flag = report_none;
      56  int trace_flag = trace_none;
      57  
      58  static struct bison_language const valid_languages[] = {
      59    /* lang,  skeleton,       ext,     hdr,     add_tab */
      60    { "c",    "c-skel.m4",    ".c",    ".h",    true },
      61    { "c++",  "c++-skel.m4",  ".cc",   ".hh",   true },
      62    { "d",    "d-skel.m4",    ".d",    ".d",    false },
      63    { "java", "java-skel.m4", ".java", ".java", false },
      64    { "", "", "", "", false }
      65  };
      66  
      67  int skeleton_prio = default_prio;
      68  const char *skeleton = NULL;
      69  int language_prio = default_prio;
      70  struct bison_language const *language = &valid_languages[0];
      71  
      72  typedef int* (xargmatch_fn) (const char *context, const char *arg);
      73  
      74  void
      75  set_yacc (location loc)
      76  {
      77    yacc_loc = loc;
      78    if (getenv ("POSIXLY_CORRECT"))
      79      muscle_percent_define_insert ("posix",
      80                                    loc,
      81                                    muscle_keyword, "",
      82                                    MUSCLE_PERCENT_DEFINE_D);
      83  }
      84  
      85  
      86  /** Decode an option's key.
      87   *
      88   *  \param opt        option being decoded.
      89   *  \param xargmatch  matching function.
      90   *  \param all        the value of the argument 'all'.
      91   *  \param flags      the flags to update
      92   *  \param arg        the subarguments to decode.
      93   *                    If null, then activate all the flags.
      94   *  \param no         length of the potential "no-" prefix.
      95   *                    Can be 0 or 3. If 3, negate the action of the subargument.
      96   *
      97   *  If VALUE != 0 then KEY sets flags and no-KEY clears them.
      98   *  If VALUE == 0 then KEY clears all flags from \c all and no-KEY sets all
      99   *  flags from \c all.  Thus no-none = all and no-all = none.
     100   */
     101  static void
     102  flag_argmatch (const char *opt, xargmatch_fn xargmatch,
     103                 int all, int *flags, char *arg, size_t no)
     104  {
     105    int value = *xargmatch (opt, arg + no);
     106  
     107    /* -rnone == -rno-all, and -rno-none == -rall.  */
     108    if (!value)
     109      {
     110        value = all;
     111        no = !no;
     112      }
     113  
     114    if (no)
     115      *flags &= ~value;
     116    else
     117      *flags |= value;
     118  }
     119  
     120  typedef void (usage_fn) (FILE *out);
     121  
     122  /** Decode an option's set of keys.
     123   *
     124   *  \param opt        option being decoded (e.g., --report).
     125   *  \param xargmatch  matching function.
     126   *  \param usage      function that implement --help for this option.
     127   *  \param all        the value of the argument 'all'.
     128   *  \param flags      the flags to update
     129   *  \param args       comma separated list of effective subarguments to decode.
     130   *                    If 0, then activate all the flags.
     131   */
     132  static void
     133  flags_argmatch (const char *opt,
     134                  xargmatch_fn xargmatch,
     135                  usage_fn usage,
     136                  int all, int *flags, char *args)
     137  {
     138    if (!args)
     139      *flags |= all;
     140    else if (STREQ (args, "help"))
     141      {
     142        usage (stdout);
     143        exit (EXIT_SUCCESS);
     144      }
     145    else
     146      for (args = strtok (args, ","); args; args = strtok (NULL, ","))
     147        {
     148          size_t no = STRPREFIX_LIT ("no-", args) ? 3 : 0;
     149          flag_argmatch (opt, xargmatch,
     150                         all, flags, args, no);
     151        }
     152  }
     153  
     154  
     155  /** Decode a set of sub arguments.
     156   *
     157   *  \param FlagName  the flag family to update.
     158   *  \param Args      the effective sub arguments to decode.
     159   *  \param All       the "all" value.
     160   *
     161   *  \arg FlagName_args   the list of keys.
     162   *  \arg FlagName_types  the list of values.
     163   *  \arg FlagName_flag   the flag to update.
     164   */
     165  #define FLAGS_ARGMATCH(FlagName, Args, All)                             \
     166    flags_argmatch ("--" #FlagName,                                       \
     167                    (xargmatch_fn*) argmatch_## FlagName ## _value,       \
     168                    argmatch_ ## FlagName ## _usage,                      \
     169                    All, &FlagName ## _flag, Args)
     170  
     171  /*---------------------.
     172  | --color's handling.  |
     173  `---------------------*/
     174  
     175  enum color
     176    {
     177      color_always,
     178      color_never,
     179      color_auto
     180    };
     181  
     182  ARGMATCH_DEFINE_GROUP (color, enum color)
     183  
     184  static const argmatch_color_doc argmatch_color_docs[] =
     185  {
     186    { "always",     N_("colorize the output") },
     187    { "never",      N_("don't colorize the output") },
     188    { "auto",       N_("colorize if the output device is a tty") },
     189    { NULL, NULL },
     190  };
     191  
     192  static const argmatch_color_arg argmatch_color_args[] =
     193  {
     194    { "always",   color_always },
     195    { "yes",      color_always },
     196    { "never",    color_never },
     197    { "no",       color_never },
     198    { "auto",     color_auto },
     199    { "tty",      color_auto },
     200    { NULL, color_always },
     201  };
     202  
     203  const argmatch_color_group_type argmatch_color_group =
     204  {
     205    argmatch_color_args,
     206    argmatch_color_docs,
     207    /* TRANSLATORS: Use the same translation for WHEN as in the
     208       --color=WHEN help message.  */
     209    N_("WHEN can be one of the following:"),
     210    NULL
     211  };
     212  
     213  
     214  /*----------------------.
     215  | --report's handling.  |
     216  `----------------------*/
     217  
     218  ARGMATCH_DEFINE_GROUP (report, enum report)
     219  
     220  static const argmatch_report_doc argmatch_report_docs[] =
     221  {
     222    { "states",          N_("describe the states") },
     223    { "itemsets",        N_("complete the core item sets with their closure") },
     224    { "lookaheads",      N_("explicitly associate lookahead tokens to items") },
     225    { "solved",          N_("describe shift/reduce conflicts solving") },
     226    { "counterexamples", N_("generate conflict counterexamples") },
     227    { "all",             N_("include all the above information") },
     228    { "none",            N_("disable the report") },
     229    { NULL, NULL },
     230  };
     231  
     232  static const argmatch_report_arg argmatch_report_args[] =
     233  {
     234    { "none",            report_none },
     235    { "states",          report_states },
     236    { "itemsets",        report_states | report_itemsets },
     237    { "lookaheads",      report_states | report_lookaheads },
     238    { "solved",          report_states | report_solved_conflicts },
     239    { "counterexamples", report_cex },
     240    { "cex",             report_cex },
     241    { "all",             report_all },
     242    { NULL, report_none },
     243  };
     244  
     245  const argmatch_report_group_type argmatch_report_group =
     246  {
     247    argmatch_report_args,
     248    argmatch_report_docs,
     249    /* TRANSLATORS: Use the same translation for THINGS as in the
     250       --report=THINGS help message.  */
     251    N_("THINGS is a list of comma separated words that can include:"),
     252    NULL
     253  };
     254  
     255  /*---------------------.
     256  | --trace's handling.  |
     257  `---------------------*/
     258  
     259  ARGMATCH_DEFINE_GROUP (trace, enum trace)
     260  
     261  static const argmatch_trace_doc argmatch_trace_docs[] =
     262  {
     263    /* Meant for developers only, don't translate them.  */
     264    { "none",       "no traces" },
     265    { "locations",  "full display of the locations" },
     266    { "scan",       "grammar scanner traces" },
     267    { "parse",      "grammar parser traces" },
     268    { "automaton",  "construction of the automaton" },
     269    { "bitsets",    "use of bitsets" },
     270    { "closure",    "input/output of closure" },
     271    { "grammar",    "reading, reducing the grammar" },
     272    { "resource",   "memory consumption (where available)" },
     273    { "sets",       "grammar sets: firsts, nullable etc." },
     274    { "muscles",    "m4 definitions passed to the skeleton" },
     275    { "tools",      "m4 invocation" },
     276    { "m4-early",   "m4 traces starting from the start" },
     277    { "m4",         "m4 traces starting from the skeleton evaluation" },
     278    { "skeleton",   "skeleton postprocessing" },
     279    { "time",       "time consumption" },
     280    { "ielr",       "IELR conversion" },
     281    { "cex",        "counterexample generation"},
     282    { "all",        "all of the above" },
     283    { NULL, NULL},
     284  };
     285  
     286  static const argmatch_trace_arg argmatch_trace_args[] =
     287  {
     288    { "none",      trace_none },
     289    { "locations", trace_locations },
     290    { "scan",      trace_scan },
     291    { "parse",     trace_parse },
     292    { "automaton", trace_automaton },
     293    { "bitsets",   trace_bitsets },
     294    { "closure",   trace_closure },
     295    { "grammar",   trace_grammar },
     296    { "resource",  trace_resource },
     297    { "sets",      trace_sets },
     298    { "muscles",   trace_muscles },
     299    { "tools",     trace_tools },
     300    { "m4-early",  trace_m4_early },
     301    { "m4",        trace_m4 },
     302    { "skeleton",  trace_skeleton },
     303    { "time",      trace_time },
     304    { "ielr",      trace_ielr },
     305    { "cex",       trace_cex },
     306    { "all",       trace_all },
     307    { NULL,        trace_none},
     308  };
     309  
     310  const argmatch_trace_group_type argmatch_trace_group =
     311  {
     312    argmatch_trace_args,
     313    argmatch_trace_docs,
     314    N_("TRACES is a list of comma separated words that can include:"),
     315    NULL
     316  };
     317  
     318  /*-----------------------.
     319  | --feature's handling.  |
     320  `-----------------------*/
     321  
     322  ARGMATCH_DEFINE_GROUP (feature, enum feature)
     323  
     324  static const argmatch_feature_doc argmatch_feature_docs[] =
     325  {
     326    { "caret",       N_("show errors with carets") },
     327    { "fixit",       N_("show machine-readable fixes") },
     328    { "syntax-only", N_("do not generate any file") },
     329    { "all",         N_("all of the above") },
     330    { "none",        N_("disable all of the above") },
     331    { NULL, NULL }
     332  };
     333  
     334  static const argmatch_feature_arg argmatch_feature_args[] =
     335  {
     336    { "none",                          feature_none },
     337    { "caret",                         feature_caret },
     338    { "diagnostics-show-caret",        feature_caret },
     339    { "fixit",                         feature_fixit },
     340    { "diagnostics-parseable-fixits",  feature_fixit },
     341    { "syntax-only",                   feature_syntax_only },
     342    { "all",                           feature_all },
     343    { NULL, feature_none}
     344  };
     345  
     346  const argmatch_feature_group_type argmatch_feature_group =
     347  {
     348    argmatch_feature_args,
     349    argmatch_feature_docs,
     350    /* TRANSLATORS: Use the same translation for FEATURES as in the
     351       --feature=FEATURES help message.  */
     352    N_("FEATURES is a list of comma separated words that can include:"),
     353    NULL
     354  };
     355  
     356  /*-------------------------------------------.
     357  | Display the help message and exit STATUS.  |
     358  `-------------------------------------------*/
     359  
     360   _Noreturn
     361  static void usage (int);
     362  
     363  static void
     364  usage (int status)
     365  {
     366    if (status != 0)
     367      fprintf (stderr, _("Try '%s --help' for more information.\n"),
     368               program_name);
     369    else
     370      {
     371        /* For ../build-aux/cross-options.pl to work, use the format:
     372                  ^  -S, --long[=ARGS] (whitespace)
     373           A --long option is required.
     374           Otherwise, add exceptions to ../build-aux/cross-options.pl.  */
     375  
     376        printf (_("Usage: %s [OPTION]... FILE\n"), program_name);
     377        fputs (_("\
     378  Generate a deterministic LR or generalized LR (GLR) parser employing\n\
     379  LALR(1), IELR(1), or canonical LR(1) parser tables.\n\
     380  \n\
     381  "), stdout);
     382  
     383        fputs (_("\
     384  Mandatory arguments to long options are mandatory for short options too.\n\
     385  "), stdout);
     386        fputs (_("\
     387  The same is true for optional arguments.\n\
     388  "), stdout);
     389        putc ('\n', stdout);
     390  
     391        fputs (_("\
     392  Operation Modes:\n\
     393    -h, --help                 display this help and exit\n\
     394    -V, --version              output version information and exit\n\
     395        --print-localedir      output directory containing locale-dependent data\n\
     396                               and exit\n\
     397        --print-datadir        output directory containing skeletons and XSLT\n\
     398                               and exit\n\
     399    -u, --update               apply fixes to the source grammar file and exit\n\
     400    -f, --feature[=FEATURES]   activate miscellaneous features\n\
     401  \n\
     402  "), stdout);
     403  
     404        argmatch_feature_usage (stdout);
     405        putc ('\n', stdout);
     406  
     407        fputs (_("\
     408  Diagnostics:\n\
     409    -W, --warnings[=CATEGORY]  report the warnings falling in CATEGORY\n\
     410        --color[=WHEN]         whether to colorize the diagnostics\n\
     411        --style=FILE           specify the CSS FILE for colorizer diagnostics\n\
     412  \n\
     413  "), stdout);
     414  
     415        warning_usage (stdout);
     416        putc ('\n', stdout);
     417  
     418        argmatch_color_usage (stdout);
     419        putc ('\n', stdout);
     420  
     421        fputs (_("\
     422  Tuning the Parser:\n\
     423    -L, --language=LANGUAGE          specify the output programming language\n\
     424    -S, --skeleton=FILE              specify the skeleton to use\n\
     425    -t, --debug                      instrument the parser for tracing\n\
     426                                     same as '-Dparse.trace'\n\
     427        --locations                  enable location support\n\
     428    -D, --define=NAME[=VALUE]        similar to '%define NAME VALUE'\n\
     429    -F, --force-define=NAME[=VALUE]  override '%define NAME VALUE'\n\
     430    -p, --name-prefix=PREFIX         prepend PREFIX to the external symbols\n\
     431                                     deprecated by '-Dapi.prefix={PREFIX}'\n\
     432    -l, --no-lines                   don't generate '#line' directives\n\
     433    -k, --token-table                include a table of token names\n\
     434    -y, --yacc                       emulate POSIX Yacc\n\
     435  "), stdout);
     436        putc ('\n', stdout);
     437  
     438        fputs (_("\
     439  Output Files:\n\
     440    -H, --header=[FILE]           also produce a header file\n\
     441    -d                            likewise but cannot specify FILE (for POSIX Yacc)\n\
     442    -r, --report=THINGS           also produce details on the automaton\n\
     443        --report-file=FILE        write report to FILE\n\
     444    -v, --verbose                 same as '--report=state'\n\
     445    -b, --file-prefix=PREFIX      specify a PREFIX for output files\n\
     446    -o, --output=FILE             leave output to FILE\n\
     447    -g, --graph[=FILE]            also output a graph of the automaton\n\
     448        --html[=FILE]             also output an HTML report of the automaton\n\
     449    -x, --xml[=FILE]              also output an XML report of the automaton\n\
     450    -M, --file-prefix-map=OLD=NEW replace prefix OLD with NEW when writing file paths\n\
     451                                  in output files\n\
     452  "), stdout);
     453        putc ('\n', stdout);
     454  
     455        argmatch_report_usage (stdout);
     456        putc ('\n', stdout);
     457  
     458        printf (_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
     459        printf (_("%s home page: <%s>.\n"), PACKAGE_NAME, PACKAGE_URL);
     460        fputs (_("General help using GNU software: "
     461                 "<https://www.gnu.org/gethelp/>.\n"),
     462               stdout);
     463  
     464  #if (defined __GLIBC__ && __GLIBC__ >= 2) && !defined __UCLIBC__
     465        /* Don't output this redundant message for English locales.
     466           Note we still output for 'C' so that it gets included in the
     467           man page.  */
     468        const char *lc_messages = setlocale (LC_MESSAGES, NULL);
     469        if (lc_messages && !STREQ (lc_messages, "en_"))
     470          /* TRANSLATORS: Replace LANG_CODE in this URL with your language code to
     471             form one of the URLs at https://translationproject.org/team/.
     472             Otherwise, replace the entire URL with your translation team's
     473             email address.  */
     474          fputs (_("Report translation bugs to "
     475                   "<https://translationproject.org/team/>.\n"), stdout);
     476  #endif
     477        fputs (_("For complete documentation, run: info bison.\n"), stdout);
     478      }
     479  
     480    exit (status);
     481  }
     482  
     483  
     484  /*------------------------------.
     485  | Display the version message.  |
     486  `------------------------------*/
     487  
     488  static void
     489  version (void)
     490  {
     491    /* Some efforts were made to ease the translators' task, please
     492       continue.  */
     493    printf ("bison (GNU Bison) %s", VERSION);
     494    putc ('\n', stdout);
     495    fputs (_("Written by Robert Corbett and Richard Stallman.\n"), stdout);
     496    putc ('\n', stdout);
     497  
     498    fprintf (stdout,
     499             _("Copyright (C) %d Free Software Foundation, Inc.\n"),
     500             PACKAGE_COPYRIGHT_YEAR);
     501  
     502    fputs (_("\
     503  This is free software; see the source for copying conditions.  There is NO\n\
     504  warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
     505  "),
     506           stdout);
     507  }
     508  
     509  
     510  /*-------------------------------------.
     511  | --skeleton and --language handling.  |
     512  `--------------------------------------*/
     513  
     514  void
     515  skeleton_arg (char const *arg, int prio, location loc)
     516  {
     517    if (prio < skeleton_prio)
     518      {
     519        skeleton_prio = prio;
     520        skeleton = arg;
     521      }
     522    else if (prio == skeleton_prio)
     523      complain (&loc, complaint,
     524                _("multiple skeleton declarations are invalid"));
     525  }
     526  
     527  void
     528  language_argmatch (char const *arg, int prio, location loc)
     529  {
     530    char const *msg = NULL;
     531  
     532    if (prio < language_prio)
     533      {
     534        for (int i = 0; valid_languages[i].language[0]; ++i)
     535          if (c_strcasecmp (arg, valid_languages[i].language) == 0)
     536            {
     537              language_prio = prio;
     538              language = &valid_languages[i];
     539              return;
     540            }
     541        msg = _("%s: invalid language");
     542      }
     543    else if (language_prio == prio)
     544      msg = _("multiple language declarations are invalid");
     545  
     546    if (msg)
     547      complain (&loc, complaint, msg, quotearg_colon (arg));
     548  }
     549  
     550  /*----------------------.
     551  | Process the options.  |
     552  `----------------------*/
     553  
     554  /* Shorts options.
     555     Should be computed from long_options.  */
     556  static char const short_options[] =
     557    "D:"
     558    "F:"
     559    "H::"
     560    "L:"
     561    "S:"
     562    "T::"
     563    "V"
     564    "W::"
     565    "b:"
     566    "d"
     567    "f::"
     568    "g::"
     569    "h"
     570    "k"
     571    "l"
     572    "M:"
     573    "o:"
     574    "p:"
     575    "r:"
     576    "t"
     577    "u"   /* --update */
     578    "v"
     579    "x::"
     580    "y"
     581    ;
     582  
     583  /* Values for long options that do not have single-letter equivalents.  */
     584  enum
     585  {
     586    COLOR_OPTION = CHAR_MAX + 1,
     587    FIXED_OUTPUT_FILES_OPTION,
     588    HTML_OPTION,
     589    LOCATIONS_OPTION,
     590    PRINT_DATADIR_OPTION,
     591    PRINT_LOCALEDIR_OPTION,
     592    REPORT_FILE_OPTION,
     593    STYLE_OPTION
     594  };
     595  
     596  /* In the same order as in usage(), and in the documentation.  */
     597  static struct option const long_options[] =
     598  {
     599    /* Operation modes. */
     600    { "help",            no_argument,       0,   'h' },
     601    { "version",         no_argument,       0,   'V' },
     602    { "print-localedir", no_argument,       0,   PRINT_LOCALEDIR_OPTION },
     603    { "print-datadir",   no_argument,       0,   PRINT_DATADIR_OPTION   },
     604    { "update",          no_argument,       0,   'u' },
     605    { "feature",         optional_argument, 0,   'f' },
     606  
     607    /* Diagnostics.  */
     608    { "warnings",        optional_argument,  0, 'W' },
     609    { "color",           optional_argument,  0,  COLOR_OPTION },
     610    { "style",           optional_argument,  0,  STYLE_OPTION },
     611  
     612    /* Tuning the Parser. */
     613    { "language",       required_argument,   0, 'L' },
     614    { "skeleton",       required_argument,   0, 'S' },
     615    { "debug",          no_argument,         0, 't' },
     616    { "locations",      no_argument,         0, LOCATIONS_OPTION },
     617    { "define",         required_argument,   0, 'D' },
     618    { "force-define",   required_argument,   0, 'F' },
     619    { "name-prefix",    required_argument,   0, 'p' },
     620    { "no-lines",       no_argument,         0, 'l' },
     621    { "token-table",    no_argument,         0, 'k' },
     622    { "yacc",           no_argument,         0, 'y' },
     623  
     624    /* Output Files. */
     625    { "header",          optional_argument,   0,   'H' },
     626    { "defines",         optional_argument,   0,   'd' },
     627    { "report",          required_argument,   0,   'r' },
     628    { "report-file",     required_argument,   0,   REPORT_FILE_OPTION },
     629    { "verbose",         no_argument,         0,   'v' },
     630    { "file-prefix",     required_argument,   0,   'b' },
     631    { "output",          required_argument,   0,   'o' },
     632    { "graph",           optional_argument,   0,   'g' },
     633    { "html",            optional_argument,   0,   HTML_OPTION },
     634    { "xml",             optional_argument,   0,   'x' },
     635    { "file-prefix-map", required_argument,   0,   'M' },
     636  
     637    /* Hidden. */
     638    { "fixed-output-files", no_argument,       0,  FIXED_OUTPUT_FILES_OPTION },
     639    { "output-file",        required_argument, 0,  'o' },
     640    { "trace",              optional_argument, 0,  'T' },
     641  
     642    {0, 0, 0, 0}
     643  };
     644  
     645  /* Build a location for the current command line argument. */
     646  static location
     647  command_line_location (void)
     648  {
     649    location res;
     650    /* "<command line>" is used in GCC's messages about -D. */
     651    boundary_set (&res.start, uniqstr_new ("<command line>"), optind - 1, -1, -1);
     652    res.end = res.start;
     653    return res;
     654  }
     655  
     656  
     657  /* Handle the command line options for color support.  Do it early, so
     658     that error messages from getargs be also colored as per the user's
     659     request.  This is consistent with the way GCC and Clang behave.  */
     660  
     661  static void
     662  getargs_colors (int argc, char *argv[])
     663  {
     664    for (int i = 1; i < argc; i++)
     665      {
     666        const char *arg = argv[i];
     667        if (STRPREFIX_LIT ("--color=", arg))
     668          {
     669            const char *color = arg + strlen ("--color=");
     670            if (STREQ (color, "debug"))
     671              color_debug = true;
     672            else
     673              handle_color_option (color);
     674          }
     675        else if (STREQ ("--color", arg))
     676          handle_color_option (NULL);
     677        else if (STRPREFIX_LIT ("--style=", arg))
     678          {
     679            const char *style = arg + strlen ("--style=");
     680            handle_style_option (style);
     681          }
     682      }
     683    complain_init_color ();
     684  }
     685  
     686  
     687  void
     688  getargs (int argc, char *argv[])
     689  {
     690    getargs_colors (argc, argv);
     691  
     692    int c;
     693    while ((c = getopt_long (argc, argv, short_options, long_options, NULL))
     694           != -1)
     695    {
     696      location loc = command_line_location ();
     697      switch (c)
     698        {
     699          /* ASCII Sorting for short options (i.e., upper case then
     700             lower case), and then long-only options.  */
     701  
     702        case 0:
     703          /* Certain long options cause getopt_long to return 0.  */
     704          break;
     705  
     706        case 'D': /* -DNAME[=(VALUE|"VALUE"|{VALUE})]. */
     707        case 'F': /* -FNAME[=(VALUE|"VALUE"|{VALUE})]. */
     708          {
     709            char *name = optarg;
     710            char *value = strchr (optarg, '=');
     711            muscle_kind kind = muscle_keyword;
     712            if (value)
     713              {
     714                char *end = value + strlen (value) - 1;
     715                *value++ = 0;
     716                if (*value == '{' && *end == '}')
     717                  {
     718                    kind = muscle_code;
     719                    ++value;
     720                    *end = 0;
     721                  }
     722                else if (*value == '"' && *end == '"')
     723                  {
     724                    kind = muscle_string;
     725                    ++value;
     726                    *end = 0;
     727                  }
     728              }
     729            muscle_percent_define_insert (name, loc,
     730                                          kind, value ? value : "",
     731                                          c == 'D' ? MUSCLE_PERCENT_DEFINE_D
     732                                                   : MUSCLE_PERCENT_DEFINE_F);
     733          }
     734          break;
     735  
     736        case 'H':
     737        case 'd':
     738          header_flag = true;
     739          if (optarg)
     740            {
     741              free (spec_header_file);
     742              spec_header_file = xstrdup (optarg);
     743            }
     744          break;
     745  
     746        case 'L':
     747          language_argmatch (optarg, command_line_prio, loc);
     748          break;
     749  
     750        case 'M': // -MOLDPREFIX=NEWPREFIX
     751          {
     752            char *newprefix = strchr (optarg, '=');
     753            if (newprefix)
     754              {
     755                *newprefix = '\0';
     756                add_prefix_map (optarg, newprefix + 1);
     757              }
     758            else
     759              {
     760                complain (&loc, complaint, _("invalid argument for %s: %s"),
     761                          quote ("--file-prefix-map"), quotearg_n (1, optarg));
     762              }
     763          }
     764          break;
     765  
     766        case 'S':
     767          skeleton_arg (optarg, command_line_prio, loc);
     768          break;
     769  
     770        case 'T':
     771          FLAGS_ARGMATCH (trace, optarg, trace_all);
     772          break;
     773  
     774        case 'V':
     775          version ();
     776          exit (EXIT_SUCCESS);
     777  
     778        case 'f':
     779          FLAGS_ARGMATCH (feature, optarg, feature_all);
     780          break;
     781  
     782        case 'W':
     783          warnings_argmatch (optarg);
     784          break;
     785  
     786        case 'b':
     787          spec_file_prefix = optarg;
     788          break;
     789  
     790        case 'g':
     791          graph_flag = true;
     792          if (optarg)
     793            {
     794              free (spec_graph_file);
     795              spec_graph_file = xstrdup (optarg);
     796            }
     797          break;
     798  
     799        case 'h':
     800          usage (EXIT_SUCCESS);
     801  
     802        case 'k':
     803          token_table_flag = true;
     804          break;
     805  
     806        case 'l':
     807          no_lines_flag = true;
     808          break;
     809  
     810        case 'o':
     811          spec_outfile = optarg;
     812          break;
     813  
     814        case 'p':
     815          spec_name_prefix = optarg;
     816          break;
     817  
     818        case 'r':
     819          FLAGS_ARGMATCH (report, optarg, report_all);
     820          break;
     821  
     822        case 't':
     823          muscle_percent_define_insert ("parse.trace",
     824                                        loc,
     825                                        muscle_keyword, "",
     826                                        MUSCLE_PERCENT_DEFINE_D);
     827          break;
     828  
     829        case 'u':
     830          update_flag = true;
     831          feature_flag |= feature_syntax_only;
     832          break;
     833  
     834        case 'v':
     835          report_flag |= report_states;
     836          break;
     837  
     838        case 'x':
     839          xml_flag = true;
     840          if (optarg)
     841            {
     842              free (spec_xml_file);
     843              spec_xml_file = xstrdup (optarg);
     844            }
     845          break;
     846  
     847        case 'y':
     848          warning_argmatch ("yacc", 0, 0);
     849          set_yacc (loc);
     850          break;
     851  
     852        case COLOR_OPTION:
     853          /* Handled in getargs_colors. */
     854          break;
     855  
     856        case HTML_OPTION:
     857          html_flag = true;
     858          xml_flag = true;
     859          if (optarg)
     860            {
     861              free (spec_html_file);
     862              spec_html_file = xstrdup (optarg);
     863            }
     864          break;
     865  
     866        case FIXED_OUTPUT_FILES_OPTION:
     867          complain (&loc, Wdeprecated,
     868                    _("deprecated option: %s, use %s"),
     869                    quote ("--fixed-output-files"), quote_n (1, "-o y.tab.c"));
     870          spec_outfile = "y.tab.c";
     871          break;
     872  
     873        case LOCATIONS_OPTION:
     874          muscle_percent_define_ensure ("locations", loc, true);
     875          break;
     876  
     877        case PRINT_LOCALEDIR_OPTION:
     878          printf ("%s\n", LOCALEDIR);
     879          exit (EXIT_SUCCESS);
     880  
     881        case PRINT_DATADIR_OPTION:
     882          printf ("%s\n", pkgdatadir ());
     883          exit (EXIT_SUCCESS);
     884  
     885        case REPORT_FILE_OPTION:
     886          free (spec_verbose_file);
     887          spec_verbose_file = xstrdup (optarg);
     888          break;
     889  
     890        case STYLE_OPTION:
     891          /* Handled in getargs_colors. */
     892          break;
     893  
     894        default:
     895          usage (EXIT_FAILURE);
     896        }
     897    }
     898  
     899    if (argc - optind != 1)
     900      {
     901        if (argc - optind < 1)
     902          error (0, 0, _("missing operand"));
     903        else
     904          error (0, 0, _("extra operand %s"), quote (argv[optind + 1]));
     905        usage (EXIT_FAILURE);
     906      }
     907  
     908    grammar_file = uniqstr_new (argv[optind]);
     909    MUSCLE_INSERT_C_STRING ("file_name", grammar_file);
     910  }
     911  
     912  void
     913  tr (char *s, char from, char to)
     914  {
     915    for (; *s; ++s)
     916      if (*s == from)
     917        *s = to;
     918  }