bison-patches
[Top][All Lists]
Advanced

[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





reply via email to

[Prev in Thread] Current Thread [Next in Thread]