Node:Debugging, Next:Invocation, Previous:Context Dependency, Up:Top
If a Bison grammar compiles properly but doesn't do what you want when it
runs, the yydebug
parser-trace feature can help you figure out why.
To enable compilation of trace facilities, you must define the macro
YYDEBUG
to a nonzero value when you compile the parser. You
could use -DYYDEBUG=1
as a compiler option or you could put
#define YYDEBUG 1
in the C declarations section of the grammar
file (see The C Declarations Section).
Alternatively, use the -t
option when you run Bison
(see Invoking Bison) or the %debug
declaration
(see Bison Declaration Summary). We suggest that
you always define YYDEBUG
so that debugging is always possible.
The trace facility outputs messages with macro calls of the form
YYFPRINTF (stderr, format, args)
where
format and args are the usual printf
format and
arguments. If you define YYDEBUG
to a nonzero value but do not
define YYFPRINTF
, <stdio.h>
is automatically included
and YYPRINTF
is defined to fprintf
.
Once you have compiled the program with trace facilities, the way to
request a trace is to store a nonzero value in the variable yydebug
.
You can do this by making the C code do it (in main
, perhaps), or
you can alter the value with a C debugger.
Each step taken by the parser when yydebug
is nonzero produces a
line or two of trace information, written on stderr
. The trace
messages tell you these things:
yylex
, what kind of token was read.
To make sense of this information, it helps to refer to the listing file
produced by the Bison -v
option (see Invoking Bison). This file
shows the meaning of each state in terms of positions in various rules, and
also what each state will do with each possible input token. As you read
the successive trace messages, you can see that the parser is functioning
according to its specification in the listing file. Eventually you will
arrive at the place where something undesirable happens, and you will see
which parts of the grammar are to blame.
The parser file is a C program and you can use C debuggers on it, but it's not easy to interpret what it is doing. The parser function is a finite-state machine interpreter, and aside from the actions it executes the same code over and over. Only the values of variables show where in the grammar it is working.
The debugging information normally gives the token type of each token
read, but not its semantic value. You can optionally define a macro
named YYPRINT
to provide a way to print the value. If you define
YYPRINT
, it should take three arguments. The parser will pass a
standard I/O stream, the numeric code for the token type, and the token
value (from yylval
).
Here is an example of YYPRINT
suitable for the multi-function
calculator (see Declarations for mfcalc
):
#define YYPRINT(file, type, value) yyprint (file, type, value) static void yyprint (FILE *file, int type, YYSTYPE value) { if (type == VAR) fprintf (file, " %s", value.tptr->name); else if (type == NUM) fprintf (file, " %d", value.val); }