+#include <algorithm>
+#include <iostream>
+#include <sstream>
+
+#define STAGE_MAX ($max * 10) // max = $max
+
+#define USE_TOKEN_CTOR $token_ctor
+#define USE_VARIANTS $variant
+
+ // Prototype of the yylex function providing subsequent tokens.
+ static
+#if USE_TOKEN_CTOR
+ yy::parser::symbol_type yylex();
+#else
+ yy::parser::token_type yylex(yy::parser::semantic_type* yylvalp,
+ yy::parser::location_type* yyllocp);
+#endif
+
+ // Conversion to string.
+ template <typename T>
+ inline
+ std::string
+ string_cast (const T& t)
+ {
+ std::ostringstream o;
+ o << t;
+ return o.str ();
+ }
+}
+
+%token END_OF_FILE 0
+EOF
+
+ if ($variant)
+ {
+ print $out <<'EOF';
+%token <std::string> TEXT
+%token <int> NUMBER
+%printer { std::cerr << "Number: " << $$; } <int>
+%printer { std::cerr << "Text: " << $$; } <std::string>
+%type <std::string> text result
+
+%%
+result:
+ text { /* Throw away the result. */ }
+;
+
+text:
+ /* nothing */ { /* This will generate an empty string */ }
+| text TEXT { std::swap ($$, $2); }
+| text NUMBER { $$ = string_cast($2); }
+;
+EOF
+ }
+ else
+ {
+ # Not using Bison variants.
+ print $out <<'EOF';
+%union {int ival; std::string* sval;}
+%token <sval> TEXT
+%token <ival> NUMBER
+%printer { std::cerr << "Number: " << $$; } <ival>
+%printer { std::cerr << "Text: " << *$$; } <sval>
+%type <sval> text result
+
+%%
+result:
+ text { delete $1; }
+;
+
+text:
+ /* nothing */ { $$ = new std::string; }
+| text TEXT { delete $1; $$ = $2; }
+| text NUMBER { delete $1; $$ = new std::string (string_cast ($2)); }
+;
+EOF
+ }
+
+ print $out <<'EOF';
+%%
+#
+
+static
+#if USE_TOKEN_CTOR
+yy::parser::symbol_type yylex()
+#else
+yy::parser::token_type yylex(yy::parser::semantic_type* yylvalp,
+ yy::parser::location_type* yyllocp)
+#endif
+{
+ typedef yy::parser::location_type location_type;
+ typedef yy::parser::token token;
+ static int stage = -1;
+ ++stage;
+ if (stage == STAGE_MAX)
+ {
+#if USE_TOKEN_CTOR
+ return yy::parser::make_END_OF_FILE (location_type ());
+#else
+ *yyllocp = location_type ();
+ return token::END_OF_FILE;
+#endif
+ }
+ else if (stage % 2)
+ {
+#if USE_TOKEN_CTOR
+ return yy::parser::make_NUMBER (stage, location_type ());
+#else
+# if defined ONE_STAGE_BUILD
+ yylvalp->build(stage);
+# elif USE_VARIANTS
+ yylvalp->build<int>() = stage;
+# else
+ yylvalp->ival = stage;
+# endif
+ *yyllocp = location_type ();
+ return token::NUMBER;
+#endif
+ }
+ else
+ {
+#if USE_TOKEN_CTOR
+ return yy::parser::make_TEXT ("A string.", location_type ());
+#else
+# if defined ONE_STAGE_BUILD
+ yylvalp->build(std::string("A string."));
+# elif USE_VARIANTS
+ yylvalp->build<std::string>() = std::string("A string.");
+# else
+ yylvalp->sval = new std::string("A string.");
+# endif
+ *yyllocp = location_type ();
+ return token::TEXT;
+#endif
+ }
+ abort();
+}
+
+// Mandatory error function
+void
+yy::parser::error(const yy::parser::location_type& loc, const std::string& msg)
+{
+ std::cerr << loc << ": " << msg << std::endl;
+}
+
+int main(int argc, char *argv[])
+{
+ yy::parser p;
+#if YYDEBUG
+ p.set_debug_level(!!getenv("YYDEBUG"));
+#endif
+ p.parse();
+ return 0;
+}
+EOF
+}
+
+##################################################################
+
+=item C<generate_grammar ($name, $base, @directive)>
+
+Generate F<$base.y> by calling C<&generate_grammar_$name>.
+
+=cut
+
+sub generate_grammar ($$@)
+{
+ my ($name, $base, @directive) = @_;
+ verbose 3, "Generating $base.y\n";
+ my %generator =