133 // Class definitions may appear multiple times - but only because we are trying to |
133 // Class definitions may appear multiple times - but only because we are trying to |
134 // "compile" all sources irrespective of build configuration. |
134 // "compile" all sources irrespective of build configuration. |
135 // Nested classes may be forward-declared inside a definition, and defined in another file. |
135 // Nested classes may be forward-declared inside a definition, and defined in another file. |
136 // The latter will detach the class' child list, so clones need a backlink to the original |
136 // The latter will detach the class' child list, so clones need a backlink to the original |
137 // definition (either one in case of multiple definitions). |
137 // definition (either one in case of multiple definitions). |
|
138 // Namespaces can have tr() functions as well, so we need to track parent definitions for |
|
139 // them as well. The complication is that we may have to deal with a forrest instead of |
|
140 // a tree - in that case the parent will be arbitrary. However, it seem likely that |
|
141 // Q_DECLARE_TR_FUNCTIONS would be used either in "class-like" namespaces with a central |
|
142 // header or only locally in a file. |
138 Namespace *classDef; |
143 Namespace *classDef; |
139 |
144 |
140 QString trQualification; |
145 QString trQualification; |
141 |
146 |
142 bool hasTrFunctions; |
147 bool hasTrFunctions; |
254 static QStringList stringListifySegments(const QList<HashString> &namespaces); |
259 static QStringList stringListifySegments(const QList<HashString> &namespaces); |
255 bool qualifyOneCallbackOwn(const Namespace *ns, void *context) const; |
260 bool qualifyOneCallbackOwn(const Namespace *ns, void *context) const; |
256 bool qualifyOneCallbackUsing(const Namespace *ns, void *context) const; |
261 bool qualifyOneCallbackUsing(const Namespace *ns, void *context) const; |
257 bool qualifyOne(const NamespaceList &namespaces, int nsCnt, const HashString &segment, |
262 bool qualifyOne(const NamespaceList &namespaces, int nsCnt, const HashString &segment, |
258 NamespaceList *resolved) const; |
263 NamespaceList *resolved) const; |
259 bool fullyQualify(const NamespaceList &namespaces, const QList<HashString> &segments, |
264 bool fullyQualify(const NamespaceList &namespaces, int nsCnt, |
260 bool isDeclaration, |
265 const QList<HashString> &segments, bool isDeclaration, |
261 NamespaceList *resolved, QStringList *unresolved) const; |
266 NamespaceList *resolved, QStringList *unresolved) const; |
262 bool fullyQualify(const NamespaceList &namespaces, const QString &segments, |
267 bool fullyQualify(const NamespaceList &namespaces, |
263 bool isDeclaration, |
268 const QList<HashString> &segments, bool isDeclaration, |
|
269 NamespaceList *resolved, QStringList *unresolved) const; |
|
270 bool fullyQualify(const NamespaceList &namespaces, |
|
271 const QString &segments, bool isDeclaration, |
264 NamespaceList *resolved, QStringList *unresolved) const; |
272 NamespaceList *resolved, QStringList *unresolved) const; |
265 bool findNamespaceCallback(const Namespace *ns, void *context) const; |
273 bool findNamespaceCallback(const Namespace *ns, void *context) const; |
266 const Namespace *findNamespace(const NamespaceList &namespaces, int nsCount = -1) const; |
274 const Namespace *findNamespace(const NamespaceList &namespaces, int nsCount = -1) const; |
267 void enterNamespace(NamespaceList *namespaces, const HashString &name); |
275 void enterNamespace(NamespaceList *namespaces, const HashString &name); |
268 void truncateNamespaces(NamespaceList *namespaces, int lenght); |
276 void truncateNamespaces(NamespaceList *namespaces, int lenght); |
269 Namespace *modifyNamespace(NamespaceList *namespaces, bool tryOrigin = true); |
277 Namespace *modifyNamespace(NamespaceList *namespaces, bool haveLast = true); |
270 |
278 |
271 enum { |
279 enum { |
272 Tok_Eof, Tok_class, Tok_friend, Tok_namespace, Tok_using, Tok_return, |
280 Tok_Eof, Tok_class, Tok_friend, Tok_namespace, Tok_using, Tok_return, |
273 Tok_tr = 10, Tok_trUtf8, Tok_translate, Tok_translateUtf8, Tok_trid, |
281 Tok_tr = 10, Tok_trUtf8, Tok_translate, Tok_translateUtf8, Tok_trid, |
274 Tok_Q_OBJECT = 20, Tok_Q_DECLARE_TR_FUNCTIONS, |
282 Tok_Q_OBJECT = 20, Tok_Q_DECLARE_TR_FUNCTIONS, |
343 void CppParser::setInput(const QString &in) |
350 void CppParser::setInput(const QString &in) |
344 { |
351 { |
345 yyInStr = in; |
352 yyInStr = in; |
346 yyFileName = QString(); |
353 yyFileName = QString(); |
347 yySourceCodec = 0; |
354 yySourceCodec = 0; |
348 yySourceIsUnicode = true; |
|
349 yyForceUtf8 = true; |
355 yyForceUtf8 = true; |
350 } |
356 } |
351 |
357 |
352 void CppParser::setInput(QTextStream &ts, const QString &fileName) |
358 void CppParser::setInput(QTextStream &ts, const QString &fileName) |
353 { |
359 { |
354 yyInStr = ts.readAll(); |
360 yyInStr = ts.readAll(); |
355 yyFileName = fileName; |
361 yyFileName = fileName; |
356 yySourceCodec = ts.codec(); |
362 yySourceCodec = ts.codec(); |
357 yySourceIsUnicode = yySourceCodec->name().startsWith("UTF-"); |
|
358 yyForceUtf8 = false; |
363 yyForceUtf8 = false; |
359 } |
364 } |
360 |
365 |
361 /* |
366 /* |
362 The first part of this source file is the C++ tokenizer. We skip |
367 The first part of this source file is the C++ tokenizer. We skip |
956 functionContext = state->functionContext; |
961 functionContext = state->functionContext; |
957 functionContextUnresolved = state->functionContextUnresolved; |
962 functionContextUnresolved = state->functionContextUnresolved; |
958 pendingContext = state->pendingContext; |
963 pendingContext = state->pendingContext; |
959 } |
964 } |
960 |
965 |
961 Namespace *CppParser::modifyNamespace(NamespaceList *namespaces, bool tryOrigin) |
966 Namespace *CppParser::modifyNamespace(NamespaceList *namespaces, bool haveLast) |
962 { |
967 { |
963 Namespace *pns, *ns = &results->rootNamespace; |
968 Namespace *pns, *ns = &results->rootNamespace; |
964 for (int i = 1; i < namespaces->count(); ++i) { |
969 for (int i = 1; i < namespaces->count(); ++i) { |
965 pns = ns; |
970 pns = ns; |
966 if (!(ns = pns->children.value(namespaces->at(i)))) { |
971 if (!(ns = pns->children.value(namespaces->at(i)))) { |
967 do { |
972 do { |
968 ns = new Namespace; |
973 ns = new Namespace; |
969 if (tryOrigin) |
974 if (haveLast || i < namespaces->count() - 1) |
970 if (const Namespace *ons = findNamespace(*namespaces, i + 1)) |
975 if (const Namespace *ons = findNamespace(*namespaces, i + 1)) |
971 ns->classDef = ons->classDef; |
976 ns->classDef = ons->classDef; |
972 pns->children.insert(namespaces->at(i), ns); |
977 pns->children.insert(namespaces->at(i), ns); |
973 pns = ns; |
978 pns = ns; |
974 } while (++i < namespaces->count()); |
979 } while (++i < namespaces->count()); |
1050 *data->resolved << data->segment; |
1055 *data->resolved << data->segment; |
1051 return true; |
1056 return true; |
1052 } |
1057 } |
1053 QHash<HashString, NamespaceList>::ConstIterator nsai = ns->aliases.constFind(data->segment); |
1058 QHash<HashString, NamespaceList>::ConstIterator nsai = ns->aliases.constFind(data->segment); |
1054 if (nsai != ns->aliases.constEnd()) { |
1059 if (nsai != ns->aliases.constEnd()) { |
1055 *data->resolved = *nsai; |
1060 const NamespaceList &nsl = *nsai; |
|
1061 if (nsl.last().value().isEmpty()) { // Delayed alias resolution |
|
1062 NamespaceList &nslIn = *const_cast<NamespaceList *>(&nsl); |
|
1063 nslIn.removeLast(); |
|
1064 NamespaceList nslOut; |
|
1065 if (!fullyQualify(data->namespaces, data->nsCount, nslIn, false, &nslOut, 0)) { |
|
1066 const_cast<Namespace *>(ns)->aliases.remove(data->segment); |
|
1067 return false; |
|
1068 } |
|
1069 nslIn = nslOut; |
|
1070 } |
|
1071 *data->resolved = nsl; |
1056 return true; |
1072 return true; |
1057 } |
1073 } |
1058 return false; |
1074 return false; |
1059 } |
1075 } |
1060 |
1076 |
1120 if (unresolved) |
1136 if (unresolved) |
1121 *unresolved = stringListifySegments(segments.mid(initSegIdx)); |
1137 *unresolved = stringListifySegments(segments.mid(initSegIdx)); |
1122 return false; |
1138 return false; |
1123 } |
1139 } |
1124 |
1140 |
1125 bool CppParser::fullyQualify(const NamespaceList &namespaces, const QString &quali, |
1141 bool CppParser::fullyQualify(const NamespaceList &namespaces, |
1126 bool isDeclaration, |
1142 const QList<HashString> &segments, bool isDeclaration, |
|
1143 NamespaceList *resolved, QStringList *unresolved) const |
|
1144 { |
|
1145 return fullyQualify(namespaces, namespaces.count(), |
|
1146 segments, isDeclaration, resolved, unresolved); |
|
1147 } |
|
1148 |
|
1149 bool CppParser::fullyQualify(const NamespaceList &namespaces, |
|
1150 const QString &quali, bool isDeclaration, |
1127 NamespaceList *resolved, QStringList *unresolved) const |
1151 NamespaceList *resolved, QStringList *unresolved) const |
1128 { |
1152 { |
1129 static QString strColons(QLatin1String("::")); |
1153 static QString strColons(QLatin1String("::")); |
1130 |
1154 |
1131 QList<HashString> segments; |
1155 QList<HashString> segments; |
1401 |
1425 |
1402 QString CppParser::transcode(const QString &str, bool utf8) |
1426 QString CppParser::transcode(const QString &str, bool utf8) |
1403 { |
1427 { |
1404 static const char tab[] = "abfnrtv"; |
1428 static const char tab[] = "abfnrtv"; |
1405 static const char backTab[] = "\a\b\f\n\r\t\v"; |
1429 static const char backTab[] = "\a\b\f\n\r\t\v"; |
1406 const QString in = (!utf8 || yySourceIsUnicode) |
1430 // This function has to convert back to bytes, as C's \0* sequences work at that level. |
1407 ? str : QString::fromUtf8(yySourceCodec->fromUnicode(str).data()); |
1431 const QByteArray in = yyForceUtf8 ? str.toUtf8() : tor->codec()->fromUnicode(str); |
1408 QString out; |
1432 QByteArray out; |
1409 |
1433 |
1410 out.reserve(in.length()); |
1434 out.reserve(in.length()); |
1411 for (int i = 0; i < in.length();) { |
1435 for (int i = 0; i < in.length();) { |
1412 ushort c = in[i++].unicode(); |
1436 uchar c = in[i++]; |
1413 if (c == '\\') { |
1437 if (c == '\\') { |
1414 if (i >= in.length()) |
1438 if (i >= in.length()) |
1415 break; |
1439 break; |
1416 c = in[i++].unicode(); |
1440 c = in[i++]; |
1417 |
1441 |
1418 if (c == '\n') |
1442 if (c == '\n') |
1419 continue; |
1443 continue; |
1420 |
1444 |
1421 if (c == 'x') { |
1445 if (c == 'x') { |
1422 QByteArray hex; |
1446 QByteArray hex; |
1423 while (i < in.length() && isxdigit((c = in[i].unicode()))) { |
1447 while (i < in.length() && isxdigit((c = in[i]))) { |
1424 hex += c; |
1448 hex += c; |
1425 i++; |
1449 i++; |
1426 } |
1450 } |
1427 out += hex.toUInt(0, 16); |
1451 out += hex.toUInt(0, 16); |
1428 } else if (c >= '0' && c < '8') { |
1452 } else if (c >= '0' && c < '8') { |
1429 QByteArray oct; |
1453 QByteArray oct; |
1430 int n = 0; |
1454 int n = 0; |
1431 oct += c; |
1455 oct += c; |
1432 while (n < 2 && i < in.length() && (c = in[i].unicode()) >= '0' && c < '8') { |
1456 while (n < 2 && i < in.length() && (c = in[i]) >= '0' && c < '8') { |
1433 i++; |
1457 i++; |
1434 n++; |
1458 n++; |
1435 oct += c; |
1459 oct += c; |
1436 } |
1460 } |
1437 out += oct.toUInt(0, 8); |
1461 out += oct.toUInt(0, 8); |
1438 } else { |
1462 } else { |
1439 const char *p = strchr(tab, c); |
1463 const char *p = strchr(tab, c); |
1440 out += QChar(QLatin1Char(!p ? c : backTab[p - tab])); |
1464 out += !p ? c : backTab[p - tab]; |
1441 } |
1465 } |
1442 } else { |
1466 } else { |
1443 out += c; |
1467 out += c; |
1444 } |
1468 } |
1445 } |
1469 } |
1446 return out; |
1470 return (utf8 || yyForceUtf8) ? QString::fromUtf8(out.constData(), out.length()) |
|
1471 : tor->codec()->toUnicode(out); |
1447 } |
1472 } |
1448 |
1473 |
1449 void CppParser::recordMessage( |
1474 void CppParser::recordMessage( |
1450 int line, const QString &context, const QString &text, const QString &comment, |
1475 int line, const QString &context, const QString &text, const QString &comment, |
1451 const QString &extracomment, const QString &msgid, const TranslatorMessage::ExtraData &extra, |
1476 const QString &extracomment, const QString &msgid, const TranslatorMessage::ExtraData &extra, |
1659 } |
1683 } |
1660 yyTok = getToken(); |
1684 yyTok = getToken(); |
1661 } |
1685 } |
1662 NamespaceList nsl; |
1686 NamespaceList nsl; |
1663 if (fullyQualify(namespaces, fullName, false, &nsl, 0)) |
1687 if (fullyQualify(namespaces, fullName, false, &nsl, 0)) |
1664 modifyNamespace(&namespaces, false)->usings << HashStringList(nsl); |
1688 modifyNamespace(&namespaces)->usings << HashStringList(nsl); |
1665 } else { |
1689 } else { |
1666 QList<HashString> fullName; |
1690 QList<HashString> fullName; |
1667 if (yyTok == Tok_ColonColon) |
1691 if (yyTok == Tok_ColonColon) |
1668 fullName.append(HashString(QString())); |
1692 fullName.append(HashString(QString())); |
1669 while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { |
1693 while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { |
1851 extra.clear(); |
1879 extra.clear(); |
1852 break; |
1880 break; |
1853 case Tok_trid: |
1881 case Tok_trid: |
1854 if (!tor) |
1882 if (!tor) |
1855 goto case_default; |
1883 goto case_default; |
1856 if (sourcetext.isEmpty()) { |
1884 if (!msgid.isEmpty()) |
1857 yyTok = getToken(); |
1885 qWarning("%s:%d: //= cannot be used with qtTrId() / QT_TRID_NOOP(). Ignoring\n", |
1858 } else { |
1886 qPrintable(yyFileName), yyLineNo); |
1859 if (!msgid.isEmpty()) |
1887 //utf8 = false; // Maybe use //%% or something like that |
1860 qWarning("%s:%d: //= cannot be used with qtTrId() / QT_TRID_NOOP(). Ignoring\n", |
1888 line = yyLineNo; |
1861 qPrintable(yyFileName), yyLineNo); |
1889 yyTok = getToken(); |
1862 //utf8 = false; // Maybe use //%% or something like that |
1890 if (match(Tok_LeftParen) && matchString(&msgid) && !msgid.isEmpty()) { |
1863 line = yyLineNo; |
1891 bool plural = match(Tok_Comma); |
1864 yyTok = getToken(); |
1892 recordMessage(line, QString(), sourcetext, QString(), extracomment, |
1865 if (match(Tok_LeftParen) && matchString(&msgid) && !msgid.isEmpty()) { |
1893 msgid, extra, false, plural); |
1866 bool plural = match(Tok_Comma); |
1894 } |
1867 recordMessage(line, QString(), sourcetext, QString(), extracomment, |
1895 sourcetext.clear(); |
1868 msgid, extra, false, plural); |
|
1869 } |
|
1870 sourcetext.clear(); |
|
1871 } |
|
1872 extracomment.clear(); |
1896 extracomment.clear(); |
1873 msgid.clear(); |
1897 msgid.clear(); |
1874 extra.clear(); |
1898 extra.clear(); |
1875 break; |
1899 break; |
1876 case Tok_Q_DECLARE_TR_FUNCTIONS: |
1900 case Tok_Q_DECLARE_TR_FUNCTIONS: |
1877 if (getMacroArgs()) { |
1901 if (getMacroArgs()) { |
1878 Namespace *ns = modifyNamespace(&namespaces, true); |
1902 Namespace *ns = modifyNamespace(&namespaces); |
1879 ns->hasTrFunctions = true; |
1903 ns->hasTrFunctions = true; |
1880 ns->trQualification = yyWord; |
1904 ns->trQualification = yyWord; |
1881 ns->trQualification.detach(); |
1905 ns->trQualification.detach(); |
1882 } |
1906 } |
1883 yyTok = getToken(); |
1907 yyTok = getToken(); |
1884 break; |
1908 break; |
1885 case Tok_Q_OBJECT: |
1909 case Tok_Q_OBJECT: |
1886 modifyNamespace(&namespaces, true)->hasTrFunctions = true; |
1910 modifyNamespace(&namespaces)->hasTrFunctions = true; |
1887 yyTok = getToken(); |
1911 yyTok = getToken(); |
1888 break; |
1912 break; |
1889 case Tok_Ident: |
1913 case Tok_Ident: |
1890 prefix += yyWord; |
1914 prefix += yyWord; |
1891 prefix.detach(); |
1915 prefix.detach(); |
1894 prefix.clear(); |
1918 prefix.clear(); |
1895 if (yyTok == Tok_Ident && !yyParenDepth) |
1919 if (yyTok == Tok_Ident && !yyParenDepth) |
1896 prospectiveContext.clear(); |
1920 prospectiveContext.clear(); |
1897 } |
1921 } |
1898 break; |
1922 break; |
1899 case Tok_Comment: |
1923 case Tok_Comment: { |
1900 if (!tor) |
1924 if (!tor) |
1901 goto case_default; |
1925 goto case_default; |
1902 if (yyWord.startsWith(QLatin1Char(':'))) { |
1926 const QChar *ptr = yyWord.unicode(); |
1903 yyWord.remove(0, 1); |
1927 if (*ptr == QLatin1Char(':') && ptr[1].isSpace()) { |
|
1928 yyWord.remove(0, 2); |
1904 extracomment += yyWord; |
1929 extracomment += yyWord; |
1905 extracomment.detach(); |
1930 extracomment.detach(); |
1906 } else if (yyWord.startsWith(QLatin1Char('='))) { |
1931 } else if (*ptr == QLatin1Char('=') && ptr[1].isSpace()) { |
1907 yyWord.remove(0, 1); |
1932 yyWord.remove(0, 2); |
1908 msgid = yyWord.simplified(); |
1933 msgid = yyWord.simplified(); |
1909 msgid.detach(); |
1934 msgid.detach(); |
1910 } else if (yyWord.startsWith(QLatin1Char('~'))) { |
1935 } else if (*ptr == QLatin1Char('~') && ptr[1].isSpace()) { |
1911 yyWord.remove(0, 1); |
1936 yyWord.remove(0, 2); |
1912 text = yyWord.trimmed(); |
1937 text = yyWord.trimmed(); |
1913 int k = text.indexOf(QLatin1Char(' ')); |
1938 int k = text.indexOf(QLatin1Char(' ')); |
1914 if (k > -1) |
1939 if (k > -1) |
1915 extra.insert(text.left(k), text.mid(k + 1).trimmed()); |
1940 extra.insert(text.left(k), text.mid(k + 1).trimmed()); |
1916 text.clear(); |
1941 text.clear(); |
1917 } else if (yyWord.startsWith(QLatin1Char('%'))) { |
1942 } else if (*ptr == QLatin1Char('%') && ptr[1].isSpace()) { |
1918 sourcetext.reserve(sourcetext.length() + yyWord.length()); |
1943 sourcetext.reserve(sourcetext.length() + yyWord.length() - 2); |
1919 ushort *ptr = (ushort *)sourcetext.data() + sourcetext.length(); |
1944 ushort *ptr = (ushort *)sourcetext.data() + sourcetext.length(); |
1920 int p = 1, c; |
1945 int p = 2, c; |
1921 forever { |
1946 forever { |
1922 if (p >= yyWord.length()) |
1947 if (p >= yyWord.length()) |
1923 break; |
1948 break; |
1924 c = yyWord.unicode()[p++].unicode(); |
1949 c = yyWord.unicode()[p++].unicode(); |
1925 if (isspace(c)) |
1950 if (isspace(c)) |
2120 |
2146 |
2121 CppParser parser; |
2147 CppParser parser; |
2122 QTextStream ts(&file); |
2148 QTextStream ts(&file); |
2123 ts.setCodec(codec); |
2149 ts.setCodec(codec); |
2124 ts.setAutoDetectUnicode(true); |
2150 ts.setAutoDetectUnicode(true); |
2125 if (ts.codec()->name() == "UTF-16") |
2151 parser.setInput(ts, filename); |
|
2152 if (cd.m_outputCodec.isEmpty() && ts.codec()->name() == "UTF-16") |
2126 translator.setCodecName("System"); |
2153 translator.setCodecName("System"); |
2127 parser.setInput(ts, filename); |
|
2128 Translator *tor = new Translator; |
2154 Translator *tor = new Translator; |
2129 tor->setCodecName(translator.codecName()); |
2155 tor->setCodecName(translator.codecName()); |
2130 parser.setTranslator(tor); |
2156 parser.setTranslator(tor); |
2131 QSet<QString> inclusions; |
2157 QSet<QString> inclusions; |
2132 parser.parse(cd.m_defaultContext, cd, inclusions); |
2158 parser.parse(cd.m_defaultContext, cd, inclusions); |