From 0f9aa307a30f1a10e5d214da7a8ae5e452ad24cc Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 26 Nov 2021 12:54:50 +0100 Subject: [PATCH] ClangCodeModel: Highlight Q_PROPERTY declarations with clangd We re-use the moc parser for this purpose. Change-Id: Ib0ef4f727d1f0b862a202a95a3ae9c551cb502a5 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: David Schulz --- src/plugins/clangcodemodel/CMakeLists.txt | 10 + src/plugins/clangcodemodel/clangcodemodel.pro | 12 + src/plugins/clangcodemodel/clangcodemodel.qbs | 25 + src/plugins/clangcodemodel/clangdclient.cpp | 21 + .../clangdqpropertyhighlighter.cpp | 427 ++++++ .../clangdqpropertyhighlighter.h | 52 + src/plugins/clangcodemodel/moc/keywords.cpp | 1045 +++++++++++++ src/plugins/clangcodemodel/moc/parser.cpp | 64 + src/plugins/clangcodemodel/moc/parser.h | 110 ++ src/plugins/clangcodemodel/moc/ppkeywords.cpp | 235 +++ .../clangcodemodel/moc/preprocessor.cpp | 1317 +++++++++++++++++ src/plugins/clangcodemodel/moc/preprocessor.h | 92 ++ src/plugins/clangcodemodel/moc/symbols.h | 193 +++ src/plugins/clangcodemodel/moc/token.cpp | 45 + src/plugins/clangcodemodel/moc/token.h | 276 ++++ src/plugins/clangcodemodel/moc/utils.h | 110 ++ .../clangcodemodel/test/clangdtests.cpp | 21 +- .../test/data/highlighting/highlighting.cpp | 4 +- 18 files changed, 4050 insertions(+), 9 deletions(-) create mode 100644 src/plugins/clangcodemodel/clangdqpropertyhighlighter.cpp create mode 100644 src/plugins/clangcodemodel/clangdqpropertyhighlighter.h create mode 100644 src/plugins/clangcodemodel/moc/keywords.cpp create mode 100644 src/plugins/clangcodemodel/moc/parser.cpp create mode 100644 src/plugins/clangcodemodel/moc/parser.h create mode 100644 src/plugins/clangcodemodel/moc/ppkeywords.cpp create mode 100644 src/plugins/clangcodemodel/moc/preprocessor.cpp create mode 100644 src/plugins/clangcodemodel/moc/preprocessor.h create mode 100644 src/plugins/clangcodemodel/moc/symbols.h create mode 100644 src/plugins/clangcodemodel/moc/token.cpp create mode 100644 src/plugins/clangcodemodel/moc/token.h create mode 100644 src/plugins/clangcodemodel/moc/utils.h diff --git a/src/plugins/clangcodemodel/CMakeLists.txt b/src/plugins/clangcodemodel/CMakeLists.txt index e8f15a2303b..ee5bc7540fc 100644 --- a/src/plugins/clangcodemodel/CMakeLists.txt +++ b/src/plugins/clangcodemodel/CMakeLists.txt @@ -30,6 +30,7 @@ add_qtc_plugin(ClangCodeModel clangdiagnosticmanager.cpp clangdiagnosticmanager.h clangdiagnostictooltipwidget.cpp clangdiagnostictooltipwidget.h clangdquickfixfactory.cpp clangdquickfixfactory.h + clangdqpropertyhighlighter.cpp clangdqpropertyhighlighter.h clangeditordocumentparser.cpp clangeditordocumentparser.h clangeditordocumentprocessor.cpp clangeditordocumentprocessor.h clangfixitoperation.cpp clangfixitoperation.h @@ -52,6 +53,15 @@ add_qtc_plugin(ClangCodeModel EXPLICIT_MOC clangcodemodelplugin.h ) +extend_qtc_plugin(ClangCodeModel + SOURCES + moc/parser.cpp moc/parser.h + moc/preprocessor.cpp moc/preprocessor.h + moc/symbols.h + moc/token.cpp moc/token.h + moc/utils.h +) + extend_qtc_plugin(ClangCodeModel CONDITION WITH_TESTS SOURCES diff --git a/src/plugins/clangcodemodel/clangcodemodel.pro b/src/plugins/clangcodemodel/clangcodemodel.pro index 5675ea9d57e..fc81fab9e01 100644 --- a/src/plugins/clangcodemodel/clangcodemodel.pro +++ b/src/plugins/clangcodemodel/clangcodemodel.pro @@ -24,6 +24,7 @@ SOURCES += \ clangdiagnosticfilter.cpp \ clangdiagnosticmanager.cpp \ clangdiagnostictooltipwidget.cpp \ + clangdqpropertyhighlighter.cpp \ clangeditordocumentparser.cpp \ clangeditordocumentprocessor.cpp \ clangfixitoperation.cpp \ @@ -44,6 +45,9 @@ SOURCES += \ clangdclient.cpp \ clangdquickfixfactory.cpp \ clangdlocatorfilters.cpp \ + moc/parser.cpp \ + moc/preprocessor.cpp \ + moc/token.cpp HEADERS += \ clangactivationsequencecontextprocessor.h \ @@ -65,6 +69,7 @@ HEADERS += \ clangdiagnosticfilter.h \ clangdiagnosticmanager.h \ clangdiagnostictooltipwidget.h \ + clangdqpropertyhighlighter.h \ clangeditordocumentparser.h \ clangeditordocumentprocessor.h \ clangfixitoperation.h \ @@ -86,6 +91,13 @@ HEADERS += \ clangdclient.h \ clangdquickfixfactory.h \ clangdlocatorfilters.h \ + moc/keywords.cpp \ + moc/parser.h \ + moc/ppkeywords.cpp \ + moc/preprocessor.h \ + moc/symbols.h \ + moc/token.h \ + moc/utils.h FORMS += clangprojectsettingswidget.ui diff --git a/src/plugins/clangcodemodel/clangcodemodel.qbs b/src/plugins/clangcodemodel/clangcodemodel.qbs index 7b6689ad45f..75a7f6bc90f 100644 --- a/src/plugins/clangcodemodel/clangcodemodel.qbs +++ b/src/plugins/clangcodemodel/clangcodemodel.qbs @@ -66,6 +66,8 @@ QtcPlugin { "clangdiagnostictooltipwidget.h", "clangdlocatorfilters.cpp", "clangdlocatorfilters.h", + "clangdqpropertyhighlighter.cpp", + "clangdqpropertyhighlighter.h", "clangdquickfixfactory.cpp", "clangdquickfixfactory.h", "clangeditordocumentparser.cpp", @@ -106,6 +108,29 @@ QtcPlugin { "clangutils.h", ] + Group { + name: "moc sources" + prefix: "moc/" + files: [ + "parser.cpp", + "parser.h", + "preprocessor.cpp", + "preprocessor.h", + "symbols.h", + "token.cpp", + "token.h", + "utils.h", + ] + Group { + name: "weirdly-named moc headers" + files: [ + "keywords.cpp", + "ppkeywords.cpp", + ] + fileTags: "hpp" + } + } + Group { name: "Tests" condition: qtc.testsEnabled diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 032f7b62608..17937fbbd3a 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -28,6 +28,7 @@ #include "clangcompletionassistprocessor.h" #include "clangcompletioncontextanalyzer.h" #include "clangdiagnosticmanager.h" +#include "clangdqpropertyhighlighter.h" #include "clangmodelmanagersupport.h" #include "clangpreprocessorassistproposalitem.h" #include "clangtextmark.h" @@ -3232,6 +3233,26 @@ ExtraHighlightingResultsCollector::ExtraHighlightingResultsCollector( void ExtraHighlightingResultsCollector::collect() { + for (int i = 0; i < m_results.length(); ++i) { + const HighlightingResult res = m_results.at(i); + if (res.textStyles.mainStyle != C_PREPROCESSOR || res.length != 10) + continue; + const int pos = Utils::Text::positionInText(m_doc, res.line, res.column); + if (subViewLen(m_docContent, pos, 10) != QLatin1String("Q_PROPERTY")) + continue; + int endPos; + if (i < m_results.length() - 1) { + const HighlightingResult nextRes = m_results.at(i + 1); + endPos = Utils::Text::positionInText(m_doc, nextRes.line, nextRes.column); + } else { + endPos = m_docContent.length(); + } + const QString qPropertyString = m_docContent.mid(pos, endPos - pos); + QPropertyHighlighter propHighlighter(m_doc, qPropertyString, pos); + for (const HighlightingResult &newRes : propHighlighter.highlight()) + m_results.insert(++i, newRes); + } + if (!m_ast.isValid()) return; visitNode(m_ast); diff --git a/src/plugins/clangcodemodel/clangdqpropertyhighlighter.cpp b/src/plugins/clangcodemodel/clangdqpropertyhighlighter.cpp new file mode 100644 index 00000000000..96bbc14d420 --- /dev/null +++ b/src/plugins/clangcodemodel/clangdqpropertyhighlighter.cpp @@ -0,0 +1,427 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "clangdqpropertyhighlighter.h" + +#include "moc/parser.h" +#include "moc/preprocessor.h" +#include "moc/utils.h" + +#include + +#include + +using namespace TextEditor; + +namespace ClangCodeModel { +namespace Internal { + +class QPropertyHighlighter::Private +{ +public: + QByteArray lexemUntil(Token target); + + void highlightProperty(); + + const QTextDocument *document; + QString input; + int position; + Preprocessor pp; + Parser parser; + TextEditor::HighlightingResults results; + +private: + void highlightType(); + void highlightAttributes(); + void highlightRevision(); + bool until(Token target); + void skipCxxAttributes(); + void addResult(TextStyle textStyle, int symbolOffset = 0); +}; + +QPropertyHighlighter::QPropertyHighlighter(const QTextDocument *doc, const QString &input, + int position) + : d(new Private) +{ + d->document = doc; + d->input = input; + d->position = position; + + d->pp.macros["Q_MOC_RUN"]; + d->pp.macros["__cplusplus"]; + + // Don't stumble over GCC extensions + Macro dummyVariadicFunctionMacro; + dummyVariadicFunctionMacro.isFunction = true; + dummyVariadicFunctionMacro.isVariadic = true; + dummyVariadicFunctionMacro.arguments += Symbol(0, PP_IDENTIFIER, "__VA_ARGS__"); + d->pp.macros["__attribute__"] = dummyVariadicFunctionMacro; + d->pp.macros["__declspec"] = dummyVariadicFunctionMacro; +} + +QPropertyHighlighter::~QPropertyHighlighter() { delete d; } + +const HighlightingResults QPropertyHighlighter::highlight() +{ + try { + d->highlightProperty(); + return d->results; + } catch (const MocParseException &) { + return {}; + } +} + +void QPropertyHighlighter::Private::highlightProperty() +{ + parser.symbols = pp.preprocessed({}, input.toUtf8()); + parser.next(Q_PROPERTY_TOKEN); + parser.next(LPAREN); + highlightType(); + parser.next(); + addResult(C_FIELD); + highlightAttributes(); +} + +void QPropertyHighlighter::Private::highlightType() +{ + for (;;) { + skipCxxAttributes(); + switch (parser.next()) { + case SIGNED: + case UNSIGNED: + case CONST_TOKEN: + case VOLATILE: + addResult(C_KEYWORD); + continue; + case Q_MOC_COMPAT_TOKEN: + case Q_INVOKABLE_TOKEN: + case Q_SCRIPTABLE_TOKEN: + case Q_SIGNALS_TOKEN: + case Q_SLOTS_TOKEN: + case Q_SIGNAL_TOKEN: + case Q_SLOT_TOKEN: + return; + case NOTOKEN: + return; + default: + parser.prev(); + break; + } + break; + } + + skipCxxAttributes(); + parser.test(ENUM) || parser.test(CLASS) || parser.test(STRUCT); + for(;;) { + skipCxxAttributes(); + switch (parser.next()) { + case IDENTIFIER: + addResult(C_TYPE); + break; + case CHAR_TOKEN: + case SHORT_TOKEN: + case INT_TOKEN: + case LONG_TOKEN: + addResult(C_KEYWORD); + // preserve '[unsigned] long long', 'short int', 'long int', 'long double' + if (parser.test(LONG_TOKEN) || parser.test(INT_TOKEN) || parser.test(DOUBLE)) { + parser.prev(); + continue; + } + break; + case FLOAT_TOKEN: + case DOUBLE: + case VOID_TOKEN: + case BOOL_TOKEN: + case AUTO: + addResult(C_KEYWORD); + break; + case NOTOKEN: + return; + default: + parser.prev(); + break; + } + if (parser.test(LANGLE)) { + if (results.size() < 2) { + // '<' cannot start a type + return; + } + until(RANGLE); // TODO: Highlight template parameter? + } + if (parser.test(SCOPE)) { + addResult(C_PUNCTUATION); + } else { + break; + } + } + while (parser.test(CONST_TOKEN) || parser.test(VOLATILE) || parser.test(SIGNED) + || parser.test(UNSIGNED) || parser.test(STAR) || parser.test(AND) + || parser.test(ANDAND)) { + TextStyle textStyle = parser.test(CONST_TOKEN) || parser.test(VOLATILE) + ? C_KEYWORD + : parser.test(SIGNED) || parser.test(UNSIGNED) + ? C_TYPE + : C_PUNCTUATION; + addResult(textStyle); + } +} + +void QPropertyHighlighter::Private::highlightAttributes() +{ + auto checkIsFunction = [&](const QByteArray &def, const char *name) { + if (def.endsWith(')')) { + QByteArray msg = "Providing a function for "; + msg += name; + msg += " in a property declaration is not be supported in Qt 6."; + parser.error(msg.constData()); + } + }; + + while (parser.test(IDENTIFIER)) { + const QByteArray l = parser.lexem(); + if (l[0] == 'C' && l == "CONSTANT") { + addResult(C_KEYWORD); + continue; + } else if (l[0] == 'F' && l == "FINAL") { + addResult(C_KEYWORD); + continue; + } else if (l[0] == 'N' && l == "NAME") { + addResult(C_KEYWORD); + parser.next(IDENTIFIER); + addResult(C_FIELD); + continue; + } else if (l[0] == 'R' && l == "REQUIRED") { + addResult(C_KEYWORD); + continue; + } else if (l[0] == 'R' && l == "REVISION" && parser.test(LPAREN)) { + parser.prev(); + highlightRevision(); + continue; + } + + QByteArray v, v2; + if (parser.test(LPAREN)) { + v = lexemUntil(RPAREN); + v = v.mid(1, v.length() - 2); // removes the '(' and ')' + } else if (parser.test(INTEGER_LITERAL)) { + v = parser.lexem(); + if (l != "REVISION") + parser.error(1); + } else { + addResult(C_KEYWORD); + parser.next(IDENTIFIER); + addResult(C_FUNCTION); + v = parser.lexem(); + if (parser.test(LPAREN)) + v2 = lexemUntil(RPAREN); + else if (v != "true" && v != "false") + v2 = "()"; + } + switch (l[0]) { + case 'M': + if (l != "MEMBER") + parser.error(2); + break; + case 'R': + if (l == "READ") + break; + if (l == "RESET") + break; + if (l == "REVISION") { + parser.prev(); + highlightRevision(); + break; + } + parser.error(2); + break; + case 'S': + if (l == "SCRIPTABLE") { + checkIsFunction(v + v2, "SCRIPTABLE"); + } else if (l == "STORED") { + checkIsFunction(v + v2, "STORED"); + } else + parser.error(2); + break; + case 'W': if (l != "WRITE") parser.error(2); + break; + case 'B': if (l != "BINDABLE") parser.error(2); + break; + case 'D': if (l != "DESIGNABLE") parser.error(2); + checkIsFunction(v + v2, "DESIGNABLE"); + break; + case 'N': if (l != "NOTIFY") parser.error(2); + break; + case 'U': if (l != "USER") parser.error(2); + checkIsFunction(v + v2, "USER"); + break; + default: + parser.error(2); + } + } +} + +void QPropertyHighlighter::Private::highlightRevision() +{ + addResult(C_KEYWORD); + QByteArray revisionString; + const bool hasParen = parser.test(LPAREN); + if (hasParen) { + revisionString = lexemUntil(RPAREN); + revisionString.remove(0, 1); + revisionString.chop(1); + revisionString.replace(',', '.'); + } else { + parser.next(INTEGER_LITERAL); + revisionString = parser.lexem(); + } + QVersionNumber version = QVersionNumber::fromString(QString::fromUtf8(revisionString)); + if (version.isNull() || version.segmentCount() > 2) + parser.error("Invalid revision"); +} + +QByteArray QPropertyHighlighter::Private::lexemUntil(Token target) +{ + int from = parser.index; + until(target); + QByteArray s; + while (from <= parser.index) { + QByteArray n = parser.symbols.at(from++-1).lexem(); + if (s.size() && n.size()) { + char prev = s.at(s.size()-1); + char next = n.at(0); + if ((is_ident_char(prev) && is_ident_char(next)) + || (prev == '<' && next == ':') + || (prev == '>' && next == '>')) + s += ' '; + } + s += n; + } + return s; +} + +bool QPropertyHighlighter::Private::until(Token target) +{ + int braceCount = 0; + int brackCount = 0; + int parenCount = 0; + int angleCount = 0; + if (parser.index) { + switch(parser.symbols.at(parser.index-1).token) { + case LBRACE: ++braceCount; break; + case LBRACK: ++brackCount; break; + case LPAREN: ++parenCount; break; + case LANGLE: ++angleCount; break; + default: break; + } + } + + //when searching commas within the default argument, we should take care of template depth (anglecount) + // unfortunatelly, we do not have enough semantic information to know if '<' is the operator< or + // the beginning of a template type. so we just use heuristics. + int possible = -1; + + while (parser.index < parser.symbols.size()) { + Token t = parser.symbols.at(parser.index++).token; + switch (t) { + case LBRACE: ++braceCount; break; + case RBRACE: --braceCount; break; + case LBRACK: ++brackCount; break; + case RBRACK: --brackCount; break; + case LPAREN: ++parenCount; break; + case RPAREN: --parenCount; break; + case LANGLE: + if (parenCount == 0 && braceCount == 0) + ++angleCount; + break; + case RANGLE: + if (parenCount == 0 && braceCount == 0) + --angleCount; + break; + case GTGT: + if (parenCount == 0 && braceCount == 0) { + angleCount -= 2; + t = RANGLE; + } + break; + default: break; + } + if (t == target + && braceCount <= 0 + && brackCount <= 0 + && parenCount <= 0 + && (target != RANGLE || angleCount <= 0)) { + if (target != COMMA || angleCount <= 0) + return true; + possible = parser.index; + } + + if (target == COMMA && t == EQ && possible != -1) { + parser.index = possible; + return true; + } + + if (braceCount < 0 || brackCount < 0 || parenCount < 0 + || (target == RANGLE && angleCount < 0)) { + --parser.index; + break; + } + + if (braceCount <= 0 && t == SEMIC) { + // Abort on semicolon. Allow recovering bad template parsing (QTBUG-31218) + break; + } + } + + if (target == COMMA && angleCount != 0 && possible != -1) { + parser.index = possible; + return true; + } + + return false; +} + +void QPropertyHighlighter::Private::skipCxxAttributes() +{ + int rewind = parser.index; + if (parser.test(LBRACK) && parser.test(LBRACK) && until(RBRACK) && parser.test(RBRACK)) + return; + parser.index = rewind; +} + +void QPropertyHighlighter::Private::addResult(TextStyle textStyle, int symbolOffset) +{ + const Symbol &s = parser.symbol_lookup(symbolOffset); + int line, column; + Utils::Text::convertPosition(document, position + s.from, &line, &column); + if (line > 0 && column > 0) { + TextStyles styles; + styles.mainStyle = textStyle; + results << HighlightingResult(line, column, s.len, styles); + } +} + +} // namespace Internal +} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangdqpropertyhighlighter.h b/src/plugins/clangcodemodel/clangdqpropertyhighlighter.h new file mode 100644 index 00000000000..70689da4774 --- /dev/null +++ b/src/plugins/clangcodemodel/clangdqpropertyhighlighter.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +QT_BEGIN_NAMESPACE +class QTextDocument; +QT_END_NAMESPACE + +namespace ClangCodeModel { +namespace Internal { + +class QPropertyHighlighter +{ +public: + QPropertyHighlighter(const QTextDocument *doc, const QString &input, int position); + ~QPropertyHighlighter(); + + const TextEditor::HighlightingResults highlight(); + +private: + class Private; + Private * const d; +}; + +} // namespace Internal +} // namespace ClangCodeModel + diff --git a/src/plugins/clangcodemodel/moc/keywords.cpp b/src/plugins/clangcodemodel/moc/keywords.cpp new file mode 100644 index 00000000000..5492c71942c --- /dev/null +++ b/src/plugins/clangcodemodel/moc/keywords.cpp @@ -0,0 +1,1045 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// auto generated +// DO NOT EDIT. + +static const short keyword_trans[][128] = { + {0,0,0,0,0,0,0,0,0,579,576,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 579,252,577,580,8,38,239,578,25,26,236,234,30,235,27,237, + 22,22,22,22,22,22,22,22,22,22,34,41,23,39,24,43, + 0,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,21,8,8,8,8,8,8,8,8,8,31,582,32,238,8, + 0,1,2,3,4,5,6,7,8,9,8,8,10,11,12,13, + 14,8,15,16,17,18,19,20,8,8,8,36,245,37,248,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,192,0,173,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,240,0,0,0,0,0,287, + 0,0,341,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,109,0,0,0,0,0,0,280,0,0,0,121,0,0,80, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,229,0,0,0,0,0,0,0,0,0,312, + 0,0,0,0,0,0,0,0,0,44,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,327,0,133,0, + 0,0,0,0,0,0,0,0,168,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,308,0,0,339, + 0,0,116,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,326,0,0,0,0,0,0,0,198,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,125,0,0,0,227,0,0,0,0,0,0,0,0,0,253, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,150,0,0,163,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,290,222,0,0,497,0,0,0, + 0,0,0,0,55,0,0,330,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,97,0,0,94,0,0,0,0,0,0,0, + 0,0,107,0,0,0,0,0,0,89,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,140,0, + 0,0,0,194,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,144,0,0,0,0,0,208, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,283,0,0,0,0,335,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,521,0,0,0,0,0,0,0,0,0,0,357, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,33,0,263,272,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,273,264,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,42,0,0,0,28,0, + 585,585,585,585,585,585,585,585,585,585,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,40,0,0,0,32,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,259,37,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,56,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,136,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,176,0,66,0,0,0,0,0,0, + 0,0,0,0,353,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,249,81,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,82,345,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,113,0,0,0,0,92,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,95,0,0,0,0,0,0, + 0,0,104,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,319,110,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,141,0,0,0,0,0,0, + 0,0,0,302,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,151,0,0,0,0,0,156, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 169,0,0,0,182,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,203,0,0,170, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,199,0,0,0, + 0,0,0,0,294,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,317,0,0,209,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,298,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,223,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,321,0,0,0,0,0,230,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,276,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,277,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,256,278,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,584,0,0,0,0,583, + 0,0,0,0,0,0,0,0,0,0,0,0,0,258,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,274,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,261,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,242,0,0,0,0,0,0,0,0,0,0,0,0,0,246, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,262,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,275,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,494,0,0,0,300,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,475,424,408,416,380,0,484,0,0,0,565,364,358, + 386,0,557,472,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,394,0,0,0, + 0,0,387,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,511,0,0,0,0,0,388, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,412,0,0,0,0,0,0,0,0,0,0,0,413, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,420,0,0,0,0,0,0,0,0,0,0,0,421, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,454,432,0,0,437,0,0,0,446,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,540,0,473,0,0,0,501,0,0,507,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,486,0,533,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 549,0,0,517,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} +}; + +static const struct +{ + Token token; + short next; + char defchar; + short defnext; + Token ident; +} keywords[] = { + {NOTOKEN, 0, 0, 0, NOTOKEN}, + {CHARACTER, 1, 0, 0, NOTOKEN}, + {CHARACTER, 2, 0, 0, NOTOKEN}, + {CHARACTER, 3, 0, 0, NOTOKEN}, + {CHARACTER, 4, 0, 0, NOTOKEN}, + {CHARACTER, 5, 0, 0, NOTOKEN}, + {CHARACTER, 6, 0, 0, NOTOKEN}, + {CHARACTER, 0, 111, 350, NOTOKEN}, + {CHARACTER, 0, 0, 0, NOTOKEN}, + {CHARACTER, 7, 0, 0, NOTOKEN}, + {CHARACTER, 0, 111, 295, NOTOKEN}, + {CHARACTER, 0, 117, 186, NOTOKEN}, + {CHARACTER, 8, 0, 0, NOTOKEN}, + {CHARACTER, 0, 112, 215, NOTOKEN}, + {CHARACTER, 9, 0, 0, NOTOKEN}, + {CHARACTER, 0, 101, 65, NOTOKEN}, + {CHARACTER, 10, 0, 0, NOTOKEN}, + {CHARACTER, 11, 0, 0, NOTOKEN}, + {CHARACTER, 12, 0, 0, NOTOKEN}, + {CHARACTER, 13, 0, 0, NOTOKEN}, + {CHARACTER, 14, 0, 0, NOTOKEN}, + {CHARACTER, 15, 0, 0, NOTOKEN}, + {DIGIT, 0, 0, 0, NOTOKEN}, + {LANGLE, 16, 0, 0, NOTOKEN}, + {RANGLE, 17, 0, 0, NOTOKEN}, + {LPAREN, 0, 0, 0, NOTOKEN}, + {RPAREN, 0, 0, 0, NOTOKEN}, + {DOT, 18, 0, 0, NOTOKEN}, + {INCOMPLETE, 0, 46, 29, NOTOKEN}, + {ELIPSIS, 0, 0, 0, NOTOKEN}, + {COMMA, 0, 0, 0, NOTOKEN}, + {LBRACK, 0, 0, 0, NOTOKEN}, + {RBRACK, 0, 0, 0, NOTOKEN}, + {LBRACK, 0, 58, 35, NOTOKEN}, + {COLON, 19, 0, 0, NOTOKEN}, + {LANGLE_SCOPE, 0, 0, 0, NOTOKEN}, + {LBRACE, 0, 0, 0, NOTOKEN}, + {RBRACE, 0, 0, 0, NOTOKEN}, + {PERCENT, 20, 0, 0, NOTOKEN}, + {EQ, 0, 61, 267, NOTOKEN}, + {SCOPE, 0, 0, 0, NOTOKEN}, + {SEMIC, 0, 0, 0, NOTOKEN}, + {DOTSTAR, 0, 0, 0, NOTOKEN}, + {QUESTION, 0, 0, 0, NOTOKEN}, + {CHARACTER, 0, 110, 45, CHARACTER}, + {CHARACTER, 0, 97, 46, CHARACTER}, + {CHARACTER, 0, 109, 47, CHARACTER}, + {CHARACTER, 0, 105, 48, CHARACTER}, + {CHARACTER, 0, 99, 49, CHARACTER}, + {CHARACTER, 0, 95, 50, CHARACTER}, + {CHARACTER, 0, 99, 51, CHARACTER}, + {CHARACTER, 0, 97, 52, CHARACTER}, + {CHARACTER, 0, 115, 53, CHARACTER}, + {CHARACTER, 0, 116, 54, CHARACTER}, + {DYNAMIC_CAST, 0, 0, 0, CHARACTER}, + {CHARACTER, 21, 0, 0, CHARACTER}, + {CHARACTER, 0, 116, 57, CHARACTER}, + {CHARACTER, 0, 105, 58, CHARACTER}, + {CHARACTER, 0, 99, 59, CHARACTER}, + {STATIC, 0, 95, 60, CHARACTER}, + {CHARACTER, 0, 99, 61, CHARACTER}, + {CHARACTER, 0, 97, 62, CHARACTER}, + {CHARACTER, 0, 115, 63, CHARACTER}, + {CHARACTER, 0, 116, 64, CHARACTER}, + {STATIC_CAST, 0, 0, 0, CHARACTER}, + {CHARACTER, 22, 0, 0, CHARACTER}, + {CHARACTER, 0, 110, 67, CHARACTER}, + {CHARACTER, 0, 116, 68, CHARACTER}, + {CHARACTER, 0, 101, 69, CHARACTER}, + {CHARACTER, 0, 114, 70, CHARACTER}, + {CHARACTER, 0, 112, 71, CHARACTER}, + {CHARACTER, 0, 114, 72, CHARACTER}, + {CHARACTER, 0, 101, 73, CHARACTER}, + {CHARACTER, 0, 116, 74, CHARACTER}, + {CHARACTER, 0, 95, 75, CHARACTER}, + {CHARACTER, 0, 99, 76, CHARACTER}, + {CHARACTER, 0, 97, 77, CHARACTER}, + {CHARACTER, 0, 115, 78, CHARACTER}, + {CHARACTER, 0, 116, 79, CHARACTER}, + {REINTERPRET_CAST, 0, 0, 0, CHARACTER}, + {CHARACTER, 23, 0, 0, CHARACTER}, + {CHARACTER, 24, 0, 0, CHARACTER}, + {CHARACTER, 0, 116, 83, CHARACTER}, + {CONST_TOKEN, 0, 95, 84, CHARACTER}, + {CHARACTER, 0, 99, 85, CHARACTER}, + {CHARACTER, 0, 97, 86, CHARACTER}, + {CHARACTER, 0, 115, 87, CHARACTER}, + {CHARACTER, 0, 116, 88, CHARACTER}, + {CONST_CAST, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 112, 90, CHARACTER}, + {CHARACTER, 0, 101, 91, CHARACTER}, + {CHARACTER, 25, 0, 0, CHARACTER}, + {CHARACTER, 0, 100, 93, CHARACTER}, + {TYPEID, 0, 0, 0, CHARACTER}, + {CHARACTER, 26, 0, 0, CHARACTER}, + {CHARACTER, 0, 115, 96, CHARACTER}, + {THIS, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 109, 98, CHARACTER}, + {CHARACTER, 0, 112, 99, CHARACTER}, + {CHARACTER, 0, 108, 100, CHARACTER}, + {CHARACTER, 0, 97, 101, CHARACTER}, + {CHARACTER, 0, 116, 102, CHARACTER}, + {CHARACTER, 0, 101, 103, CHARACTER}, + {TEMPLATE, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 111, 105, CHARACTER}, + {CHARACTER, 0, 119, 106, CHARACTER}, + {THROW, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 121, 108, CHARACTER}, + {TRY, 0, 0, 0, CHARACTER}, + {CHARACTER, 27, 0, 0, CHARACTER}, + {CHARACTER, 0, 99, 111, CHARACTER}, + {CHARACTER, 0, 104, 112, CHARACTER}, + {CATCH, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 101, 114, CHARACTER}, + {CHARACTER, 0, 102, 115, CHARACTER}, + {TYPEDEF, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 105, 117, CHARACTER}, + {CHARACTER, 0, 101, 118, CHARACTER}, + {CHARACTER, 0, 110, 119, CHARACTER}, + {CHARACTER, 0, 100, 120, CHARACTER}, + {FRIEND, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 97, 122, CHARACTER}, + {CHARACTER, 0, 115, 123, CHARACTER}, + {CHARACTER, 0, 115, 124, CHARACTER}, + {CLASS, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 109, 126, CHARACTER}, + {CHARACTER, 0, 101, 127, CHARACTER}, + {CHARACTER, 0, 115, 128, CHARACTER}, + {CHARACTER, 0, 112, 129, CHARACTER}, + {CHARACTER, 0, 97, 130, CHARACTER}, + {CHARACTER, 0, 99, 131, CHARACTER}, + {CHARACTER, 0, 101, 132, CHARACTER}, + {NAMESPACE, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 117, 134, CHARACTER}, + {CHARACTER, 0, 109, 135, CHARACTER}, + {ENUM, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 117, 137, CHARACTER}, + {CHARACTER, 0, 99, 138, CHARACTER}, + {CHARACTER, 0, 116, 139, CHARACTER}, + {STRUCT, 0, 0, 0, CHARACTER}, + {CHARACTER, 28, 0, 0, CHARACTER}, + {CHARACTER, 0, 111, 142, CHARACTER}, + {CHARACTER, 0, 110, 143, CHARACTER}, + {UNION, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 114, 145, CHARACTER}, + {CHARACTER, 0, 116, 146, CHARACTER}, + {CHARACTER, 0, 117, 147, CHARACTER}, + {CHARACTER, 0, 97, 148, CHARACTER}, + {CHARACTER, 0, 108, 149, CHARACTER}, + {VIRTUAL, 0, 0, 0, CHARACTER}, + {CHARACTER, 29, 0, 0, CHARACTER}, + {CHARACTER, 0, 118, 152, CHARACTER}, + {CHARACTER, 0, 97, 153, CHARACTER}, + {CHARACTER, 0, 116, 154, CHARACTER}, + {CHARACTER, 0, 101, 155, CHARACTER}, + {PRIVATE, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 116, 157, CHARACTER}, + {CHARACTER, 0, 101, 158, CHARACTER}, + {CHARACTER, 0, 99, 159, CHARACTER}, + {CHARACTER, 0, 116, 160, CHARACTER}, + {CHARACTER, 0, 101, 161, CHARACTER}, + {CHARACTER, 0, 100, 162, CHARACTER}, + {PROTECTED, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 98, 164, CHARACTER}, + {CHARACTER, 0, 108, 165, CHARACTER}, + {CHARACTER, 0, 105, 166, CHARACTER}, + {CHARACTER, 0, 99, 167, CHARACTER}, + {PUBLIC, 0, 0, 0, CHARACTER}, + {CHARACTER, 30, 0, 0, CHARACTER}, + {CHARACTER, 31, 0, 0, CHARACTER}, + {CHARACTER, 0, 114, 171, CHARACTER}, + {CHARACTER, 0, 116, 172, CHARACTER}, + {EXPORT, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 116, 174, CHARACTER}, + {CHARACTER, 0, 111, 175, CHARACTER}, + {AUTO, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 105, 177, CHARACTER}, + {CHARACTER, 0, 115, 178, CHARACTER}, + {CHARACTER, 0, 116, 179, CHARACTER}, + {CHARACTER, 0, 101, 180, CHARACTER}, + {CHARACTER, 0, 114, 181, CHARACTER}, + {REGISTER, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 101, 183, CHARACTER}, + {CHARACTER, 0, 114, 184, CHARACTER}, + {CHARACTER, 0, 110, 185, CHARACTER}, + {EXTERN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 116, 187, CHARACTER}, + {CHARACTER, 0, 97, 188, CHARACTER}, + {CHARACTER, 0, 98, 189, CHARACTER}, + {CHARACTER, 0, 108, 190, CHARACTER}, + {CHARACTER, 0, 101, 191, CHARACTER}, + {MUTABLE, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 109, 193, CHARACTER}, + {ASM, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 105, 195, CHARACTER}, + {CHARACTER, 0, 110, 196, CHARACTER}, + {CHARACTER, 0, 103, 197, CHARACTER}, + {USING, 0, 0, 0, CHARACTER}, + {CHARACTER, 32, 0, 0, CHARACTER}, + {CHARACTER, 0, 105, 200, CHARACTER}, + {CHARACTER, 0, 110, 201, CHARACTER}, + {CHARACTER, 0, 101, 202, CHARACTER}, + {INLINE, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 105, 204, CHARACTER}, + {CHARACTER, 0, 99, 205, CHARACTER}, + {CHARACTER, 0, 105, 206, CHARACTER}, + {CHARACTER, 0, 116, 207, CHARACTER}, + {EXPLICIT, 0, 0, 0, CHARACTER}, + {CHARACTER, 33, 0, 0, CHARACTER}, + {CHARACTER, 0, 97, 210, CHARACTER}, + {CHARACTER, 0, 116, 211, CHARACTER}, + {CHARACTER, 0, 105, 212, CHARACTER}, + {CHARACTER, 0, 108, 213, CHARACTER}, + {CHARACTER, 0, 101, 214, CHARACTER}, + {VOLATILE, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 101, 216, CHARACTER}, + {CHARACTER, 0, 114, 217, CHARACTER}, + {CHARACTER, 0, 97, 218, CHARACTER}, + {CHARACTER, 0, 116, 219, CHARACTER}, + {CHARACTER, 0, 111, 220, CHARACTER}, + {CHARACTER, 0, 114, 221, CHARACTER}, + {OPERATOR, 0, 0, 0, CHARACTER}, + {CHARACTER, 34, 0, 0, CHARACTER}, + {CHARACTER, 0, 101, 224, CHARACTER}, + {CHARACTER, 0, 111, 225, CHARACTER}, + {CHARACTER, 0, 102, 226, CHARACTER}, + {SIZEOF, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 119, 228, CHARACTER}, + {NEW, 0, 0, 0, CHARACTER}, + {CHARACTER, 35, 0, 0, CHARACTER}, + {CHARACTER, 0, 101, 231, CHARACTER}, + {CHARACTER, 0, 116, 232, CHARACTER}, + {CHARACTER, 0, 101, 233, CHARACTER}, + {DELETE, 0, 0, 0, CHARACTER}, + {PLUS, 36, 0, 0, NOTOKEN}, + {MINUS, 37, 0, 0, NOTOKEN}, + {STAR, 0, 61, 257, NOTOKEN}, + {SLASH, 38, 0, 0, NOTOKEN}, + {HAT, 0, 61, 260, NOTOKEN}, + {AND, 39, 0, 0, NOTOKEN}, + {CHARACTER, 0, 116, 241, CHARACTER}, + {CHARACTER, 40, 0, 0, CHARACTER}, + {CHARACTER, 0, 110, 243, CHARACTER}, + {CHARACTER, 0, 100, 244, CHARACTER}, + {AND, 0, 0, 0, CHARACTER}, + {OR, 41, 0, 0, NOTOKEN}, + {CHARACTER, 0, 114, 247, CHARACTER}, + {OR, 0, 0, 0, CHARACTER}, + {TILDE, 0, 0, 0, NOTOKEN}, + {CHARACTER, 0, 112, 250, CHARACTER}, + {CHARACTER, 0, 108, 251, CHARACTER}, + {TILDE, 0, 0, 0, CHARACTER}, + {NOT, 0, 61, 268, NOTOKEN}, + {CHARACTER, 0, 116, 254, CHARACTER}, + {NOT, 0, 95, 269, CHARACTER}, + {PLUS_EQ, 0, 0, 0, NOTOKEN}, + {MINUS_EQ, 0, 0, 0, NOTOKEN}, + {STAR_EQ, 0, 0, 0, NOTOKEN}, + {SLASH_EQ, 0, 0, 0, NOTOKEN}, + {PERCENT_EQ, 0, 0, 0, NOTOKEN}, + {HAT_EQ, 0, 0, 0, NOTOKEN}, + {AND_EQ, 0, 0, 0, NOTOKEN}, + {OR_EQ, 0, 0, 0, NOTOKEN}, + {LTLT, 0, 61, 266, NOTOKEN}, + {GTGT, 0, 61, 265, NOTOKEN}, + {GTGT_EQ, 0, 0, 0, NOTOKEN}, + {LTLT_EQ, 0, 0, 0, NOTOKEN}, + {EQEQ, 0, 0, 0, NOTOKEN}, + {NE, 0, 0, 0, NOTOKEN}, + {CHARACTER, 0, 101, 270, CHARACTER}, + {CHARACTER, 0, 113, 271, CHARACTER}, + {NE, 0, 0, 0, CHARACTER}, + {LE, 0, 0, 0, NOTOKEN}, + {GE, 0, 0, 0, NOTOKEN}, + {ANDAND, 0, 0, 0, NOTOKEN}, + {OROR, 0, 0, 0, NOTOKEN}, + {INCR, 0, 0, 0, NOTOKEN}, + {DECR, 0, 0, 0, NOTOKEN}, + {ARROW, 0, 42, 279, NOTOKEN}, + {ARROW_STAR, 0, 0, 0, NOTOKEN}, + {CHARACTER, 0, 97, 281, CHARACTER}, + {CHARACTER, 0, 114, 282, CHARACTER}, + {CHAR_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 104, 284, CHARACTER}, + {CHARACTER, 0, 97, 285, CHARACTER}, + {CHARACTER, 0, 114, 286, CHARACTER}, + {WCHAR_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 111, 288, CHARACTER}, + {CHARACTER, 0, 108, 289, CHARACTER}, + {BOOL_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 111, 291, CHARACTER}, + {CHARACTER, 0, 114, 292, CHARACTER}, + {CHARACTER, 0, 116, 293, CHARACTER}, + {SHORT_TOKEN, 0, 0, 0, CHARACTER}, + {INT_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 110, 296, CHARACTER}, + {CHARACTER, 0, 103, 297, CHARACTER}, + {LONG_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 110, 299, CHARACTER}, + {CHARACTER, 42, 0, 0, CHARACTER}, + {CHARACTER, 0, 100, 301, CHARACTER}, + {SIGNED, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 105, 303, CHARACTER}, + {CHARACTER, 0, 103, 304, CHARACTER}, + {CHARACTER, 0, 110, 305, CHARACTER}, + {CHARACTER, 0, 101, 306, CHARACTER}, + {CHARACTER, 0, 100, 307, CHARACTER}, + {UNSIGNED, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 111, 309, CHARACTER}, + {CHARACTER, 0, 97, 310, CHARACTER}, + {CHARACTER, 0, 116, 311, CHARACTER}, + {FLOAT_TOKEN, 0, 0, 0, CHARACTER}, + {DO, 0, 117, 313, CHARACTER}, + {CHARACTER, 0, 98, 314, CHARACTER}, + {CHARACTER, 0, 108, 315, CHARACTER}, + {CHARACTER, 0, 101, 316, CHARACTER}, + {DOUBLE, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 100, 318, CHARACTER}, + {VOID_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 101, 320, CHARACTER}, + {CASE, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 97, 322, CHARACTER}, + {CHARACTER, 0, 117, 323, CHARACTER}, + {CHARACTER, 0, 108, 324, CHARACTER}, + {CHARACTER, 0, 116, 325, CHARACTER}, + {DEFAULT, 0, 0, 0, CHARACTER}, + {IF, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 115, 328, CHARACTER}, + {CHARACTER, 0, 101, 329, CHARACTER}, + {ELSE, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 105, 331, CHARACTER}, + {CHARACTER, 0, 116, 332, CHARACTER}, + {CHARACTER, 0, 99, 333, CHARACTER}, + {CHARACTER, 0, 104, 334, CHARACTER}, + {SWITCH, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 105, 336, CHARACTER}, + {CHARACTER, 0, 108, 337, CHARACTER}, + {CHARACTER, 0, 101, 338, CHARACTER}, + {WHILE, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 114, 340, CHARACTER}, + {FOR, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 101, 342, CHARACTER}, + {CHARACTER, 0, 97, 343, CHARACTER}, + {CHARACTER, 0, 107, 344, CHARACTER}, + {BREAK, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 105, 346, CHARACTER}, + {CHARACTER, 0, 110, 347, CHARACTER}, + {CHARACTER, 0, 117, 348, CHARACTER}, + {CHARACTER, 0, 101, 349, CHARACTER}, + {CONTINUE, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 116, 351, CHARACTER}, + {CHARACTER, 0, 111, 352, CHARACTER}, + {GOTO, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 117, 354, CHARACTER}, + {CHARACTER, 0, 114, 355, CHARACTER}, + {CHARACTER, 0, 110, 356, CHARACTER}, + {RETURN, 0, 0, 0, CHARACTER}, + {CHARACTER, 43, 0, 0, CHARACTER}, + {CHARACTER, 0, 66, 359, CHARACTER}, + {CHARACTER, 0, 74, 360, CHARACTER}, + {CHARACTER, 0, 69, 361, CHARACTER}, + {CHARACTER, 0, 67, 362, CHARACTER}, + {CHARACTER, 0, 84, 363, CHARACTER}, + {Q_OBJECT_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 65, 365, CHARACTER}, + {CHARACTER, 0, 77, 366, CHARACTER}, + {CHARACTER, 0, 69, 367, CHARACTER}, + {CHARACTER, 0, 83, 368, CHARACTER}, + {CHARACTER, 0, 80, 369, CHARACTER}, + {CHARACTER, 0, 65, 370, CHARACTER}, + {CHARACTER, 0, 67, 371, CHARACTER}, + {CHARACTER, 0, 69, 372, CHARACTER}, + {Q_NAMESPACE_TOKEN, 0, 95, 373, CHARACTER}, + {CHARACTER, 0, 69, 374, CHARACTER}, + {CHARACTER, 0, 88, 375, CHARACTER}, + {CHARACTER, 0, 80, 376, CHARACTER}, + {CHARACTER, 0, 79, 377, CHARACTER}, + {CHARACTER, 0, 82, 378, CHARACTER}, + {CHARACTER, 0, 84, 379, CHARACTER}, + {Q_NAMESPACE_EXPORT_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 65, 381, CHARACTER}, + {CHARACTER, 0, 68, 382, CHARACTER}, + {CHARACTER, 0, 71, 383, CHARACTER}, + {CHARACTER, 0, 69, 384, CHARACTER}, + {CHARACTER, 0, 84, 385, CHARACTER}, + {Q_GADGET_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 44, 0, 0, CHARACTER}, + {CHARACTER, 45, 0, 0, CHARACTER}, + {CHARACTER, 0, 80, 389, CHARACTER}, + {CHARACTER, 0, 69, 390, CHARACTER}, + {CHARACTER, 0, 82, 391, CHARACTER}, + {CHARACTER, 0, 84, 392, CHARACTER}, + {CHARACTER, 0, 89, 393, CHARACTER}, + {Q_PROPERTY_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 85, 395, CHARACTER}, + {CHARACTER, 0, 71, 396, CHARACTER}, + {CHARACTER, 0, 73, 397, CHARACTER}, + {CHARACTER, 0, 78, 398, CHARACTER}, + {CHARACTER, 0, 95, 399, CHARACTER}, + {CHARACTER, 0, 77, 400, CHARACTER}, + {CHARACTER, 0, 69, 401, CHARACTER}, + {CHARACTER, 0, 84, 402, CHARACTER}, + {CHARACTER, 0, 65, 403, CHARACTER}, + {CHARACTER, 0, 68, 404, CHARACTER}, + {CHARACTER, 0, 65, 405, CHARACTER}, + {CHARACTER, 0, 84, 406, CHARACTER}, + {CHARACTER, 0, 65, 407, CHARACTER}, + {Q_PLUGIN_METADATA_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 78, 409, CHARACTER}, + {CHARACTER, 0, 85, 410, CHARACTER}, + {CHARACTER, 0, 77, 411, CHARACTER}, + {Q_ENUM_TOKEN, 46, 0, 0, CHARACTER}, + {Q_ENUMS_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 78, 414, CHARACTER}, + {CHARACTER, 0, 83, 415, CHARACTER}, + {Q_ENUM_NS_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 76, 417, CHARACTER}, + {CHARACTER, 0, 65, 418, CHARACTER}, + {CHARACTER, 0, 71, 419, CHARACTER}, + {Q_FLAG_TOKEN, 47, 0, 0, CHARACTER}, + {Q_FLAGS_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 78, 422, CHARACTER}, + {CHARACTER, 0, 83, 423, CHARACTER}, + {Q_FLAG_NS_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 69, 425, CHARACTER}, + {CHARACTER, 0, 67, 426, CHARACTER}, + {CHARACTER, 0, 76, 427, CHARACTER}, + {CHARACTER, 0, 65, 428, CHARACTER}, + {CHARACTER, 0, 82, 429, CHARACTER}, + {CHARACTER, 0, 69, 430, CHARACTER}, + {CHARACTER, 0, 95, 431, CHARACTER}, + {CHARACTER, 48, 0, 0, CHARACTER}, + {CHARACTER, 0, 76, 433, CHARACTER}, + {CHARACTER, 0, 65, 434, CHARACTER}, + {CHARACTER, 0, 71, 435, CHARACTER}, + {CHARACTER, 0, 83, 436, CHARACTER}, + {Q_DECLARE_FLAGS_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 78, 438, CHARACTER}, + {CHARACTER, 0, 84, 439, CHARACTER}, + {CHARACTER, 0, 69, 440, CHARACTER}, + {CHARACTER, 0, 82, 441, CHARACTER}, + {CHARACTER, 0, 70, 442, CHARACTER}, + {CHARACTER, 0, 65, 443, CHARACTER}, + {CHARACTER, 0, 67, 444, CHARACTER}, + {CHARACTER, 0, 69, 445, CHARACTER}, + {Q_DECLARE_INTERFACE_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 69, 447, CHARACTER}, + {CHARACTER, 0, 84, 448, CHARACTER}, + {CHARACTER, 0, 65, 449, CHARACTER}, + {CHARACTER, 0, 84, 450, CHARACTER}, + {CHARACTER, 0, 89, 451, CHARACTER}, + {CHARACTER, 0, 80, 452, CHARACTER}, + {CHARACTER, 0, 69, 453, CHARACTER}, + {Q_DECLARE_METATYPE_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 88, 455, CHARACTER}, + {CHARACTER, 0, 84, 456, CHARACTER}, + {CHARACTER, 0, 69, 457, CHARACTER}, + {CHARACTER, 0, 78, 458, CHARACTER}, + {CHARACTER, 0, 83, 459, CHARACTER}, + {CHARACTER, 0, 73, 460, CHARACTER}, + {CHARACTER, 0, 79, 461, CHARACTER}, + {CHARACTER, 0, 78, 462, CHARACTER}, + {CHARACTER, 0, 95, 463, CHARACTER}, + {CHARACTER, 0, 73, 464, CHARACTER}, + {CHARACTER, 0, 78, 465, CHARACTER}, + {CHARACTER, 0, 84, 466, CHARACTER}, + {CHARACTER, 0, 69, 467, CHARACTER}, + {CHARACTER, 0, 82, 468, CHARACTER}, + {CHARACTER, 0, 70, 469, CHARACTER}, + {CHARACTER, 0, 65, 470, CHARACTER}, + {CHARACTER, 0, 67, 471, CHARACTER}, + {CHARACTER, 0, 69, 445, CHARACTER}, + {CHARACTER, 49, 0, 0, CHARACTER}, + {CHARACTER, 0, 84, 474, CHARACTER}, + {CHARACTER, 0, 83, 420, CHARACTER}, + {CHARACTER, 0, 76, 476, CHARACTER}, + {CHARACTER, 0, 65, 477, CHARACTER}, + {CHARACTER, 0, 83, 478, CHARACTER}, + {CHARACTER, 0, 83, 479, CHARACTER}, + {CHARACTER, 0, 73, 480, CHARACTER}, + {CHARACTER, 0, 78, 481, CHARACTER}, + {CHARACTER, 0, 70, 482, CHARACTER}, + {CHARACTER, 0, 79, 483, CHARACTER}, + {Q_CLASSINFO_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 78, 485, CHARACTER}, + {CHARACTER, 50, 0, 0, CHARACTER}, + {CHARACTER, 0, 69, 487, CHARACTER}, + {CHARACTER, 0, 82, 488, CHARACTER}, + {CHARACTER, 0, 70, 489, CHARACTER}, + {CHARACTER, 0, 65, 490, CHARACTER}, + {CHARACTER, 0, 67, 491, CHARACTER}, + {CHARACTER, 0, 69, 492, CHARACTER}, + {CHARACTER, 0, 83, 493, CHARACTER}, + {Q_INTERFACES_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 108, 495, CHARACTER}, + {CHARACTER, 0, 115, 496, CHARACTER}, + {SIGNALS, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 111, 498, CHARACTER}, + {CHARACTER, 0, 116, 499, CHARACTER}, + {CHARACTER, 0, 115, 500, CHARACTER}, + {SLOTS, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 71, 502, CHARACTER}, + {CHARACTER, 0, 78, 503, CHARACTER}, + {CHARACTER, 0, 65, 504, CHARACTER}, + {CHARACTER, 0, 76, 505, CHARACTER}, + {Q_SIGNAL_TOKEN, 0, 83, 506, CHARACTER}, + {Q_SIGNALS_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 79, 508, CHARACTER}, + {CHARACTER, 0, 84, 509, CHARACTER}, + {Q_SLOT_TOKEN, 0, 83, 510, CHARACTER}, + {Q_SLOTS_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 86, 512, CHARACTER}, + {CHARACTER, 0, 65, 513, CHARACTER}, + {CHARACTER, 0, 84, 514, CHARACTER}, + {CHARACTER, 0, 69, 515, CHARACTER}, + {CHARACTER, 0, 95, 516, CHARACTER}, + {CHARACTER, 51, 0, 0, CHARACTER}, + {CHARACTER, 0, 76, 518, CHARACTER}, + {CHARACTER, 0, 79, 519, CHARACTER}, + {CHARACTER, 0, 84, 520, CHARACTER}, + {Q_PRIVATE_SLOT_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 95, 522, CHARACTER}, + {CHARACTER, 0, 77, 523, CHARACTER}, + {CHARACTER, 0, 79, 524, CHARACTER}, + {CHARACTER, 0, 67, 525, CHARACTER}, + {CHARACTER, 0, 95, 526, CHARACTER}, + {CHARACTER, 0, 67, 527, CHARACTER}, + {CHARACTER, 0, 79, 528, CHARACTER}, + {CHARACTER, 0, 77, 529, CHARACTER}, + {CHARACTER, 0, 80, 530, CHARACTER}, + {CHARACTER, 0, 65, 531, CHARACTER}, + {CHARACTER, 0, 84, 532, CHARACTER}, + {Q_MOC_COMPAT_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 79, 534, CHARACTER}, + {CHARACTER, 0, 75, 535, CHARACTER}, + {CHARACTER, 0, 65, 536, CHARACTER}, + {CHARACTER, 0, 66, 537, CHARACTER}, + {CHARACTER, 0, 76, 538, CHARACTER}, + {CHARACTER, 0, 69, 539, CHARACTER}, + {Q_INVOKABLE_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 82, 541, CHARACTER}, + {CHARACTER, 0, 73, 542, CHARACTER}, + {CHARACTER, 0, 80, 543, CHARACTER}, + {CHARACTER, 0, 84, 544, CHARACTER}, + {CHARACTER, 0, 65, 545, CHARACTER}, + {CHARACTER, 0, 66, 546, CHARACTER}, + {CHARACTER, 0, 76, 547, CHARACTER}, + {CHARACTER, 0, 69, 548, CHARACTER}, + {Q_SCRIPTABLE_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 82, 550, CHARACTER}, + {CHARACTER, 0, 79, 551, CHARACTER}, + {CHARACTER, 0, 80, 552, CHARACTER}, + {CHARACTER, 0, 69, 553, CHARACTER}, + {CHARACTER, 0, 82, 554, CHARACTER}, + {CHARACTER, 0, 84, 555, CHARACTER}, + {CHARACTER, 0, 89, 556, CHARACTER}, + {Q_PRIVATE_PROPERTY_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 69, 558, CHARACTER}, + {CHARACTER, 0, 86, 559, CHARACTER}, + {CHARACTER, 0, 73, 560, CHARACTER}, + {CHARACTER, 0, 83, 561, CHARACTER}, + {CHARACTER, 0, 73, 562, CHARACTER}, + {CHARACTER, 0, 79, 563, CHARACTER}, + {CHARACTER, 0, 78, 564, CHARACTER}, + {Q_REVISION_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 79, 566, CHARACTER}, + {CHARACTER, 0, 67, 567, CHARACTER}, + {CHARACTER, 0, 95, 568, CHARACTER}, + {CHARACTER, 0, 73, 569, CHARACTER}, + {CHARACTER, 0, 78, 570, CHARACTER}, + {CHARACTER, 0, 67, 571, CHARACTER}, + {CHARACTER, 0, 76, 572, CHARACTER}, + {CHARACTER, 0, 85, 573, CHARACTER}, + {CHARACTER, 0, 68, 574, CHARACTER}, + {CHARACTER, 0, 69, 575, CHARACTER}, + {Q_MOC_INCLUDE_TOKEN, 0, 0, 0, CHARACTER}, + {NEWLINE, 0, 0, 0, NOTOKEN}, + {QUOTE, 0, 0, 0, NOTOKEN}, + {SINGLEQUOTE, 0, 0, 0, NOTOKEN}, + {WHITESPACE, 0, 0, 0, NOTOKEN}, + {HASH, 0, 35, 581, HASH}, + {PP_HASHHASH, 0, 0, 0, NOTOKEN}, + {BACKSLASH, 0, 0, 0, NOTOKEN}, + {CPP_COMMENT, 0, 0, 0, NOTOKEN}, + {C_COMMENT, 0, 0, 0, NOTOKEN}, + {FLOATING_LITERAL, 0, 0, 0, NOTOKEN} +}; diff --git a/src/plugins/clangcodemodel/moc/parser.cpp b/src/plugins/clangcodemodel/moc/parser.cpp new file mode 100644 index 00000000000..d887924d626 --- /dev/null +++ b/src/plugins/clangcodemodel/moc/parser.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "parser.h" +#include "utils.h" +#include +#include + +QT_BEGIN_NAMESPACE + +#ifdef USE_LEXEM_STORE +Symbol::LexemStore Symbol::lexemStore; +#endif + +#ifdef Q_CC_MSVC +#define ErrorFormatString "%s(%d:%d): " +#else +#define ErrorFormatString "%s:%d:%d: " +#endif + +void Parser::error(int rollback) { + index -= rollback; + error(); +} +void Parser::error(const char *) { throw MocParseException(); } + +void Parser::warning(const char *msg) { + if (displayWarnings && msg) + fprintf(stderr, ErrorFormatString "warning: %s\n", + currentFilenames.top().constData(), qMax(0, index > 0 ? symbol().lineNum : 0), 1, msg); +} + +void Parser::note(const char *msg) { + if (displayNotes && msg) + fprintf(stderr, ErrorFormatString "note: %s\n", + currentFilenames.top().constData(), qMax(0, index > 0 ? symbol().lineNum : 0), 1, msg); +} + +QT_END_NAMESPACE diff --git a/src/plugins/clangcodemodel/moc/parser.h b/src/plugins/clangcodemodel/moc/parser.h new file mode 100644 index 00000000000..9206ba08be4 --- /dev/null +++ b/src/plugins/clangcodemodel/moc/parser.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PARSER_H +#define PARSER_H + +#include "symbols.h" + +#include + +QT_BEGIN_NAMESPACE + +struct MocParseException {}; + +class Parser +{ +public: + Parser():index(0), displayWarnings(true), displayNotes(true) {} + Symbols symbols; + int index; + bool displayWarnings; + bool displayNotes; + + struct IncludePath + { + inline explicit IncludePath(const QByteArray &_path) + : path(_path), isFrameworkPath(false) {} + QByteArray path; + bool isFrameworkPath; + }; + QList includes; + + std::stack currentFilenames; + + inline bool hasNext() const { return (index < symbols.size()); } + inline Token next() { if (index >= symbols.size()) return NOTOKEN; return symbols.at(index++).token; } + inline Token peek() { if (index >= symbols.size()) return NOTOKEN; return symbols.at(index).token; } + bool test(Token); + void next(Token); + void next(Token, const char *msg); + inline void prev() {--index;} + inline Token lookup(int k = 1); + inline const Symbol &symbol_lookup(int k = 1) { return symbols.at(index-1+k);} + inline Token token() { return symbols.at(index-1).token;} + inline QByteArray lexem() { return symbols.at(index-1).lexem();} + inline QByteArray unquotedLexem() { return symbols.at(index-1).unquotedLexem();} + inline const Symbol &symbol() { return symbols.at(index-1);} + + Q_NORETURN void error(int rollback); + Q_NORETURN void error(const char *msg = nullptr); + void warning(const char * = nullptr); + void note(const char * = nullptr); + +}; + +inline bool Parser::test(Token token) +{ + if (index < symbols.size() && symbols.at(index).token == token) { + ++index; + return true; + } + return false; +} + +inline Token Parser::lookup(int k) +{ + const int l = index - 1 + k; + return l < symbols.size() ? symbols.at(l).token : NOTOKEN; +} + +inline void Parser::next(Token token) +{ + if (!test(token)) + error(); +} + +inline void Parser::next(Token token, const char *msg) +{ + if (!test(token)) + error(msg); +} + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/clangcodemodel/moc/ppkeywords.cpp b/src/plugins/clangcodemodel/moc/ppkeywords.cpp new file mode 100644 index 00000000000..b94abf8cd82 --- /dev/null +++ b/src/plugins/clangcodemodel/moc/ppkeywords.cpp @@ -0,0 +1,235 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// auto generated +// DO NOT EDIT. + +static const short pp_keyword_trans[][128] = { + {0,0,0,0,0,0,0,0,0,98,12,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 98,76,96,13,1,60,62,97,9,10,58,56,11,57,102,59, + 6,6,6,6,6,6,6,6,6,6,92,0,7,81,8,91, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,0,101,0,61,1, + 0,1,2,3,4,1,1,1,1,1,1,1,1,1,5,1, + 1,1,1,1,1,1,1,1,1,1,1,0,68,0,71,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,79,87,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,88,80,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,93,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,14,34,0,0,0,20,0,0,0,0,0,0, + 0,0,0,0,0,22,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,21,0,0,0,0,0,0,0,44,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,27,0,0,0,0,0,0,0,0,0,30,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,35,0,40,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0, + 0,0,0,38,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,99, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,65,0,0,0,0,0,0,0,0,0,0,0,0,0,69, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 103,103,103,103,103,103,103,103,103,103,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} +}; + +static const struct +{ + PP_Token token; + short next; + char defchar; + short defnext; + PP_Token ident; +} pp_keywords[] = { + {PP_NOTOKEN, 0, 0, 0, PP_NOTOKEN}, + {PP_CHARACTER, 0, 0, 0, PP_NOTOKEN}, + {PP_CHARACTER, 0, 105, 63, PP_NOTOKEN}, + {PP_CHARACTER, 0, 111, 72, PP_NOTOKEN}, + {PP_CHARACTER, 0, 101, 50, PP_NOTOKEN}, + {PP_CHARACTER, 0, 111, 77, PP_NOTOKEN}, + {PP_DIGIT, 0, 0, 0, PP_NOTOKEN}, + {PP_LANGLE, 1, 0, 0, PP_NOTOKEN}, + {PP_RANGLE, 2, 0, 0, PP_NOTOKEN}, + {PP_LPAREN, 0, 0, 0, PP_NOTOKEN}, + {PP_RPAREN, 0, 0, 0, PP_NOTOKEN}, + {PP_COMMA, 0, 0, 0, PP_NOTOKEN}, + {PP_NEWLINE, 0, 0, 0, PP_NOTOKEN}, + {PP_HASH, 3, 0, 0, PP_HASH}, + {PP_HASH, 0, 101, 15, PP_HASH}, + {PP_HASH, 0, 102, 16, PP_HASH}, + {PP_HASH, 0, 105, 17, PP_HASH}, + {PP_HASH, 0, 110, 18, PP_HASH}, + {PP_HASH, 0, 101, 19, PP_HASH}, + {PP_DEFINE, 0, 0, 0, PP_HASH}, + {PP_HASH, 4, 0, 0, PP_HASH}, + {PP_IF, 5, 0, 0, PP_HASH}, + {PP_HASH, 0, 110, 23, PP_HASH}, + {PP_HASH, 0, 100, 24, PP_HASH}, + {PP_HASH, 0, 101, 25, PP_HASH}, + {PP_HASH, 0, 102, 26, PP_HASH}, + {PP_UNDEF, 0, 0, 0, PP_HASH}, + {PP_HASH, 0, 101, 28, PP_HASH}, + {PP_HASH, 0, 102, 29, PP_HASH}, + {PP_IFDEF, 0, 0, 0, PP_HASH}, + {PP_HASH, 0, 100, 31, PP_HASH}, + {PP_HASH, 0, 101, 32, PP_HASH}, + {PP_HASH, 0, 102, 33, PP_HASH}, + {PP_IFNDEF, 0, 0, 0, PP_HASH}, + {PP_HASH, 6, 0, 0, PP_HASH}, + {PP_HASH, 7, 0, 0, PP_HASH}, + {PP_HASH, 0, 102, 37, PP_HASH}, + {PP_ELIF, 0, 0, 0, PP_HASH}, + {PP_HASH, 0, 101, 39, PP_HASH}, + {PP_ELSE, 0, 0, 0, PP_HASH}, + {PP_HASH, 0, 100, 41, PP_HASH}, + {PP_HASH, 0, 105, 42, PP_HASH}, + {PP_HASH, 0, 102, 43, PP_HASH}, + {PP_ENDIF, 0, 0, 0, PP_HASH}, + {PP_HASH, 0, 99, 45, PP_HASH}, + {PP_HASH, 0, 108, 46, PP_HASH}, + {PP_HASH, 0, 117, 47, PP_HASH}, + {PP_HASH, 0, 100, 48, PP_HASH}, + {PP_HASH, 0, 101, 49, PP_HASH}, + {PP_INCLUDE, 0, 0, 0, PP_HASH}, + {PP_CHARACTER, 0, 102, 51, PP_CHARACTER}, + {PP_CHARACTER, 0, 105, 52, PP_CHARACTER}, + {PP_CHARACTER, 0, 110, 53, PP_CHARACTER}, + {PP_CHARACTER, 0, 101, 54, PP_CHARACTER}, + {PP_CHARACTER, 0, 100, 55, PP_CHARACTER}, + {PP_DEFINED, 0, 0, 0, PP_CHARACTER}, + {PP_PLUS, 0, 0, 0, PP_NOTOKEN}, + {PP_MINUS, 0, 0, 0, PP_NOTOKEN}, + {PP_STAR, 0, 0, 0, PP_NOTOKEN}, + {PP_SLASH, 8, 0, 0, PP_NOTOKEN}, + {PP_PERCENT, 0, 58, 94, PP_NOTOKEN}, + {PP_HAT, 0, 0, 0, PP_NOTOKEN}, + {PP_AND, 0, 38, 89, PP_NOTOKEN}, + {PP_CHARACTER, 0, 116, 64, PP_CHARACTER}, + {PP_CHARACTER, 9, 0, 0, PP_CHARACTER}, + {PP_CHARACTER, 0, 110, 66, PP_CHARACTER}, + {PP_CHARACTER, 0, 100, 67, PP_CHARACTER}, + {PP_AND, 0, 0, 0, PP_CHARACTER}, + {PP_OR, 0, 124, 90, PP_NOTOKEN}, + {PP_CHARACTER, 0, 114, 70, PP_CHARACTER}, + {PP_OR, 0, 0, 0, PP_CHARACTER}, + {PP_TILDE, 0, 0, 0, PP_NOTOKEN}, + {PP_CHARACTER, 0, 109, 73, PP_CHARACTER}, + {PP_CHARACTER, 0, 112, 74, PP_CHARACTER}, + {PP_CHARACTER, 0, 108, 75, PP_CHARACTER}, + {PP_TILDE, 0, 0, 0, PP_CHARACTER}, + {PP_NOT, 0, 61, 83, PP_NOTOKEN}, + {PP_CHARACTER, 0, 116, 78, PP_CHARACTER}, + {PP_NOT, 0, 95, 84, PP_CHARACTER}, + {PP_LTLT, 0, 0, 0, PP_NOTOKEN}, + {PP_GTGT, 0, 0, 0, PP_NOTOKEN}, + {PP_INCOMPLETE, 0, 61, 82, PP_NOTOKEN}, + {PP_EQEQ, 0, 0, 0, PP_NOTOKEN}, + {PP_NE, 0, 0, 0, PP_NOTOKEN}, + {PP_CHARACTER, 0, 101, 85, PP_CHARACTER}, + {PP_CHARACTER, 0, 113, 86, PP_CHARACTER}, + {PP_NE, 0, 0, 0, PP_CHARACTER}, + {PP_LE, 0, 0, 0, PP_NOTOKEN}, + {PP_GE, 0, 0, 0, PP_NOTOKEN}, + {PP_ANDAND, 0, 0, 0, PP_NOTOKEN}, + {PP_OROR, 0, 0, 0, PP_NOTOKEN}, + {PP_QUESTION, 0, 0, 0, PP_NOTOKEN}, + {PP_COLON, 0, 0, 0, PP_NOTOKEN}, + {PP_HASHHASH, 0, 0, 0, PP_NOTOKEN}, + {PP_INCOMPLETE, 0, 37, 95, PP_NOTOKEN}, + {PP_INCOMPLETE, 0, 58, 93, PP_NOTOKEN}, + {PP_QUOTE, 0, 0, 0, PP_NOTOKEN}, + {PP_SINGLEQUOTE, 0, 0, 0, PP_NOTOKEN}, + {PP_WHITESPACE, 0, 0, 0, PP_NOTOKEN}, + {PP_CPP_COMMENT, 0, 0, 0, PP_NOTOKEN}, + {PP_C_COMMENT, 0, 0, 0, PP_NOTOKEN}, + {PP_BACKSLASH, 0, 0, 0, PP_NOTOKEN}, + {PP_INCOMPLETE, 10, 0, 0, PP_NOTOKEN}, + {PP_FLOATING_LITERAL, 0, 0, 0, PP_NOTOKEN} +}; diff --git a/src/plugins/clangcodemodel/moc/preprocessor.cpp b/src/plugins/clangcodemodel/moc/preprocessor.cpp new file mode 100644 index 00000000000..f8d1f96beeb --- /dev/null +++ b/src/plugins/clangcodemodel/moc/preprocessor.cpp @@ -0,0 +1,1317 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2014 Olivier Goffart +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "preprocessor.h" +#include "utils.h" +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +#include "ppkeywords.cpp" +#include "keywords.cpp" + +// transform \r\n into \n +// \r into \n (os9 style) +// backslash-newlines into newlines +static QByteArray cleaned(const QByteArray &input) +{ + QByteArray result; + result.resize(input.size()); + const char *data = input.constData(); + const char *end = input.constData() + input.size(); + char *output = result.data(); + + int newlines = 0; + while (data != end) { + bool takeLine = (*data == '#'); + if (*data == '%' && *(data+1) == ':') { + takeLine = true; + ++data; + } + if (takeLine) { + *output = '#'; + ++output; + do ++data; while (data != end && is_space(*data)); + } + while (data != end) { + // handle \\\n, \\\r\n and \\\r + if (*data == '\\') { + if (*(data + 1) == '\r') { + ++data; + } + if (data != end && (*(data + 1) == '\n' || (*data) == '\r')) { + ++newlines; + data += 1; + if (data != end && *data != '\r') + data += 1; + continue; + } + } else if (*data == '\r' && *(data + 1) == '\n') { // reduce \r\n to \n + ++data; + } + if (data == end) + break; + + char ch = *data; + if (ch == '\r') // os9: replace \r with \n + ch = '\n'; + *output = ch; + ++output; + + if (*data == '\n') { + // output additional newlines to keep the correct line-numbering + // for the lines following the backslash-newline sequence(s) + while (newlines) { + *output = '\n'; + ++output; + --newlines; + } + ++data; + break; + } + ++data; + } + } + result.resize(output - result.constData()); + return result; +} + +bool Preprocessor::preprocessOnly = false; +void Preprocessor::skipUntilEndif() +{ + while(index < symbols.size() - 1 && symbols.at(index).token != PP_ENDIF){ + switch (symbols.at(index).token) { + case PP_IF: + case PP_IFDEF: + case PP_IFNDEF: + ++index; + skipUntilEndif(); + break; + default: + ; + } + ++index; + } +} + +bool Preprocessor::skipBranch() +{ + while (index < symbols.size() - 1 + && (symbols.at(index).token != PP_ENDIF + && symbols.at(index).token != PP_ELIF + && symbols.at(index).token != PP_ELSE) + ){ + switch (symbols.at(index).token) { + case PP_IF: + case PP_IFDEF: + case PP_IFNDEF: + ++index; + skipUntilEndif(); + break; + default: + ; + } + ++index; + } + return (index < symbols.size() - 1); +} + + +Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocessor::TokenizeMode mode) +{ + Symbols symbols; + // Preallocate some space to speed up the code below. + // The magic divisor value was found by calculating the average ratio between + // input size and the final size of symbols. + // This yielded a value of 16.x when compiling Qt Base. + symbols.reserve(input.size() / 16); + const char *begin = input.constData(); + const char *data = begin; + while (*data) { + if (mode == TokenizeCpp || mode == TokenizeDefine) { + int column = 0; + + const char *lexem = data; + int state = 0; + Token token = NOTOKEN; + for (;;) { + if (static_cast(*data) < 0) { + ++data; + continue; + } + int nextindex = keywords[state].next; + int next = 0; + if (*data == keywords[state].defchar) + next = keywords[state].defnext; + else if (!state || nextindex) + next = keyword_trans[nextindex][(int)*data]; + if (!next) + break; + state = next; + token = keywords[state].token; + ++data; + } + + // suboptimal, is_ident_char should use a table + if (keywords[state].ident && is_ident_char(*data)) + token = keywords[state].ident; + + if (token == NOTOKEN) { + if (*data) + ++data; + // an error really, but let's ignore this input + // to not confuse moc later. However in pre-processor + // only mode let's continue. + if (!Preprocessor::preprocessOnly) + continue; + } + + ++column; + + if (token > SPECIAL_TREATMENT_MARK) { + switch (token) { + case QUOTE: + data = skipQuote(data); + token = STRING_LITERAL; + // concatenate multi-line strings for easier + // STRING_LITERAL handling in moc + if (!Preprocessor::preprocessOnly + && !symbols.isEmpty() + && symbols.constLast().token == STRING_LITERAL) { + + const QByteArray newString + = '\"' + + symbols.constLast().unquotedLexem() + + input.mid(lexem - begin + 1, data - lexem - 2) + + '\"'; + symbols.last() = Symbol(symbols.constLast().lineNum, + STRING_LITERAL, + newString); + continue; + } + break; + case SINGLEQUOTE: + while (*data && (*data != '\'' + || (*(data-1)=='\\' + && *(data-2)!='\\'))) + ++data; + if (*data) + ++data; + token = CHARACTER_LITERAL; + break; + case LANGLE_SCOPE: + // split <:: into two tokens, < and :: + token = LANGLE; + data -= 2; + break; + case DIGIT: + while (is_digit_char(*data) || *data == '\'') + ++data; + if (!*data || *data != '.') { + token = INTEGER_LITERAL; + if (data - lexem == 1 && + (*data == 'x' || *data == 'X' + || *data == 'b' || *data == 'B') + && *lexem == '0') { + ++data; + while (is_hex_char(*data) || *data == '\'') + ++data; + } + break; + } + token = FLOATING_LITERAL; + ++data; + Q_FALLTHROUGH(); + case FLOATING_LITERAL: + while (is_digit_char(*data) || *data == '\'') + ++data; + if (*data == '+' || *data == '-') + ++data; + if (*data == 'e' || *data == 'E') { + ++data; + while (is_digit_char(*data) || *data == '\'') + ++data; + } + if (*data == 'f' || *data == 'F' + || *data == 'l' || *data == 'L') + ++data; + break; + case HASH: + if (column == 1 && mode == TokenizeCpp) { + mode = PreparePreprocessorStatement; + while (*data && (*data == ' ' || *data == '\t')) + ++data; + if (is_ident_char(*data)) + mode = TokenizePreprocessorStatement; + continue; + } + break; + case PP_HASHHASH: + if (mode == TokenizeCpp) + continue; + break; + case NEWLINE: + ++lineNum; + if (mode == TokenizeDefine) { + mode = TokenizeCpp; + // emit the newline token + break; + } + continue; + case BACKSLASH: + { + const char *rewind = data; + while (*data && (*data == ' ' || *data == '\t')) + ++data; + if (*data && *data == '\n') { + ++data; + continue; + } + data = rewind; + } break; + case CHARACTER: + while (is_ident_char(*data)) + ++data; + token = IDENTIFIER; + break; + case C_COMMENT: + if (*data) { + if (*data == '\n') + ++lineNum; + ++data; + if (*data) { + if (*data == '\n') + ++lineNum; + ++data; + } + } + while (*data && (*(data-1) != '/' || *(data-2) != '*')) { + if (*data == '\n') + ++lineNum; + ++data; + } + token = WHITESPACE; // one comment, one whitespace + Q_FALLTHROUGH(); + case WHITESPACE: + if (column == 1) + column = 0; + while (*data && (*data == ' ' || *data == '\t')) + ++data; + if (Preprocessor::preprocessOnly) // tokenize whitespace + break; + continue; + case CPP_COMMENT: + while (*data && *data != '\n') + ++data; + continue; // ignore safely, the newline is a separator + default: + continue; //ignore + } + } +#ifdef USE_LEXEM_STORE + if (!Preprocessor::preprocessOnly + && token != IDENTIFIER + && token != STRING_LITERAL + && token != FLOATING_LITERAL + && token != INTEGER_LITERAL) + symbols += Symbol(lineNum, token); + else +#endif + symbols += Symbol(lineNum, token, input, lexem-begin, data-lexem); + + } else { // Preprocessor + + const char *lexem = data; + int state = 0; + Token token = NOTOKEN; + if (mode == TokenizePreprocessorStatement) { + state = pp_keyword_trans[0][(int)'#']; + mode = TokenizePreprocessor; + } + for (;;) { + if (static_cast(*data) < 0) { + ++data; + continue; + } + int nextindex = pp_keywords[state].next; + int next = 0; + if (*data == pp_keywords[state].defchar) + next = pp_keywords[state].defnext; + else if (!state || nextindex) + next = pp_keyword_trans[nextindex][(int)*data]; + if (!next) + break; + state = next; + token = pp_keywords[state].token; + ++data; + } + // suboptimal, is_ident_char should use a table + if (pp_keywords[state].ident && is_ident_char(*data)) + token = pp_keywords[state].ident; + + switch (token) { + case NOTOKEN: + if (*data) + ++data; + break; + case PP_DEFINE: + mode = PrepareDefine; + break; + case PP_IFDEF: + symbols += Symbol(lineNum, PP_IF); + symbols += Symbol(lineNum, PP_DEFINED); + continue; + case PP_IFNDEF: + symbols += Symbol(lineNum, PP_IF); + symbols += Symbol(lineNum, PP_NOT); + symbols += Symbol(lineNum, PP_DEFINED); + continue; + case PP_INCLUDE: + mode = TokenizeInclude; + break; + case PP_QUOTE: + data = skipQuote(data); + token = PP_STRING_LITERAL; + break; + case PP_SINGLEQUOTE: + while (*data && (*data != '\'' + || (*(data-1)=='\\' + && *(data-2)!='\\'))) + ++data; + if (*data) + ++data; + token = PP_CHARACTER_LITERAL; + break; + case PP_DIGIT: + while (is_digit_char(*data) || *data == '\'') + ++data; + if (!*data || *data != '.') { + token = PP_INTEGER_LITERAL; + if (data - lexem == 1 && + (*data == 'x' || *data == 'X') + && *lexem == '0') { + ++data; + while (is_hex_char(*data) || *data == '\'') + ++data; + } + break; + } + token = PP_FLOATING_LITERAL; + ++data; + Q_FALLTHROUGH(); + case PP_FLOATING_LITERAL: + while (is_digit_char(*data) || *data == '\'') + ++data; + if (*data == '+' || *data == '-') + ++data; + if (*data == 'e' || *data == 'E') { + ++data; + while (is_digit_char(*data) || *data == '\'') + ++data; + } + if (*data == 'f' || *data == 'F' + || *data == 'l' || *data == 'L') + ++data; + break; + case PP_CHARACTER: + if (mode == PreparePreprocessorStatement) { + // rewind entire token to begin + data = lexem; + mode = TokenizePreprocessorStatement; + continue; + } + while (is_ident_char(*data)) + ++data; + token = PP_IDENTIFIER; + + if (mode == PrepareDefine) { + symbols += Symbol(lineNum, token, input, lexem-begin, data-lexem); + // make sure we explicitly add the whitespace here if the next char + // is not an opening brace, so we can distinguish correctly between + // regular and function macros + if (*data != '(') + symbols += Symbol(lineNum, WHITESPACE); + mode = TokenizeDefine; + continue; + } + break; + case PP_C_COMMENT: + if (*data) { + if (*data == '\n') + ++lineNum; + ++data; + if (*data) { + if (*data == '\n') + ++lineNum; + ++data; + } + } + while (*data && (*(data-1) != '/' || *(data-2) != '*')) { + if (*data == '\n') + ++lineNum; + ++data; + } + token = PP_WHITESPACE; // one comment, one whitespace + Q_FALLTHROUGH(); + case PP_WHITESPACE: + while (*data && (*data == ' ' || *data == '\t')) + ++data; + continue; // the preprocessor needs no whitespace + case PP_CPP_COMMENT: + while (*data && *data != '\n') + ++data; + continue; // ignore safely, the newline is a separator + case PP_NEWLINE: + ++lineNum; + mode = TokenizeCpp; + break; + case PP_BACKSLASH: + { + const char *rewind = data; + while (*data && (*data == ' ' || *data == '\t')) + ++data; + if (*data && *data == '\n') { + ++data; + continue; + } + data = rewind; + } break; + case PP_LANGLE: + if (mode != TokenizeInclude) + break; + token = PP_STRING_LITERAL; + while (*data && *data != '\n' && *(data-1) != '>') + ++data; + break; + default: + break; + } + if (mode == PreparePreprocessorStatement) + continue; +#ifdef USE_LEXEM_STORE + if (token != PP_IDENTIFIER + && token != PP_STRING_LITERAL + && token != PP_FLOATING_LITERAL + && token != PP_INTEGER_LITERAL) + symbols += Symbol(lineNum, token); + else +#endif + symbols += Symbol(lineNum, token, input, lexem-begin, data-lexem); + } + } + symbols += Symbol(); // eof symbol + return symbols; +} + +void Preprocessor::macroExpand(Symbols *into, Preprocessor *that, const Symbols &toExpand, int &index, + int lineNum, bool one, const QSet &excludeSymbols) +{ + SymbolStack symbols; + SafeSymbols sf; + sf.symbols = toExpand; + sf.index = index; + sf.excludedSymbols = excludeSymbols; + symbols.push(sf); + + if (toExpand.isEmpty()) + return; + + for (;;) { + QByteArray macro; + Symbols newSyms = macroExpandIdentifier(that, symbols, lineNum, ¯o); + + if (macro.isEmpty()) { + // not a macro + Symbol s = symbols.symbol(); + s.lineNum = lineNum; + *into += s; + } else { + SafeSymbols sf; + sf.symbols = newSyms; + sf.index = 0; + sf.expandedMacro = macro; + symbols.push(sf); + } + if (!symbols.hasNext() || (one && symbols.size() == 1)) + break; + symbols.next(); + } + + if (symbols.size()) + index = symbols.top().index; + else + index = toExpand.size(); +} + + +Symbols Preprocessor::macroExpandIdentifier(Preprocessor *that, SymbolStack &symbols, int lineNum, QByteArray *macroName) +{ + Symbol s = symbols.symbol(); + + // not a macro + if (s.token != PP_IDENTIFIER || !that->macros.contains(s) || symbols.dontReplaceSymbol(s.lexem())) { + return Symbols(); + } + + const Macro ¯o = that->macros.value(s); + *macroName = s.lexem(); + + Symbols expansion; + if (!macro.isFunction) { + expansion = macro.symbols; + } else { + bool haveSpace = false; + while (symbols.test(PP_WHITESPACE)) { haveSpace = true; } + if (!symbols.test(PP_LPAREN)) { + *macroName = QByteArray(); + Symbols syms; + if (haveSpace) + syms += Symbol(lineNum, PP_WHITESPACE); + syms += s; + syms.last().lineNum = lineNum; + return syms; + } + QVarLengthArray arguments; + while (symbols.hasNext()) { + Symbols argument; + // strip leading space + while (symbols.test(PP_WHITESPACE)) {} + int nesting = 0; + bool vararg = macro.isVariadic && (arguments.size() == macro.arguments.size() - 1); + while (symbols.hasNext()) { + Token t = symbols.next(); + if (t == PP_LPAREN) { + ++nesting; + } else if (t == PP_RPAREN) { + --nesting; + if (nesting < 0) + break; + } else if (t == PP_COMMA && nesting == 0) { + if (!vararg) + break; + } + argument += symbols.symbol(); + } + arguments += argument; + + if (nesting < 0) + break; + else if (!symbols.hasNext()) + that->error("missing ')' in macro usage"); + } + + // empty VA_ARGS + if (macro.isVariadic && arguments.size() == macro.arguments.size() - 1) + arguments += Symbols(); + + // now replace the macro arguments with the expanded arguments + enum Mode { + Normal, + Hash, + HashHash + } mode = Normal; + + for (int i = 0; i < macro.symbols.size(); ++i) { + const Symbol &s = macro.symbols.at(i); + if (s.token == HASH || s.token == PP_HASHHASH) { + mode = (s.token == HASH ? Hash : HashHash); + continue; + } + int index = macro.arguments.indexOf(s); + if (mode == Normal) { + if (index >= 0 && index < arguments.size()) { + // each argument undoergoes macro expansion if it's not used as part of a # or ## + if (i == macro.symbols.size() - 1 || macro.symbols.at(i + 1).token != PP_HASHHASH) { + Symbols arg = arguments.at(index); + int idx = 1; + macroExpand(&expansion, that, arg, idx, lineNum, false, symbols.excludeSymbols()); + } else { + expansion += arguments.at(index); + } + } else { + expansion += s; + } + } else if (mode == Hash) { + if (index < 0) { + that->error("'#' is not followed by a macro parameter"); + continue; + } else if (index >= arguments.size()) { + that->error("Macro invoked with too few parameters for a use of '#'"); + continue; + } + + const Symbols &arg = arguments.at(index); + QByteArray stringified; + for (int i = 0; i < arg.size(); ++i) { + stringified += arg.at(i).lexem(); + } + stringified.replace('"', "\\\""); + stringified.prepend('"'); + stringified.append('"'); + expansion += Symbol(lineNum, STRING_LITERAL, stringified); + } else if (mode == HashHash){ + if (s.token == WHITESPACE) + continue; + + while (expansion.size() && expansion.constLast().token == PP_WHITESPACE) + expansion.pop_back(); + + Symbol next = s; + if (index >= 0 && index < arguments.size()) { + const Symbols &arg = arguments.at(index); + if (arg.size() == 0) { + mode = Normal; + continue; + } + next = arg.at(0); + } + + if (!expansion.isEmpty() && expansion.constLast().token == s.token + && expansion.constLast().token != STRING_LITERAL) { + Symbol last = expansion.takeLast(); + + QByteArray lexem = last.lexem() + next.lexem(); + expansion += Symbol(lineNum, last.token, lexem); + } else { + expansion += next; + } + + if (index >= 0 && index < arguments.size()) { + const Symbols &arg = arguments.at(index); + for (int i = 1; i < arg.size(); ++i) + expansion += arg.at(i); + } + } + mode = Normal; + } + if (mode != Normal) + that->error("'#' or '##' found at the end of a macro argument"); + + } + + return expansion; +} + +void Preprocessor::substituteUntilNewline(Symbols &substituted) +{ + while (hasNext()) { + Token token = next(); + if (token == PP_IDENTIFIER) { + macroExpand(&substituted, this, symbols, index, symbol().lineNum, true); + } else if (token == PP_DEFINED) { + bool braces = test(PP_LPAREN); + next(PP_IDENTIFIER); + Symbol definedOrNotDefined = symbol(); + definedOrNotDefined.token = macros.contains(definedOrNotDefined)? PP_MOC_TRUE : PP_MOC_FALSE; + substituted += definedOrNotDefined; + if (braces) + test(PP_RPAREN); + continue; + } else if (token == PP_NEWLINE) { + substituted += symbol(); + break; + } else { + substituted += symbol(); + } + } +} + + +class PP_Expression : public Parser +{ +public: + int value() { index = 0; return unary_expression_lookup() ? conditional_expression() : 0; } + + int conditional_expression(); + int logical_OR_expression(); + int logical_AND_expression(); + int inclusive_OR_expression(); + int exclusive_OR_expression(); + int AND_expression(); + int equality_expression(); + int relational_expression(); + int shift_expression(); + int additive_expression(); + int multiplicative_expression(); + int unary_expression(); + bool unary_expression_lookup(); + int primary_expression(); + bool primary_expression_lookup(); +}; + +int PP_Expression::conditional_expression() +{ + int value = logical_OR_expression(); + if (test(PP_QUESTION)) { + int alt1 = conditional_expression(); + int alt2 = test(PP_COLON) ? conditional_expression() : 0; + return value ? alt1 : alt2; + } + return value; +} + +int PP_Expression::logical_OR_expression() +{ + int value = logical_AND_expression(); + if (test(PP_OROR)) + return logical_OR_expression() || value; + return value; +} + +int PP_Expression::logical_AND_expression() +{ + int value = inclusive_OR_expression(); + if (test(PP_ANDAND)) + return logical_AND_expression() && value; + return value; +} + +int PP_Expression::inclusive_OR_expression() +{ + int value = exclusive_OR_expression(); + if (test(PP_OR)) + return value | inclusive_OR_expression(); + return value; +} + +int PP_Expression::exclusive_OR_expression() +{ + int value = AND_expression(); + if (test(PP_HAT)) + return value ^ exclusive_OR_expression(); + return value; +} + +int PP_Expression::AND_expression() +{ + int value = equality_expression(); + if (test(PP_AND)) + return value & AND_expression(); + return value; +} + +int PP_Expression::equality_expression() +{ + int value = relational_expression(); + switch (next()) { + case PP_EQEQ: + return value == equality_expression(); + case PP_NE: + return value != equality_expression(); + default: + prev(); + return value; + } +} + +int PP_Expression::relational_expression() +{ + int value = shift_expression(); + switch (next()) { + case PP_LANGLE: + return value < relational_expression(); + case PP_RANGLE: + return value > relational_expression(); + case PP_LE: + return value <= relational_expression(); + case PP_GE: + return value >= relational_expression(); + default: + prev(); + return value; + } +} + +int PP_Expression::shift_expression() +{ + int value = additive_expression(); + switch (next()) { + case PP_LTLT: + return value << shift_expression(); + case PP_GTGT: + return value >> shift_expression(); + default: + prev(); + return value; + } +} + +int PP_Expression::additive_expression() +{ + int value = multiplicative_expression(); + switch (next()) { + case PP_PLUS: + return value + additive_expression(); + case PP_MINUS: + return value - additive_expression(); + default: + prev(); + return value; + } +} + +int PP_Expression::multiplicative_expression() +{ + int value = unary_expression(); + switch (next()) { + case PP_STAR: + { + // get well behaved overflow behavior by converting to long + // and then back to int + // NOTE: A conformant preprocessor would need to work intmax_t/ + // uintmax_t according to [cpp.cond], 19.1 ยง10 + // But we're not compliant anyway + qint64 result = qint64(value) * qint64(multiplicative_expression()); + return int(result); + } + case PP_PERCENT: + { + int remainder = multiplicative_expression(); + return remainder ? value % remainder : 0; + } + case PP_SLASH: + { + int div = multiplicative_expression(); + return div ? value / div : 0; + } + default: + prev(); + return value; + }; +} + +int PP_Expression::unary_expression() +{ + switch (next()) { + case PP_PLUS: + return unary_expression(); + case PP_MINUS: + return -unary_expression(); + case PP_NOT: + return !unary_expression(); + case PP_TILDE: + return ~unary_expression(); + case PP_MOC_TRUE: + return 1; + case PP_MOC_FALSE: + return 0; + default: + prev(); + return primary_expression(); + } +} + +bool PP_Expression::unary_expression_lookup() +{ + Token t = lookup(); + return (primary_expression_lookup() + || t == PP_PLUS + || t == PP_MINUS + || t == PP_NOT + || t == PP_TILDE + || t == PP_DEFINED); +} + +int PP_Expression::primary_expression() +{ + int value; + if (test(PP_LPAREN)) { + value = conditional_expression(); + test(PP_RPAREN); + } else { + next(); + value = lexem().toInt(nullptr, 0); + } + return value; +} + +bool PP_Expression::primary_expression_lookup() +{ + Token t = lookup(); + return (t == PP_IDENTIFIER + || t == PP_INTEGER_LITERAL + || t == PP_FLOATING_LITERAL + || t == PP_MOC_TRUE + || t == PP_MOC_FALSE + || t == PP_LPAREN); +} + +int Preprocessor::evaluateCondition() +{ + PP_Expression expression; + expression.currentFilenames = currentFilenames; + + substituteUntilNewline(expression.symbols); + + return expression.value(); +} + +static QByteArray readOrMapFile(QFile *file) +{ + const qint64 size = file->size(); + char *rawInput = reinterpret_cast(file->map(0, size)); + return rawInput ? QByteArray::fromRawData(rawInput, size) : file->readAll(); +} + +static void mergeStringLiterals(Symbols *_symbols) +{ + Symbols &symbols = *_symbols; + for (Symbols::iterator i = symbols.begin(); i != symbols.end(); ++i) { + if (i->token == STRING_LITERAL) { + Symbols::Iterator mergeSymbol = i; + int literalsLength = mergeSymbol->len; + while (++i != symbols.end() && i->token == STRING_LITERAL) + literalsLength += i->len - 2; // no quotes + + if (literalsLength != mergeSymbol->len) { + QByteArray mergeSymbolOriginalLexem = mergeSymbol->unquotedLexem(); + QByteArray &mergeSymbolLexem = mergeSymbol->lex; + mergeSymbolLexem.resize(0); + mergeSymbolLexem.reserve(literalsLength); + mergeSymbolLexem.append('"'); + mergeSymbolLexem.append(mergeSymbolOriginalLexem); + for (Symbols::iterator j = mergeSymbol + 1; j != i; ++j) + mergeSymbolLexem.append(j->lex.constData() + j->from + 1, j->len - 2); // append j->unquotedLexem() + mergeSymbolLexem.append('"'); + mergeSymbol->len = mergeSymbol->lex.length(); + mergeSymbol->from = 0; + i = symbols.erase(mergeSymbol + 1, i); + } + if (i == symbols.end()) + break; + } + } +} + +static QByteArray searchIncludePaths(const QList &includepaths, + const QByteArray &include) +{ + QFileInfo fi; + for (int j = 0; j < includepaths.size() && !fi.exists(); ++j) { + const Parser::IncludePath &p = includepaths.at(j); + if (p.isFrameworkPath) { + const int slashPos = include.indexOf('/'); + if (slashPos == -1) + continue; + fi.setFile(QString::fromLocal8Bit(p.path + '/' + include.left(slashPos) + ".framework/Headers/"), + QString::fromLocal8Bit(include.mid(slashPos + 1))); + } else { + fi.setFile(QString::fromLocal8Bit(p.path), QString::fromLocal8Bit(include)); + } + // try again, maybe there's a file later in the include paths with the same name + // (186067) + if (fi.isDir()) { + fi = QFileInfo(); + continue; + } + } + + if (!fi.exists() || fi.isDir()) + return QByteArray(); + return fi.canonicalFilePath().toLocal8Bit(); +} + +QByteArray Preprocessor::resolveInclude(const QByteArray &include, const QByteArray &relativeTo) +{ + if (!relativeTo.isEmpty()) { + QFileInfo fi; + fi.setFile(QFileInfo(QString::fromLocal8Bit(relativeTo)).dir(), QString::fromLocal8Bit(include)); + if (fi.exists() && !fi.isDir()) + return fi.canonicalFilePath().toLocal8Bit(); + } + + auto it = nonlocalIncludePathResolutionCache.find(include); + if (it == nonlocalIncludePathResolutionCache.end()) + it = nonlocalIncludePathResolutionCache.insert(include, searchIncludePaths(includes, include)); + return it.value(); +} + +void Preprocessor::preprocess(const QByteArray &filename, Symbols &preprocessed) +{ + currentFilenames.push(filename); + preprocessed.reserve(preprocessed.size() + symbols.size()); + while (hasNext()) { + Token token = next(); + + switch (token) { + case PP_INCLUDE: + { + int lineNum = symbol().lineNum; + QByteArray include; + bool local = false; + if (test(PP_STRING_LITERAL)) { + local = lexem().startsWith('\"'); + include = unquotedLexem(); + } else + continue; + until(PP_NEWLINE); + + include = resolveInclude(include, local ? filename : QByteArray()); + if (include.isNull()) + continue; + + if (Preprocessor::preprocessedIncludes.contains(include)) + continue; + Preprocessor::preprocessedIncludes.insert(include); + + QFile file(QString::fromLocal8Bit(include.constData())); + if (!file.open(QFile::ReadOnly)) + continue; + + QByteArray input = readOrMapFile(&file); + + file.close(); + if (input.isEmpty()) + continue; + + Symbols saveSymbols = symbols; + int saveIndex = index; + + // phase 1: get rid of backslash-newlines + input = cleaned(input); + + // phase 2: tokenize for the preprocessor + symbols = tokenize(input); + input.clear(); + + index = 0; + + // phase 3: preprocess conditions and substitute macros + preprocessed += Symbol(0, MOC_INCLUDE_BEGIN, include); + preprocess(include, preprocessed); + preprocessed += Symbol(lineNum, MOC_INCLUDE_END, include); + + symbols = saveSymbols; + index = saveIndex; + continue; + } + case PP_DEFINE: + { + next(); + QByteArray name = lexem(); + if (name.isEmpty() || !is_ident_start(name[0])) + error(); + Macro macro; + macro.isVariadic = false; + if (test(LPAREN)) { + // we have a function macro + macro.isFunction = true; + parseDefineArguments(¯o); + } else { + macro.isFunction = false; + } + int start = index; + until(PP_NEWLINE); + macro.symbols.reserve(index - start - 1); + + // remove whitespace where there shouldn't be any: + // Before and after the macro, after a # and around ## + Token lastToken = HASH; // skip shitespace at the beginning + for (int i = start; i < index - 1; ++i) { + Token token = symbols.at(i).token; + if (token == WHITESPACE) { + if (lastToken == PP_HASH || lastToken == HASH || + lastToken == PP_HASHHASH || + lastToken == WHITESPACE) + continue; + } else if (token == PP_HASHHASH) { + if (!macro.symbols.isEmpty() && + lastToken == WHITESPACE) + macro.symbols.pop_back(); + } + macro.symbols.append(symbols.at(i)); + lastToken = token; + } + // remove trailing whitespace + while (!macro.symbols.isEmpty() && + (macro.symbols.constLast().token == PP_WHITESPACE || macro.symbols.constLast().token == WHITESPACE)) + macro.symbols.pop_back(); + + if (!macro.symbols.isEmpty()) { + if (macro.symbols.constFirst().token == PP_HASHHASH || + macro.symbols.constLast().token == PP_HASHHASH) { + error("'##' cannot appear at either end of a macro expansion"); + } + } + macros.insert(name, macro); + continue; + } + case PP_UNDEF: { + next(); + QByteArray name = lexem(); + until(PP_NEWLINE); + macros.remove(name); + continue; + } + case PP_IDENTIFIER: { + // substitute macros + macroExpand(&preprocessed, this, symbols, index, symbol().lineNum, true); + continue; + } + case PP_HASH: + until(PP_NEWLINE); + continue; // skip unknown preprocessor statement + case PP_IFDEF: + case PP_IFNDEF: + case PP_IF: + while (!evaluateCondition()) { + if (!skipBranch()) + break; + if (test(PP_ELIF)) { + } else { + until(PP_NEWLINE); + break; + } + } + continue; + case PP_ELIF: + case PP_ELSE: + skipUntilEndif(); + Q_FALLTHROUGH(); + case PP_ENDIF: + until(PP_NEWLINE); + continue; + case PP_NEWLINE: + continue; + case SIGNALS: + case SLOTS: { + Symbol sym = symbol(); + if (macros.contains("QT_NO_KEYWORDS")) + sym.token = IDENTIFIER; + else + sym.token = (token == SIGNALS ? Q_SIGNALS_TOKEN : Q_SLOTS_TOKEN); + preprocessed += sym; + } continue; + default: + break; + } + preprocessed += symbol(); + } + + currentFilenames.pop(); +} + +Symbols Preprocessor::preprocessed(const QByteArray &filename, QByteArray input) +{ + if (input.isEmpty()) + return symbols; + + // phase 1: get rid of backslash-newlines + input = cleaned(input); + + // phase 2: tokenize for the preprocessor + index = 0; + symbols = tokenize(input); + +#if 0 + for (int j = 0; j < symbols.size(); ++j) + fprintf(stderr, "line %d: %s(%s)\n", + symbols[j].lineNum, + symbols[j].lexem().constData(), + tokenTypeName(symbols[j].token)); +#endif + + // phase 3: preprocess conditions and substitute macros + Symbols result; + // Preallocate some space to speed up the code below. + // The magic value was found by logging the final size + // and calculating an average when running moc over FOSS projects. + result.reserve(input.size() / 300000); + preprocess(filename, result); + mergeStringLiterals(&result); + +#if 0 + for (int j = 0; j < result.size(); ++j) + fprintf(stderr, "line %d: %s(%s)\n", + result[j].lineNum, + result[j].lexem().constData(), + tokenTypeName(result[j].token)); +#endif + + return result; +} + +void Preprocessor::parseDefineArguments(Macro *m) +{ + Symbols arguments; + while (hasNext()) { + while (test(PP_WHITESPACE)) {} + Token t = next(); + if (t == PP_RPAREN) + break; + if (t != PP_IDENTIFIER) { + QByteArray l = lexem(); + if (l == "...") { + m->isVariadic = true; + arguments += Symbol(symbol().lineNum, PP_IDENTIFIER, "__VA_ARGS__"); + while (test(PP_WHITESPACE)) {} + if (!test(PP_RPAREN)) + error("missing ')' in macro argument list"); + break; + } else if (!is_identifier(l.constData(), l.length())) { + error("Unexpected character in macro argument list."); + } + } + + Symbol arg = symbol(); + if (arguments.contains(arg)) + error("Duplicate macro parameter."); + arguments += symbol(); + + while (test(PP_WHITESPACE)) {} + t = next(); + if (t == PP_RPAREN) + break; + if (t == PP_COMMA) + continue; + if (lexem() == "...") { + //GCC extension: #define FOO(x, y...) x(y) + // The last argument was already parsed. Just mark the macro as variadic. + m->isVariadic = true; + while (test(PP_WHITESPACE)) {} + if (!test(PP_RPAREN)) + error("missing ')' in macro argument list"); + break; + } + error("Unexpected character in macro argument list."); + } + m->arguments = arguments; + while (test(PP_WHITESPACE)) {} +} + +void Preprocessor::until(Token t) +{ + while(hasNext() && next() != t) + ; +} + +QT_END_NAMESPACE diff --git a/src/plugins/clangcodemodel/moc/preprocessor.h b/src/plugins/clangcodemodel/moc/preprocessor.h new file mode 100644 index 00000000000..7de81c0cbff --- /dev/null +++ b/src/plugins/clangcodemodel/moc/preprocessor.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PREPROCESSOR_H +#define PREPROCESSOR_H + +#include "parser.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE + +struct Macro +{ + Macro() : isFunction(false), isVariadic(false) {} + bool isFunction; + bool isVariadic; + Symbols arguments; + Symbols symbols; +}; + +#ifdef USE_LEXEM_STORE +typedef QByteArray MacroName; +#else +typedef SubArray MacroName; +#endif +typedef QHash Macros; + +class QFile; + +class Preprocessor : public Parser +{ +public: + Preprocessor(){} + static bool preprocessOnly; + QList frameworks; + QSet preprocessedIncludes; + QHash nonlocalIncludePathResolutionCache; + Macros macros; + QByteArray resolveInclude(const QByteArray &filename, const QByteArray &relativeTo); + Symbols preprocessed(const QByteArray &filename, QByteArray input); + + void parseDefineArguments(Macro *m); + + void skipUntilEndif(); + bool skipBranch(); + + void substituteUntilNewline(Symbols &substituted); + static Symbols macroExpandIdentifier(Preprocessor *that, SymbolStack &symbols, int lineNum, QByteArray *macroName); + static void macroExpand(Symbols *into, Preprocessor *that, const Symbols &toExpand, int &index, int lineNum, bool one, + const QSet &excludeSymbols = QSet()); + + int evaluateCondition(); + + enum TokenizeMode { TokenizeCpp, TokenizePreprocessor, PreparePreprocessorStatement, TokenizePreprocessorStatement, TokenizeInclude, PrepareDefine, TokenizeDefine }; + static Symbols tokenize(const QByteArray &input, int lineNum = 1, TokenizeMode mode = TokenizeCpp); + +private: + void until(Token); + + void preprocess(const QByteArray &filename, Symbols &preprocessed); +}; + +QT_END_NAMESPACE + +#endif // PREPROCESSOR_H diff --git a/src/plugins/clangcodemodel/moc/symbols.h b/src/plugins/clangcodemodel/moc/symbols.h new file mode 100644 index 00000000000..bbb1312cdc1 --- /dev/null +++ b/src/plugins/clangcodemodel/moc/symbols.h @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2013 Olivier Goffart +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SYMBOLS_H +#define SYMBOLS_H + +#include "token.h" +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +//#define USE_LEXEM_STORE + +struct SubArray +{ + inline SubArray():from(0),len(-1){} + inline SubArray(const QByteArray &a):array(a),from(0), len(a.size()){} + inline SubArray(const char *s):array(s),from(0) { len = array.size(); } + inline SubArray(const QByteArray &a, int from, int len):array(a), from(from), len(len){} + QByteArray array; + int from, len; + inline bool operator==(const SubArray &other) const { + if (len != other.len) + return false; + for (int i = 0; i < len; ++i) + if (array.at(from + i) != other.array.at(other.from + i)) + return false; + return true; + } +}; + +inline size_t qHash(const SubArray &key) +{ + return qHash(QLatin1String(key.array.constData() + key.from, key.len)); +} + + +struct Symbol +{ + +#ifdef USE_LEXEM_STORE + typedef QHash LexemStore; + static LexemStore lexemStore; + + inline Symbol() : lineNum(-1),token(NOTOKEN){} + inline Symbol(int lineNum, Token token): + lineNum(lineNum), token(token){} + inline Symbol(int lineNum, Token token, const QByteArray &lexem): + lineNum(lineNum), token(token),lex(lexem){} + inline Symbol(int lineNum, Token token, const QByteArray &lexem, int from, int len): + lineNum(lineNum), token(token){ + LexemStore::const_iterator it = lexemStore.constFind(SubArray(lexem, from, len)); + + if (it != lexemStore.constEnd()) { + lex = it.key().array; + } else { + lex = lexem.mid(from, len); + lexemStore.insert(lex, QHashDummyValue()); + } + } + int lineNum; + Token token; + inline QByteArray unquotedLexem() const { return lex.mid(1, lex.length()-2); } + inline QByteArray lexem() const { return lex; } + inline operator QByteArray() const { return lex; } + QByteArray lex; + +#else + + inline Symbol() : lineNum(-1),token(NOTOKEN), from(0),len(-1) {} + inline Symbol(int lineNum, Token token): + lineNum(lineNum), token(token), from(0), len(-1) {} + inline Symbol(int lineNum, Token token, const QByteArray &lexem): + lineNum(lineNum), token(token), lex(lexem), from(0) { len = lex.size(); } + inline Symbol(int lineNum, Token token, const QByteArray &lexem, int from, int len): + lineNum(lineNum), token(token),lex(lexem),from(from), len(len){} + int lineNum; + Token token; + inline QByteArray lexem() const { return lex.mid(from, len); } + inline QByteArray unquotedLexem() const { return lex.mid(from+1, len-2); } + inline operator SubArray() const { return SubArray(lex, from, len); } + bool operator==(const Symbol& o) const + { + return SubArray(lex, from, len) == SubArray(o.lex, o.from, o.len); + } + QByteArray lex; + int from, len; + +#endif +}; +Q_DECLARE_TYPEINFO(Symbol, Q_RELOCATABLE_TYPE); + +typedef QList Symbols; + +struct SafeSymbols { + Symbols symbols; + QByteArray expandedMacro; + QSet excludedSymbols; + int index; +}; +Q_DECLARE_TYPEINFO(SafeSymbols, Q_RELOCATABLE_TYPE); + +class SymbolStack : public QStack +{ +public: + inline bool hasNext() { + while (!isEmpty() && top().index >= top().symbols.size()) + pop(); + return !isEmpty(); + } + inline Token next() { + while (!isEmpty() && top().index >= top().symbols.size()) + pop(); + if (isEmpty()) + return NOTOKEN; + return top().symbols.at(top().index++).token; + } + bool test(Token); + inline const Symbol &symbol() const { return top().symbols.at(top().index-1); } + inline Token token() { return symbol().token; } + inline QByteArray lexem() const { return symbol().lexem(); } + inline QByteArray unquotedLexem() { return symbol().unquotedLexem(); } + + bool dontReplaceSymbol(const QByteArray &name); + QSet excludeSymbols(); +}; + +inline bool SymbolStack::test(Token token) +{ + int stackPos = size() - 1; + while (stackPos >= 0 && at(stackPos).index >= at(stackPos).symbols.size()) + --stackPos; + if (stackPos < 0) + return false; + if (at(stackPos).symbols.at(at(stackPos).index).token == token) { + next(); + return true; + } + return false; +} + +inline bool SymbolStack::dontReplaceSymbol(const QByteArray &name) +{ + for (int i = 0; i < size(); ++i) { + if (name == at(i).expandedMacro || at(i).excludedSymbols.contains(name)) + return true; + } + return false; +} + +inline QSet SymbolStack::excludeSymbols() +{ + QSet set; + for (int i = 0; i < size(); ++i) { + set << at(i).expandedMacro; + set += at(i).excludedSymbols; + } + return set; +} + +QT_END_NAMESPACE + +#endif // SYMBOLS_H diff --git a/src/plugins/clangcodemodel/moc/token.cpp b/src/plugins/clangcodemodel/moc/token.cpp new file mode 100644 index 00000000000..cf1aa102c77 --- /dev/null +++ b/src/plugins/clangcodemodel/moc/token.cpp @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "token.h" + +QT_BEGIN_NAMESPACE + +#if defined(DEBUG_MOC) +const char *tokenTypeName(Token t) +{ + switch (t) { +#define CREATE_CASE(Name) case Name: return #Name; + FOR_ALL_TOKENS(CREATE_CASE) +#undef CREATE_CASE + } + return ""; +} +#endif + +QT_END_NAMESPACE diff --git a/src/plugins/clangcodemodel/moc/token.h b/src/plugins/clangcodemodel/moc/token.h new file mode 100644 index 00000000000..6f803e92f8b --- /dev/null +++ b/src/plugins/clangcodemodel/moc/token.h @@ -0,0 +1,276 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TOKEN_H +#define TOKEN_H + +#include + +QT_BEGIN_NAMESPACE + +#define FOR_ALL_TOKENS(F) \ + F(NOTOKEN) \ + F(IDENTIFIER) \ + F(INTEGER_LITERAL) \ + F(CHARACTER_LITERAL) \ + F(STRING_LITERAL) \ + F(BOOLEAN_LITERAL) \ + F(HEADER_NAME) \ + F(LANGLE) \ + F(RANGLE) \ + F(LPAREN) \ + F(RPAREN) \ + F(ELIPSIS) \ + F(LBRACK) \ + F(RBRACK) \ + F(LBRACE) \ + F(RBRACE) \ + F(EQ) \ + F(SCOPE) \ + F(SEMIC) \ + F(COLON) \ + F(DOTSTAR) \ + F(QUESTION) \ + F(DOT) \ + F(DYNAMIC_CAST) \ + F(STATIC_CAST) \ + F(REINTERPRET_CAST) \ + F(CONST_CAST) \ + F(TYPEID) \ + F(THIS) \ + F(TEMPLATE) \ + F(THROW) \ + F(TRY) \ + F(CATCH) \ + F(TYPEDEF) \ + F(FRIEND) \ + F(CLASS) \ + F(NAMESPACE) \ + F(ENUM) \ + F(STRUCT) \ + F(UNION) \ + F(VIRTUAL) \ + F(PRIVATE) \ + F(PROTECTED) \ + F(PUBLIC) \ + F(EXPORT) \ + F(AUTO) \ + F(REGISTER) \ + F(EXTERN) \ + F(MUTABLE) \ + F(ASM) \ + F(USING) \ + F(INLINE) \ + F(EXPLICIT) \ + F(STATIC) \ + F(CONST_TOKEN) \ + F(VOLATILE) \ + F(OPERATOR) \ + F(SIZEOF) \ + F(NEW) \ + F(DELETE) \ + F(PLUS) \ + F(MINUS) \ + F(STAR) \ + F(SLASH) \ + F(PERCENT) \ + F(HAT) \ + F(AND) \ + F(OR) \ + F(TILDE) \ + F(NOT) \ + F(PLUS_EQ) \ + F(MINUS_EQ) \ + F(STAR_EQ) \ + F(SLASH_EQ) \ + F(PERCENT_EQ) \ + F(HAT_EQ) \ + F(AND_EQ) \ + F(OR_EQ) \ + F(LTLT) \ + F(GTGT) \ + F(GTGT_EQ) \ + F(LTLT_EQ) \ + F(EQEQ) \ + F(NE) \ + F(LE) \ + F(GE) \ + F(ANDAND) \ + F(OROR) \ + F(INCR) \ + F(DECR) \ + F(COMMA) \ + F(ARROW_STAR) \ + F(ARROW) \ + F(CHAR_TOKEN) \ + F(WCHAR_TOKEN) \ + F(BOOL_TOKEN) \ + F(SHORT_TOKEN) \ + F(INT_TOKEN) \ + F(LONG_TOKEN) \ + F(SIGNED) \ + F(UNSIGNED) \ + F(FLOAT_TOKEN) \ + F(DOUBLE) \ + F(VOID_TOKEN) \ + F(CASE) \ + F(DEFAULT) \ + F(IF) \ + F(ELSE) \ + F(SWITCH) \ + F(WHILE) \ + F(DO) \ + F(FOR) \ + F(BREAK) \ + F(CONTINUE) \ + F(GOTO) \ + F(SIGNALS) \ + F(SLOTS) \ + F(RETURN) \ + F(Q_OBJECT_TOKEN) \ + F(Q_GADGET_TOKEN) \ + F(Q_NAMESPACE_TOKEN) \ + F(Q_NAMESPACE_EXPORT_TOKEN) \ + F(Q_PROPERTY_TOKEN) \ + F(Q_PLUGIN_METADATA_TOKEN) \ + F(Q_ENUMS_TOKEN) \ + F(Q_ENUM_TOKEN) \ + F(Q_ENUM_NS_TOKEN) \ + F(Q_FLAGS_TOKEN) \ + F(Q_FLAG_TOKEN) \ + F(Q_FLAG_NS_TOKEN) \ + F(Q_DECLARE_FLAGS_TOKEN) \ + F(Q_DECLARE_INTERFACE_TOKEN) \ + F(Q_DECLARE_METATYPE_TOKEN) \ + F(Q_CLASSINFO_TOKEN) \ + F(Q_INTERFACES_TOKEN) \ + F(Q_SIGNALS_TOKEN) \ + F(Q_SLOTS_TOKEN) \ + F(Q_SIGNAL_TOKEN) \ + F(Q_SLOT_TOKEN) \ + F(Q_PRIVATE_SLOT_TOKEN) \ + F(Q_MOC_COMPAT_TOKEN) \ + F(Q_INVOKABLE_TOKEN) \ + F(Q_SCRIPTABLE_TOKEN) \ + F(Q_PRIVATE_PROPERTY_TOKEN) \ + F(Q_REVISION_TOKEN) \ + F(Q_MOC_INCLUDE_TOKEN) \ + F(SPECIAL_TREATMENT_MARK) \ + F(MOC_INCLUDE_BEGIN) \ + F(MOC_INCLUDE_END) \ + F(CPP_COMMENT) \ + F(C_COMMENT) \ + F(FLOATING_LITERAL) \ + F(HASH) \ + F(QUOTE) \ + F(SINGLEQUOTE) \ + F(LANGLE_SCOPE) \ + F(DIGIT) \ + F(CHARACTER) \ + F(NEWLINE) \ + F(WHITESPACE) \ + F(BACKSLASH) \ + F(INCOMPLETE) \ + F(PP_DEFINE) \ + F(PP_UNDEF) \ + F(PP_IF) \ + F(PP_IFDEF) \ + F(PP_IFNDEF) \ + F(PP_ELIF) \ + F(PP_ELSE) \ + F(PP_ENDIF) \ + F(PP_INCLUDE) \ + F(PP_HASHHASH) \ + F(PP_HASH) \ + F(PP_DEFINED) \ + F(PP_INCOMPLETE) \ + F(PP_MOC_TRUE) \ + F(PP_MOC_FALSE) + + +enum Token { + +#define CREATE_ENUM_VALUE(Name) Name, + FOR_ALL_TOKENS(CREATE_ENUM_VALUE) +#undef CREATE_ENUM_VALUE + + // aliases + PP_AND = AND, + PP_ANDAND = ANDAND, + PP_BACKSLASH = BACKSLASH, + PP_CHARACTER = CHARACTER, + PP_CHARACTER_LITERAL = CHARACTER_LITERAL, + PP_COLON = COLON, + PP_COMMA = COMMA, + PP_CPP_COMMENT = CPP_COMMENT, + PP_C_COMMENT = C_COMMENT, + PP_DIGIT = DIGIT, + PP_EQEQ = EQEQ, + PP_FLOATING_LITERAL = FLOATING_LITERAL, + PP_GE = GE, + PP_GTGT = GTGT, + PP_HAT = HAT, + PP_IDENTIFIER = IDENTIFIER, + PP_INTEGER_LITERAL = INTEGER_LITERAL, + PP_LANGLE = LANGLE, + PP_LE = LE, + PP_LPAREN = LPAREN, + PP_LTLT = LTLT, + PP_MINUS = MINUS, + PP_NE = NE, + PP_NEWLINE = NEWLINE, + PP_NOTOKEN = NOTOKEN, + PP_NOT = NOT, + PP_OR = OR, + PP_OROR = OROR, + PP_PERCENT = PERCENT, + PP_PLUS = PLUS, + PP_QUESTION = QUESTION, + PP_QUOTE = QUOTE, + PP_RANGLE = RANGLE, + PP_RPAREN = RPAREN, + PP_SINGLEQUOTE = SINGLEQUOTE, + PP_SLASH = SLASH, + PP_STAR = STAR, + PP_STRING_LITERAL = STRING_LITERAL, + PP_TILDE = TILDE, + PP_WHITESPACE = WHITESPACE, + Q_META_TOKEN_BEGIN = Q_OBJECT_TOKEN, + Q_META_TOKEN_END = SPECIAL_TREATMENT_MARK +}; + +// for debugging only +#if defined(DEBUG_MOC) +const char *tokenTypeName(Token t); +#endif + +typedef Token PP_Token; + +QT_END_NAMESPACE + +#endif // TOKEN_H diff --git a/src/plugins/clangcodemodel/moc/utils.h b/src/plugins/clangcodemodel/moc/utils.h new file mode 100644 index 00000000000..4cb1d903453 --- /dev/null +++ b/src/plugins/clangcodemodel/moc/utils.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef UTILS_H +#define UTILS_H + +#include + +QT_BEGIN_NAMESPACE + +inline bool is_whitespace(char s) +{ + return (s == ' ' || s == '\t' || s == '\n'); +} + +inline bool is_space(char s) +{ + return (s == ' ' || s == '\t'); +} + +inline bool is_ident_start(char s) +{ + return ((s >= 'a' && s <= 'z') + || (s >= 'A' && s <= 'Z') + || s == '_' || s == '$' + ); +} + +inline bool is_ident_char(char s) +{ + return ((s >= 'a' && s <= 'z') + || (s >= 'A' && s <= 'Z') + || (s >= '0' && s <= '9') + || s == '_' || s == '$' + ); +} + +inline bool is_identifier(const char *s, int len) +{ + if (len < 1) + return false; + if (!is_ident_start(*s)) + return false; + for (int i = 1; i < len; ++i) + if (!is_ident_char(s[i])) + return false; + return true; +} + +inline bool is_digit_char(char s) +{ + return (s >= '0' && s <= '9'); +} + +inline bool is_octal_char(char s) +{ + return (s >= '0' && s <= '7'); +} + +inline bool is_hex_char(char s) +{ + return ((s >= 'a' && s <= 'f') + || (s >= 'A' && s <= 'F') + || (s >= '0' && s <= '9') + ); +} + +inline const char *skipQuote(const char *data) +{ + while (*data && (*data != '\"')) { + if (*data == '\\') { + ++data; + if (!*data) break; + } + ++data; + } + + if (*data) //Skip last quote + ++data; + return data; +} + +QT_END_NAMESPACE + +#endif // UTILS_H diff --git a/src/plugins/clangcodemodel/test/clangdtests.cpp b/src/plugins/clangcodemodel/test/clangdtests.cpp index ecfabb33297..93aae99ecd3 100644 --- a/src/plugins/clangcodemodel/test/clangdtests.cpp +++ b/src/plugins/clangcodemodel/test/clangdtests.cpp @@ -1056,12 +1056,26 @@ void ClangdTestHighlighting::test_data() << QList{C_PREPROCESSOR} << 0; QTest::newRow("Q_PROPERTY (property name)") << 599 << 52 << 599 << 56 << QList{C_FIELD} << 0; + QTest::newRow("Q_PROPERTY (READ keyword)") << 599 << 57 << 599 << 61 + << QList{C_KEYWORD} << 0; QTest::newRow("Q_PROPERTY (getter)") << 599 << 62 << 599 << 69 << QList{C_FUNCTION} << 0; + QTest::newRow("Q_PROPERTY (WRITE keyword)") << 599 << 70 << 599 << 75 + << QList{C_KEYWORD} << 0; + QTest::newRow("Q_PROPERTY (setter)") << 599 << 76 << 599 << 83 + << QList{C_FUNCTION} << 0; + QTest::newRow("Q_PROPERTY (NOTIFY keyword)") << 599 << 84 << 599 << 90 + << QList{C_KEYWORD} << 0; QTest::newRow("Q_PROPERTY (notifier)") << 599 << 91 << 599 << 102 << QList{C_FUNCTION} << 0; + QTest::newRow("Q_PROPERTY (SCRIPTABLE keyword)") << 599 << 103 << 599 << 113 + << QList{C_KEYWORD} << 0; + QTest::newRow("Q_PROPERTY (REVISION keyword)") << 599 << 119 << 599 << 127 + << QList{C_KEYWORD} << 0; QTest::newRow("Q_PROPERTY (type)") << 600 << 22 << 600 << 29 << QList{C_TYPE} << 0; + QTest::newRow("Q_PROPERTY (REVISION keyword [new])") << 600 << 46 << 600 << 54 + << QList{C_KEYWORD} << 0; QTest::newRow("multi-line Q_PROPERTY (macro name)") << 704 << 5 << 704 << 15 << QList{C_PREPROCESSOR} << 0; QTest::newRow("multi-line Q_PROPERTY (property name)") << 718 << 13 << 718 << 17 @@ -1298,13 +1312,6 @@ void ClangdTestHighlighting::test() "https://github.com/clangd/clangd/issues/878", Abort); } - QEXPECT_FAIL("Q_PROPERTY (property name)", "FIXME: How to do this?", Abort); - QEXPECT_FAIL("Q_PROPERTY (getter)", "FIXME: How to do this?", Abort); - QEXPECT_FAIL("Q_PROPERTY (notifier)", "FIXME: How to do this?", Abort); - QEXPECT_FAIL("Q_PROPERTY (type)", "FIXME: How to do this?", Abort); - QEXPECT_FAIL("multi-line Q_PROPERTY (property name)", "FIXME: How to do this?", Abort); - QEXPECT_FAIL("multi-line Q_PROPERTY (getter)", "FIXME: How to do this?", Abort); - QEXPECT_FAIL("multi-line Q_PROPERTY (notifier)", "FIXME: How to do this?", Abort); QEXPECT_FAIL("old-style signal (signal)", "check if and how we want to support this", Abort); QEXPECT_FAIL("old-style signal (signal parameter)", "check if and how we want to support this", Abort); diff --git a/src/plugins/clangcodemodel/test/data/highlighting/highlighting.cpp b/src/plugins/clangcodemodel/test/data/highlighting/highlighting.cpp index 54716d79a3f..2290abf3a73 100644 --- a/src/plugins/clangcodemodel/test/data/highlighting/highlighting.cpp +++ b/src/plugins/clangcodemodel/test/data/highlighting/highlighting.cpp @@ -596,8 +596,8 @@ Undeclared u; #define SIGNAL(arg) #arg #define SLOT(arg) #arg class Property { - Q_PROPERTY(const volatile unsigned long long * prop READ getProp WRITE setProp NOTIFY propChanged) - Q_PROPERTY(const QString str READ getStr) + Q_PROPERTY(const volatile unsigned long long * prop READ getProp WRITE setProp NOTIFY propChanged SCRIPTABLE true REVISION 1) + Q_PROPERTY(const QString str READ getStr REVISION(1,0)) }; struct X {