bison-patches
[Top][All Lists]
Advanced

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

Re: --report


From: Akim Demaille
Subject: Re: --report
Date: 25 May 2002 17:26:39 +0200
User-agent: Gnus/5.0808 (Gnus v5.8.8) XEmacs/21.4 (Honest Recruiter)

>>>>> "Paul" == Paul Eggert <address@hidden> writes:

>> I prefer too, but I've always been told, in particular in
>> scientific papers, to promote passive :(

Paul> Yes, scientific text often prefers the passive voice, [...]

Thanks for all this information Paul.


>> Arg.  We disagree on the way to express gotos.  To me, it is an
>> heresy to name `exp' a lookahead here, both from the theoretical
>> point of view, and the implementation point of view.

Paul> Fair enough.  But I still didn't understand the text.  Perhaps
Paul> you might want to reread it with my confusion in mind.

I'm appending below the patch I'm installing.  I hope it will be
clearer.  [Arg, I had not realized the test suite needs to be adjusted
to, so it will be applied once I'm fully done.]  I'm installing it
since it will then be easier to discuss small changes to it.

>> | Better yet, I would use an enum,
>> 
>> I refrain using enums when I play bitwise tricks.  In such a
>> framework, the advantage of enums vs #defines is unclear to me (as,
>> I doubt that debuggers are able to report the value `a|b' as the
>> string `a|b' in case of enums.  Put after all, why not.).

Paul> Many debuggers can't see defines, so you can't use such a
Paul> debugger to print the value of an expression that involves a
Paul> defined symbol.

I must have been unclear: precisely thinking about debuggers, because
I know no debugger that with

        enum foo { a = 1, b = 2 };
        foo bar = 3;

would report bar as a | b, I feel less attracted by enums.


[...]
Paul> There are of course some advantages to the Pascal-like rules,
Paul> but the modern consensus is that C enums are just integers, and
Paul> we might as well use that consensus rather than fight it.

:)

I hear you 5/5 :)

Index: ChangeLog
from  Akim Demaille  <address@hidden>
        
        * doc/bison.texinfo (Debugging): Split into...
        (Tracing): this new section, its former contents, and...
        (Understanding): this new section.
        * src/getargs.h, src/getargs.c (verbose_flag): Remove, replaced
        by...
        (report_flag): this.
        Adjust all dependencies.
        (report_args, report_types, report_argmatch): New.
        (usage, getargs): Report/support -r, --report.
        * src/options.c (option_table): For the time being disable
        %verbose.
        Support --report/-r, so remove -r from the obsolete --raw.
        * src/print.c: Attach full item sets and lookaheads reports to
        report_flag instead of trace_flag.
        * lib/argmatch.h, lib/argmatch.c: New, from Fileutils 4.1.
        
Index: NEWS
--- NEWS Mon, 06 May 2002 19:46:46 +0200 akim
+++ NEWS Sat, 25 May 2002 17:03:47 +0200 akim
@@ -72,6 +72,13 @@
   the compiler supports ANSI C or is a C++ compiler, as enums.
   This helps debuggers producing symbols instead of values.
 
+* Reports
+  In addition to --verbose, bison supports --report=THINGS, which
+  produces additional information:
+
+  `itemset'      complete the core item sets with their closure
+  `lookahead'    explicitly associate lookaheads to items
+
 
 Changes in version 1.35, 2002-03-25:
 
Index: TODO
--- TODO Wed, 08 May 2002 11:29:49 +0200 akim
+++ TODO Sat, 25 May 2002 17:08:54 +0200 akim
@@ -1,5 +1,23 @@
 -*- outline -*-
 
+* documentation
+Explain $axiom (and maybe change its name: BTYacc names it goal).
+Complete the glossary (item, axiom, ?).
+
+* report documentation
+Extend with error.  The hard part will probably be finding the right
+rule so that a single state does not exhibit to many yet undocumented
+``features''.  Maybe an empty action ought to be presented too.  Shall
+we try to make a single grammar with all these features, or should we
+have several very small grammars?
+
+* documentation
+Some history of Bison and some bibliography would be most welcome.
+Are there any Texinfo standards for bibliography?
+
+* %verbose
+under what form should it be kept?
+
 * Several %unions
 I think this is a pleasant (but useless currently) feature, but in the
 future, I want a means to %include other bits of grammars, and _then_
@@ -21,130 +39,25 @@
          char *sval;
        }
 
-* Experimental report features
-Decide whether they should be enabled, or optional.  For instance, on:
-
-       input:
-         exp
-       | input exp
-       ;
-
-       exp:
-         token1 "1"
-       | token2 "2"
-       | token3 "3"
-       ;
-
-       token1: token;
-       token2: token;
-       token3: token;
-
-the traditional Bison reports:
-
-       state 0
-
-           $axiom  ->  . input $   (rule 0)
-
-           token       shift, and go to state 1
-
-           input       go to state 2
-           exp         go to state 3
-           token1      go to state 4
-           token2      go to state 5
-           token3      go to state 6
-
-       state 1
-
-           token1  ->  token .   (rule 6)
-           token2  ->  token .   (rule 7)
-           token3  ->  token .   (rule 8)
-
-           "2"         reduce using rule 7 (token2)
-           "3"         reduce using rule 8 (token3)
-           $default    reduce using rule 6 (token1)
-
-while with --trace, i.e., when enabling both the display of non-core
-item sets and the display of lookaheads, Bison now displays:
-
-       state 0
-
-           $axiom  ->  . input $   (rule 0)
-           input  ->  . exp   (rule 1)
-           input  ->  . input exp   (rule 2)
-           exp  ->  . token1 "1"   (rule 3)
-           exp  ->  . token2 "2"   (rule 4)
-           exp  ->  . token3 "3"   (rule 5)
-           token1  ->  . token   (rule 6)
-           token2  ->  . token   (rule 7)
-           token3  ->  . token   (rule 8)
-
-           token       shift, and go to state 1
-
-           input       go to state 2
-           exp         go to state 3
-           token1      go to state 4
-           token2      go to state 5
-           token3      go to state 6
-
-       state 1
-
-           token1  ->  token .  ["1"]   (rule 6)
-           token2  ->  token .  ["2"]   (rule 7)
-           token3  ->  token .  ["3"]   (rule 8)
-
-           "2"         reduce using rule 7 (token2)
-           "3"         reduce using rule 8 (token3)
-           $default    reduce using rule 6 (token1)
-
-so decide whether this should be an option, or always enabled.  I'm in
-favor of making it the default, but maybe we should tune the output to
-distinguish core item sets from non core:
-
-       state 0
-           Core:
-           $axiom  ->  . input $   (rule 0)
-
-           Derived:
-           input  ->  . exp   (rule 1)
-           input  ->  . input exp   (rule 2)
-           exp  ->  . token1 "1"   (rule 3)
-           exp  ->  . token2 "2"   (rule 4)
-           exp  ->  . token3 "3"   (rule 5)
-           token1  ->  . token   (rule 6)
-           token2  ->  . token   (rule 7)
-           token3  ->  . token   (rule 8)
-
-           token       shift, and go to state 1
-
-           input       go to state 2
-           exp         go to state 3
-           token1      go to state 4
-           token2      go to state 5
-           token3      go to state 6
-
-
-> So, it seems clear that it has to be an additional option :)
-
-Paul:
-
-       There will be further such options in the future, so I'd make
-       them all operands of the --report option.  E.g., you could do
-       something like this:
+* --report=conflict-path
+Provide better assistance for understanding the conflicts by providing
+a sample text exhibiting the (LALR) ambiguity.
 
-       --report=state --report=lookahead --report=itemset
-       --report=conflict-path
+* report
+Solved conflicts should not be reported in the beginning of the file.
+Rather they should be reported within each state description.  Also,
+now that the symbol providing the precedence of a rule is kept, it is
+possible to explain why a conflict was solved this way.  E.g., instead
+of
 
-       where "--verbose" is equivalent to "--report=state", and where
-       "--report=conflict-path" reports each path to a conflict
-       state.
+   Conflict in state 8 between rule 2 and token '+' resolved as reduce.
 
-       (As a minor point, I prefer avoiding plurals in option names.
-       It's partly for brevity, and partly to avoid wearing out the
-       's' keys in our keyboards.  :-)
+we can (in state 8) report something like
 
-To implement this, see in the Fileutils the latest versions of
-argmatch and so forth.
+   Conflict between rule 2 and token '+' resolved as reduce
+   because '*' < '+'.
 
+or something like that.
 
 * Coding system independence
 Paul notes:
Index: doc/bison.texinfo
--- doc/bison.texinfo Thu, 02 May 2002 19:30:29 +0200 akim
+++ doc/bison.texinfo Sat, 25 May 2002 16:49:50 +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::         Understanding 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.
 
+Understanding 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{Understanding, , 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,414 @@ 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
+representation of it, either textually or graphically (as a @sc{vcg}
+file).
+
+The textual file is generated when the options @option{--report} or
address@hidden are specified, see @xref{Invocation, , Invoking
+Bison}.  Its 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
+
address@hidden 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
address@hidden, it creates a file @file{calc.output} with contents
+detailed below.  The order of the output and the exact presentation
+might vary, but the interpretation is the same.
+
+The first section includes details on conflicts that 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
+The next section lists states that still have conflicts.
+
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
address@hidden token, useless
address@hidden useless token
address@hidden nonterminal, useless
address@hidden useless nonterminal
address@hidden rule, useless
address@hidden useless rule
+The next section reports useless tokens, nonterminal and rules.  Useless
+nonterminals and rules are 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 next section reproduces the exact grammar that Bison used:
+
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 reports the uses of the symbols:
+
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 @dfn{pointed rules}.  Each
+item is a production rule together with a point (marked by @samp{.})
+that the input cursor.
+
address@hidden
+state 0
+
+    $axiom  ->  . exp $   (rule 0)
+
+    NUM        shift, and go to state 1
+
+    exp        go to state 2
address@hidden example
+
+This reads as follows: ``state 0 corresponds to being at the very
+beginning of the parsing, in the initial rule, right before the start
+symbol (here, @code{exp}).  When the parser returns to this state right
+after having reduced a rule that produced an @code{exp}, the control
+flow jumps to state 2.  If there is no such transition on a nonterminal
+symbol, and the lookahead is a @code{NUM}, then this token is shifted on
+the parse stack, and the control flow jumps to state 1.  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
+Even though the only active rule in state 0 seems to be rule 0, the
+report lists @code{NUM} as a lookahead symbol because @code{NUM} can be
+at the beginning of any rule deriving an @code{exp}.  By default Bison
+reports the so-called @dfn{core} or @dfn{kernel} of the item set, but if
+you want to see more detail you can invoke @command{bison} with
address@hidden to list all the items, include 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
+In state 2, the automaton can only shift a symbol.  For instance,
+because of the item @samp{exp -> exp . '+' exp}, if the lookahead if
address@hidden, it will be shifted on the parse stack, and the automaton
+control will jump to state 4, corresponding to the item @samp{exp -> exp
+'+' . exp}.  Since there is no default action, any other token than
+those listed above will trigger a parse error.
+
+The state 3 is named the @dfn{final state}, or the @dfn{accepting
+state}:
+
address@hidden
+state 3
+
+    $axiom  ->  exp $ .   (rule 0)
+
+    $default   accept
address@hidden example
+
address@hidden
+the initial rule is completed (the start symbol and the end
+of input were read), the parsing exits successfully.
+
+The interpretation of states 4 to 7 is straightforward, and is left to
+the reader.
+
address@hidden
+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
address@hidden example
+
+As was announced in beginning of the report, @samp{State 8 contains 1
+shift/reduce conflict}:
+
address@hidden
+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)
address@hidden example
+
+Indeed, there are two actions associated to the lookahead @samp{/}:
+either shifting (and going to state 7), or reducing rule 1.  The
+conflict means that either the grammar is ambiguous, or the parser lacks
+information to make the right decision.  Indeed the grammar is
+ambiguous, as, since we did not specify the precedence of @samp{/}, the
+sentence @samp{NUM + NUM / NUM} can be parsed as @samp{NUM + (NUM /
+NUM)}, which corresponds to shifting @samp{/}, or as @samp{(NUM + NUM) /
+NUM}, which corresponds to reducing rule 1.
+
+Because in LALR(1) parsing a single decision can be made, Bison
+arbitrarily chose to disable the reduction, see @ref{Shift/Reduce, ,
+Shift/Reduce Conflicts}.  Discarded actions are reported in between
+square brackets.
+
+Note that all the previous states had a single possible action: either
+shifting the next token and going to the corresponding state, or
+reducing a single rule.  In the other cases, i.e., when shifting
address@hidden reducing is possible or when @emph{several} reductions are
+possible, the lookahead is required to select the action.  State 8 is
+one such state: if the lookahead is @samp{*} or @samp{/} then the action
+is shifting, otherwise the action is reducing rule 1.  In other words,
+the first two items, corresponding to rule 1, are not eligible when the
+lookahead is @samp{*}, since we specified that @samp{*} has higher
+precedence that @samp{+}.  More generally, some items are eligible only
+with some set of possible lookaheads.  When run with
address@hidden, Bison specifies these lookaheads:
+
address@hidden
+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)
address@hidden example
+
+The remaining states are similar:
+
address@hidden
+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
+Observe that state 11 contains conflicts due to the lack of precedence
+of @samp{/} wrt @samp{+}, @samp{-}, and @samp{*}, but also because the
+associativity of @samp{/} is not specified.
+
+
address@hidden Tracing
address@hidden Tracing Your Parser
 @findex yydebug
 @cindex debugging
 @cindex tracing the parser
@@ -5059,6 +5462,8 @@ @node Debugging
 @}
 @end smallexample
 
address@hidden ================================================= Invoking Bison
+
 @node Invocation
 @chapter Invoking Bison
 @cindex invoking Bison
@@ -5158,7 +5563,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 +5609,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 +5791,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 +5856,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 Sat, 25 May 2002 16:55:11 +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_flag & report_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 Sat, 25 May 2002 17:04:06 +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 meaningful 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_states | report_itemsets, report_states | report_itemsets,
+  report_states | report_lookaheads, report_states | 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 that can include:\n\
+  `state'        describe the states\n\
+  `itemset'      complete the core item sets with their closure\n\
+  `lookahead'    explicitly associate lookaheads to items\n\
+  `all'          include 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 Sat, 25 May 2002 16:53:55 +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,21 @@
 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.  */
+enum
+  {
+    report_none = 0,
+    report_states = 1 << 0,
+    report_itemsets = 1 << 1,
+    report_lookaheads = 1 << 2,
+    report_all = ~0
+  };
+
+extern int report_flag;
 
 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 Sat, 25 May 2002 16:57:59 +0200 akim
@@ -91,7 +91,7 @@
   compute_output_file_names ();
 
   /* Output the detailed report on the grammar.  */
-  if (verbose_flag)
+  if (report_flag)
     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 Sat, 25 May 2002 17:12:02 +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_flag & report_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_flag & report_lookaheads)
            {
              int j, k;
              int nlookaheads = 0;
@@ -513,10 +512,9 @@
 
   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 the whole state item sets, not only the kernels, are wanted,
+     `closure' will be run, which needs memory allocation/deallocation.   */
+  if (report_flag & report_itemsets)
     new_closure (nritems);
   /* Storage for print_reductions.  */
   shiftset =  bitset_create (ntokens, BITSET_FIXED);
@@ -525,7 +523,7 @@
     print_state (out, states[i]);
   bitset_free (shiftset);
   bitset_free (lookaheadset);
-  if (trace_flag)
+  if (report_flag & report_itemsets)
     free_closure ();
 
   xfclose (out);
Index: lib/argmatch.h
--- lib/argmatch.h Sat, 25 May 2002 17:19:30 +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 Sat, 25 May 2002 17:19:30 +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]