]> git.saurik.com Git - bison.git/commitdiff
Extract calc++ from the documentation.
authorAkim Demaille <akim@epita.fr>
Tue, 5 Jul 2005 07:21:30 +0000 (07:21 +0000)
committerAkim Demaille <akim@epita.fr>
Tue, 5 Jul 2005 07:21:30 +0000 (07:21 +0000)
* doc/bison.texinfo (Calc++): Add the extraction marks.
* examples/extexi: New, from the aborted GNU Programming 2E.
Separate the different paragraph of a file with empty lines.
* examples/Makefile: Use it to extract the whole calc++ example.

ChangeLog
doc/bison.texinfo
examples/calc++/Makefile
examples/calc++/calc++-driver.cc
examples/calc++/calc++-driver.hh
examples/calc++/calc++-parser.yy
examples/calc++/calc++-scanner.ll
examples/calc++/calc++.cc
examples/extexi [new file with mode: 0644]

index 6d06d1d47965d480754d66455b8923b9f17da091..149ffc689e93b7568eec82f3cd537f8cae60d16e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2005-07-05  Akim Demaille  <akim@epita.fr>
+
+       Extract calc++ from the documentation.
+       * doc/bison.texinfo (Calc++): Add the extraction marks.
+       * examples/extexi: New, from the aborted GNU Programming 2E.
+       Separate the different paragraph of a file with empty lines.
+       * examples/Makefile: Use it to extract the whole calc++ example.
+
 2005-06-24  Akim Demaille  <akim@epita.fr>
 
        * doc/bison.texinfo (C++ Parser Interface): Use defcv to define
index 380bc152acabff3ef2d0be9a7cd8b0fcd83111c1..5f7b6c388b6b4287d93788541dda86df6e0d0e0e 100644 (file)
@@ -7031,6 +7031,7 @@ The declaration of this driver class, @file{calc++-driver.hh}, is as
 follows.  The first part includes the CPP guard and imports the
 required standard library components.
 
+@comment file: calc++-driver.hh
 @example
 #ifndef CALCXX_DRIVER_HH
 # define CALCXX_DRIVER_HH
@@ -7045,10 +7046,15 @@ do.  Because the driver's declaration is the one that will be imported
 by the rest of the project, it is saner to forward declare the
 parser's information here.
 
+@comment file: calc++-driver.hh
 @example
 // Forward declarations.
 union YYSTYPE;
-namespace yy @{ class calcxx_parser; @}
+namespace yy
+@{
+  class location;
+  class calcxx_parser;
+@}
 class calcxx_driver;
 @end example
 
@@ -7057,9 +7063,11 @@ Then comes the declaration of the scanning function.  Flex expects
 the signature of @code{yylex} to be defined in the macro
 @code{YY_DECL}, and the C++ parser expects it to be declared.  We can
 factor both as follows.
+
+@comment file: calc++-driver.hh
 @example
 // Announce to Flex the prototype we want for lexing function, ...
-# define YY_DECL                                               \
+# define YY_DECL                                                \
   int yylex (YYSTYPE* yylval, yy::location* yylloc, calcxx_driver& driver)
 // ... and declare it for the parser's sake.
 YY_DECL;
@@ -7069,6 +7077,7 @@ YY_DECL;
 The @code{calcxx_driver} class is then declared with its most obvious
 members.
 
+@comment file: calc++-driver.hh
 @example
 // Conducting the whole scanning and parsing of Calc++.
 class calcxx_driver
@@ -7087,6 +7096,7 @@ To encapsulate the coordination with the Flex scanner, it is useful to
 have two members function to open and close the scanning phase.
 members.
 
+@comment file: calc++-driver.hh
 @example
   // Handling the scanner.
   void scan_begin ();
@@ -7097,6 +7107,7 @@ members.
 @noindent
 Similarly for the parser itself.
 
+@comment file: calc++-driver.hh
 @example
   // Handling the parser.
   void parse (const std::string& f);
@@ -7110,6 +7121,7 @@ dumping them on the standard error output, we will pass them to the
 compiler driver using the following two member functions.  Finally, we
 close the class declaration and CPP guard.
 
+@comment file: calc++-driver.hh
 @example
   // Error handling.
   void error (const yy::location& l, const std::string& m);
@@ -7123,6 +7135,7 @@ member function deserves some attention.  The @code{error} functions
 are simple stubs, they should actually register the located error
 messages and set error state.
 
+@comment file: calc++-driver.cc
 @example
 #include "calc++-driver.hh"
 #include "calc++-parser.hh"
@@ -7169,6 +7182,8 @@ The parser definition file @file{calc++-parser.yy} starts by asking
 for the C++ skeleton, the creation of the parser header file, and
 specifies the name of the parser class.  It then includes the required
 headers.
+
+@comment file: calc++-parser.yy
 @example
 %skeleton "lalr1.cc"                          /*  -*- C++ -*- */
 %define "parser_class_name" "calcxx_parser"
@@ -7184,6 +7199,7 @@ The driver is passed by reference to the parser and to the scanner.
 This provides a simple but effective pure interface, not relying on
 global variables.
 
+@comment file: calc++-parser.yy
 @example
 // The parsing context.
 %parse-param @{ calcxx_driver& driver @}
@@ -7196,6 +7212,7 @@ first location's file name.  Afterwards new locations are computed
 relatively to the previous locations: the file name will be
 automatically propagated.
 
+@comment file: calc++-parser.yy
 @example
 %locations
 %initial-action
@@ -7209,6 +7226,7 @@ automatically propagated.
 Use the two following directives to enable parser tracing and verbose
 error messages.
 
+@comment file: calc++-parser.yy
 @example
 %debug
 %error-verbose
@@ -7218,6 +7236,7 @@ error messages.
 Semantic values cannot use ``real'' objects, but only pointers to
 them.
 
+@comment file: calc++-parser.yy
 @example
 // Symbols.
 %union
@@ -7234,6 +7253,7 @@ of ``$end''.  Similarly user friendly named are provided for each
 symbol.  Note that the tokens names are prefixed by @code{TOKEN_} to
 avoid name clashes.
 
+@comment file: calc++-parser.yy
 @example
 %token        YYEOF          0 "end of file"
 %token        TOKEN_ASSIGN     ":="
@@ -7246,6 +7266,7 @@ avoid name clashes.
 To enable memory deallocation during error recovery, use
 @code{%destructor}.
 
+@comment file: calc++-parser.yy
 @example
 %printer    @{ debug_stream () << *$$; @} "identifier"
 %destructor @{ delete $$; @} "identifier"
@@ -7256,6 +7277,7 @@ To enable memory deallocation during error recovery, use
 @noindent
 The grammar itself is straightforward.
 
+@comment file: calc++-parser.yy
 @example
 %%
 %start unit;
@@ -7281,9 +7303,11 @@ exp: exp '+' exp   @{ $$ = $1 + $3; @}
 Finally the @code{error} member function registers the errors to the
 driver.
 
+@comment file: calc++-parser.yy
 @example
 void
-yy::calcxx_parser::error (const location_type& l, const std::string& m)
+yy::calcxx_parser::error (const yy::calcxx_parser::location_type& l,
+                          const std::string& m)
 @{
   driver.error (l, m);
 @}
@@ -7295,6 +7319,7 @@ yy::calcxx_parser::error (const location_type& l, const std::string& m)
 The Flex scanner first includes the driver declaration, then the
 parser's to get the set of defined tokens.
 
+@comment file: calc++-scanner.ll
 @example
 %@{                                            /* -*- C++ -*- */
 # include <string>
@@ -7309,6 +7334,7 @@ Because there is no @code{#include}-like feature we don't need
 actual file, this is not an interactive session with the user.
 Finally we enable the scanner tracing features.
 
+@comment file: calc++-scanner.ll
 @example
 %option noyywrap nounput batch debug
 @end example
@@ -7316,6 +7342,7 @@ Finally we enable the scanner tracing features.
 @noindent
 Abbreviations allow for more readable rules.
 
+@comment file: calc++-scanner.ll
 @example
 id    [a-zA-Z][a-zA-Z_0-9]*
 int   [0-9]+
@@ -7331,6 +7358,7 @@ cursor is adjusted, and each time blanks are matched, the begin cursor
 is moved onto the end cursor to effectively ignore the blanks
 preceding tokens.  Comments would be treated equally.
 
+@comment file: calc++-scanner.ll
 @example
 %%
 %@{
@@ -7345,6 +7373,7 @@ preceding tokens.  Comments would be treated equally.
 The rules are simple, just note the use of the driver to report
 errors.
 
+@comment file: calc++-scanner.ll
 @example
 [-+*/]     return yytext[0];
 ":="       return TOKEN_ASSIGN;
@@ -7358,6 +7387,7 @@ errors.
 Finally, because the scanner related driver's member function depend
 on the scanner's data, it is simpler to implement them in this file.
 
+@comment file: calc++-scanner.ll
 @example
 void
 calcxx_driver::scan_begin ()
@@ -7379,6 +7409,7 @@ calcxx_driver::scan_end ()
 
 The top level file, @file{calc++.cc}, poses no problem.
 
+@comment file: calc++.cc
 @example
 #include <iostream>
 #include "calc++-driver.hh"
index cad628b211e82db6f30d7ee9c4d1a04749ecf99a..5a56f3d58f4c35c196fb1382bebf38e2f4602f06 100644 (file)
@@ -13,3 +13,23 @@ clean:
              calc++-parser.cc calc++-parser.hh \
              calc++-scanner.cc \
              calc++
+
+## ------------ ##
+## Extracting.  ##
+## ------------ ##
+
+EXTRACTED = \
+calc++-driver.hh calc++-driver.cc \
+calc++-parser.yy \
+calc++-scanner.ll \
+calc++.cc
+
+doc = ../../doc/bison.texinfo
+extexi = gawk -f ../extexi
+
+RECURSIVE_TARGETS += extract
+
+$(EXTRACTED): $(doc) ../extexi
+       $(extexi) $(doc) -- $(EXTRACTED)
+
+extract extract-am: $(EXTRACTED)
index 13df5294760111b8702fd3004f5c7f186ef0f22e..cfce494dad68ef6cad6bbeee04d38b24a18ae4f3 100644 (file)
@@ -1,9 +1,9 @@
+#line 7140 "../../doc/bison.texinfo"
 #include "calc++-driver.hh"
 #include "calc++-parser.hh"
 
 calcxx_driver::calcxx_driver ()
-  : trace_scanning (false),
-    trace_parsing (false)
+  : trace_scanning (false), trace_parsing (false)
 {
   variables["one"] = 1;
   variables["two"] = 2;
index 8b3ed532d39fd680743dcc78d975e680fd3413a5..fc3f5c2383ae7d74f8f90f18b561b9c7090c5313 100644 (file)
@@ -1,64 +1,47 @@
+#line 7036 "../../doc/bison.texinfo"
 #ifndef CALCXX_DRIVER_HH
 # define CALCXX_DRIVER_HH
 # include <string>
 # include <map>
-
-/// Forward declarations.
+#line 7051 "../../doc/bison.texinfo"
+// Forward declarations.
 union YYSTYPE;
-
 namespace yy
 {
-  class calcxx_parser;
   class location;
+  class calcxx_parser;
 }
-
 class calcxx_driver;
-
+#line 7069 "../../doc/bison.texinfo"
 // Announce to Flex the prototype we want for lexing function, ...
-# define YY_DECL                                               \
+# define YY_DECL                                                \
   int yylex (YYSTYPE* yylval, yy::location* yylloc, calcxx_driver& driver)
 // ... and declare it for the parser's sake.
 YY_DECL;
-
-/// Conducting the whole scanning and parsing of Calc++.
+#line 7082 "../../doc/bison.texinfo"
+// Conducting the whole scanning and parsing of Calc++.
 class calcxx_driver
 {
 public:
   calcxx_driver ();
   virtual ~calcxx_driver ();
 
-  /// The variables.
   std::map<std::string, int> variables;
 
-  /// \name Handling the scanner.
-  /// \{
-  /// Open \a file for scanning.
+  int result;
+#line 7101 "../../doc/bison.texinfo"
+  // Handling the scanner.
   void scan_begin ();
-  /// End scanning, clean up memory.
   void scan_end ();
-  /// Whether to enable scanner traces.
   bool trace_scanning;
-  /// \}
-
-  /// \name Handling the parser.
-  /// \{
-  /// Parse the file \a f.
+#line 7112 "../../doc/bison.texinfo"
+  // Handling the parser.
   void parse (const std::string& f);
-  /// The file being parsed.
   std::string file;
-  /// Whether to enable parsing traces.
   bool trace_parsing;
-  /// \}
-
-  /// The result.
-  int result;
-
-  /// \name Error handling.
-  /// \{
-  /// Register a located error.
+#line 7126 "../../doc/bison.texinfo"
+  // Error handling.
   void error (const yy::location& l, const std::string& m);
-  /// Register an error.
   void error (const std::string& m);
-  /// \}
 };
-#endif
+#endif // ! CALCXX_DRIVER_HH
index 672814349b9c489aec7bd171773d845e03bbe003..89f0a2cca9f7c639945f485ba50687119861214a 100644 (file)
@@ -1,48 +1,44 @@
-%skeleton "lalr1.cc"                                  /*  -*- C++ -*- */
+#line 7188 "../../doc/bison.texinfo"
+%skeleton "lalr1.cc"                          /*  -*- C++ -*- */
 %define "parser_class_name" "calcxx_parser"
 %defines
 %{
 # include <string>
 # include "calc++-driver.hh"
 %}
-
-%error-verbose
-
+#line 7204 "../../doc/bison.texinfo"
 // The parsing context.
 %parse-param { calcxx_driver& driver }
 %lex-param   { calcxx_driver& driver }
-
+#line 7217 "../../doc/bison.texinfo"
 %locations
 %initial-action
 {
   // Initialize the initial location.
   @$.begin.filename = @$.end.filename = &driver.file;
 };
-
-// Define yydebug.
+#line 7231 "../../doc/bison.texinfo"
 %debug
-
+%error-verbose
+#line 7241 "../../doc/bison.texinfo"
 // Symbols.
-
 %union
 {
-  /// Value of a numeric literal.
   int          ival;
-  /// Name of a variable.
   std::string *sval;
 };
-
+#line 7258 "../../doc/bison.texinfo"
 %token        YYEOF          0 "end of file"
 %token        TOKEN_ASSIGN     ":="
 %token <sval> TOKEN_IDENTIFIER "identifier"
 %token <ival> TOKEN_NUMBER     "number"
 %type  <ival> exp              "expression"
-
+#line 7271 "../../doc/bison.texinfo"
 %printer    { debug_stream () << *$$; } "identifier"
 %destructor { delete $$; } "identifier"
 
 %printer    { debug_stream () << $$; } "number" "expression"
-
+#line 7282 "../../doc/bison.texinfo"
 %%
 %start unit;
 unit: assignments exp  { driver.result = $2; };
@@ -61,8 +57,10 @@ exp: exp '+' exp   { $$ = $1 + $3; }
    | TOKEN_IDENTIFIER  { $$ = driver.variables[*$1]; }
    | TOKEN_NUMBER      { $$ = $1; };
 %%
+#line 7308 "../../doc/bison.texinfo"
 void
-yy::calcxx_parser::error (const location& l, const std::string& m)
+yy::calcxx_parser::error (const yy::calcxx_parser::location_type& l,
+                          const std::string& m)
 {
   driver.error (l, m);
 }
index dd9a8b8a9543c5c8da7fea9fa45f937a9deb1522..7b1e4ef790eef8081cb40735a8a3ffdd6285d2eb 100644 (file)
@@ -1,33 +1,28 @@
-%{                                                            /* -*- C++ -*- */
-
+%{                                            /* -*- C++ -*- */
 # include <string>
-# include <cerrno>
 # include "calc++-driver.hh"
 # include "calc++-parser.hh"
 %}
 
-%option noyywrap nounput debug batch
+%option noyywrap nounput batch debug
 
 id    [a-zA-Z][a-zA-Z_0-9]*
 int   [0-9]+
 blank [ \t]
 
 %%
-
 %{
-# define YY_USER_ACTION  yylloc->columns (yyleng);
   yylloc->step ();
+# define YY_USER_ACTION  yylloc->columns (yyleng);
 %}
 {blank}+   yylloc->step ();
 [\n]+      yylloc->lines (yyleng); yylloc->step ();
 
-
 [-+*/]     return yytext[0];
 ":="       return TOKEN_ASSIGN;
 {int}      yylval->ival = atoi (yytext); return TOKEN_NUMBER;
 {id}       yylval->sval = new std::string (yytext); return TOKEN_IDENTIFIER;
 .          driver.error (*yylloc, "invalid character");
-
 %%
 
 void
index 44e74c8033dd72516e8cb991a97958a332a1b107..92163968b228641af1a79a8300f1cf1adb5fde10 100644 (file)
@@ -1,3 +1,4 @@
+#line 7414 "../../doc/bison.texinfo"
 #include <iostream>
 #include "calc++-driver.hh"
 
diff --git a/examples/extexi b/examples/extexi
new file mode 100644 (file)
index 0000000..b7af17a
--- /dev/null
@@ -0,0 +1,133 @@
+# Extract all examples from the manual source.            -*- AWK -*-
+
+# This file is part of GNU M4
+# Copyright 1992, 2000, 2001 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307  USA
+
+# This script is for use with any New AWK.
+# Well, now it uses ARGV/ARGC, and I don't know if it's New AWK portable.
+#
+# Usage: extexi input-file.texi ... -- [FILES to extract]
+BEGIN {
+  if (!output_dir)
+    output_dir = ".";
+  for (argc = 1; argc < ARGC; ++argc)
+    if (ARGV[argc] == "--")
+      break;
+  for (i = argc + 1; i < ARGC; ++i)
+    file_wanted[ARGV[i]] = 1;
+  ARGC = argc;
+}
+
+/^@node / {
+  if (seq > 0)
+    print "AT_CLEANUP";
+
+  split ($0, tmp, ",");
+  node = substr(tmp[1], 7);
+  seq = 0;
+}
+
+/^@comment file: / {
+  if (!file_wanted[$3])
+    message("ignoring " $3);
+  else
+    {
+      message("extracting " $3);
+      file = $3;
+    }
+}
+
+/^@example$/, /^@end example$/ {
+  if (!file)
+    next;
+
+  if ($0 ~ /^@example$/)
+    {
+      input = files_output[file] ? "\n" : "";
+
+      # FNR is starting at 0 instead of 1, and
+      # #line report the line number of the *next* line.
+      # => + 2.
+      # Note that recent Bison support it, but not Flex.
+      if (file ~ /\.[chy]*$/)
+       input = "#line " (FNR + 1) " \"" FILENAME "\"\n";
+      next;
+    }
+
+  if ($0 ~ /^@end example$/)
+    {
+      if (input == "")
+       fatal("no contents: " file);
+
+      input = normalize(input);
+      # No spurious end of line: use printf.
+      if (files_output[file])
+       printf ("%s", input) >> output_dir "/" file;
+      else
+       printf ("%s", input) > output_dir "/" file;
+      close (output_dir "/" file);
+      files_output[file] = 1;
+
+      file = input = "";
+      next;
+    }
+
+  input = input $0 "\n";
+}
+
+
+# We have to handle CONTENTS line per line, since anchors in AWK are
+# referring to the whole string, not the lines.
+function normalize(contents,    i, lines, n, line, res) {
+  # Remove the Texinfo tags.
+  n = split (contents, lines, "\n");
+  # We don't want the last field which empty: it's behind the last \n.
+  for (i = 1; i < n; ++i)
+    {
+      line = lines[i];
+
+      # Whole line commands.
+      if (line ~ /^@(c |comment|dots|end (ignore|group)|ignore|group)/)
+       # Gperf accepts empty lines as valid input!!!
+       if (file ~ /\.gperf$/)
+         continue;
+       else
+         line = "";
+
+      gsub (/^@result\{\}/, "", line);
+      gsub (/^@error\{\}/,  "", line);
+      gsub ("@[{]", "{", line);
+      gsub ("@}", "}", line);
+      gsub ("@@", "@", line);
+      gsub ("@comment.*", "", line);
+
+      res = res line "\n";
+    }
+  return res;
+}
+
+
+function message(msg) {
+  # FNR starts at 0 instead of 1 for line numbers.
+  print "extexi: " FILENAME ":" (FNR + 1) ": " msg > "/dev/stderr";
+}
+
+function fatal(msg) {
+  message(msg);
+  exit 1
+}