8.4.1 Enabling Traces

There are several means to enable compilation of trace facilities:

the macro YYDEBUG

Define the macro YYDEBUG to a nonzero value when you compile the
parser. This is compliant with POSIX Yacc. You could use
‘-DYYDEBUG=1’ as a compiler option or you could put ‘#define
YYDEBUG 1’ in the prologue of the grammar file (see The
Prologue).

If the %define variable api.prefix is used (see Multiple Parsers in the Same Program), for instance ‘%define
api.prefix x’, then if CDEBUG is defined, its value controls the
tracing feature (enabled if and only if nonzero); otherwise tracing is
enabled if and only if YYDEBUG is nonzero.

the option -t (POSIX Yacc compliant)

the option --debug (Bison extension)

Use the ‘-t’ option when you run Bison (see Invoking
Bison). With ‘%define api.prefix {c}’, it defines CDEBUG to 1,
otherwise it defines YYDEBUG to 1.

Add the ‘%define parse.trace’ directive (see parse.trace), or pass the -Dparse.trace option
(see Bison Options). This is a Bison extension, which is especially
useful for languages that don’t use a preprocessor. Unless POSIX and Yacc
portability matter to you, this is the preferred solution.

We suggest that you always enable the trace option 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 variadic
arguments. If you define YYDEBUG to a nonzero value but do not
define YYFPRINTF, <stdio.h> is automatically included
and YYFPRINTF 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:

Each time the parser calls yylex, what kind of token was read.

Each time a token is shifted, the depth and complete contents of the
state stack (see Parser States).

Each time a rule is reduced, which rule it is, and the complete contents
of the state stack afterward.

To make sense of this information, it helps to refer to the automaton
description file (see Understanding Your Parser).
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 implementation file is a C/C++/Java program and you can use
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.