Previous: Enabling Traces, Up: Tracing Your Parser [Contents][Index]
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]