From 4e67d70e177b663126c044de1716c7bd13dfe842 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 29 Sep 2015 16:24:52 +0300 Subject: [PATCH] qt fixes for xcode7 added --- .../plugins/platforms/cocoa/qcocoacursor.mm | 323 ++++++++ .../qtbase/src/tools/qlalr/lalr.cpp | 773 ++++++++++++++++++ 2 files changed, 1096 insertions(+) create mode 100644 Telegram/_qt_5_5_0_patch/qtbase/src/plugins/platforms/cocoa/qcocoacursor.mm create mode 100644 Telegram/_qt_5_5_0_patch/qtbase/src/tools/qlalr/lalr.cpp diff --git a/Telegram/_qt_5_5_0_patch/qtbase/src/plugins/platforms/cocoa/qcocoacursor.mm b/Telegram/_qt_5_5_0_patch/qtbase/src/plugins/platforms/cocoa/qcocoacursor.mm new file mode 100644 index 000000000..922809f90 --- /dev/null +++ b/Telegram/_qt_5_5_0_patch/qtbase/src/plugins/platforms/cocoa/qcocoacursor.mm @@ -0,0 +1,323 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcocoacursor.h" +#include "qcocoawindow.h" +#include "qcocoahelpers.h" +#include "qcocoaautoreleasepool.h" + +#include + +QT_BEGIN_NAMESPACE + +QCocoaCursor::QCocoaCursor() +{ +} + +QCocoaCursor::~QCocoaCursor() +{ + // release cursors + QHash::const_iterator i = m_cursors.constBegin(); + while (i != m_cursors.constEnd()) { + [*i release]; + ++i; + } +} + +void QCocoaCursor::changeCursor(QCursor *cursor, QWindow *window) +{ + NSCursor * cocoaCursor = convertCursor(cursor); + + if (QPlatformWindow * platformWindow = window->handle()) + static_cast(platformWindow)->setWindowCursor(cocoaCursor); +} + +QPoint QCocoaCursor::pos() const +{ + return qt_mac_flipPoint([NSEvent mouseLocation]).toPoint(); +} + +void QCocoaCursor::setPos(const QPoint &position) +{ + CGPoint pos; + pos.x = position.x(); + pos.y = position.y(); + + CGEventRef e = CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, kCGMouseButtonLeft); + CGEventPost(kCGHIDEventTap, e); + CFRelease(e); +} + +NSCursor *QCocoaCursor::convertCursor(QCursor * cursor) +{ + const Qt::CursorShape newShape = cursor ? cursor->shape() : Qt::ArrowCursor; + NSCursor *cocoaCursor; + + // Check for a suitable built-in NSCursor first: + switch (newShape) { + case Qt::ArrowCursor: + cocoaCursor= [NSCursor arrowCursor]; + break; + case Qt::CrossCursor: + cocoaCursor = [NSCursor crosshairCursor]; + break; + case Qt::IBeamCursor: + cocoaCursor = [NSCursor IBeamCursor]; + break; + case Qt::WhatsThisCursor: //for now just use the pointing hand + case Qt::PointingHandCursor: + cocoaCursor = [NSCursor pointingHandCursor]; + break; + case Qt::SplitVCursor: + cocoaCursor = [NSCursor resizeUpDownCursor]; + break; + case Qt::SplitHCursor: + cocoaCursor = [NSCursor resizeLeftRightCursor]; + break; + case Qt::OpenHandCursor: + cocoaCursor = [NSCursor openHandCursor]; + break; + case Qt::ClosedHandCursor: + cocoaCursor = [NSCursor closedHandCursor]; + break; + case Qt::DragMoveCursor: + cocoaCursor = [NSCursor crosshairCursor]; + break; + case Qt::DragCopyCursor: + cocoaCursor = [NSCursor crosshairCursor]; + break; + case Qt::DragLinkCursor: + cocoaCursor = [NSCursor dragLinkCursor]; + break; + default : { + // No suitable OS cursor exist, use cursors provided + // by Qt for the rest. Check for a cached cursor: + cocoaCursor = m_cursors.value(newShape); + if (cocoaCursor && cursor->shape() == Qt::BitmapCursor) { + [cocoaCursor release]; + cocoaCursor = 0; + } + if (cocoaCursor == 0) { + cocoaCursor = createCursorData(cursor); + if (cocoaCursor == 0) + return [NSCursor arrowCursor]; + + m_cursors.insert(newShape, cocoaCursor); + } + + break; } + } + return cocoaCursor; +} + + +// Creates an NSCursor for the given QCursor. +NSCursor *QCocoaCursor::createCursorData(QCursor *cursor) +{ + /* Note to self... *** + * mask x data + * 0xFF x 0x00 == fully opaque white + * 0x00 x 0xFF == xor'd black + * 0xFF x 0xFF == fully opaque black + * 0x00 x 0x00 == fully transparent + */ +#define QT_USE_APPROXIMATE_CURSORS +#ifdef QT_USE_APPROXIMATE_CURSORS + static const uchar cur_ver_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x0f, 0xf0, + 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00 }; + static const uchar mcur_ver_bits[] = { + 0x00, 0x00, 0x03, 0x80, 0x07, 0xc0, 0x0f, 0xe0, 0x1f, 0xf0, 0x3f, 0xf8, + 0x7f, 0xfc, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x7f, 0xfc, 0x3f, 0xf8, + 0x1f, 0xf0, 0x0f, 0xe0, 0x07, 0xc0, 0x03, 0x80 }; + + static const uchar cur_hor_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x18, 0x30, + 0x38, 0x38, 0x7f, 0xfc, 0x7f, 0xfc, 0x38, 0x38, 0x18, 0x30, 0x08, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const uchar mcur_hor_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x04, 0x40, 0x0c, 0x60, 0x1c, 0x70, 0x3c, 0x78, + 0x7f, 0xfc, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0x7f, 0xfc, 0x3c, 0x78, + 0x1c, 0x70, 0x0c, 0x60, 0x04, 0x40, 0x00, 0x00 }; + + static const uchar cur_fdiag_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf8, 0x00, 0xf8, 0x00, 0x78, + 0x00, 0xf8, 0x01, 0xd8, 0x23, 0x88, 0x37, 0x00, 0x3e, 0x00, 0x3c, 0x00, + 0x3e, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const uchar mcur_fdiag_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x07, 0xfc, 0x03, 0xfc, 0x01, 0xfc, 0x00, 0xfc, + 0x41, 0xfc, 0x63, 0xfc, 0x77, 0xdc, 0x7f, 0x8c, 0x7f, 0x04, 0x7e, 0x00, + 0x7f, 0x00, 0x7f, 0x80, 0x7f, 0xc0, 0x00, 0x00 }; + + static const uchar cur_bdiag_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x3e, 0x00, + 0x37, 0x00, 0x23, 0x88, 0x01, 0xd8, 0x00, 0xf8, 0x00, 0x78, 0x00, 0xf8, + 0x01, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const uchar mcur_bdiag_bits[] = { + 0x00, 0x00, 0x7f, 0xc0, 0x7f, 0x80, 0x7f, 0x00, 0x7e, 0x00, 0x7f, 0x04, + 0x7f, 0x8c, 0x77, 0xdc, 0x63, 0xfc, 0x41, 0xfc, 0x00, 0xfc, 0x01, 0xfc, + 0x03, 0xfc, 0x07, 0xfc, 0x00, 0x00, 0x00, 0x00 }; + + static const unsigned char cur_up_arrow_bits[] = { + 0x00, 0x80, 0x01, 0x40, 0x01, 0x40, 0x02, 0x20, 0x02, 0x20, 0x04, 0x10, + 0x04, 0x10, 0x08, 0x08, 0x0f, 0x78, 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, + 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0xc0 }; + static const unsigned char mcur_up_arrow_bits[] = { + 0x00, 0x80, 0x01, 0xc0, 0x01, 0xc0, 0x03, 0xe0, 0x03, 0xe0, 0x07, 0xf0, + 0x07, 0xf0, 0x0f, 0xf8, 0x0f, 0xf8, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, + 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0 }; +#endif + const uchar *cursorData = 0; + const uchar *cursorMaskData = 0; + QPoint hotspot = cursor->hotSpot(); + + switch (cursor->shape()) { + case Qt::BitmapCursor: { + if (cursor->pixmap().isNull()) + return createCursorFromBitmap(cursor->bitmap(), cursor->mask(), hotspot); + else + return createCursorFromPixmap(cursor->pixmap(), hotspot); + break; } + case Qt::BlankCursor: { + QPixmap pixmap = QPixmap(16, 16); + pixmap.fill(Qt::transparent); + return createCursorFromPixmap(pixmap); + break; } + case Qt::WaitCursor: { + QPixmap pixmap = QPixmap(QLatin1String(":/qt-project.org/mac/cursors/images/spincursor.png")); + return createCursorFromPixmap(pixmap, hotspot); + break; } + case Qt::SizeAllCursor: { + QPixmap pixmap = QPixmap(QLatin1String(":/qt-project.org/mac/cursors/images/sizeallcursor.png")); + return createCursorFromPixmap(pixmap, QPoint(8, 8)); + break; } + case Qt::BusyCursor: { + QPixmap pixmap = QPixmap(QLatin1String(":/qt-project.org/mac/cursors/images/waitcursor.png")); + return createCursorFromPixmap(pixmap, hotspot); + break; } + case Qt::ForbiddenCursor: { + QPixmap pixmap = QPixmap(QLatin1String(":/qt-project.org/mac/cursors/images/forbiddencursor.png")); + return createCursorFromPixmap(pixmap, hotspot); + break; } +#define QT_USE_APPROXIMATE_CURSORS +#ifdef QT_USE_APPROXIMATE_CURSORS + case Qt::SizeVerCursor: + cursorData = cur_ver_bits; + cursorMaskData = mcur_ver_bits; + hotspot = QPoint(8, 8); + break; + case Qt::SizeHorCursor: + cursorData = cur_hor_bits; + cursorMaskData = mcur_hor_bits; + hotspot = QPoint(8, 8); + break; + case Qt::SizeBDiagCursor: + cursorData = cur_fdiag_bits; + cursorMaskData = mcur_fdiag_bits; + hotspot = QPoint(8, 8); + break; + case Qt::SizeFDiagCursor: + cursorData = cur_bdiag_bits; + cursorMaskData = mcur_bdiag_bits; + hotspot = QPoint(8, 8); + break; + case Qt::UpArrowCursor: + cursorData = cur_up_arrow_bits; + cursorMaskData = mcur_up_arrow_bits; + hotspot = QPoint(8, 0); + break; +#endif + default: + qWarning("Qt: QCursor::update: Invalid cursor shape %d", cursor->shape()); + return 0; + } + + // Create an NSCursor from image data if this a self-provided cursor. + if (cursorData) { + QBitmap bitmap(QBitmap::fromData(QSize(16, 16), cursorData, QImage::Format_Mono)); + QBitmap mask(QBitmap::fromData(QSize(16, 16), cursorMaskData, QImage::Format_Mono)); + return (createCursorFromBitmap(&bitmap, &mask, hotspot)); + } + + return 0; // should not happen, all cases covered above +} + +NSCursor *QCocoaCursor::createCursorFromBitmap(const QBitmap *bitmap, const QBitmap *mask, const QPoint hotspot) +{ + QImage finalCursor(bitmap->size(), QImage::Format_ARGB32); + QImage bmi = bitmap->toImage().convertToFormat(QImage::Format_RGB32); + QImage bmmi = mask->toImage().convertToFormat(QImage::Format_RGB32); + for (int row = 0; row < finalCursor.height(); ++row) { + QRgb *bmData = reinterpret_cast(bmi.scanLine(row)); + QRgb *bmmData = reinterpret_cast(bmmi.scanLine(row)); + QRgb *finalData = reinterpret_cast(finalCursor.scanLine(row)); + for (int col = 0; col < finalCursor.width(); ++col) { + if (bmmData[col] == 0xff000000 && bmData[col] == 0xffffffff) { + finalData[col] = 0xffffffff; + } else if (bmmData[col] == 0xff000000 && bmData[col] == 0xffffffff) { + finalData[col] = 0x7f000000; + } else if (bmmData[col] == 0xffffffff && bmData[col] == 0xffffffff) { + finalData[col] = 0x00000000; + } else { + finalData[col] = 0xff000000; + } + } + } + + return createCursorFromPixmap(QPixmap::fromImage(finalCursor), hotspot); +} + +NSCursor *QCocoaCursor::createCursorFromPixmap(const QPixmap pixmap, const QPoint hotspot) +{ + NSPoint hotSpot = NSMakePoint(hotspot.x(), hotspot.y()); + NSImage *nsimage; + if (pixmap.devicePixelRatio() > 1.0) { + QSize layoutSize = pixmap.size() / pixmap.devicePixelRatio(); + QPixmap scaledPixmap = pixmap.scaled(layoutSize); + nsimage = static_cast(qt_mac_create_nsimage(scaledPixmap)); + CGImageRef cgImage = qt_mac_toCGImage(pixmap.toImage()); + NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage]; + [nsimage addRepresentation:imageRep]; + [imageRep release]; + CGImageRelease(cgImage); + } else { + nsimage = static_cast(qt_mac_create_nsimage(pixmap)); + } + + NSCursor *nsCursor = [[NSCursor alloc] initWithImage:nsimage hotSpot: hotSpot]; + [nsimage release]; + return nsCursor; +} + +QT_END_NAMESPACE diff --git a/Telegram/_qt_5_5_0_patch/qtbase/src/tools/qlalr/lalr.cpp b/Telegram/_qt_5_5_0_patch/qtbase/src/tools/qlalr/lalr.cpp new file mode 100644 index 000000000..cb8071b7d --- /dev/null +++ b/Telegram/_qt_5_5_0_patch/qtbase/src/tools/qlalr/lalr.cpp @@ -0,0 +1,773 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the utils of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "lalr.h" + +#include + +#include + +#define QLALR_NO_DEBUG_NULLABLES +#define QLALR_NO_DEBUG_LOOKBACKS +#define QLALR_NO_DEBUG_DIRECT_READS +#define QLALR_NO_DEBUG_READS +#define QLALR_NO_DEBUG_INCLUDES +#define QLALR_NO_DEBUG_LOOKAHEADS + +QT_BEGIN_NAMESPACE +QTextStream qerr (stderr, QIODevice::WriteOnly); +QTextStream qout (stdout, QIODevice::WriteOnly); + +bool operator < (Name a, Name b) +{ + return *a < *b; +} + +bool operator < (ItemPointer a, ItemPointer b) +{ + return &*a < &*b; +} + +bool operator < (StatePointer a, StatePointer b) +{ + return &*a < &*b; +} +QT_END_NAMESPACE + +bool Read::operator < (const Read &other) const +{ + if (state == other.state) + return nt < other.nt; + + return state < other.state; +} + +bool Include::operator < (const Include &other) const +{ + if (state == other.state) + return nt < other.nt; + + return state < other.state; +} + +bool Lookback::operator < (const Lookback &other) const +{ + if (state == other.state) + return nt < other.nt; + + return state < other.state; +} + +QTextStream &operator << (QTextStream &out, const Name &n) +{ + return out << *n; +} + +QTextStream &operator << (QTextStream &out, const Rule &r) +{ + out << *r.lhs << " ::="; + + for (NameList::const_iterator name = r.rhs.begin (); name != r.rhs.end (); ++name) + out << " " << **name; + + return out; +} + +QTextStream &operator << (QTextStream &out, const NameSet &ns) +{ + out << "{"; + + for (NameSet::const_iterator n = ns.begin (); n != ns.end (); ++n) + { + if (n != ns.begin ()) + out << ", "; + + out << *n; + } + + return out << "}"; +} + +Item Item::next () const +{ + Q_ASSERT (! isReduceItem ()); + + Item n; + n.rule = rule; + n.dot = dot; + ++n.dot; + + return n; +} + +QTextStream &operator << (QTextStream &out, const Item &item) +{ + RulePointer r = item.rule; + + out << *r->lhs << ":"; + for (NameList::iterator name = r->rhs.begin (); name != r->rhs.end (); ++name) + { + out << " "; + + if (item.dot == name) + out << ". "; + + out << **name; + } + + if (item.isReduceItem ()) + out << " ."; + + return out; +} + +State::State (Grammar *g): + defaultReduce (g->rules.end ()) +{ +} + +QPair State::insert (const Item &item) +{ + ItemPointer it = std::find (kernel.begin (), kernel.end (), item); + + if (it != kernel.end ()) + return qMakePair (it, false); + + return qMakePair (kernel.insert (it, item), true); +} + +QPair State::insertClosure (const Item &item) +{ + ItemPointer it = std::find (closure.begin (), closure.end (), item); + + if (it != closure.end ()) + return qMakePair (it, false); + + return qMakePair (closure.insert (it, item), true); +} + + +///////////////////////////////////////////////////////////// +// Grammar +///////////////////////////////////////////////////////////// +Grammar::Grammar (): + start (names.end ()) +{ + expected_shift_reduce = 0; + expected_reduce_reduce = 0; + current_prec = 0; + current_assoc = NonAssoc; + + table_name = QLatin1String ("parser_table"); + + tk_end = intern ("$end"); + terminals.insert (tk_end); + spells.insert (tk_end, "end of file"); + + /*tk_error= terminals.insert (intern ("error"))*/; +} + +Name Grammar::intern (const QString &id) +{ + Name name = std::find (names.begin (), names.end (), id); + + if (name == names.end ()) + name = names.insert (names.end (), id); + + return name; +} + +void Grammar::buildRuleMap () +{ + NameSet undefined; + for (RulePointer rule = rules.begin (); rule != rules.end (); ++rule) + { + for (NameList::iterator it = rule->rhs.begin (); it != rule->rhs.end (); ++it) + { + Name name = *it; + if (isTerminal (name) || declared_lhs.find (name) != declared_lhs.end () + || undefined.find (name) != undefined.end ()) + continue; + + undefined.insert(name); + fprintf (stderr, "*** Warning. Symbol `%s' is not defined\n", qPrintable (*name)); + } + + rule_map.insert (rule->lhs, rule); + } +} + +void Grammar::buildExtendedGrammar () +{ + accept_symbol = intern ("$accept"); + goal = rules.insert (rules.end (), Rule ()); + goal->lhs = accept_symbol; + goal->rhs.push_back (start); + goal->rhs.push_back (tk_end); + + non_terminals.insert (accept_symbol); +} + +struct __Nullable: public std::unary_function +{ + Automaton *_M_automaton; + + __Nullable (Automaton *aut): + _M_automaton (aut) {} + + bool operator () (Name name) const + { return _M_automaton->nullables.find (name) != _M_automaton->nullables.end (); } +}; + +Automaton::Automaton (Grammar *g): + _M_grammar (g), + start (states.end ()) +{ +} + +int Automaton::id (RulePointer rule) +{ + return 1 + std::distance (_M_grammar->rules.begin (), rule); +} + +int Automaton::id (Name name) +{ + return std::distance (_M_grammar->names.begin (), name); +} + +int Automaton::id (StatePointer state) +{ + return std::distance (states.begin (), state); +} + +void Automaton::build () +{ + Item item; + item.rule = _M_grammar->goal; + item.dot = _M_grammar->goal->rhs.begin (); + + State tmp (_M_grammar); + tmp.insert (item); + start = internState (tmp).first; + + closure (start); + + buildNullables (); + buildLookbackSets (); + buildReads (); + buildIncludesAndFollows (); + buildLookaheads (); + buildDefaultReduceActions (); +} + +void Automaton::buildNullables () +{ + bool changed = true; + + while (changed) + { + changed = false; + + for (RulePointer rule = _M_grammar->rules.begin (); rule != _M_grammar->rules.end (); ++rule) + { + NameList::iterator nn = std::find_if (rule->rhs.begin (), rule->rhs.end (), std::not1 (__Nullable (this))); + + if (nn == rule->rhs.end ()) + changed |= nullables.insert (rule->lhs).second; + } + } + +#ifndef QLALR_NO_DEBUG_NULLABLES + qerr << "nullables = {" << nullables << endl; +#endif +} + +QPair Automaton::internState (const State &state) +{ + StatePointer it = std::find (states.begin (), states.end (), state); + + if (it != states.end ()) + return qMakePair (it, false); + + return qMakePair (states.insert (it, state), true); +} + +struct _Bucket +{ + QLinkedList items; + + void insert (ItemPointer item) + { items.push_back (item); } + + State toState (Automaton *aut) + { + State st (aut->_M_grammar); + + for (QLinkedList::iterator item = items.begin (); item != items.end (); ++item) + st.insert ((*item)->next ()); + + return st; + } +}; + +void Automaton::closure (StatePointer state) +{ + if (! state->closure.empty ()) // ### not true. + return; + + typedef QMap bucket_map_type; + + bucket_map_type buckets; + QStack working_list; + + for (ItemPointer item = state->kernel.begin (); item != state->kernel.end (); ++item) + working_list.push (item); + + state->closure = state->kernel; + + while (! working_list.empty ()) + { + ItemPointer item = working_list.top (); + working_list.pop (); + + if (item->isReduceItem ()) + continue; + + buckets [*item->dot].insert (item); + + if (_M_grammar->isNonTerminal (*item->dot)) + { + foreach (RulePointer rule, _M_grammar->rule_map.values (*item->dot)) + { + Item ii; + ii.rule = rule; + ii.dot = rule->rhs.begin (); + + QPair r = state->insertClosure (ii); + + if (r.second) + working_list.push (r.first); + } + } + } + + QList todo; + + for (bucket_map_type::iterator bucket = buckets.begin (); bucket != buckets.end (); ++bucket) + { + QPair r = internState (bucket->toState (this)); + + StatePointer target = r.first; + + if (r.second) + todo.push_back (target); + + state->bundle.insert (bucket.key(), target); + } + + while (! todo.empty ()) + { + closure (todo.front ()); + todo.pop_front (); + } +} + +void Automaton::buildLookbackSets () +{ + for (StatePointer p = states.begin (); p != states.end (); ++p) + { + for (Bundle::iterator a = p->bundle.begin (); a != p->bundle.end (); ++a) + { + Name A = a.key (); + + if (! _M_grammar->isNonTerminal (A)) + continue; + + foreach (RulePointer rule, _M_grammar->rule_map.values (A)) + { + StatePointer q = p; + + for (NameList::iterator dot = rule->rhs.begin (); dot != rule->rhs.end (); ++dot) + q = q->bundle.value (*dot, states.end ()); + + Q_ASSERT (q != states.end ()); + + ItemPointer item = q->closure.begin (); + + for (; item != q->closure.end (); ++item) + { + if (item->rule == rule && item->dot == item->end_rhs ()) + break; + } + + if (item == q->closure.end ()) + { + Q_ASSERT (q == p); + Q_ASSERT (rule->rhs.begin () == rule->rhs.end ()); + + for (item = q->closure.begin (); item != q->closure.end (); ++item) + { + if (item->rule == rule && item->dot == item->end_rhs ()) + break; + } + } + + Q_ASSERT (item != q->closure.end ()); + + lookbacks.insert (item, Lookback (p, A)); + +#ifndef QLALR_NO_DEBUG_LOOKBACKS + qerr << "*** (" << id (q) << ", " << *rule << ") lookback (" << id (p) << ", " << *A << ")" << endl; +#endif + } + } + } +} + +void Automaton::buildDirectReads () +{ + for (StatePointer q = states.begin (); q != states.end (); ++q) + { + for (Bundle::iterator a = q->bundle.begin (); a != q->bundle.end (); ++a) + { + if (! _M_grammar->isNonTerminal (a.key ())) + continue; + + StatePointer r = a.value (); + + for (Bundle::iterator z = r->bundle.begin (); z != r->bundle.end (); ++z) + { + Name sym = z.key (); + + if (! _M_grammar->isTerminal (sym)) + continue; + + q->reads [a.key ()].insert (sym); + } + } + +#ifndef QLALR_NO_DEBUG_DIRECT_READS + for (QMap::iterator dr = q->reads.begin (); dr != q->reads.end (); ++dr) + qerr << "*** DR(" << id (q) << ", " << dr.key () << ") = " << dr.value () << endl; +#endif + } +} + +void Automaton::buildReadsDigraph () +{ + for (StatePointer q = states.begin (); q != states.end (); ++q) + { + for (Bundle::iterator a = q->bundle.begin (); a != q->bundle.end (); ++a) + { + if (! _M_grammar->isNonTerminal (a.key ())) + continue; + + StatePointer r = a.value (); + + for (Bundle::iterator z = r->bundle.begin (); z != r->bundle.end (); ++z) + { + Name sym = z.key (); + + if (! _M_grammar->isNonTerminal(sym) || nullables.find (sym) == nullables.end ()) + continue; + + ReadsGraph::iterator source = ReadsGraph::get (Read (q, a.key ())); + ReadsGraph::iterator target = ReadsGraph::get (Read (r, sym)); + + source->insertEdge (target); + +#ifndef QLALR_NO_DEBUG_READS + qerr << "*** "; + dump (qerr, source); + qerr << " reads "; + dump (qerr, target); + qerr << endl; +#endif + } + } + } +} + +void Automaton::buildReads () +{ + buildDirectReads (); + buildReadsDigraph (); + + _M_reads_dfn = 0; + + for (ReadsGraph::iterator node = ReadsGraph::begin_nodes (); node != ReadsGraph::end_nodes (); ++node) + { + if (! node->root) + continue; + + visitReadNode (node); + } + + for (ReadsGraph::iterator node = ReadsGraph::begin_nodes (); node != ReadsGraph::end_nodes (); ++node) + visitReadNode (node); +} + +void Automaton::visitReadNode (ReadNode node) +{ + if (node->dfn != 0) + return; // nothing to do + + int N = node->dfn = ++_M_reads_dfn; + _M_reads_stack.push (node); + +#ifndef QLALR_NO_DEBUG_INCLUDES + // qerr << "*** Debug. visit node (" << id (node->data.state) << ", " << node->data.nt << ") N = " << N << endl; +#endif + + for (ReadsGraph::edge_iterator edge = node->begin (); edge != node->end (); ++edge) + { + ReadsGraph::iterator r = *edge; + + visitReadNode (r); + + node->dfn = qMin (N, r->dfn); + + NameSet &dst = node->data.state->reads [node->data.nt]; + NameSet &src = r->data.state->reads [r->data.nt]; + dst.insert (src.begin (), src.end ()); + } + + if (node->dfn == N) + { + ReadsGraph::iterator tos = _M_reads_stack.top (); + + do { + tos = _M_reads_stack.top (); + _M_reads_stack.pop (); + tos->dfn = INT_MAX; + } while (tos != node); + } +} + +void Automaton::buildIncludesAndFollows () +{ + for (StatePointer p = states.begin (); p != states.end (); ++p) + p->follows = p->reads; + + buildIncludesDigraph (); + + _M_includes_dfn = 0; + + for (IncludesGraph::iterator node = IncludesGraph::begin_nodes (); node != IncludesGraph::end_nodes (); ++node) + { + if (! node->root) + continue; + + visitIncludeNode (node); + } + + for (IncludesGraph::iterator node = IncludesGraph::begin_nodes (); node != IncludesGraph::end_nodes (); ++node) + visitIncludeNode (node); +} + +void Automaton::buildIncludesDigraph () +{ + for (StatePointer pp = states.begin (); pp != states.end (); ++pp) + { + for (Bundle::iterator a = pp->bundle.begin (); a != pp->bundle.end (); ++a) + { + Name name = a.key (); + + if (! _M_grammar->isNonTerminal (name)) + continue; + + foreach (RulePointer rule, _M_grammar->rule_map.values (name)) + { + StatePointer p = pp; + + for (NameList::iterator A = rule->rhs.begin (); A != rule->rhs.end (); ++A) + { + NameList::iterator dot = A; + ++dot; + + if (_M_grammar->isNonTerminal (*A) && dot == rule->rhs.end ()) + { + // found an include edge. + IncludesGraph::iterator target = IncludesGraph::get (Include (pp, name)); + IncludesGraph::iterator source = IncludesGraph::get (Include (p, *A)); + + source->insertEdge (target); + +#ifndef QLALR_NO_DEBUG_INCLUDES + qerr << "*** (" << id (p) << ", " << *A << ") includes (" << id (pp) << ", " << *name << ")" << endl; +#endif // QLALR_NO_DEBUG_INCLUDES + + continue; + } + + p = p->bundle.value (*A); + + if (! _M_grammar->isNonTerminal (*A)) + continue; + + NameList::iterator first_not_nullable = std::find_if (dot, rule->rhs.end (), std::not1 (__Nullable (this))); + if (first_not_nullable != rule->rhs.end ()) + continue; + + // found an include edge. + IncludesGraph::iterator target = IncludesGraph::get (Include (pp, name)); + IncludesGraph::iterator source = IncludesGraph::get (Include (p, *A)); + + source->insertEdge (target); + +#ifndef QLALR_NO_DEBUG_INCLUDES + qerr << "*** (" << id (p) << ", " << *A << ") includes (" << id (pp) << ", " << *name << ")" << endl; +#endif // QLALR_NO_DEBUG_INCLUDES + } + } + } + } +} + +void Automaton::visitIncludeNode (IncludeNode node) +{ + if (node->dfn != 0) + return; // nothing to do + + int N = node->dfn = ++_M_includes_dfn; + _M_includes_stack.push (node); + +#ifndef QLALR_NO_DEBUG_INCLUDES + // qerr << "*** Debug. visit node (" << id (node->data.state) << ", " << node->data.nt << ") N = " << N << endl; +#endif + + for (IncludesGraph::edge_iterator edge = node->begin (); edge != node->end (); ++edge) + { + IncludesGraph::iterator r = *edge; + + visitIncludeNode (r); + + node->dfn = qMin (N, r->dfn); + +#ifndef QLALR_NO_DEBUG_INCLUDES + qerr << "*** Merge. follows"; + dump (qerr, node); + qerr << " += follows"; + dump (qerr, r); + qerr << endl; +#endif + + NameSet &dst = node->data.state->follows [node->data.nt]; + NameSet &src = r->data.state->follows [r->data.nt]; + + dst.insert (src.begin (), src.end ()); + } + + if (node->dfn == N) + { + IncludesGraph::iterator tos = _M_includes_stack.top (); + + do { + tos = _M_includes_stack.top (); + _M_includes_stack.pop (); + tos->dfn = INT_MAX; + } while (tos != node); + } +} + +void Automaton::buildLookaheads () +{ + for (StatePointer p = states.begin (); p != states.end (); ++p) + { + for (ItemPointer item = p->closure.begin (); item != p->closure.end (); ++item) + { + foreach (Lookback lookback, lookbacks.values (item)) + { + StatePointer q = lookback.state; + +#ifndef QLALR_NO_DEBUG_LOOKAHEADS + qerr << "(" << id (p) << ", " << *item->rule << ") lookbacks "; + dump (qerr, lookback); + qerr << " with follows (" << id (q) << ", " << lookback.nt << ") = " << q->follows [lookback.nt] << endl; +#endif + + lookaheads [item].insert (q->follows [lookback.nt].begin (), q->follows [lookback.nt].end ()); + } + } + + // propagate the lookahead in the kernel + ItemPointer k = p->kernel.begin (); + ItemPointer c = p->closure.begin (); + + for (; k != p->kernel.end (); ++k, ++c) + lookaheads [k] = lookaheads [c]; + } +} + +void Automaton::buildDefaultReduceActions () +{ + for (StatePointer state = states.begin (); state != states.end (); ++state) + { + ItemPointer def = state->closure.end (); + int size = -1; + + for (ItemPointer item = state->closure.begin (); item != state->closure.end (); ++item) + { + if (item->dot != item->end_rhs ()) + continue; + + int la = lookaheads.value (item).size (); + if (def == state->closure.end () || la > size) + { + def = item; + size = la; + } + } + + if (def != state->closure.end ()) + { + Q_ASSERT (size >= 0); + state->defaultReduce = def->rule; + } + } +} + +void Automaton::dump (QTextStream &out, IncludeNode incl) +{ + out << "(" << id (incl->data.state) << ", " << incl->data.nt << ")"; +} + +void Automaton::dump (QTextStream &out, ReadNode rd) +{ + out << "(" << id (rd->data.state) << ", " << rd->data.nt << ")"; +} + +void Automaton::dump (QTextStream &out, const Lookback &lp) +{ + out << "(" << id (lp.state) << ", " << lp.nt << ")"; +}