summaryrefslogtreecommitdiffstats
path: root/util/qlalr/cppgenerator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'util/qlalr/cppgenerator.cpp')
-rw-r--r--util/qlalr/cppgenerator.cpp750
1 files changed, 0 insertions, 750 deletions
diff --git a/util/qlalr/cppgenerator.cpp b/util/qlalr/cppgenerator.cpp
deleted file mode 100644
index d48c059397..0000000000
--- a/util/qlalr/cppgenerator.cpp
+++ /dev/null
@@ -1,750 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QLALR module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "cppgenerator.h"
-
-#include "lalr.h"
-#include "recognizer.h"
-
-#include <QtCore/qbitarray.h>
-#include <QtCore/qtextstream.h>
-#include <QtCore/qfile.h>
-#include <QtCore/qmap.h>
-
-
-QString CppGenerator::copyrightHeader() const
-{
- return QLatin1String(
- "/****************************************************************************\n"
- "**\n"
- "** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).\n"
- "** Contact: http://www.qt-project.org/legal\n"
- "**\n"
- "** This file is part of the Qt Toolkit.\n"
- "**\n"
- "** $QT_BEGIN_LICENSE:LGPL$\n"
- "** Commercial License Usage\n"
- "** Licensees holding valid commercial Qt licenses may use this file in\n"
- "** accordance with the commercial license agreement provided with the\n"
- "** Software or, alternatively, in accordance with the terms contained in\n"
- "** a written agreement between you and Digia. For licensing terms and\n"
- "** conditions see http://qt.digia.com/licensing. For further information\n"
- "** use the contact form at http://qt.digia.com/contact-us.\n"
- "**\n"
- "** GNU Lesser General Public License Usage\n"
- "** Alternatively, this file may be used under the terms of the GNU Lesser\n"
- "** General Public License version 2.1 as published by the Free Software\n"
- "** Foundation and appearing in the file LICENSE.LGPL included in the\n"
- "** packaging of this file. Please review the following information to\n"
- "** ensure the GNU Lesser General Public License version 2.1 requirements\n"
- "** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.\n"
- "**\n"
- "** In addition, as a special exception, Digia gives you certain additional\n"
- "** rights. These rights are described in the Digia Qt LGPL Exception\n"
- "** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.\n"
- "**\n"
- "** GNU General Public License Usage\n"
- "** Alternatively, this file may be used under the terms of the GNU\n"
- "** General Public License version 3.0 as published by the Free Software\n"
- "** Foundation and appearing in the file LICENSE.GPL included in the\n"
- "** packaging of this file. Please review the following information to\n"
- "** ensure the GNU General Public License version 3.0 requirements will be\n"
- "** met: http://www.gnu.org/copyleft/gpl.html.\n"
- "**\n"
- "**\n"
- "** $QT_END_LICENSE$\n"
- "**\n"
- "****************************************************************************/\n"
- "\n");
-}
-
-QString CppGenerator::privateCopyrightHeader() const
-{
- return QLatin1String(
- "//\n"
- "// W A R N I N G\n"
- "// -------------\n"
- "//\n"
- "// This file is not part of the Qt API. It exists for the convenience\n"
- "// of other Qt classes. This header file may change from version to\n"
- "// version without notice, or even be removed.\n"
- "//\n"
- "// We mean it.\n"
- "//\n");
-}
-
-QString CppGenerator::startIncludeGuard(const QString &fileName)
-{
- const QString normalized(QString(fileName).replace(QLatin1Char('.'), QLatin1Char('_')).toUpper());
-
- return QString::fromLatin1("#ifndef %1\n"
- "#define %2\n").arg(normalized, normalized);
-}
-
-QString CppGenerator::endIncludeGuard(const QString &fileName)
-{
- const QString normalized(QString(fileName).replace(QLatin1Char('.'), QLatin1Char('_')).toUpper());
-
- return QString::fromLatin1("#endif // %1\n").arg(normalized);
-}
-
-void CppGenerator::operator () ()
-{
- // action table...
- state_count = aut.states.size ();
- terminal_count = grammar.terminals.size ();
- non_terminal_count = grammar.non_terminals.size ();
-
-#define ACTION(i, j) table [(i) * terminal_count + (j)]
-#define GOTO(i, j) pgoto [(i) * non_terminal_count + (j)]
-
- int *table = new int [state_count * terminal_count];
- ::memset (table, 0, state_count * terminal_count * sizeof (int));
-
- int *pgoto = new int [state_count * non_terminal_count];
- ::memset (pgoto, 0, state_count * non_terminal_count * sizeof (int));
-
- accept_state = -1;
- int shift_reduce_conflict_count = 0;
- int reduce_reduce_conflict_count = 0;
-
- for (StatePointer state = aut.states.begin (); state != aut.states.end (); ++state)
- {
- int q = aut.id (state);
-
- for (Bundle::iterator a = state->bundle.begin (); a != state->bundle.end (); ++a)
- {
- int symbol = aut.id (a.key ());
- int r = aut.id (a.value ());
-
- Q_ASSERT (r < state_count);
-
- if (grammar.isNonTerminal (a.key ()))
- {
- Q_ASSERT (symbol >= terminal_count && symbol < grammar.names.size ());
- GOTO (q, symbol - terminal_count) = r;
- }
-
- else
- ACTION (q, symbol) = r;
- }
-
- for (ItemPointer item = state->closure.begin (); item != state->closure.end (); ++item)
- {
- if (item->dot != item->end_rhs ())
- continue;
-
- int r = aut.id (item->rule);
-
- NameSet lookaheads = aut.lookaheads.value (item);
-
- if (item->rule == grammar.goal)
- accept_state = q;
-
- foreach (Name s, lookaheads)
- {
- int &u = ACTION (q, aut.id (s));
-
- if (u == 0)
- u = - r;
-
- else if (u < 0)
- {
- if (verbose)
- qout << "*** Warning. Found a reduce/reduce conflict in state " << q << " on token ``" << s << "'' between rule "
- << r << " and " << -u << endl;
-
- ++reduce_reduce_conflict_count;
-
- u = qMax (u, -r);
-
- if (verbose)
- qout << "\tresolved using rule " << -u << endl;
- }
-
- else if (u > 0)
- {
- if (item->rule->prec != grammar.names.end() && grammar.token_info.contains (s))
- {
- Grammar::TokenInfo info_r = grammar.token_info.value (item->rule->prec);
- Grammar::TokenInfo info_s = grammar.token_info.value (s);
-
- if (info_r.prec > info_s.prec)
- u = -r;
- else if (info_r.prec == info_s.prec)
- {
- switch (info_r.assoc) {
- case Grammar::Left:
- u = -r;
- break;
- case Grammar::Right:
- // shift... nothing to do
- break;
- case Grammar::NonAssoc:
- u = 0;
- break;
- } // switch
- }
- }
-
- else
- {
- ++shift_reduce_conflict_count;
-
- if (verbose)
- qout << "*** Warning. Found a shift/reduce conflict in state " << q << " on token ``" << s << "'' with rule " << r << endl;
- }
- }
- }
- }
- }
-
- if (shift_reduce_conflict_count || reduce_reduce_conflict_count)
- {
- if (shift_reduce_conflict_count != grammar.expected_shift_reduce
- || reduce_reduce_conflict_count != grammar.expected_reduce_reduce)
- qerr << "*** Conflicts: " << shift_reduce_conflict_count << " shift/reduce, " << reduce_reduce_conflict_count << " reduce/reduce" << endl;
-
- if (verbose)
- qout << endl << "*** Conflicts: " << shift_reduce_conflict_count << " shift/reduce, " << reduce_reduce_conflict_count << " reduce/reduce" << endl
- << endl;
- }
-
- QBitArray used_rules (grammar.rules.count ());
-
- int q = 0;
- for (StatePointer state = aut.states.begin (); state != aut.states.end (); ++state, ++q)
- {
- for (int j = 0; j < terminal_count; ++j)
- {
- int &u = ACTION (q, j);
-
- if (u < 0)
- used_rules.setBit (-u - 1);
- }
- }
-
- for (int i = 0; i < used_rules.count (); ++i)
- {
- if (! used_rules.testBit (i))
- {
- RulePointer rule = grammar.rules.begin () + i;
-
- if (rule != grammar.goal)
- qerr << "*** Warning: Rule ``" << *rule << "'' is useless!" << endl;
- }
- }
-
- q = 0;
- for (StatePointer state = aut.states.begin (); state != aut.states.end (); ++state, ++q)
- {
- for (int j = 0; j < terminal_count; ++j)
- {
- int &u = ACTION (q, j);
-
- if (u >= 0)
- continue;
-
- RulePointer rule = grammar.rules.begin () + (- u - 1);
-
- if (state->defaultReduce == rule)
- u = 0;
- }
- }
-
- // ... compress the goto table
- defgoto.resize (non_terminal_count);
- for (int j = 0; j < non_terminal_count; ++j)
- {
- count.fill (0, state_count);
-
- int &mx = defgoto [j];
-
- for (int i = 0; i < state_count; ++i)
- {
- int r = GOTO (i, j);
-
- if (! r)
- continue;
-
- ++count [r];
-
- if (count [r] > count [mx])
- mx = r;
- }
- }
-
- for (int i = 0; i < state_count; ++i)
- {
- for (int j = 0; j < non_terminal_count; ++j)
- {
- int &r = GOTO (i, j);
-
- if (r == defgoto [j])
- r = 0;
- }
- }
-
- compressed_action (table, state_count, terminal_count);
- compressed_goto (pgoto, state_count, non_terminal_count);
-
- delete[] table;
- table = 0;
-
- delete[] pgoto;
- pgoto = 0;
-
-#undef ACTION
-#undef GOTO
-
- if (! grammar.merged_output.isEmpty())
- {
- QFile f(grammar.merged_output);
- if (! f.open (QFile::WriteOnly))
- {
- fprintf (stderr, "*** cannot create %s\n", qPrintable(grammar.merged_output));
- return;
- }
-
- QTextStream out (&f);
-
- // copyright headers must come first, otherwise the headers tests will fail
- if (copyright)
- {
- out << copyrightHeader()
- << privateCopyrightHeader()
- << endl;
- }
-
- out << "// This file was generated by qlalr - DO NOT EDIT!\n";
-
- out << startIncludeGuard(grammar.merged_output) << endl;
-
- if (copyright) {
- out << "#if defined(ERROR)" << endl
- << "# undef ERROR" << endl
- << "#endif" << endl << endl;
- }
-
- generateDecl (out);
- generateImpl (out);
- out << p.decls();
- out << p.impls();
- out << endl;
-
- out << endIncludeGuard(grammar.merged_output) << endl;
-
- return;
- }
-
- // default behaviour
- QString declFileName = grammar.table_name.toLower () + QLatin1String("_p.h");
- QString bitsFileName = grammar.table_name.toLower () + QLatin1String(".cpp");
-
- { // decls...
- QFile f (declFileName);
- f.open (QFile::WriteOnly);
- QTextStream out (&f);
-
- QString prot = declFileName.toUpper ().replace (QLatin1Char ('.'), QLatin1Char ('_'));
-
- // copyright headers must come first, otherwise the headers tests will fail
- if (copyright)
- {
- out << copyrightHeader()
- << privateCopyrightHeader()
- << endl;
- }
-
- out << "// This file was generated by qlalr - DO NOT EDIT!\n";
-
- out << "#ifndef " << prot << endl
- << "#define " << prot << endl
- << endl;
-
- if (copyright) {
- out << "#include <QtCore/qglobal.h>" << endl << endl;
- out << "QT_BEGIN_NAMESPACE" << endl << endl;
- }
- generateDecl (out);
- if (copyright)
- out << "QT_END_NAMESPACE" << endl;
-
- out << "#endif // " << prot << endl << endl;
- } // end decls
-
- { // bits...
- QFile f (bitsFileName);
- f.open (QFile::WriteOnly);
- QTextStream out (&f);
-
- // copyright headers must come first, otherwise the headers tests will fail
- if (copyright)
- out << copyrightHeader();
-
- out << "// This file was generated by qlalr - DO NOT EDIT!\n";
-
- out << "#include \"" << declFileName << "\"" << endl << endl;
- if (copyright)
- out << "QT_BEGIN_NAMESPACE" << endl << endl;
- generateImpl(out);
- if (copyright)
- out << "QT_END_NAMESPACE" << endl;
-
- } // end bits
-
- if (! grammar.decl_file_name.isEmpty ())
- {
- QFile f (grammar.decl_file_name);
- f.open (QFile::WriteOnly);
- QTextStream out (&f);
- out << p.decls();
- }
-
- if (! grammar.impl_file_name.isEmpty ())
- {
- QFile f (grammar.impl_file_name);
- f.open (QFile::WriteOnly);
- QTextStream out (&f);
- out << p.impls();
- }
-}
-
-QString CppGenerator::debugInfoProt() const
-{
- QString prot = QLatin1String("QLALR_NO_");
- prot += grammar.table_name.toUpper();
- prot += QLatin1String("_DEBUG_INFO");
- return prot;
-}
-
-void CppGenerator::generateDecl (QTextStream &out)
-{
- out << "class " << grammar.table_name << endl
- << "{" << endl
- << "public:" << endl
- << " enum VariousConstants {" << endl;
-
- foreach (Name t, grammar.terminals)
- {
- QString name = *t;
- int value = std::distance (grammar.names.begin (), t);
-
- if (name == QLatin1String ("$end"))
- name = QLatin1String ("EOF_SYMBOL");
-
- else if (name == QLatin1String ("$accept"))
- name = QLatin1String ("ACCEPT_SYMBOL");
-
- else
- name.prepend (grammar.token_prefix);
-
- out << " " << name << " = " << value << "," << endl;
- }
-
- out << endl
- << " ACCEPT_STATE = " << accept_state << "," << endl
- << " RULE_COUNT = " << grammar.rules.size () << "," << endl
- << " STATE_COUNT = " << state_count << "," << endl
- << " TERMINAL_COUNT = " << terminal_count << "," << endl
- << " NON_TERMINAL_COUNT = " << non_terminal_count << "," << endl
- << endl
- << " GOTO_INDEX_OFFSET = " << compressed_action.index.size () << "," << endl
- << " GOTO_INFO_OFFSET = " << compressed_action.info.size () << "," << endl
- << " GOTO_CHECK_OFFSET = " << compressed_action.check.size () << endl
- << " };" << endl
- << endl
- << " static const char *const spell [];" << endl
- << " static const short lhs [];" << endl
- << " static const short rhs [];" << endl;
-
- if (debug_info)
- {
- QString prot = debugInfoProt();
-
- out << endl << "#ifndef " << prot << endl
- << " static const int rule_index [];" << endl
- << " static const int rule_info [];" << endl
- << "#endif // " << prot << endl << endl;
- }
-
- out << " static const short goto_default [];" << endl
- << " static const short action_default [];" << endl
- << " static const short action_index [];" << endl
- << " static const short action_info [];" << endl
- << " static const short action_check [];" << endl
- << endl
- << " static inline int nt_action (int state, int nt)" << endl
- << " {" << endl
- << " const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt;" << endl
- << " if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt)" << endl
- << " return goto_default [nt];" << endl
- << endl
- << " return action_info [GOTO_INFO_OFFSET + yyn];" << endl
- << " }" << endl
- << endl
- << " static inline int t_action (int state, int token)" << endl
- << " {" << endl
- << " const int yyn = action_index [state] + token;" << endl
- << endl
- << " if (yyn < 0 || action_check [yyn] != token)" << endl
- << " return - action_default [state];" << endl
- << endl
- << " return action_info [yyn];" << endl
- << " }" << endl
- << "};" << endl
- << endl
- << endl;
-}
-
-void CppGenerator::generateImpl (QTextStream &out)
-{
- int idx = 0;
-
- out << "const char *const " << grammar.table_name << "::spell [] = {";
- idx = 0;
-
- QMap<Name, int> name_ids;
- bool first_nt = true;
-
- for (Name t = grammar.names.begin (); t != grammar.names.end (); ++t, ++idx)
- {
- bool terminal = grammar.isTerminal (t);
-
- if (! (debug_info || terminal))
- break;
-
- name_ids.insert (t, idx);
-
- if (idx)
- out << ", ";
-
- if (! (idx % 10))
- out << endl << " ";
-
- if (terminal)
- {
- QString spell = grammar.spells.value (t);
-
- if (spell.isEmpty ())
- out << "0";
- else
- out << "\"" << spell << "\"";
- }
- else
- {
- if (first_nt)
- {
- first_nt = false;
- QString prot = debugInfoProt();
- out << endl << "#ifndef " << prot << endl;
- }
- out << "\"" << *t << "\"";
- }
- }
-
- if (debug_info)
- out << endl << "#endif // " << debugInfoProt() << endl;
-
- out << "};" << endl << endl;
-
- out << "const short " << grammar.table_name << "::lhs [] = {";
- idx = 0;
- for (RulePointer rule = grammar.rules.begin (); rule != grammar.rules.end (); ++rule, ++idx)
- {
- if (idx)
- out << ", ";
-
- if (! (idx % 10))
- out << endl << " ";
-
- out << aut.id (rule->lhs);
- }
- out << "};" << endl << endl;
-
- out << "const short " << grammar.table_name << "::rhs [] = {";
- idx = 0;
- for (RulePointer rule = grammar.rules.begin (); rule != grammar.rules.end (); ++rule, ++idx)
- {
- if (idx)
- out << ", ";
-
- if (! (idx % 10))
- out << endl << " ";
-
- out << rule->rhs.size ();
- }
- out << "};" << endl << endl;
-
- if (debug_info)
- {
- QString prot = debugInfoProt();
-
- out << endl << "#ifndef " << prot << endl;
- out << "const int " << grammar.table_name << "::rule_info [] = {";
- idx = 0;
- for (RulePointer rule = grammar.rules.begin (); rule != grammar.rules.end (); ++rule, ++idx)
- {
- out << endl << " ";
-
- if (idx)
- out << ", ";
- else
- out << " ";
-
- out << name_ids.value(rule->lhs);
-
- foreach (Name n, rule->rhs)
- out << ", " << name_ids.value (n);
- }
- out << "};" << endl << endl;
-
- out << "const int " << grammar.table_name << "::rule_index [] = {";
- idx = 0;
- int offset = 0;
- for (RulePointer rule = grammar.rules.begin (); rule != grammar.rules.end (); ++rule, ++idx)
- {
- if (idx)
- out << ", ";
-
- if (! (idx % 10))
- out << endl << " ";
-
- out << offset;
- offset += rule->rhs.size () + 1;
- }
- out << "};" << endl
- << "#endif // " << prot << endl << endl;
- }
-
- out << "const short " << grammar.table_name << "::action_default [] = {";
- idx = 0;
- for (StatePointer state = aut.states.begin (); state != aut.states.end (); ++state, ++idx)
- {
- if (state != aut.states.begin ())
- out << ", ";
-
- if (! (idx % 10))
- out << endl << " ";
-
- if (state->defaultReduce != grammar.rules.end ())
- out << aut.id (state->defaultReduce);
- else
- out << "0";
- }
- out << "};" << endl << endl;
-
- out << "const short " << grammar.table_name << "::goto_default [] = {";
- for (int i = 0; i < defgoto.size (); ++i)
- {
- if (i)
- out << ", ";
-
- if (! (i % 10))
- out << endl << " ";
-
- out << defgoto [i];
- }
- out << "};" << endl << endl;
-
- out << "const short " << grammar.table_name << "::action_index [] = {";
- for (int i = 0; i < compressed_action.index.size (); ++i)
- {
- if (! (i % 10))
- out << endl << " ";
-
- out << compressed_action.index [i] << ", ";
- }
- out << endl;
- for (int i = 0; i < compressed_goto.index.size (); ++i)
- {
- if (i)
- out << ", ";
-
- if (! (i % 10))
- out << endl << " ";
-
- out << compressed_goto.index [i];
- }
- out << "};" << endl << endl;
-
- out << "const short " << grammar.table_name << "::action_info [] = {";
- for (int i = 0; i < compressed_action.info.size (); ++i)
- {
- if (! (i % 10))
- out << endl << " ";
-
- out << compressed_action.info [i] << ", ";
- }
- out << endl;
- for (int i = 0; i < compressed_goto.info.size (); ++i)
- {
- if (i)
- out << ", ";
-
- if (! (i % 10))
- out << endl << " ";
-
- out << compressed_goto.info [i];
- }
- out << "};" << endl << endl;
-
- out << "const short " << grammar.table_name << "::action_check [] = {";
- for (int i = 0; i < compressed_action.check.size (); ++i)
- {
- if (! (i % 10))
- out << endl << " ";
-
- out << compressed_action.check [i] << ", ";
- }
- out << endl;
- for (int i = 0; i < compressed_goto.check.size (); ++i)
- {
- if (i)
- out << ", ";
-
- if (! (i % 10))
- out << endl << " ";
-
- out << compressed_goto.check [i];
- }
- out << "};" << endl << endl;
-}