[Top][All Lists]
[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
- --report,
Akim Demaille <=