]> 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
 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.
 
 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
 @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.
 
 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;
 @example
 // Forward declarations.
 union YYSTYPE;
-namespace yy @{ class calcxx_parser; @}
+namespace yy
+@{
+  class location;
+  class calcxx_parser;
+@}
 class calcxx_driver;
 @end example
 
 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.
 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, ...
 @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;
   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.
 
 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
 @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.
 
 have two members function to open and close the scanning phase.
 members.
 
+@comment file: calc++-driver.hh
 @example
   // Handling the scanner.
   void scan_begin ();
 @example
   // Handling the scanner.
   void scan_begin ();
@@ -7097,6 +7107,7 @@ members.
 @noindent
 Similarly for the parser itself.
 
 @noindent
 Similarly for the parser itself.
 
+@comment file: calc++-driver.hh
 @example
   // Handling the parser.
   void parse (const std::string& f);
 @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.
 
 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);
 @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.
 
 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"
 @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.
 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"
 @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.
 
 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 @}
 @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.
 
 relatively to the previous locations: the file name will be
 automatically propagated.
 
+@comment file: calc++-parser.yy
 @example
 %locations
 %initial-action
 @example
 %locations
 %initial-action
@@ -7209,6 +7226,7 @@ automatically propagated.
 Use the two following directives to enable parser tracing and verbose
 error messages.
 
 Use the two following directives to enable parser tracing and verbose
 error messages.
 
+@comment file: calc++-parser.yy
 @example
 %debug
 %error-verbose
 @example
 %debug
 %error-verbose
@@ -7218,6 +7236,7 @@ error messages.
 Semantic values cannot use ``real'' objects, but only pointers to
 them.
 
 Semantic values cannot use ``real'' objects, but only pointers to
 them.
 
+@comment file: calc++-parser.yy
 @example
 // Symbols.
 %union
 @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.
 
 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     ":="
 @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}.
 
 To enable memory deallocation during error recovery, use
 @code{%destructor}.
 
+@comment file: calc++-parser.yy
 @example
 %printer    @{ debug_stream () << *$$; @} "identifier"
 %destructor @{ delete $$; @} "identifier"
 @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.
 
 @noindent
 The grammar itself is straightforward.
 
+@comment file: calc++-parser.yy
 @example
 %%
 %start unit;
 @example
 %%
 %start unit;
@@ -7281,9 +7303,11 @@ exp: exp '+' exp   @{ $$ = $1 + $3; @}
 Finally the @code{error} member function registers the errors to the
 driver.
 
 Finally the @code{error} member function registers the errors to the
 driver.
 
+@comment file: calc++-parser.yy
 @example
 void
 @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);
 @}
 @{
   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.
 
 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>
 @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.
 
 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
 @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.
 
 @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]+
 @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.
 
 is moved onto the end cursor to effectively ignore the blanks
 preceding tokens.  Comments would be treated equally.
 
+@comment file: calc++-scanner.ll
 @example
 %%
 %@{
 @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.
 
 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;
 @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.
 
 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 ()
 @example
 void
 calcxx_driver::scan_begin ()
@@ -7379,6 +7409,7 @@ calcxx_driver::scan_end ()
 
 The top level file, @file{calc++.cc}, poses no problem.
 
 
 The top level file, @file{calc++.cc}, poses no problem.
 
+@comment file: calc++.cc
 @example
 #include <iostream>
 #include "calc++-driver.hh"
 @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++
              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 ()
 #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;
 {
   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>
 #ifndef CALCXX_DRIVER_HH
 # define CALCXX_DRIVER_HH
 # include <string>
 # include <map>
-
-/// Forward declarations.
+#line 7051 "../../doc/bison.texinfo"
+// Forward declarations.
 union YYSTYPE;
 union YYSTYPE;
-
 namespace yy
 {
 namespace yy
 {
-  class calcxx_parser;
   class location;
   class location;
+  class calcxx_parser;
 }
 }
-
 class calcxx_driver;
 class calcxx_driver;
-
+#line 7069 "../../doc/bison.texinfo"
 // Announce to Flex the prototype we want for lexing function, ...
 // 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;
   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 ();
 
 class calcxx_driver
 {
 public:
   calcxx_driver ();
   virtual ~calcxx_driver ();
 
-  /// The variables.
   std::map<std::string, int> 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 ();
   void scan_begin ();
-  /// End scanning, clean up memory.
   void scan_end ();
   void scan_end ();
-  /// Whether to enable scanner traces.
   bool trace_scanning;
   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);
   void parse (const std::string& f);
-  /// The file being parsed.
   std::string file;
   std::string file;
-  /// Whether to enable parsing traces.
   bool trace_parsing;
   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);
   void error (const yy::location& l, const std::string& m);
-  /// Register an error.
   void error (const std::string& m);
   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"
 %}
 %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 }
 // 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;
 };
 %locations
 %initial-action
 {
   // Initialize the initial location.
   @$.begin.filename = @$.end.filename = &driver.file;
 };
-
-// Define yydebug.
+#line 7231 "../../doc/bison.texinfo"
 %debug
 %debug
-
+%error-verbose
+#line 7241 "../../doc/bison.texinfo"
 // Symbols.
 // Symbols.
-
 %union
 {
 %union
 {
-  /// Value of a numeric literal.
   int          ival;
   int          ival;
-  /// Name of a variable.
   std::string *sval;
 };
   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"
 %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"
 %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; };
 %%
 %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; };
 %%
    | TOKEN_IDENTIFIER  { $$ = driver.variables[*$1]; }
    | TOKEN_NUMBER      { $$ = $1; };
 %%
+#line 7308 "../../doc/bison.texinfo"
 void
 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);
 }
 {
   driver.error (l, m);
 }
index dd9a8b8a9543c5c8da7fea9fa45f937a9deb1522..7b1e4ef790eef8081cb40735a8a3ffdd6285d2eb 100644 (file)
@@ -1,33 +1,28 @@
-%{                                                            /* -*- C++ -*- */
-
+%{                                            /* -*- C++ -*- */
 # include <string>
 # include <string>
-# include <cerrno>
 # include "calc++-driver.hh"
 # include "calc++-parser.hh"
 %}
 
 # 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]
 
 %%
 
 id    [a-zA-Z][a-zA-Z_0-9]*
 int   [0-9]+
 blank [ \t]
 
 %%
-
 %{
 %{
-# define YY_USER_ACTION  yylloc->columns (yyleng);
   yylloc->step ();
   yylloc->step ();
+# define YY_USER_ACTION  yylloc->columns (yyleng);
 %}
 {blank}+   yylloc->step ();
 [\n]+      yylloc->lines (yyleng); yylloc->step ();
 
 %}
 {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");
 [-+*/]     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
 %%
 
 void
index 44e74c8033dd72516e8cb991a97958a332a1b107..92163968b228641af1a79a8300f1cf1adb5fde10 100644 (file)
@@ -1,3 +1,4 @@
+#line 7414 "../../doc/bison.texinfo"
 #include <iostream>
 #include "calc++-driver.hh"
 
 #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
+}