[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
doc: mfcalc: demonstrate %printer
From: |
Akim Demaille |
Subject: |
doc: mfcalc: demonstrate %printer |
Date: |
Thu, 15 Mar 2012 17:27:06 +0100 |
This is a first stab at documenting %printer. I tend to
think this should be demonstrated in the sections about
mfcalc, as it is good practice, but maybe I should move
all this in the "Debugging Your Parser" chapter. Even
if I still rely on mfcalc to demonstrate the feature.
I still have to document %printer more formally, as
%destructor is.
But then again, I'm not sure where. Should it be next
to %destructor, in "Bison Declarations", or be where YYPRINT
used to be documented, i.e., the "Debugging Your Parser" chapter.
I like the first option, because after all that section
(Bison Declarations) is more or less structured as a
genuine file would be, but on the other hand, documenting
into "Understanding" groups related things together.
This is for master, but if easy to back port, I will include
it in maint. And then I think I am done with maint, so
we could start the release process for 2.5.1.
From e4dcd86fc36dac8e77eedb05f33e9a997e11abfe Mon Sep 17 00:00:00 2001
From: Akim Demaille <address@hidden>
Date: Thu, 15 Mar 2012 16:16:26 +0100
Subject: [PATCH 6/6] doc: mfcalc: demonstrate %printer.
* doc/bison.texinfo (Mfcalc Traces): New.
---
doc/bison.texinfo | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 177 insertions(+), 8 deletions(-)
diff --git a/doc/bison.texinfo b/doc/bison.texinfo
index 3f4687d..91fc358 100644
--- a/doc/bison.texinfo
+++ b/doc/bison.texinfo
@@ -176,6 +176,7 @@ Location Tracking Calculator: @code{ltcalc}
Multi-Function Calculator: @code{mfcalc}
* Mfcalc Declarations:: Bison declarations for multi-function calculator.
+* Mfcalc Traces:: Run-time debug traces.
* Mfcalc Rules:: Grammar rules for the calculator.
* Mfcalc Symbol Table:: Symbol table management subroutines.
* Mfcalc Lexer:: The lexical analyzer.
@@ -2351,6 +2352,7 @@ Note that multiple assignment and nested function calls
are permitted.
@menu
* Mfcalc Declarations:: Bison declarations for multi-function calculator.
+* Mfcalc Traces:: Run-time debug traces.
* Mfcalc Rules:: Grammar rules for the calculator.
* Mfcalc Symbol Table:: Symbol table management subroutines.
* Mfcalc Lexer:: The lexical analyzer.
@@ -2373,6 +2375,7 @@ Here are the C and Bison declarations for the
multi-function calculator.
void yyerror (char const *);
address@hidden
@end group
+
@group
%union @{
double val; /* For returning numbers. */
@@ -2380,7 +2383,7 @@ Here are the C and Bison declarations for the
multi-function calculator.
@}
@end group
%token <val> NUM /* Simple double precision number. */
-%token <tptr> VAR FNCT /* Variable and Function. */
+%token <tptr> VAR FNCT /* Variable and function. */
%type <val> exp
@group
@@ -2390,7 +2393,6 @@ Here are the C and Bison declarations for the
multi-function calculator.
%precedence NEG /* negation--unary minus */
%right '^' /* exponentiation */
@end group
-%% /* The grammar follows. */
@end example
The above grammar introduces only two new features of the Bison language.
@@ -2415,6 +2417,166 @@ normally declared implicitly by the rules that define
them. But
@code{exp} must be declared explicitly so we can specify its value type.
@xref{Type Decl, ,Nonterminal Symbols}.
address@hidden Mfcalc Traces
address@hidden Enabling Debug Traces for @code{mfcalc}
+
+In addition, in order to support run-time traces, the prologue is extend
+with:
address@hidden file: mfcalc.y
address@hidden
+/* Generate the parser description file. */
+%verbose
+/* Enable run-time traces (yydebug). */
+%define parse.trace
+
+/* Formatting semantic values. */
+%printer @{ fprintf (yyoutput, "%s", $$->name); @} VAR;
+%printer @{ fprintf (yyoutput, "%s()", $$->name); @} FNCT;
+%printer @{ fprintf (yyoutput, "%g", $$); @} <val>;
address@hidden example
+
+The @code{%define} directive will instruct Bison to generate run-time trace
+support. Then, activation of these traces is controlled at run-time by the
address@hidden 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 that parser; this is the purpose of (admittedly ill-named)
address@hidden directive.
+
+The set of @code{%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., @code{VAR} or @code{FNCT}), or on the type
+tag: since @code{<val>} is the type for both @code{NUM} and @code{exp}, this
+printer will be used for them.
+
+Anticipating the completion of the sources of this example, here is a sample
+of the information provided by run-time traces. The function @code{main} is
+modified so that option @option{-p} activates the generated tracing code.
+The traces are sent onto the standard error.
+
address@hidden
+$ @kbd{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
address@hidden example
+
address@hidden
+This first batch shows a specific feature of this grammar: the first rule
+(which is in line 34 of @file{mfcalc.y} can be reduced without even having
+to look for the first token. The resulting left-hand symbol (@code{$$}) is
+a valueless (@samp{()}) @code{input} non terminal (@code{nterm}).
+
+Then the parser calls the scanner.
address@hidden
+Reading a token: Next token is token FNCT (sin())
+Shifting token FNCT (sin())
+Entering state 6
address@hidden example
+
address@hidden
+That token (@code{token}) is a function (@code{FNCT}) whose value is
address@hidden as formatted per our @code{%printer} specification: @samp{sin()}.
+The parser stores (@code{Shifting}) that token, and others, until it can do
+something about it.
+
address@hidden
+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
address@hidden example
+
address@hidden
+The previous reduction demonstrates the @code{%printer} directive for
address@hidden<val>}: both the token @code{NUM} and the resulting non-terminal
address@hidden have @samp{1} as value.
+
address@hidden
+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
address@hidden example
+
address@hidden
+The rule for the subtraction was just reduced. The parser is about to
+discover the end of the call to @code{sin}.
+
address@hidden
+Next token is token ')' ()
+Shifting token ')' ()
+Entering state 31
+Reducing stack by rule 9 (line 47):
+ $1 = token FNCT (sin())
+ $2 = token '(' ()
+ $3 = nterm exp (0.000000)
+ $4 = token ')' ()
+-> $$ = nterm exp (0.000000)
+Stack now 0 1
+Entering state 11
address@hidden example
+
address@hidden
+Finally, the end-of-line allow the parser to complete the computation, and
+display its result.
+
address@hidden
+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' ()
address@hidden 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
address@hidden example
+
+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.
+
address@hidden
+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 ()
address@hidden example
+
@node Mfcalc Rules
@subsection Grammar Rules for @code{mfcalc}
@@ -2424,6 +2586,7 @@ those which mention @code{VAR} or @code{FNCT}, are new.
@comment file: mfcalc.y
@example
+%% /* The grammar follows. */
@group
input: /* empty */
| input line
@@ -2696,7 +2859,8 @@ yylex (void)
@subsection The @code{mfcalc} Main
The error reporting function is unchanged, and the new version of
address@hidden includes a call to @code{init_table}:
address@hidden includes a call to @code{init_table} and sets the @code{yydebug}
+on user demand:
@comment file: mfcalc.y
@smallexample
@@ -2714,6 +2878,11 @@ yyerror (char const *s)
int
main (int argc, char const* argv[])
@{
+ int i;
+ /* Enable parse traces on option -p. */
+ for (i = 1; i < argc; ++i)
+ if (!strcmp(argv[i], "-p"))
+ yydebug = 1;
init_table ();
return yyparse ();
@}
@@ -10052,7 +10221,7 @@ void
calcxx_driver::scan_begin ()
@{
yy_flex_debug = trace_scanning;
- if (file == "-")
+ if (file.empty () || file == "-")
yyin = stdin;
else if (!(yyin = fopen (file.c_str (), "r")))
@{
@@ -10087,12 +10256,12 @@ main (int argc, char *argv[])
@{
int res = 0;
calcxx_driver driver;
- for (++argv; argv[0]; ++argv)
- if (*argv == std::string ("-p"))
+ for (int i = 1; i < argc; ++i)
+ if (argv[i] == std::string ("-p"))
driver.trace_parsing = true;
- else if (*argv == std::string ("-s"))
+ else if (argv[i] == std::string ("-s"))
driver.trace_scanning = true;
- else if (!driver.parse (*argv))
+ else if (!driver.parse (argv[i]))
std::cout << driver.result << std::endl;
else
res = 1;
--
1.7.9.2
- doc: mfcalc: demonstrate %printer,
Akim Demaille <=