mirror of https://github.com/procxx/kepka.git
qt fixes for xcode7 added
This commit is contained in:
parent
94fe669c6e
commit
4e67d70e17
|
@ -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 <QtGui/QBitmap>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QCocoaCursor::QCocoaCursor()
|
||||
{
|
||||
}
|
||||
|
||||
QCocoaCursor::~QCocoaCursor()
|
||||
{
|
||||
// release cursors
|
||||
QHash<Qt::CursorShape, NSCursor *>::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<QCocoaWindow *>(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<QRgb *>(bmi.scanLine(row));
|
||||
QRgb *bmmData = reinterpret_cast<QRgb *>(bmmi.scanLine(row));
|
||||
QRgb *finalData = reinterpret_cast<QRgb *>(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<NSImage *>(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<NSImage *>(qt_mac_create_nsimage(pixmap));
|
||||
}
|
||||
|
||||
NSCursor *nsCursor = [[NSCursor alloc] initWithImage:nsimage hotSpot: hotSpot];
|
||||
[nsimage release];
|
||||
return nsCursor;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
|
@ -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 <limits.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#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<ItemPointer, bool> 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<ItemPointer, bool> 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<Name, bool>
|
||||
{
|
||||
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<StatePointer, bool> 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<ItemPointer> items;
|
||||
|
||||
void insert (ItemPointer item)
|
||||
{ items.push_back (item); }
|
||||
|
||||
State toState (Automaton *aut)
|
||||
{
|
||||
State st (aut->_M_grammar);
|
||||
|
||||
for (QLinkedList<ItemPointer>::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<Name, _Bucket> bucket_map_type;
|
||||
|
||||
bucket_map_type buckets;
|
||||
QStack<ItemPointer> 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<ItemPointer, bool> r = state->insertClosure (ii);
|
||||
|
||||
if (r.second)
|
||||
working_list.push (r.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QList<StatePointer> todo;
|
||||
|
||||
for (bucket_map_type::iterator bucket = buckets.begin (); bucket != buckets.end (); ++bucket)
|
||||
{
|
||||
QPair<StatePointer, bool> 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<Name, NameSet>::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 << ")";
|
||||
}
|
Loading…
Reference in New Issue