bison-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

--report


From: Akim Demaille
Subject: --report
Date: 20 May 2002 20:11:47 +0200
User-agent: Gnus/5.0808 (Gnus v5.8.8) XEmacs/21.4 (Common Lisp)

This is a proto patch only, given that I have not finished writing the
documentation.  Also, I'm not sure how to handle %verbose yet, nor if
I want to keep it as is (unless it was in 1.35, I don't recall): maybe
%report is a better feature.

Anyway, I would really appreciate comments on 1. the code patch
(including the wording of --help), and 2. the proto documentation.

Index: doc/bison.texinfo
--- doc/bison.texinfo Thu, 02 May 2002 19:30:29 +0200 akim
+++ doc/bison.texinfo Mon, 20 May 2002 20:10:28 +0200 akim
@@ -5,9 +5,7 @@
 @settitle Bison @value{VERSION}
 @setchapternewpage odd
 
address@hidden
 @finalout
address@hidden iftex
 
 @c SMALL BOOK version
 @c This edition has been formatted so that you can format and print it in
@@ -23,6 +21,7 @@
 @c Check COPYRIGHT dates.  should be updated in the titlepage, ifinfo
 @c titlepage; should NOT be changed in the GPL.  --mew
 
address@hidden FIXME: I don't understand this `iftex'.  Obsolete? --akim.
 @iftex
 @syncodeindex fn cp
 @syncodeindex vr cp
@@ -154,7 +153,7 @@ @node Top
 * Error Recovery::    Writing rules for error recovery.
 * Context Dependency::  What to do if your language syntax is too
                         messy for Bison to handle straightforwardly.
-* Debugging::         Debugging Bison parsers that parse wrong.
+* Debugging::         Tuning or debugging Bison parsers.
 * Invocation::        How to run Bison (to produce the parser source file).
 * Table of Symbols::  All the keywords of the Bison language are explained.
 * Glossary::          Basic concepts are explained.
@@ -299,6 +298,11 @@ @node Top
 * Tie-in Recovery::   Lexical tie-ins have implications for how
                         error recovery rules must be written.
 
+Tuning or Debugging Your Parser
+
+* Understanding::     Understanding the structure of your parser.
+* Tracing::           Tracing the execution of your parser.
+
 Invoking Bison
 
 * Bison Options::     All the options described in detail,
@@ -707,9 +711,9 @@ @node Bison Parser
 those cases your code should respect the identifiers reserved by those
 headers.  On some address@hidden hosts, @code{<alloca.h>},
 @code{<stddef.h>}, and @code{<stdlib.h>} are included as needed to
-declare memory allocators and related types.
-Other system headers may be included if you define @code{YYDEBUG} to a
-nonzero value (@pxref{Debugging, ,Debugging Your Parser}).
+declare memory allocators and related types.  Other system headers may
+be included if you define @code{YYDEBUG} to a nonzero value
+(@pxref{Tracing, ,Tracing Your Parser}).
 
 @node Stages
 @section Stages in Using Bison
@@ -2351,14 +2355,14 @@ expseq1:  exp
 @end example
 
 @noindent
-Any kind of sequence can be defined using either left recursion or
-right recursion, but you should always use left recursion, because it
-can parse a sequence of any number of elements with bounded stack
-space.  Right recursion uses up space on the Bison stack in proportion
-to the number of elements in the sequence, because all the elements
-must be shifted onto the stack before the rule can be applied even
-once.  @xref{Algorithm, ,The Bison Parser Algorithm }, for
-further explanation of this.
+Any kind of sequence can be defined using either left recursion or right
+recursion, but you should always use left recursion, because it can
+parse a sequence of any number of elements with bounded stack space.
+Right recursion uses up space on the Bison stack in proportion to the
+number of elements in the sequence, because all the elements must be
+shifted onto the stack before the rule can be applied even once.
address@hidden, ,The Bison Parser Algorithm}, for further explanation
+of this.
 
 @cindex mutual recursion
 @dfn{Indirect} or @dfn{mutual} recursion occurs when the result of the
@@ -3276,7 +3280,7 @@ directives:
 @item %debug
 In the parser file, define the macro @code{YYDEBUG} to 1 if it is not
 already defined, so that the debugging facilities are compiled.
address@hidden, ,Debugging Your Parser}.
address@hidden, ,Tracing Your Parser}.
 
 @item %defines
 Write an extra output file containing macro definitions for the token
@@ -3386,17 +3390,10 @@ directives:
 @item %verbose
 Write an extra output file containing verbose descriptions of the
 parser states and what is done for each type of look-ahead token in
-that state.
-
-This file also describes all the conflicts, both those resolved by
-operator precedence and the unresolved ones.
+that state. @xref{Unerstanding, , Understanding Your Parser}, for more
+information.
 
-The file's name is made by removing @samp{.tab.c} or @samp{.c} from
-the parser output file name, and adding @samp{.output} instead.
 
-Therefore, if the input file is @file{foo.y}, then the parser file is
-called @file{foo.tab.c} by default.  As a consequence, the verbose
-output file is called @file{foo.output}.
 
 @item %yacc
 Pretend the option @option{--yacc} was given, i.e., imitate Yacc,
@@ -4954,8 +4951,353 @@ expr:   @dots{}
 be such that you can be sure that it always will, or always won't, have to
 clear the flag.
 
address@hidden ================================================== Debugging 
Your Parser
+
 @node Debugging
 @chapter Debugging Your Parser
+
+Developing a parser can be a challenge, especially if you don't
+understand the algorithm (@pxref{Algorithm, ,The Bison Parser
+Algorithm}).  Even so, sometimes a detailed description of the automaton
+can help (@pxref{Understanding, , Understanding Your Parser}), or
+tracing the execution of the parser can give some insight on why it
+behaves improperly (@pxref{Tracing, , Tracing Your Parser}).
+
address@hidden
+* Understanding::     Understanding the structure of your parser.
+* Tracing::           Tracing the execution of your parser.
address@hidden menu
+
address@hidden Understanding
address@hidden Understanding Your Parser
+
+As documented elsewhere (@pxref{Algorithm, ,The Bison Parser Algorithm})
+Bison parsers are @dfn{shift/reduce automata}.  In some cases (much more
+frequent than one would hope), looking at this automaton is required to
+tune or simply fix a parser.
+
+Bison provides two different accesses to these automata, either
+textually or graphically (as a @sc{vcg} file).
+
address@hidden 1
+
+The textual file is generated when the options @option{--report} or
address@hidden are specified, see @xref{Invocation, , Invoking
+Bison}.
+
+also describes all the conflicts, both those resolved
+by operator precedence and the unresolved ones.
+
+The file's name is made by removing @samp{.tab.c} or @samp{.c} from
+the parser output file name, and adding @samp{.output} instead.
+
+Therefore, if the input file is @file{foo.y}, then the parser file is
+called @file{foo.tab.c} by default.  As a consequence, the verbose
+output file is called @file{foo.output}.
+
+The following grammar file, @file{calc.y}, will be used in the sequel:
+
address@hidden
+%token NUM STR
+%left '+' '-'
+%left '*'
+%%
+exp: exp '+' exp
+   | exp '-' exp
+   | exp '*' exp
+   | exp '/' exp
+   | NUM
+   ;
+useless: STR;
+%%
address@hidden example
+
+As expected, @command{bison} reports that @samp{calc.y contains 1
+useless nonterminal and 1 useless rule} and that @samp{calc.y contains 7
+shift/reduce conflicts}.  When given @option{--report=state}, in
+addition to @file{calc.tab.c}, it has created a file @file{calc.output}
+which contents is detailed address@hidden order of the paragraphs
+and the exact presentation might vary, but the interpretation is the
+same.}.
+
+The first section includes details on conflicts which were solved thanks
+to precedence and/or associativity:
+
address@hidden
+Conflict in state 8 between rule 2 and token '+' resolved as reduce.
+Conflict in state 8 between rule 2 and token '-' resolved as reduce.
+Conflict in state 8 between rule 2 and token '*' resolved as shift.
address@hidden @dots{}
address@hidden example
+
address@hidden
+Then states which still have conflicts are listed.
+
address@hidden
+State 8 contains 1 shift/reduce conflict.
+State 9 contains 1 shift/reduce conflict.
+State 10 contains 1 shift/reduce conflict.
+State 11 contains 4 shift/reduce conflicts.
address@hidden example
+
address@hidden
+Useless tokens, nonterminal and rules are reported.  Useless
+nonterminals and rules are really removed in order to produce a smaller
+parser, but useless tokens are preserved, since they might be used by
+the scanner (note the difference between ``useless'' and ``not used''
+below):
+
address@hidden
+Useless nonterminals:
+   useless
+
+Terminals which are not used:
+   STR
+
+Useless rules:
+#6     useless: STR;
address@hidden example
+
address@hidden
+The exact grammar that Bison used is then reproduced.
+
address@hidden
+Grammar
+
+  Number, Line, Rule
+    0   5 $axiom -> exp $
+    1   5 exp -> exp '+' exp
+    2   6 exp -> exp '-' exp
+    3   7 exp -> exp '*' exp
+    4   8 exp -> exp '/' exp
+    5   9 exp -> NUM
address@hidden example
+
address@hidden
+and the uses of the symbols are reported:
+
address@hidden
+Terminals, with rules where they appear
+
+$ (0) 0
+'*' (42) 3
+'+' (43) 1
+'-' (45) 2
+'/' (47) 4
+error (256)
+NUM (258) 5
+
+Nonterminals, with rules where they appear
+
+$axiom (8)
+    on left: 0
+exp (9)
+    on left: 1 2 3 4 5, on right: 0 1 2 3 4
address@hidden example
+
address@hidden
address@hidden item
address@hidden pointed rule
address@hidden rule, pointed
+Bison then proceeds onto the automaton itself, describing each state
+with it set of @dfn{items}, also known as ``pointed rules'':
+
address@hidden
+state 0
+
+    $axiom  ->  . exp $   (rule 0)
+
+    NUM        shift, and go to state 1
+
+    exp        go to state 2
address@hidden example
+
+It reads as follows: ``state 0 corresponds to being at the very
+beginning of the parsing, in the initial rule, right before the axiom
+(here, @code{exp}).  When the parser is in this state, if a reduction
+produced an @code{exp}, the control flow jumps to state 1.  If there is
+no such transition on a nonterminal symbol, and the lookahead is a
address@hidden, then this token is shifted on the parse stack, and the
+control flow jumps to state 2.  Any other lookahead triggers a parse
+error.''
+
address@hidden core, item set
address@hidden item set core
address@hidden kernel, item set
address@hidden item set core
+You might wonder how the automaton can expect a @code{NUM} while the
+only active rule in state 0 seems to be rule 0.  Actually, the reading
+point being right before an @code{exp}, the automaton knows it can be at
+the beginning of any rule deriving an @code{exp}, and by default it
+reports only the so called @dfn{core} or @dfn{kernel} of the item set.
+Invoking @command{bison} with @option{--report=itemset} lists all the
+items, including those that can be derived:
+
address@hidden
+state 0
+
+    $axiom  ->  . exp $   (rule 0)
+    exp  ->  . exp '+' exp   (rule 1)
+    exp  ->  . exp '-' exp   (rule 2)
+    exp  ->  . exp '*' exp   (rule 3)
+    exp  ->  . exp '/' exp   (rule 4)
+    exp  ->  . NUM   (rule 5)
+
+    NUM         shift, and go to state 1
+
+    exp         go to state 2
address@hidden example
+
address@hidden
+In the state 1...
+
address@hidden
+state 1
+
+    exp  ->  NUM .   (rule 5)
+
+    $default   reduce using rule 5 (exp)
address@hidden example
+
address@hidden
+the rule 5, @samp{exp: NUM;}, is completed.  Whatever the lookahead
+(@samp{$default}), the parser will reduce it.  If it was coming from
+state 0, then, after this reduction it will return to state 0, and will
+jump to state 2 (@samp{exp: go to state 2}).
+
address@hidden
+state 2
+
+    $axiom  ->  exp . $   (rule 0)
+    exp  ->  exp . '+' exp   (rule 1)
+    exp  ->  exp . '-' exp   (rule 2)
+    exp  ->  exp . '*' exp   (rule 3)
+    exp  ->  exp . '/' exp   (rule 4)
+
+    $          shift, and go to state 3
+    '+'        shift, and go to state 4
+    '-'        shift, and go to state 5
+    '*'        shift, and go to state 6
+    '/'        shift, and go to state 7
address@hidden example
+
address@hidden
+state 3
+
+    $axiom  ->  exp $ .   (rule 0)
+
+    $default   accept
+
+
+state 4
+
+    exp  ->  exp '+' . exp   (rule 1)
+
+    NUM        shift, and go to state 1
+
+    exp        go to state 8
+
+
+
+state 5
+
+    exp  ->  exp '-' . exp   (rule 2)
+
+    NUM        shift, and go to state 1
+
+    exp        go to state 9
+
+
+
+state 6
+
+    exp  ->  exp '*' . exp   (rule 3)
+
+    NUM        shift, and go to state 1
+
+    exp        go to state 10
+
+
+
+state 7
+
+    exp  ->  exp '/' . exp   (rule 4)
+
+    NUM        shift, and go to state 1
+
+    exp        go to state 11
+
+
+
+state 8
+
+    exp  ->  exp . '+' exp   (rule 1)
+    exp  ->  exp '+' exp .   (rule 1)
+    exp  ->  exp . '-' exp   (rule 2)
+    exp  ->  exp . '*' exp   (rule 3)
+    exp  ->  exp . '/' exp   (rule 4)
+
+    '*'        shift, and go to state 6
+    '/'        shift, and go to state 7
+
+    '/'        [reduce using rule 1 (exp)]
+    $default   reduce using rule 1 (exp)
+
+
+
+state 9
+
+    exp  ->  exp . '+' exp   (rule 1)
+    exp  ->  exp . '-' exp   (rule 2)
+    exp  ->  exp '-' exp .   (rule 2)
+    exp  ->  exp . '*' exp   (rule 3)
+    exp  ->  exp . '/' exp   (rule 4)
+
+    '*'        shift, and go to state 6
+    '/'        shift, and go to state 7
+
+    '/'        [reduce using rule 2 (exp)]
+    $default   reduce using rule 2 (exp)
+
+
+
+state 10
+
+    exp  ->  exp . '+' exp   (rule 1)
+    exp  ->  exp . '-' exp   (rule 2)
+    exp  ->  exp . '*' exp   (rule 3)
+    exp  ->  exp '*' exp .   (rule 3)
+    exp  ->  exp . '/' exp   (rule 4)
+
+    '/'        shift, and go to state 7
+
+    '/'        [reduce using rule 3 (exp)]
+    $default   reduce using rule 3 (exp)
+
+
+
+state 11
+
+    exp  ->  exp . '+' exp   (rule 1)
+    exp  ->  exp . '-' exp   (rule 2)
+    exp  ->  exp . '*' exp   (rule 3)
+    exp  ->  exp . '/' exp   (rule 4)
+    exp  ->  exp '/' exp .   (rule 4)
+
+    '+'        shift, and go to state 4
+    '-'        shift, and go to state 5
+    '*'        shift, and go to state 6
+    '/'        shift, and go to state 7
+
+    '+'        [reduce using rule 4 (exp)]
+    '-'        [reduce using rule 4 (exp)]
+    '*'        [reduce using rule 4 (exp)]
+    '/'        [reduce using rule 4 (exp)]
+    $default   reduce using rule 4 (exp)
address@hidden example
+
address@hidden Tracing
address@hidden Tracing Your Parser
 @findex yydebug
 @cindex debugging
 @cindex tracing the parser
@@ -5158,7 +5500,7 @@ @node Bison Options
 @itemx --debug
 In the parser file, define the macro @code{YYDEBUG} to 1 if it is not
 already defined, so that the debugging facilities are compiled.
address@hidden, ,Debugging Your Parser}.
address@hidden, ,Tracing Your Parser}.
 
 @item --locations
 Pretend that @code{%locations} was specified.  @xref{Decl Summary}.
@@ -5204,6 +5546,27 @@ @node Bison Options
 Pretend that @code{%verbose} was specified, i.e, specify prefix to use
 for all Bison output file names. @xref{Decl Summary}.
 
address@hidden -r @var{things}
address@hidden address@hidden
+Write an extra output file containing verbose description of the comma
+separated list of @var{things} among:
+
address@hidden @code
address@hidden state
+Description of the grammar, conflicts (resolved and unresolved), and
+LALR automaton.
+
address@hidden lookahead
+Implies @code{state} and augments the description of the automaton with
+each rule's lookahead set.
+
address@hidden itemset
+Implies @code{state} and augments the description of the automaton with
+the full set of items for each state, instead of its core only.
address@hidden table
+
+For instance, on the following grammar
+
 @item -v
 @itemx --verbose
 Pretend that @code{%verbose} was specified, i.e, write an extra output
@@ -5365,8 +5728,8 @@ @node Table of Symbols
 token.  @xref{Action Features, ,Special Features for Use in Actions}.
 
 @item YYDEBUG
-Macro to define to equip the parser with tracing code. @xref{Debugging,
-,Debugging Your Parser}.
+Macro to define to equip the parser with tracing code. @xref{Tracing,
+,Tracing Your Parser}.
 
 @item YYERROR
 Macro to pretend that a syntax error has just been detected: call
@@ -5430,7 +5793,7 @@ @node Table of Symbols
 @item yydebug
 External integer variable set to zero by default.  If @code{yydebug}
 is given a nonzero value, the parser will output information on input
-symbols and parser action.  @xref{Debugging, ,Debugging Your Parser}.
+symbols and parser action.  @xref{Tracing, ,Tracing Your Parser}.
 
 @item yyerrok
 Macro to cause parser to recover immediately to its normal mode
Index: lib/Makefile.am
--- lib/Makefile.am Wed, 08 May 2002 11:29:49 +0200 akim
+++ lib/Makefile.am Mon, 20 May 2002 18:44:57 +0200 akim
@@ -35,6 +35,7 @@
 EXTRA_DIST = malloc.c realloc.c strnlen.c
 
 libbison_a_SOURCES = \
+  argmatch.h argmatch.c \
   gettext.h \
   basename.c dirname.h dirname.c \
   getopt.h getopt.c getopt1.c \
Index: src/conflicts.c
--- src/conflicts.c Sun, 07 Apr 2002 20:00:35 +0200 akim
+++ src/conflicts.c Mon, 20 May 2002 18:32:18 +0200 akim
@@ -43,7 +43,7 @@
 static inline void
 log_resolution (state_t *state, int LAno, int token, const char *resolution)
 {
-  if (verbose_flag)
+  if (report_p (states))
     obstack_fgrow4 (&output_obstack,
                    _("\
 Conflict in state %d between rule %d and token %s resolved as %s.\n"),
Index: src/getargs.c
--- src/getargs.c Sat, 16 Mar 2002 13:01:57 +0100 akim
+++ src/getargs.c Mon, 20 May 2002 18:59:09 +0200 akim
@@ -19,22 +19,21 @@
    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
    02111-1307, USA.  */
 
-#include <stdio.h>
-#include "getopt.h"
 #include "system.h"
-#include "files.h"
+#include "getopt.h"
+#include "argmatch.h"
 #include "complain.h"
 #include "getargs.h"
-#include "xalloc.h"
 #include "options.h"
+#include "files.h"
 
 int debug_flag = 0;
 int defines_flag = 0;
 int locations_flag = 0;
 int no_lines_flag = 0;
 int no_parser_flag = 0;
+int report_flag = 0;
 int token_table_flag = 0;
-int verbose_flag = 0;
 int yacc_flag = 0;     /* for -y */
 int graph_flag = 0;
 int trace_flag = 0;
@@ -44,6 +43,49 @@
 
 extern char *program_name;
 
+/*----------------------.
+| --report's handling.  |
+`----------------------*/
+
+static const char * const report_args[] =
+{
+  /* In a series of synonyms, present the most meaning full first, so
+     that argmatch_valid be more readable. */
+  "none",
+  "state", "states",
+  "itemset", "itemsets",
+  "lookahead", "lookaheads",
+  "all",
+  0
+};
+
+static const int report_types[] =
+{
+  report_none,
+  report_states, report_states,
+  report_itemsets, report_itemsets,
+  report_lookaheads, report_lookaheads,
+  report_all
+};
+
+
+static void
+report_argmatch (char *args)
+{
+  char *arg = strtok (args, ",");
+  ARGMATCH_ASSERT (report_args, report_types);
+  do
+    {
+      int report = XARGMATCH ("--report", args,
+                             report_args, report_types);
+      if (report == report_none)
+       report_flag = report_none;
+      else
+       report_flag |= report;
+    }
+  while ((args = strtok (NULL, ",")));
+}
+
 /*---------------------------.
 | Display the help message.  |
 `---------------------------*/
@@ -89,10 +131,18 @@ Parser:\n\
   fputs (_("\
 Output:\n\
   -d, --defines              also produce a header file\n\
-  -v, --verbose              also produce an explanation of the automaton\n\
+  -r, --report=THINGS        also produce details on the automaton\n\
+  -v, --verbose              same as `--report=state'\n\
   -b, --file-prefix=PREFIX   specify a PREFIX for output files\n\
   -o, --output=FILE          leave output to FILE\n\
   -g, --graph                also produce a VCG description of the automaton\n\
+\n\
+THINGS is a list of comma separated words amongst:\n\
+  `state'        description of the states\n\
+  `itemset'      complete the core itemsets with their closure\n\
+  `lookahead'    explicitly associate lookaheads to items\n\
+  `all'          all the above information\n\
+  `none'         disable the report\n\
 "), stream);
   putc ('\n', stream);
 
@@ -170,7 +220,7 @@ Output:\n\
        break;
 
       case 'v':
-       verbose_flag = 1;
+       report_flag |= report_states;
        break;
 
       case 'S':
@@ -196,10 +246,6 @@ Output:\n\
        token_table_flag = 1;
        break;
 
-      case 'r':
-       fatal (_("`%s' is no longer supported"), "--raw");
-       break;
-
       case 'n':
        no_parser_flag = 1;
        break;
@@ -218,6 +264,10 @@ Output:\n\
 
       case 'p':
        spec_name_prefix = optarg;
+       break;
+
+      case 'r':
+       report_argmatch (optarg);
        break;
 
       default:
Index: src/getargs.h
--- src/getargs.h Sat, 08 Dec 2001 17:14:16 +0100 akim
+++ src/getargs.h Mon, 20 May 2002 18:55:38 +0200 akim
@@ -1,5 +1,6 @@
 /* Parse command line arguments for bison.
-   Copyright 1984, 1986, 1989, 1992, 2000, 2001 Free Software Foundation, Inc.
+   Copyright 1984, 1986, 1989, 1992, 2000, 2001, 2002
+   Free Software Foundation, Inc.
 
    This file is part of Bison, the GNU Compiler Compiler.
 
@@ -31,10 +32,19 @@
 extern int no_lines_flag;      /* for -l */
 extern int no_parser_flag;     /* for -n */
 extern int token_table_flag;           /* for -k */
-extern int verbose_flag;       /* for -v */
 extern int graph_flag;         /* for -g */
 extern int yacc_flag;                  /* for -y */
 extern int trace_flag;
+
+/* --report.  */
+#define report_none        (0)
+#define report_states      (1 << 0)
+#define report_itemsets    (1 << 1 | report_states)
+#define report_lookaheads  (1 << 2 | report_states)
+#define report_all         (~0)
+extern int report_flag;
+/* Return TRUE iff THING ought to be reported.  */
+#define report_p(Thing)   ((report_flag & report_##Thing) == report_##Thing)
 
 void getargs PARAMS ((int argc, char *argv[]));
 
Index: src/main.c
--- src/main.c Mon, 06 May 2002 19:46:46 +0200 akim
+++ src/main.c Mon, 20 May 2002 18:37:03 +0200 akim
@@ -91,7 +91,7 @@
   compute_output_file_names ();
 
   /* Output the detailed report on the grammar.  */
-  if (verbose_flag)
+  if (report_p (states))
     print_results ();
 
   /* Stop if there were errors, to avoid trashing previous output
Index: src/options.c
--- src/options.c Thu, 02 May 2002 19:30:29 +0200 akim
+++ src/options.c Mon, 20 May 2002 18:42:30 +0200 akim
@@ -29,7 +29,7 @@
 #include "options.h"
 
 /* Shorts options.  */
-const char *shortopts = "yvegdhrltknVo:b:p:S:";
+const char *shortopts = "yvegdhr:ltknVo:b:p:S:";
 
 /* A CLI option only.
    Arguments is the policy: `no', `optional', `required'.
@@ -71,6 +71,8 @@
   OPTN ("output",      required,       0,      0,   'o')
   OPTN ("output-file", required,       0,      0,   'o')
   OPTN ("graph",       optional,       0,      0,   'g')
+  OPTN ("report",      required,       0,      0,   'r')
+  OPTN ("verbose",          no,        0,      0,   'v')
 
   /* Hidden. */
   OPTN ("trace",        no,   &trace_flag,      0,     1)
@@ -111,7 +113,6 @@
 
   /* Output.  */
   BOTH ("defines",     optional,   &defines_flag,    tok_intopt,   'd')
-  BOTH ("verbose",          no,   &verbose_flag,    tok_intopt,   'v')
 
   /* Operation modes.  */
   BOTH ("fixed-output-files", no,  &yacc_flag,      tok_intopt,   'y')
@@ -122,7 +123,7 @@
   BOTH ("locations",      no, &locations_flag,       tok_intopt,     1)
   BOTH ("no-lines",       no,  &no_lines_flag,       tok_intopt,   'l')
   BOTH ("no-parser",      no, &no_parser_flag,       tok_intopt,   'n')
-  BOTH ("raw",           no,               0,       tok_obsolete, 'r')
+  BOTH ("raw",           no,               0,       tok_obsolete,   0)
   BOTH ("skeleton",       required,         0,       tok_skel,    'S')
   BOTH ("token-table",    no, &token_table_flag,     tok_intopt,   'k')
 
Index: src/print.c
--- src/print.c Sun, 05 May 2002 13:42:16 +0200 akim
+++ src/print.c Mon, 20 May 2002 18:47:24 +0200 akim
@@ -72,9 +72,8 @@
   item_number_t *sitems = state->items;
   int snritems   = state->nitems;
 
-  /* New experimental feature: if TRACE_FLAGS output all the items of
-     a state, not only its kernel.  */
-  if (trace_flag)
+  /* Output all the items of a state, not only its kernel.  */
+  if (report_p (itemsets))
     {
       closure (sitems, snritems);
       sitems = itemset;
@@ -105,8 +104,8 @@
          for (/* Nothing */; *sp >= 0; ++sp)
            fprintf (out, " %s", escape (symbols[*sp]->tag));
 
-         /* Experimental feature: display the lookaheads. */
-         if (trace_flag && state->nlookaheads)
+         /* Display the lookaheads?  */
+         if (report_p (lookaheads))
            {
              int j, k;
              int nlookaheads = 0;
@@ -513,10 +512,10 @@
 
   print_grammar (out);
 
-  /* New experimental feature: output all the items of a state, not
-     only its kernel.  Requires to run closure, which need memory
-     allocation/deallocation.  */
-  if (trace_flag)
+  /* If all the items of a state, not only its kernel, is wanted,
+     `closure' will be run, which need memory allocation/deallocation.
+     */
+  if (report_p (itemsets))
     new_closure (nritems);
   /* Storage for print_reductions.  */
   shiftset =  bitset_create (ntokens, BITSET_FIXED);
@@ -525,7 +524,7 @@
     print_state (out, states[i]);
   bitset_free (shiftset);
   bitset_free (lookaheadset);
-  if (trace_flag)
+  if (report_p (itemsets))
     free_closure ();
 
   xfclose (out);
Index: lib/argmatch.h
--- lib/argmatch.h Mon, 20 May 2002 20:10:32 +0200 akim
+++ lib/argmatch.h Mon, 20 May 2002 18:03:33 +0200 akim
@@ -0,0 +1,129 @@
+/* argmatch.h -- definitions and prototypes for argmatch.c
+   Copyright (C) 1990, 1998, 1999 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* Written by David MacKenzie <address@hidden>
+   Modified by Akim Demaille <address@hidden> */
+
+#ifndef ARGMATCH_H_
+# define ARGMATCH_H_ 1
+
+# if HAVE_CONFIG_H
+#  include <config.h>
+# endif
+
+# include <sys/types.h>
+
+# ifndef PARAMS
+#  if PROTOTYPES || (defined (__STDC__) && __STDC__)
+#   define PARAMS(args) args
+#  else
+#   define PARAMS(args) ()
+#  endif  /* GCC.  */
+# endif  /* Not PARAMS.  */
+
+/* Assert there are as many real arguments as there are values
+   (argument list ends with a NULL guard).  There is no execution
+   cost, since it will be statically evalauted to `assert (0)' or
+   `assert (1)'.  Unfortunately there is no -Wassert-0. */
+
+# undef ARRAY_CARDINALITY
+# define ARRAY_CARDINALITY(Array) (sizeof ((Array)) / sizeof (*(Array)))
+
+# define ARGMATCH_ASSERT(Arglist, Vallist)      \
+  assert (ARRAY_CARDINALITY ((Arglist)) == ARRAY_CARDINALITY ((Vallist)) + 1)
+
+/* Return the index of the element of ARGLIST (NULL terminated) that
+   matches with ARG.  If VALLIST is not NULL, then use it to resolve
+   false ambiguities (i.e., different matches of ARG but corresponding
+   to the same values in VALLIST).  */
+
+int argmatch
+  PARAMS ((const char *arg, const char *const *arglist,
+          const char *vallist, size_t valsize));
+int argcasematch
+  PARAMS ((const char *arg, const char *const *arglist,
+          const char *vallist, size_t valsize));
+
+# define ARGMATCH(Arg, Arglist, Vallist) \
+  argmatch ((Arg), (Arglist), (const char *) (Vallist), sizeof (*(Vallist)))
+
+# define ARGCASEMATCH(Arg, Arglist, Vallist) \
+  argcasematch ((Arg), (Arglist), (const char *) (Vallist), sizeof 
(*(Vallist)))
+
+/* xargmatch calls this function when it fails.  This function should not
+   return.  By default, this is a function that calls ARGMATCH_DIE which
+   in turn defaults to `exit (EXIT_FAILURE)'.  */
+typedef void (*argmatch_exit_fn) PARAMS ((void));
+extern argmatch_exit_fn argmatch_die;
+
+/* Report on stderr why argmatch failed.  Report correct values. */
+
+void argmatch_invalid
+  PARAMS ((const char *context, const char *value, int problem));
+
+/* Left for compatibility with the old name invalid_arg */
+
+# define invalid_arg(Context, Value, Problem) \
+  argmatch_invalid ((Context), (Value), (Problem))
+
+
+
+/* Report on stderr the list of possible arguments.  */
+
+void argmatch_valid
+  PARAMS ((const char *const *arglist,
+          const char *vallist, size_t valsize));
+
+# define ARGMATCH_VALID(Arglist, Vallist) \
+  argmatch_valid (Arglist, (const char *) Vallist, sizeof (*(Vallist)))
+
+
+
+/* Same as argmatch, but upon failure, reports a explanation on the
+   failure, and exits using the function EXIT_FN. */
+
+int __xargmatch_internal
+  PARAMS ((const char *context,
+          const char *arg, const char *const *arglist,
+          const char *vallist, size_t valsize,
+          int case_sensitive, argmatch_exit_fn exit_fn));
+
+/* Programmer friendly interface to __xargmatch_internal. */
+
+# define XARGMATCH(Context, Arg, Arglist, Vallist)             \
+  (Vallist [__xargmatch_internal ((Context), (Arg), (Arglist), \
+                                  (const char *) (Vallist),    \
+                                 sizeof (*(Vallist)),          \
+                                 1, argmatch_die)])
+
+# define XARGCASEMATCH(Context, Arg, Arglist, Vallist)         \
+  (Vallist [__xargmatch_internal ((Context), (Arg), (Arglist), \
+                                  (const char *) (Vallist),    \
+                                 sizeof (*(Vallist)),          \
+                                 0, argmatch_die)])
+
+/* Convert a value into a corresponding argument. */
+
+const char *argmatch_to_argument
+  PARAMS ((char const *value, const char *const *arglist,
+          const char *vallist, size_t valsize));
+
+# define ARGMATCH_TO_ARGUMENT(Value, Arglist, Vallist)                 \
+  argmatch_to_argument ((char const *) &(Value), (Arglist),            \
+                       (const char *) (Vallist), sizeof (*(Vallist)))
+
+#endif /* ARGMATCH_H_ */
Index: lib/argmatch.c
--- lib/argmatch.c Mon, 20 May 2002 20:10:32 +0200 akim
+++ lib/argmatch.c Mon, 20 May 2002 17:48:27 +0200 akim
@@ -0,0 +1,306 @@
+/* argmatch.c -- find a match for a string in an array
+   Copyright (C) 1990, 1998, 1999 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* Written by David MacKenzie <address@hidden>
+   Modified by Akim Demaille <address@hidden> */
+
+#include "argmatch.h"
+
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <string.h>
+#endif
+
+#if HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(Text) gettext (Text)
+#else
+# define _(Text) Text
+#endif
+
+#include "error.h"
+#include "quotearg.h"
+
+/* When reporting an invalid argument, show nonprinting characters
+   by using the quoting style ARGMATCH_QUOTING_STYLE.  Do not use
+   literal_quoting_style.  */
+#ifndef ARGMATCH_QUOTING_STYLE
+# define ARGMATCH_QUOTING_STYLE locale_quoting_style
+#endif
+
+/* The following test is to work around the gross typo in
+   systems like Sony NEWS-OS Release 4.0C, whereby EXIT_FAILURE
+   is defined to 0, not 1.  */
+#if !EXIT_FAILURE
+# undef EXIT_FAILURE
+# define EXIT_FAILURE 1
+#endif
+
+/* Non failing version of argmatch call this function after failing. */
+#ifndef ARGMATCH_DIE
+# define ARGMATCH_DIE exit (EXIT_FAILURE)
+#endif
+
+#ifdef ARGMATCH_DIE_DECL
+ARGMATCH_DIE_DECL;
+#endif
+
+static void
+__argmatch_die (void)
+{
+  ARGMATCH_DIE;
+}
+
+/* Used by XARGMATCH and XARGCASEMATCH.  See description in argmatch.h.
+   Default to __argmatch_die, but allow caller to change this at run-time. */
+argmatch_exit_fn argmatch_die = __argmatch_die;
+
+
+/* If ARG is an unambiguous match for an element of the
+   null-terminated array ARGLIST, return the index in ARGLIST
+   of the matched element, else -1 if it does not match any element
+   or -2 if it is ambiguous (is a prefix of more than one element).
+   If SENSITIVE, comparison is case sensitive.
+
+   If VALLIST is none null, use it to resolve ambiguities limited to
+   synonyms, i.e., for
+     "yes", "yop" -> 0
+     "no", "nope" -> 1
+   "y" is a valid argument, for `0', and "n" for `1'.  */
+
+static int
+__argmatch_internal (const char *arg, const char *const *arglist,
+                    const char *vallist, size_t valsize,
+                    int case_sensitive)
+{
+  int i;                       /* Temporary index in ARGLIST.  */
+  size_t arglen;               /* Length of ARG.  */
+  int matchind = -1;           /* Index of first nonexact match.  */
+  int ambiguous = 0;           /* If nonzero, multiple nonexact match(es).  */
+
+  arglen = strlen (arg);
+
+  /* Test all elements for either exact match or abbreviated matches.  */
+  for (i = 0; arglist[i]; i++)
+    {
+      if (case_sensitive
+         ? !strncmp (arglist[i], arg, arglen)
+         : !strncasecmp (arglist[i], arg, arglen))
+       {
+         if (strlen (arglist[i]) == arglen)
+           /* Exact match found.  */
+           return i;
+         else if (matchind == -1)
+           /* First nonexact match found.  */
+           matchind = i;
+         else
+           {
+             /* Second nonexact match found.  */
+             if (vallist == NULL
+                 || memcmp (vallist + valsize * matchind,
+                            vallist + valsize * i, valsize))
+               {
+                 /* There is a real ambiguity, or we could not
+                    disambiguate. */
+                 ambiguous = 1;
+               }
+           }
+       }
+    }
+  if (ambiguous)
+    return -2;
+  else
+    return matchind;
+}
+
+/* argmatch - case sensitive version */
+int
+argmatch (const char *arg, const char *const *arglist,
+         const char *vallist, size_t valsize)
+{
+  return __argmatch_internal (arg, arglist, vallist, valsize, 1);
+}
+
+/* argcasematch - case insensitive version */
+int
+argcasematch (const char *arg, const char *const *arglist,
+             const char *vallist, size_t valsize)
+{
+  return __argmatch_internal (arg, arglist, vallist, valsize, 0);
+}
+
+/* Error reporting for argmatch.
+   CONTEXT is a description of the type of entity that was being matched.
+   VALUE is the invalid value that was given.
+   PROBLEM is the return value from argmatch.  */
+
+void
+argmatch_invalid (const char *context, const char *value, int problem)
+{
+  char const *format = (problem == -1
+                       ? _("invalid argument %s for `%s'")
+                       : _("ambiguous argument %s for `%s'"));
+
+  error (0, 0, format, quotearg_style (ARGMATCH_QUOTING_STYLE, value), 
context);
+}
+
+/* List the valid arguments for argmatch.
+   ARGLIST is the same as in argmatch.
+   VALLIST is a pointer to an array of values.
+   VALSIZE is the size of the elements of VALLIST */
+void
+argmatch_valid (const char *const *arglist,
+               const char *vallist, size_t valsize)
+{
+  int i;
+  const char *last_val = NULL;
+
+  /* We try to put synonyms on the same line.  The assumption is that
+     synonyms follow each other */
+  fprintf (stderr, _("Valid arguments are:"));
+  for (i = 0; arglist[i]; i++)
+    if ((i == 0)
+       || memcmp (last_val, vallist + valsize * i, valsize))
+      {
+       fprintf (stderr, "\n  - `%s'", arglist[i]);
+       last_val = vallist + valsize * i;
+      }
+    else
+      {
+       fprintf (stderr, ", `%s'", arglist[i]);
+      }
+  putc ('\n', stderr);
+}
+
+/* Never failing versions of the previous functions.
+
+   CONTEXT is the context for which argmatch is called (e.g.,
+   "--version-control", or "$VERSION_CONTROL" etc.).  Upon failure,
+   calls the (supposed never to return) function EXIT_FN. */
+
+int
+__xargmatch_internal (const char *context,
+                     const char *arg, const char *const *arglist,
+                     const char *vallist, size_t valsize,
+                     int case_sensitive,
+                     argmatch_exit_fn exit_fn)
+{
+  int res = __argmatch_internal (arg, arglist,
+                                vallist, valsize,
+                                case_sensitive);
+  if (res >= 0)
+    /* Success. */
+    return res;
+
+  /* We failed.  Explain why. */
+  argmatch_invalid (context, arg, res);
+  argmatch_valid (arglist, vallist, valsize);
+  (*exit_fn) ();
+
+  return -1; /* To please the compilers. */
+}
+
+/* Look for VALUE in VALLIST, an array of objects of size VALSIZE and
+   return the first corresponding argument in ARGLIST */
+const char *
+argmatch_to_argument (const char *value,
+                     const char *const *arglist,
+                     const char *vallist, size_t valsize)
+{
+  int i;
+
+  for (i = 0; arglist[i]; i++)
+    if (!memcmp (value, vallist + valsize * i, valsize))
+      return arglist[i];
+  return NULL;
+}
+
+#ifdef TEST
+/*
+ * Based on "getversion.c" by David MacKenzie <address@hidden>
+ */
+char *program_name;
+extern const char *getenv ();
+
+/* When to make backup files.  */
+enum backup_type
+{
+  /* Never make backups.  */
+  none,
+
+  /* Make simple backups of every file.  */
+  simple,
+
+  /* Make numbered backups of files that already have numbered backups,
+     and simple backups of the others.  */
+  numbered_existing,
+
+  /* Make numbered backups of every file.  */
+  numbered
+};
+
+/* Two tables describing arguments (keys) and their corresponding
+   values */
+static const char *const backup_args[] =
+{
+  "no", "none", "off",
+  "simple", "never",
+  "existing", "nil",
+  "numbered", "t",
+  0
+};
+
+static const enum backup_type backup_vals[] =
+{
+  none, none, none,
+  simple, simple,
+  numbered_existing, numbered_existing,
+  numbered, numbered
+};
+
+int
+main (int argc, const char *const *argv)
+{
+  const char *cp;
+  enum backup_type backup_type = none;
+
+  program_name = (char *) argv[0];
+
+  if (argc > 2)
+    {
+      fprintf (stderr, "Usage: %s [VERSION_CONTROL]\n", program_name);
+      exit (1);
+    }
+
+  if ((cp = getenv ("VERSION_CONTROL")))
+    backup_type = XARGCASEMATCH ("$VERSION_CONTROL", cp,
+                                backup_args, backup_vals);
+
+  if (argc == 2)
+    backup_type = XARGCASEMATCH (program_name, argv[1],
+                                backup_args, backup_vals);
+
+  printf ("The version control is `%s'\n",
+         ARGMATCH_TO_ARGUMENT (backup_type, backup_args, backup_vals));
+
+  return 0;
+}
+#endif



reply via email to

[Prev in Thread] Current Thread [Next in Thread]