util/qlalr/cppgenerator.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the utils of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 
       
    43 #include <QtCore/QtCore>
       
    44 
       
    45 #include "cppgenerator.h"
       
    46 #include "lalr.h"
       
    47 #include "recognizer.h"
       
    48 
       
    49 QString CppGenerator::copyrightHeader() const
       
    50 {
       
    51   return QLatin1String(
       
    52     "/****************************************************************************\n"
       
    53     "**\n"
       
    54     "** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).\n"
       
    55     "** All rights reserved.\n"
       
    56     "** Contact: Nokia Corporation (qt-info@nokia.com)\n"
       
    57     "**\n"
       
    58     "** This file is part of the QtCore module of the Qt Toolkit.\n"
       
    59     "**\n"
       
    60     "** $QT_BEGIN_LICENSE:LGPL$\n"
       
    61     "** No Commercial Usage\n"
       
    62     "** This file contains pre-release code and may not be distributed.\n"
       
    63     "** You may use this file in accordance with the terms and conditions\n"
       
    64     "** contained in the Technology Preview License Agreement accompanying\n"
       
    65     "** this package.\n"
       
    66     "**\n"
       
    67     "** GNU Lesser General Public License Usage\n"
       
    68     "** Alternatively, this file may be used under the terms of the GNU Lesser\n"
       
    69     "** General Public License version 2.1 as published by the Free Software\n"
       
    70     "** Foundation and appearing in the file LICENSE.LGPL included in the\n"
       
    71     "** packaging of this file.  Please review the following information to\n"
       
    72     "** ensure the GNU Lesser General Public License version 2.1 requirements\n"
       
    73     "** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.\n"
       
    74     "**\n"
       
    75     "** In addition, as a special exception, Nokia gives you certain additional\n"
       
    76     "** rights.  These rights are described in the Nokia Qt LGPL Exception\n"
       
    77     "** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.\n"
       
    78     "**\n"
       
    79     "** If you have questions regarding the use of this file, please contact\n"
       
    80     "** Nokia at qt-info@nokia.com.\n"
       
    81     "**\n"
       
    82     "**\n"
       
    83     "**\n"
       
    84     "**\n"
       
    85     "**\n"
       
    86     "**\n"
       
    87     "**\n"
       
    88     "**\n"
       
    89     "** $QT_END_LICENSE$\n"
       
    90     "**\n"
       
    91     "****************************************************************************/\n"
       
    92     "\n");
       
    93 }
       
    94 
       
    95 QString CppGenerator::privateCopyrightHeader() const
       
    96 {
       
    97   return QLatin1String(
       
    98     "//\n"
       
    99     "//  W A R N I N G\n"
       
   100     "//  -------------\n"
       
   101     "//\n"
       
   102     "// This file is not part of the Qt API.  It exists for the convenience\n"
       
   103     "// of other Qt classes.  This header file may change from version to\n"
       
   104     "// version without notice, or even be removed.\n"
       
   105     "//\n"
       
   106     "// We mean it.\n"
       
   107     "//\n");
       
   108 }
       
   109 
       
   110 QString CppGenerator::startIncludeGuard(const QString &fileName)
       
   111 {
       
   112     const QString normalized(QString(fileName).replace(QLatin1Char('.'), QLatin1Char('_')).toUpper());
       
   113 
       
   114     return QString::fromLatin1("#ifndef %1\n"
       
   115                                "#define %2\n").arg(normalized, normalized);
       
   116 }
       
   117 
       
   118 QString CppGenerator::endIncludeGuard(const QString &fileName)
       
   119 {
       
   120     const QString normalized(QString(fileName).replace(QLatin1Char('.'), QLatin1Char('_')).toUpper());
       
   121 
       
   122     return QString::fromLatin1("#endif // %1\n").arg(normalized);
       
   123 }
       
   124 
       
   125 void CppGenerator::operator () ()
       
   126 {
       
   127   // action table...
       
   128   state_count = aut.states.size ();
       
   129   terminal_count = grammar.terminals.size ();
       
   130   non_terminal_count = grammar.non_terminals.size ();
       
   131 
       
   132 #define ACTION(i, j) table [(i) * terminal_count + (j)]
       
   133 #define GOTO(i, j) pgoto [(i) * non_terminal_count + (j)]
       
   134 
       
   135   int *table = new int [state_count * terminal_count];
       
   136   ::memset (table, 0, state_count * terminal_count * sizeof (int));
       
   137 
       
   138   int *pgoto = new int [state_count * non_terminal_count];
       
   139   ::memset (pgoto, 0, state_count * non_terminal_count * sizeof (int));
       
   140 
       
   141   accept_state = -1;
       
   142   int shift_reduce_conflict_count = 0;
       
   143   int reduce_reduce_conflict_count = 0;
       
   144 
       
   145   for (StatePointer state = aut.states.begin (); state != aut.states.end (); ++state)
       
   146     {
       
   147       int q = aut.id (state);
       
   148 
       
   149       for (Bundle::iterator a = state->bundle.begin (); a != state->bundle.end (); ++a)
       
   150         {
       
   151           int symbol = aut.id (a.key ());
       
   152           int r = aut.id (a.value ());
       
   153 
       
   154           Q_ASSERT (r < state_count);
       
   155 
       
   156           if (grammar.isNonTerminal (a.key ()))
       
   157             {
       
   158               Q_ASSERT (symbol >= terminal_count && symbol < grammar.names.size ());
       
   159               GOTO (q, symbol - terminal_count) = r;
       
   160             }
       
   161 
       
   162           else
       
   163             ACTION (q, symbol) = r;
       
   164         }
       
   165 
       
   166       for (ItemPointer item = state->closure.begin (); item != state->closure.end (); ++item)
       
   167         {
       
   168           if (item->dot != item->end_rhs ())
       
   169             continue;
       
   170 
       
   171           int r = aut.id (item->rule);
       
   172 
       
   173           NameSet lookaheads = aut.lookaheads.value (item);
       
   174 
       
   175           if (item->rule == grammar.goal)
       
   176             accept_state = q;
       
   177 
       
   178           foreach (Name s, lookaheads)
       
   179             {
       
   180               int &u = ACTION (q, aut.id (s));
       
   181 
       
   182               if (u == 0)
       
   183                 u = - r;
       
   184 
       
   185               else if (u < 0)
       
   186                 {
       
   187                   if (verbose)
       
   188                     qout << "*** Warning. Found a reduce/reduce conflict in state " << q << " on token ``" << s << "'' between rule "
       
   189                          << r << " and " << -u << endl;
       
   190 
       
   191                   ++reduce_reduce_conflict_count;
       
   192 
       
   193                   u = qMax (u, -r);
       
   194 
       
   195                   if (verbose)
       
   196                     qout << "\tresolved using rule " << -u << endl;
       
   197                 }
       
   198 
       
   199               else if (u > 0)
       
   200                 {
       
   201                   if (item->rule->prec != grammar.names.end() && grammar.token_info.contains (s))
       
   202                     {
       
   203                       Grammar::TokenInfo info_r = grammar.token_info.value (item->rule->prec);
       
   204                       Grammar::TokenInfo info_s = grammar.token_info.value (s);
       
   205 
       
   206                       if (info_r.prec > info_s.prec)
       
   207                         u = -r;
       
   208                       else if (info_r.prec == info_s.prec)
       
   209                         {
       
   210                           switch (info_r.assoc) {
       
   211                           case Grammar::Left:
       
   212                             u = -r;
       
   213                             break;
       
   214                           case Grammar::Right:
       
   215                             // shift... nothing to do
       
   216                             break;
       
   217                           case Grammar::NonAssoc:
       
   218                             u = 0;
       
   219                             break;
       
   220                           } // switch
       
   221                         }
       
   222                     }
       
   223 
       
   224                   else
       
   225                     {
       
   226                       ++shift_reduce_conflict_count;
       
   227 
       
   228                       if (verbose)
       
   229                         qout << "*** Warning. Found a shift/reduce conflict in state " << q << " on token ``" << s << "'' with rule " << r << endl;
       
   230                     }
       
   231                 }
       
   232             }
       
   233         }
       
   234     }
       
   235 
       
   236   if (shift_reduce_conflict_count || reduce_reduce_conflict_count)
       
   237     {
       
   238       if (shift_reduce_conflict_count != grammar.expected_shift_reduce
       
   239           || reduce_reduce_conflict_count != grammar.expected_reduce_reduce)
       
   240         qerr << "*** Conflicts: " << shift_reduce_conflict_count << " shift/reduce, " << reduce_reduce_conflict_count << " reduce/reduce" << endl;
       
   241 
       
   242       if (verbose)
       
   243         qout << endl << "*** Conflicts: " << shift_reduce_conflict_count << " shift/reduce, " << reduce_reduce_conflict_count << " reduce/reduce" << endl
       
   244              << endl;
       
   245     }
       
   246 
       
   247   QBitArray used_rules (grammar.rules.count ());
       
   248 
       
   249   int q = 0;
       
   250   for (StatePointer state = aut.states.begin (); state != aut.states.end (); ++state, ++q)
       
   251     {
       
   252       for (int j = 0; j < terminal_count; ++j)
       
   253         {
       
   254           int &u = ACTION (q, j);
       
   255 
       
   256           if (u < 0)
       
   257             used_rules.setBit (-u - 1);
       
   258         }
       
   259     }
       
   260 
       
   261   for (int i = 0; i < used_rules.count (); ++i)
       
   262     {
       
   263       if (! used_rules.testBit (i))
       
   264         {
       
   265           RulePointer rule = grammar.rules.begin () + i;
       
   266 
       
   267           if (rule != grammar.goal)
       
   268             qerr << "*** Warning: Rule ``" << *rule << "'' is useless!" << endl;
       
   269         }
       
   270     }
       
   271 
       
   272   q = 0;
       
   273   for (StatePointer state = aut.states.begin (); state != aut.states.end (); ++state, ++q)
       
   274     {
       
   275       for (int j = 0; j < terminal_count; ++j)
       
   276         {
       
   277           int &u = ACTION (q, j);
       
   278 
       
   279           if (u >= 0)
       
   280             continue;
       
   281 
       
   282           RulePointer rule = grammar.rules.begin () + (- u - 1);
       
   283 
       
   284           if (state->defaultReduce == rule)
       
   285             u = 0;
       
   286         }
       
   287     }
       
   288 
       
   289   // ... compress the goto table
       
   290   defgoto.resize (non_terminal_count);
       
   291   for (int j = 0; j < non_terminal_count; ++j)
       
   292     {
       
   293       count.fill (0, state_count);
       
   294 
       
   295       int &mx = defgoto [j];
       
   296 
       
   297       for (int i = 0; i < state_count; ++i)
       
   298         {
       
   299           int r = GOTO (i, j);
       
   300 
       
   301           if (! r)
       
   302             continue;
       
   303 
       
   304           ++count [r];
       
   305 
       
   306           if (count [r] > count [mx])
       
   307             mx = r;
       
   308         }
       
   309     }
       
   310 
       
   311   for (int i = 0; i < state_count; ++i)
       
   312     {
       
   313       for (int j = 0; j < non_terminal_count; ++j)
       
   314         {
       
   315           int &r = GOTO (i, j);
       
   316 
       
   317           if (r == defgoto [j])
       
   318             r = 0;
       
   319         }
       
   320     }
       
   321 
       
   322   compressed_action (table, state_count, terminal_count);
       
   323   compressed_goto (pgoto, state_count, non_terminal_count);
       
   324 
       
   325   delete[] table;
       
   326   table = 0;
       
   327 
       
   328   delete[] pgoto;
       
   329   pgoto = 0;
       
   330 
       
   331 #undef ACTION
       
   332 #undef GOTO
       
   333 
       
   334   if (! grammar.merged_output.isEmpty())
       
   335     {
       
   336       QFile f(grammar.merged_output);
       
   337       if (! f.open (QFile::WriteOnly))
       
   338         {
       
   339           fprintf (stderr, "*** cannot create %s\n", qPrintable(grammar.merged_output));
       
   340           return;
       
   341         }
       
   342 
       
   343       QTextStream out (&f);
       
   344       out << "// This file was generated by qlalr - DO NOT EDIT!\n";
       
   345 
       
   346       if (copyright)
       
   347         {
       
   348           out << copyrightHeader()
       
   349               << privateCopyrightHeader()
       
   350               << endl;
       
   351         }
       
   352 
       
   353       out << startIncludeGuard(grammar.merged_output) << endl;
       
   354 
       
   355       generateDecl (out);
       
   356       generateImpl (out);
       
   357       out << p.decls();
       
   358       out << p.impls();
       
   359       out << endl;
       
   360 
       
   361       out << endIncludeGuard(grammar.merged_output) << endl;
       
   362 
       
   363       return;
       
   364     }
       
   365 
       
   366   // default behaviour
       
   367   QString declFileName = grammar.table_name.toLower () + QLatin1String("_p.h");
       
   368   QString bitsFileName = grammar.table_name.toLower () + QLatin1String(".cpp");
       
   369 
       
   370   { // decls...
       
   371     QFile f (declFileName);
       
   372     f.open (QFile::WriteOnly);
       
   373     QTextStream out (&f);
       
   374     out << "// This file was generated by qlalr - DO NOT EDIT!\n";
       
   375 
       
   376     QString prot = declFileName.toUpper ().replace (QLatin1Char ('.'), QLatin1Char ('_'));
       
   377 
       
   378     if (copyright)
       
   379       {
       
   380         out << copyrightHeader()
       
   381             << privateCopyrightHeader()
       
   382             << endl;
       
   383       }
       
   384 
       
   385     out << "#ifndef " << prot << endl
       
   386         << "#define " << prot << endl
       
   387         << endl;
       
   388 
       
   389     generateDecl (out);
       
   390 
       
   391     out << "#endif // " << prot << endl << endl;
       
   392   } // end decls
       
   393 
       
   394   { // bits...
       
   395     QFile f (bitsFileName);
       
   396     f.open (QFile::WriteOnly);
       
   397     QTextStream out (&f);
       
   398     out << "// This file was generated by qlalr - DO NOT EDIT!\n";
       
   399 
       
   400     if (copyright)
       
   401       out << copyrightHeader();
       
   402 
       
   403     out << "#include \"" << declFileName << "\"" << endl << endl;
       
   404     generateImpl(out);
       
   405 
       
   406   } // end bits
       
   407 
       
   408   if (! grammar.decl_file_name.isEmpty ())
       
   409     {
       
   410       QFile f (grammar.decl_file_name);
       
   411       f.open (QFile::WriteOnly);
       
   412       QTextStream out (&f);
       
   413       out << "// This file was generated by qlalr - DO NOT EDIT!\n";
       
   414       out << p.decls();
       
   415     }
       
   416 
       
   417   if (! grammar.impl_file_name.isEmpty ())
       
   418     {
       
   419       QFile f (grammar.impl_file_name);
       
   420       f.open (QFile::WriteOnly);
       
   421       QTextStream out (&f);
       
   422       out << "// This file was generated by qlalr - DO NOT EDIT!\n";
       
   423       out << p.impls();
       
   424     }
       
   425 }
       
   426 
       
   427 QString CppGenerator::debugInfoProt() const
       
   428 {
       
   429     QString prot = QLatin1String("QLALR_NO_");
       
   430     prot += grammar.table_name.toUpper();
       
   431     prot += QLatin1String("_DEBUG_INFO");
       
   432     return prot;
       
   433 }
       
   434 
       
   435 void CppGenerator::generateDecl (QTextStream &out)
       
   436 {
       
   437   out << "class " << grammar.table_name << endl
       
   438       << "{" << endl
       
   439       << "public:" << endl
       
   440       << "  enum {" << endl;
       
   441 
       
   442   foreach (Name t, grammar.terminals)
       
   443     {
       
   444       QString name = *t;
       
   445       int value = std::distance (grammar.names.begin (), t);
       
   446 
       
   447       if (name == QLatin1String ("$end"))
       
   448         name = QLatin1String ("EOF_SYMBOL");
       
   449 
       
   450       else if (name == QLatin1String ("$accept"))
       
   451         name = QLatin1String ("ACCEPT_SYMBOL");
       
   452 
       
   453       else
       
   454         name.prepend (grammar.token_prefix);
       
   455 
       
   456       out << "    " << name << " = " << value << "," << endl;
       
   457     }
       
   458 
       
   459   out << endl
       
   460       << "    ACCEPT_STATE = " << accept_state << "," << endl
       
   461       << "    RULE_COUNT = " << grammar.rules.size () << "," << endl
       
   462       << "    STATE_COUNT = " << state_count << "," << endl
       
   463       << "    TERMINAL_COUNT = " << terminal_count << "," << endl
       
   464       << "    NON_TERMINAL_COUNT = " << non_terminal_count << "," << endl
       
   465       << endl
       
   466       << "    GOTO_INDEX_OFFSET = " << compressed_action.index.size () << "," << endl
       
   467       << "    GOTO_INFO_OFFSET = " << compressed_action.info.size () << "," << endl
       
   468       << "    GOTO_CHECK_OFFSET = " << compressed_action.check.size () << endl
       
   469       << "  };" << endl
       
   470       << endl
       
   471       << "  static const char  *const spell [];" << endl
       
   472       << "  static const int            lhs [];" << endl
       
   473       << "  static const int            rhs [];" << endl;
       
   474 
       
   475   if (debug_info)
       
   476     {
       
   477       QString prot = debugInfoProt();
       
   478 
       
   479       out << endl << "#ifndef " << prot << endl
       
   480           << "  static const int     rule_index [];" << endl
       
   481           << "  static const int      rule_info [];" << endl
       
   482           << "#endif // " << prot << endl << endl;
       
   483     }
       
   484 
       
   485   out << "  static const int   goto_default [];" << endl
       
   486       << "  static const int action_default [];" << endl
       
   487       << "  static const int   action_index [];" << endl
       
   488       << "  static const int    action_info [];" << endl
       
   489       << "  static const int   action_check [];" << endl
       
   490       << endl
       
   491       << "  static inline int nt_action (int state, int nt)" << endl
       
   492       << "  {" << endl
       
   493       << "    const int *const goto_index = &action_index [GOTO_INDEX_OFFSET];" << endl
       
   494       << "    const int *const goto_check = &action_check [GOTO_CHECK_OFFSET];" << endl
       
   495       << endl
       
   496       << "    const int yyn = goto_index [state] + nt;" << endl
       
   497       << endl
       
   498       << "    if (yyn < 0 || goto_check [yyn] != nt)" << endl
       
   499       << "      return goto_default [nt];" << endl
       
   500       << endl
       
   501       << "    const int *const goto_info = &action_info [GOTO_INFO_OFFSET];" << endl
       
   502       << "    return goto_info [yyn];" << endl
       
   503       << "  }" << endl
       
   504       << endl
       
   505       << "  static inline int t_action (int state, int token)" << endl
       
   506       << "  {" << endl
       
   507       << "    const int yyn = action_index [state] + token;" << endl
       
   508       << endl
       
   509       << "    if (yyn < 0 || action_check [yyn] != token)" << endl
       
   510       << "      return - action_default [state];" << endl
       
   511       << endl
       
   512       << "    return action_info [yyn];" << endl
       
   513       << "  }" << endl
       
   514       << "};" << endl
       
   515       << endl
       
   516       << endl;
       
   517 }
       
   518 
       
   519 void CppGenerator::generateImpl (QTextStream &out)
       
   520 {
       
   521   int idx = 0;
       
   522 
       
   523   out << "const char *const " << grammar.table_name << "::spell [] = {";
       
   524   idx = 0;
       
   525 
       
   526   QMap<Name, int> name_ids;
       
   527   bool first_nt = true;
       
   528 
       
   529   for (Name t = grammar.names.begin (); t != grammar.names.end (); ++t, ++idx)
       
   530     {
       
   531       bool terminal = grammar.isTerminal (t);
       
   532 
       
   533       if (! (debug_info || terminal))
       
   534         break;
       
   535 
       
   536       name_ids.insert (t, idx);
       
   537 
       
   538       if (idx)
       
   539         out << ", ";
       
   540 
       
   541       if (! (idx % 10))
       
   542         out << endl << "  ";
       
   543 
       
   544       if (terminal)
       
   545         {
       
   546           QString spell = grammar.spells.value (t);
       
   547 
       
   548           if (spell.isEmpty ())
       
   549             out << "0";
       
   550           else
       
   551             out << "\"" << spell << "\"";
       
   552         }
       
   553       else
       
   554         {
       
   555           if (first_nt)
       
   556             {
       
   557               first_nt = false;
       
   558               QString prot = debugInfoProt();
       
   559               out << endl << "#ifndef " << prot << endl;
       
   560             }
       
   561           out << "\"" << *t << "\"";
       
   562         }
       
   563     }
       
   564 
       
   565   if (debug_info)
       
   566     out << endl << "#endif // " << debugInfoProt() << endl;
       
   567 
       
   568   out << "};" << endl << endl;
       
   569 
       
   570   out << "const int " << grammar.table_name << "::lhs [] = {";
       
   571   idx = 0;
       
   572   for (RulePointer rule = grammar.rules.begin (); rule != grammar.rules.end (); ++rule, ++idx)
       
   573     {
       
   574       if (idx)
       
   575         out << ", ";
       
   576 
       
   577       if (! (idx % 10))
       
   578         out << endl << "  ";
       
   579 
       
   580       out << aut.id (rule->lhs);
       
   581     }
       
   582   out << "};" << endl << endl;
       
   583 
       
   584   out << "const int " << grammar.table_name << ":: rhs[] = {";
       
   585   idx = 0;
       
   586   for (RulePointer rule = grammar.rules.begin (); rule != grammar.rules.end (); ++rule, ++idx)
       
   587     {
       
   588       if (idx)
       
   589         out << ", ";
       
   590 
       
   591       if (! (idx % 10))
       
   592         out << endl << "  ";
       
   593 
       
   594       out << rule->rhs.size ();
       
   595     }
       
   596   out << "};" << endl << endl;
       
   597 
       
   598   if (debug_info)
       
   599     {
       
   600       QString prot = debugInfoProt();
       
   601 
       
   602       out << endl << "#ifndef " << prot << endl;
       
   603       out << "const int " << grammar.table_name << "::rule_info [] = {";
       
   604       idx = 0;
       
   605       for (RulePointer rule = grammar.rules.begin (); rule != grammar.rules.end (); ++rule, ++idx)
       
   606         {
       
   607           out << endl << "  ";
       
   608 
       
   609           if (idx)
       
   610             out << ", ";
       
   611           else
       
   612             out << "  ";
       
   613 
       
   614           out << name_ids.value(rule->lhs);
       
   615 
       
   616           foreach (Name n, rule->rhs)
       
   617             out << ", " << name_ids.value (n);
       
   618         }
       
   619       out << "};" << endl << endl;
       
   620 
       
   621       out << "const int " << grammar.table_name << "::rule_index [] = {";
       
   622       idx = 0;
       
   623       int offset = 0;
       
   624       for (RulePointer rule = grammar.rules.begin (); rule != grammar.rules.end (); ++rule, ++idx)
       
   625         {
       
   626           if (idx)
       
   627             out << ", ";
       
   628 
       
   629           if (! (idx % 10))
       
   630             out << endl << "  ";
       
   631 
       
   632           out << offset;
       
   633           offset += rule->rhs.size () + 1;
       
   634         }
       
   635       out << "};" << endl
       
   636           << "#endif // " << prot << endl << endl;
       
   637     }
       
   638 
       
   639   out << "const int " << grammar.table_name << "::action_default [] = {";
       
   640   idx = 0;
       
   641   for (StatePointer state = aut.states.begin (); state != aut.states.end (); ++state, ++idx)
       
   642     {
       
   643       if (state != aut.states.begin ())
       
   644         out << ", ";
       
   645 
       
   646       if (! (idx % 10))
       
   647         out << endl << "  ";
       
   648 
       
   649       if (state->defaultReduce != grammar.rules.end ())
       
   650         out << aut.id (state->defaultReduce);
       
   651       else
       
   652         out << "0";
       
   653     }
       
   654   out << "};" << endl << endl;
       
   655 
       
   656   out << "const int " << grammar.table_name << "::goto_default [] = {";
       
   657   for (int i = 0; i < defgoto.size (); ++i)
       
   658     {
       
   659       if (i)
       
   660         out << ", ";
       
   661 
       
   662       if (! (i % 10))
       
   663         out << endl << "  ";
       
   664 
       
   665       out << defgoto [i];
       
   666     }
       
   667   out << "};" << endl << endl;
       
   668 
       
   669   out << "const int " << grammar.table_name << "::action_index [] = {";
       
   670   for (int i = 0; i < compressed_action.index.size (); ++i)
       
   671     {
       
   672       if (! (i % 10))
       
   673         out << endl << "  ";
       
   674 
       
   675       out << compressed_action.index [i] << ", ";
       
   676     }
       
   677   out << endl;
       
   678   for (int i = 0; i < compressed_goto.index.size (); ++i)
       
   679     {
       
   680       if (i)
       
   681         out << ", ";
       
   682 
       
   683       if (! (i % 10))
       
   684         out << endl << "  ";
       
   685 
       
   686       out << compressed_goto.index [i];
       
   687     }
       
   688   out << "};" << endl << endl;
       
   689 
       
   690   out << "const int " << grammar.table_name << "::action_info [] = {";
       
   691   for (int i = 0; i < compressed_action.info.size (); ++i)
       
   692     {
       
   693       if (! (i % 10))
       
   694         out << endl << "  ";
       
   695 
       
   696       out << compressed_action.info [i] << ", ";
       
   697     }
       
   698   out << endl;
       
   699   for (int i = 0; i < compressed_goto.info.size (); ++i)
       
   700     {
       
   701       if (i)
       
   702         out << ", ";
       
   703 
       
   704       if (! (i % 10))
       
   705         out << endl << "  ";
       
   706 
       
   707       out << compressed_goto.info [i];
       
   708     }
       
   709   out << "};" << endl << endl;
       
   710 
       
   711   out << "const int " << grammar.table_name << "::action_check [] = {";
       
   712   for (int i = 0; i < compressed_action.check.size (); ++i)
       
   713     {
       
   714       if (! (i % 10))
       
   715         out << endl << "  ";
       
   716 
       
   717       out << compressed_action.check [i] << ", ";
       
   718     }
       
   719   out << endl;
       
   720   for (int i = 0; i < compressed_goto.check.size (); ++i)
       
   721     {
       
   722       if (i)
       
   723         out << ", ";
       
   724 
       
   725       if (! (i % 10))
       
   726         out << endl << "  ";
       
   727 
       
   728       out << compressed_goto.check [i];
       
   729     }
       
   730   out << "};" << endl << endl;
       
   731 }