Previous: , Up: Tracing Your Parser   [Contents][Index]


8.5.2 Enabling Debug Traces for mfcalc

The debugging information normally gives the token kind of each token read, but not its semantic value. The %printer directive allows specify how semantic values are reported, see Printing Semantic Values.

As a demonstration of %printer, consider the multi-function calculator, mfcalc (see Multi-Function Calculator: mfcalc). To enable run-time traces, and semantic value reports, insert the following directives in its prologue:

/* Generate the parser description file. */
%verbose
/* Enable run-time traces (yydebug). */
%define parse.trace

/* Formatting semantic values. */
%printer { fprintf (yyo, "%s", $$->name); } VAR;
%printer { fprintf (yyo, "%s()", $$->name); } FUN;
%printer { fprintf (yyo, "%g", $$); } <double>;

The %define directive instructs Bison to generate run-time trace support. Then, activation of these traces is controlled at run-time by the yydebug variable, which is disabled by default. Because these traces will refer to the “states” of the parser, it is helpful to ask for the creation of a description of that parser; this is the purpose of (admittedly ill-named) %verbose directive.

The set of %printer directives demonstrates how to format the semantic value in the traces. Note that the specification can be done either on the symbol type (e.g., VAR or FUN), or on the type tag: since <double> is the type for both NUM and exp, this printer will be used for them.

Here is a sample of the information provided by run-time traces. The traces are sent onto standard error.

$ echo 'sin(1-1)' | ./mfcalc -p
Starting parse
Entering state 0
Reducing stack by rule 1 (line 34):
-> $$ = nterm input ()
Stack now 0
Entering state 1

This first batch shows a specific feature of this grammar: the first rule (which is in line 34 of mfcalc.y can be reduced without even having to look for the first token. The resulting left-hand symbol ($$) is a valueless (‘()’) input nonterminal (nterm).

Then the parser calls the scanner.

Reading a token
Next token is token FUN (sin())
Shifting token FUN (sin())
Entering state 6

That token (token) is a function (FUN) whose value is ‘sin’ as formatted per our %printer specification: ‘sin()’. The parser stores (Shifting) that token, and others, until it can do something about it.

Reading a token
Next token is token '(' ()
Shifting token '(' ()
Entering state 14
Reading a token
Next token is token NUM (1.000000)
Shifting token NUM (1.000000)
Entering state 4
Reducing stack by rule 6 (line 44):
   $1 = token NUM (1.000000)
-> $$ = nterm exp (1.000000)
Stack now 0 1 6 14
Entering state 24

The previous reduction demonstrates the %printer directive for <double>: both the token NUM and the resulting nonterminal exp have ‘1’ as value.

Reading a token
Next token is token '-' ()
Shifting token '-' ()
Entering state 17
Reading a token
Next token is token NUM (1.000000)
Shifting token NUM (1.000000)
Entering state 4
Reducing stack by rule 6 (line 44):
   $1 = token NUM (1.000000)
-> $$ = nterm exp (1.000000)
Stack now 0 1 6 14 24 17
Entering state 26
Reading a token
Next token is token ')' ()
Reducing stack by rule 11 (line 49):
   $1 = nterm exp (1.000000)
   $2 = token '-' ()
   $3 = nterm exp (1.000000)
-> $$ = nterm exp (0.000000)
Stack now 0 1 6 14
Entering state 24

The rule for the subtraction was just reduced. The parser is about to discover the end of the call to sin.

Next token is token ')' ()
Shifting token ')' ()
Entering state 31
Reducing stack by rule 9 (line 47):
   $1 = token FUN (sin())
   $2 = token '(' ()
   $3 = nterm exp (0.000000)
   $4 = token ')' ()
-> $$ = nterm exp (0.000000)
Stack now 0 1
Entering state 11

Finally, the end-of-line allow the parser to complete the computation, and display its result.

Reading a token
Next token is token '\n' ()
Shifting token '\n' ()
Entering state 22
Reducing stack by rule 4 (line 40):
   $1 = nterm exp (0.000000)
   $2 = token '\n' ()
⇒ 0
-> $$ = nterm line ()
Stack now 0 1
Entering state 10
Reducing stack by rule 2 (line 35):
   $1 = nterm input ()
   $2 = nterm line ()
-> $$ = nterm input ()
Stack now 0
Entering state 1

The parser has returned into state 1, in which it is waiting for the next expression to evaluate, or for the end-of-file token, which causes the completion of the parsing.

Reading a token
Now at end of input.
Shifting token $end ()
Entering state 2
Stack now 0 1 2
Cleanup: popping token $end ()
Cleanup: popping nterm input ()

Previous: Enabling Traces, Up: Tracing Your Parser   [Contents][Index]