• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
flags_argmatch(const char * option,const char * const keys[],const int values[],int all,int * flags,char * args)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
usage(int status)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
version(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
skeleton_arg(char const * arg,int prio,location loc)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
language_argmatch(char const * arg,int prio,location loc)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
command_line_location(void)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
getargs(int argc,char * argv[])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
tr(char * s,char from,char to)758 tr (char *s, char from, char to)
759 {
760   for (; *s; s++)
761     if (*s == from)
762       *s = to;
763 }
764