author | Eckhart Koeppen <eckhart.koppen@nokia.com> |
Wed, 21 Apr 2010 20:15:53 +0300 | |
branch | RCL_3 |
changeset 13 | c0432d11811c |
parent 7 | 3f74d0d4af4c |
permissions | -rw-r--r-- |
0 | 1 |
/**************************************************************************** |
2 |
** |
|
4
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
3 |
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
0 | 4 |
** All rights reserved. |
5 |
** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 |
** |
|
7 |
** This file is part of the Qt Linguist of the Qt Toolkit. |
|
8 |
** |
|
9 |
** $QT_BEGIN_LICENSE:LGPL$ |
|
10 |
** No Commercial Usage |
|
11 |
** This file contains pre-release code and may not be distributed. |
|
12 |
** You may use this file in accordance with the terms and conditions |
|
13 |
** contained in the Technology Preview License Agreement accompanying |
|
14 |
** this package. |
|
15 |
** |
|
16 |
** GNU Lesser General Public License Usage |
|
17 |
** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 |
** General Public License version 2.1 as published by the Free Software |
|
19 |
** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 |
** packaging of this file. Please review the following information to |
|
21 |
** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 |
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 |
** |
|
24 |
** In addition, as a special exception, Nokia gives you certain additional |
|
25 |
** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 |
** |
|
28 |
** If you have questions regarding the use of this file, please contact |
|
29 |
** Nokia at qt-info@nokia.com. |
|
30 |
** |
|
31 |
** |
|
32 |
** |
|
33 |
** |
|
34 |
** |
|
35 |
** |
|
36 |
** |
|
37 |
** |
|
38 |
** $QT_END_LICENSE$ |
|
39 |
** |
|
40 |
****************************************************************************/ |
|
41 |
||
42 |
#include "lupdate.h" |
|
43 |
||
44 |
#include <translator.h> |
|
45 |
||
46 |
#include <QtCore/QBitArray> |
|
47 |
#include <QtCore/QDebug> |
|
48 |
#include <QtCore/QFileInfo> |
|
49 |
#include <QtCore/QStack> |
|
50 |
#include <QtCore/QString> |
|
51 |
#include <QtCore/QTextCodec> |
|
52 |
#include <QtCore/QTextStream> |
|
53 |
||
54 |
#include <ctype.h> // for isXXX() |
|
55 |
||
56 |
QT_BEGIN_NAMESPACE |
|
57 |
||
58 |
/* qmake ignore Q_OBJECT */ |
|
59 |
||
60 |
static QString MagicComment(QLatin1String("TRANSLATOR")); |
|
61 |
||
62 |
#define STRING(s) static QString str##s(QLatin1String(#s)) |
|
63 |
||
64 |
//#define DIAGNOSE_RETRANSLATABILITY // FIXME: should make a runtime option of this |
|
65 |
||
66 |
class HashString { |
|
67 |
public: |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
68 |
HashString() : m_hash(0x80000000) {} |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
69 |
explicit HashString(const QString &str) : m_str(str), m_hash(0x80000000) {} |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
70 |
void setValue(const QString &str) { m_str = str; m_hash = 0x80000000; } |
0 | 71 |
const QString &value() const { return m_str; } |
72 |
bool operator==(const HashString &other) const { return m_str == other.m_str; } |
|
73 |
private: |
|
74 |
QString m_str; |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
75 |
// qHash() of a QString is only 28 bits wide, so we can use |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
76 |
// the highest bit(s) as the "hash valid" flag. |
0 | 77 |
mutable uint m_hash; |
78 |
friend uint qHash(const HashString &str); |
|
79 |
}; |
|
80 |
||
81 |
uint qHash(const HashString &str) |
|
82 |
{ |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
83 |
if (str.m_hash & 0x80000000) |
0 | 84 |
str.m_hash = qHash(str.m_str); |
85 |
return str.m_hash; |
|
86 |
} |
|
87 |
||
88 |
class HashStringList { |
|
89 |
public: |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
90 |
explicit HashStringList(const QList<HashString> &list) : m_list(list), m_hash(0x80000000) {} |
0 | 91 |
const QList<HashString> &value() const { return m_list; } |
92 |
bool operator==(const HashStringList &other) const { return m_list == other.m_list; } |
|
93 |
private: |
|
94 |
QList<HashString> m_list; |
|
95 |
mutable uint m_hash; |
|
96 |
friend uint qHash(const HashStringList &list); |
|
97 |
}; |
|
98 |
||
99 |
uint qHash(const HashStringList &list) |
|
100 |
{ |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
101 |
if (list.m_hash & 0x80000000) { |
0 | 102 |
uint hash = 0; |
103 |
foreach (const HashString &qs, list.m_list) { |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
104 |
hash ^= qHash(qs) ^ 0x0ad9f526; |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
105 |
hash = ((hash << 13) & 0x0fffffff) | (hash >> 15); |
0 | 106 |
} |
107 |
list.m_hash = hash; |
|
108 |
} |
|
109 |
return list.m_hash; |
|
110 |
} |
|
111 |
||
112 |
typedef QList<HashString> NamespaceList; |
|
113 |
||
114 |
struct Namespace { |
|
115 |
||
116 |
Namespace() : |
|
117 |
classDef(this), |
|
118 |
hasTrFunctions(false), complained(false) |
|
119 |
{} |
|
120 |
~Namespace() |
|
121 |
{ |
|
122 |
qDeleteAll(children); |
|
123 |
} |
|
124 |
||
125 |
QHash<HashString, Namespace *> children; |
|
126 |
QHash<HashString, NamespaceList> aliases; |
|
127 |
QList<HashStringList> usings; |
|
128 |
||
129 |
// Class declarations set no flags and create no namespaces, so they are ignored. |
|
130 |
// Class definitions may appear multiple times - but only because we are trying to |
|
131 |
// "compile" all sources irrespective of build configuration. |
|
132 |
// Nested classes may be forward-declared inside a definition, and defined in another file. |
|
133 |
// The latter will detach the class' child list, so clones need a backlink to the original |
|
134 |
// definition (either one in case of multiple definitions). |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
135 |
// Namespaces can have tr() functions as well, so we need to track parent definitions for |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
136 |
// them as well. The complication is that we may have to deal with a forrest instead of |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
137 |
// a tree - in that case the parent will be arbitrary. However, it seem likely that |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
138 |
// Q_DECLARE_TR_FUNCTIONS would be used either in "class-like" namespaces with a central |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
139 |
// header or only locally in a file. |
0 | 140 |
Namespace *classDef; |
141 |
||
142 |
QString trQualification; |
|
143 |
||
144 |
bool hasTrFunctions; |
|
145 |
bool complained; // ... that tr functions are missing. |
|
146 |
}; |
|
147 |
||
148 |
static int nextFileId; |
|
149 |
||
150 |
class VisitRecorder { |
|
151 |
public: |
|
152 |
VisitRecorder() |
|
153 |
{ |
|
154 |
m_ba.resize(nextFileId); |
|
155 |
} |
|
156 |
bool tryVisit(int fileId) |
|
157 |
{ |
|
158 |
if (m_ba.at(fileId)) |
|
159 |
return false; |
|
160 |
m_ba[fileId] = true; |
|
161 |
return true; |
|
162 |
} |
|
163 |
private: |
|
164 |
QBitArray m_ba; |
|
165 |
}; |
|
166 |
||
167 |
struct ParseResults { |
|
168 |
int fileId; |
|
169 |
Namespace rootNamespace; |
|
170 |
QSet<const ParseResults *> includes; |
|
171 |
}; |
|
172 |
||
173 |
typedef QHash<QString, const ParseResults *> ParseResultHash; |
|
174 |
typedef QHash<QString, const Translator *> TranslatorHash; |
|
175 |
||
176 |
class CppFiles { |
|
177 |
||
178 |
public: |
|
179 |
static const ParseResults *getResults(const QString &cleanFile); |
|
180 |
static void setResults(const QString &cleanFile, const ParseResults *results); |
|
181 |
static const Translator *getTranslator(const QString &cleanFile); |
|
182 |
static void setTranslator(const QString &cleanFile, const Translator *results); |
|
183 |
static bool isBlacklisted(const QString &cleanFile); |
|
184 |
static void setBlacklisted(const QString &cleanFile); |
|
185 |
||
186 |
private: |
|
187 |
static ParseResultHash &parsedFiles(); |
|
188 |
static TranslatorHash &translatedFiles(); |
|
189 |
static QSet<QString> &blacklistedFiles(); |
|
190 |
}; |
|
191 |
||
192 |
class CppParser { |
|
193 |
||
194 |
public: |
|
195 |
CppParser(ParseResults *results = 0); |
|
196 |
void setInput(const QString &in); |
|
197 |
void setInput(QTextStream &ts, const QString &fileName); |
|
198 |
void setTranslator(Translator *_tor) { tor = _tor; } |
|
199 |
void parse(const QString &initialContext, ConversionData &cd, QSet<QString> &inclusions); |
|
200 |
void parseInternal(ConversionData &cd, QSet<QString> &inclusions); |
|
201 |
const ParseResults *recordResults(bool isHeader); |
|
202 |
void deleteResults() { delete results; } |
|
203 |
||
204 |
struct SavedState { |
|
205 |
NamespaceList namespaces; |
|
206 |
QStack<int> namespaceDepths; |
|
207 |
NamespaceList functionContext; |
|
208 |
QString functionContextUnresolved; |
|
209 |
QString pendingContext; |
|
210 |
}; |
|
211 |
||
212 |
private: |
|
213 |
struct IfdefState { |
|
214 |
IfdefState() {} |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
215 |
IfdefState(int _bracketDepth, int _braceDepth, int _parenDepth) : |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
216 |
bracketDepth(_bracketDepth), |
0 | 217 |
braceDepth(_braceDepth), |
218 |
parenDepth(_parenDepth), |
|
219 |
elseLine(-1) |
|
220 |
{} |
|
221 |
||
222 |
SavedState state; |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
223 |
int bracketDepth, bracketDepth1st; |
0 | 224 |
int braceDepth, braceDepth1st; |
225 |
int parenDepth, parenDepth1st; |
|
226 |
int elseLine; |
|
227 |
}; |
|
228 |
||
229 |
uint getChar(); |
|
230 |
uint getToken(); |
|
231 |
bool getMacroArgs(); |
|
232 |
bool match(uint t); |
|
233 |
bool matchString(QString *s); |
|
234 |
bool matchEncoding(bool *utf8); |
|
235 |
bool matchStringOrNull(QString *s); |
|
236 |
bool matchExpression(); |
|
237 |
||
238 |
QString transcode(const QString &str, bool utf8); |
|
239 |
void recordMessage( |
|
240 |
int line, const QString &context, const QString &text, const QString &comment, |
|
241 |
const QString &extracomment, const QString &msgid, const TranslatorMessage::ExtraData &extra, |
|
242 |
bool utf8, bool plural); |
|
243 |
||
244 |
void processInclude(const QString &file, ConversionData &cd, |
|
245 |
QSet<QString> &inclusions); |
|
246 |
||
247 |
void saveState(SavedState *state); |
|
248 |
void loadState(const SavedState *state); |
|
249 |
||
250 |
static QString stringifyNamespace(const NamespaceList &namespaces); |
|
251 |
static QStringList stringListifyNamespace(const NamespaceList &namespaces); |
|
252 |
typedef bool (CppParser::*VisitNamespaceCallback)(const Namespace *ns, void *context) const; |
|
253 |
bool visitNamespace(const NamespaceList &namespaces, int nsCount, |
|
254 |
VisitNamespaceCallback callback, void *context, |
|
255 |
VisitRecorder &vr, const ParseResults *rslt) const; |
|
256 |
bool visitNamespace(const NamespaceList &namespaces, int nsCount, |
|
257 |
VisitNamespaceCallback callback, void *context) const; |
|
258 |
static QStringList stringListifySegments(const QList<HashString> &namespaces); |
|
259 |
bool qualifyOneCallbackOwn(const Namespace *ns, void *context) const; |
|
260 |
bool qualifyOneCallbackUsing(const Namespace *ns, void *context) const; |
|
261 |
bool qualifyOne(const NamespaceList &namespaces, int nsCnt, const HashString &segment, |
|
7
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
262 |
NamespaceList *resolved, QSet<HashStringList> *visitedUsings) const; |
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
263 |
bool qualifyOne(const NamespaceList &namespaces, int nsCnt, const HashString &segment, |
0 | 264 |
NamespaceList *resolved) const; |
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
265 |
bool fullyQualify(const NamespaceList &namespaces, int nsCnt, |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
266 |
const QList<HashString> &segments, bool isDeclaration, |
0 | 267 |
NamespaceList *resolved, QStringList *unresolved) const; |
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
268 |
bool fullyQualify(const NamespaceList &namespaces, |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
269 |
const QList<HashString> &segments, bool isDeclaration, |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
270 |
NamespaceList *resolved, QStringList *unresolved) const; |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
271 |
bool fullyQualify(const NamespaceList &namespaces, |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
272 |
const QString &segments, bool isDeclaration, |
0 | 273 |
NamespaceList *resolved, QStringList *unresolved) const; |
274 |
bool findNamespaceCallback(const Namespace *ns, void *context) const; |
|
275 |
const Namespace *findNamespace(const NamespaceList &namespaces, int nsCount = -1) const; |
|
276 |
void enterNamespace(NamespaceList *namespaces, const HashString &name); |
|
277 |
void truncateNamespaces(NamespaceList *namespaces, int lenght); |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
278 |
Namespace *modifyNamespace(NamespaceList *namespaces, bool haveLast = true); |
0 | 279 |
|
280 |
enum { |
|
281 |
Tok_Eof, Tok_class, Tok_friend, Tok_namespace, Tok_using, Tok_return, |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
282 |
Tok_tr, Tok_trUtf8, Tok_translate, Tok_translateUtf8, Tok_trid, |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
283 |
Tok_Q_OBJECT, Tok_Q_DECLARE_TR_FUNCTIONS, |
0 | 284 |
Tok_Ident, Tok_Comment, Tok_String, Tok_Arrow, Tok_Colon, Tok_ColonColon, |
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
285 |
Tok_Equals, Tok_LeftBracket, Tok_RightBracket, |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
286 |
Tok_LeftBrace, Tok_RightBrace, Tok_LeftParen, Tok_RightParen, Tok_Comma, Tok_Semicolon, |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
287 |
Tok_Null, Tok_Integer, |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
288 |
Tok_QuotedInclude, Tok_AngledInclude, |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
289 |
Tok_Other |
0 | 290 |
}; |
291 |
||
292 |
// Tokenizer state |
|
293 |
QString yyFileName; |
|
294 |
int yyCh; |
|
295 |
bool yyAtNewline; |
|
296 |
bool yyCodecIsUtf8; |
|
297 |
bool yyForceUtf8; |
|
298 |
QString yyWord; |
|
299 |
qlonglong yyInteger; |
|
300 |
QStack<IfdefState> yyIfdefStack; |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
301 |
int yyBracketDepth; |
0 | 302 |
int yyBraceDepth; |
303 |
int yyParenDepth; |
|
304 |
int yyLineNo; |
|
305 |
int yyCurLineNo; |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
306 |
int yyBracketLineNo; |
0 | 307 |
int yyBraceLineNo; |
308 |
int yyParenLineNo; |
|
309 |
||
310 |
// the string to read from and current position in the string |
|
311 |
QTextCodec *yySourceCodec; |
|
312 |
QString yyInStr; |
|
313 |
const ushort *yyInPtr; |
|
314 |
||
315 |
// Parser state |
|
316 |
uint yyTok; |
|
317 |
||
318 |
NamespaceList namespaces; |
|
319 |
QStack<int> namespaceDepths; |
|
320 |
NamespaceList functionContext; |
|
321 |
QString functionContextUnresolved; |
|
322 |
QString prospectiveContext; |
|
323 |
QString pendingContext; |
|
324 |
ParseResults *results; |
|
325 |
Translator *tor; |
|
326 |
bool directInclude; |
|
327 |
||
328 |
SavedState savedState; |
|
329 |
int yyMinBraceDepth; |
|
330 |
bool inDefine; |
|
331 |
}; |
|
332 |
||
333 |
CppParser::CppParser(ParseResults *_results) |
|
334 |
{ |
|
335 |
tor = 0; |
|
336 |
if (_results) { |
|
337 |
results = _results; |
|
338 |
directInclude = true; |
|
339 |
} else { |
|
340 |
results = new ParseResults; |
|
341 |
directInclude = false; |
|
342 |
} |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
343 |
yyBracketDepth = 0; |
0 | 344 |
yyBraceDepth = 0; |
345 |
yyParenDepth = 0; |
|
346 |
yyCurLineNo = 1; |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
347 |
yyBracketLineNo = 1; |
0 | 348 |
yyBraceLineNo = 1; |
349 |
yyParenLineNo = 1; |
|
350 |
yyAtNewline = true; |
|
351 |
yyMinBraceDepth = 0; |
|
352 |
inDefine = false; |
|
353 |
} |
|
354 |
||
355 |
void CppParser::setInput(const QString &in) |
|
356 |
{ |
|
357 |
yyInStr = in; |
|
358 |
yyFileName = QString(); |
|
359 |
yySourceCodec = 0; |
|
360 |
yyForceUtf8 = true; |
|
361 |
} |
|
362 |
||
363 |
void CppParser::setInput(QTextStream &ts, const QString &fileName) |
|
364 |
{ |
|
365 |
yyInStr = ts.readAll(); |
|
366 |
yyFileName = fileName; |
|
367 |
yySourceCodec = ts.codec(); |
|
368 |
yyForceUtf8 = false; |
|
369 |
} |
|
370 |
||
371 |
/* |
|
372 |
The first part of this source file is the C++ tokenizer. We skip |
|
373 |
most of C++; the only tokens that interest us are defined here. |
|
374 |
Thus, the code fragment |
|
375 |
||
376 |
int main() |
|
377 |
{ |
|
378 |
printf("Hello, world!\n"); |
|
379 |
return 0; |
|
380 |
} |
|
381 |
||
382 |
is broken down into the following tokens (Tok_ omitted): |
|
383 |
||
384 |
Ident Ident LeftParen RightParen |
|
385 |
LeftBrace |
|
386 |
Ident LeftParen String RightParen Semicolon |
|
387 |
return Semicolon |
|
388 |
RightBrace. |
|
389 |
||
390 |
The 0 doesn't produce any token. |
|
391 |
*/ |
|
392 |
||
393 |
uint CppParser::getChar() |
|
394 |
{ |
|
395 |
const ushort *uc = yyInPtr; |
|
396 |
forever { |
|
397 |
ushort c = *uc; |
|
398 |
if (!c) { |
|
399 |
yyInPtr = uc; |
|
400 |
return EOF; |
|
401 |
} |
|
402 |
++uc; |
|
403 |
if (c == '\\') { |
|
404 |
ushort cc = *uc; |
|
405 |
if (cc == '\n') { |
|
406 |
++yyCurLineNo; |
|
407 |
++uc; |
|
408 |
continue; |
|
409 |
} |
|
410 |
if (cc == '\r') { |
|
411 |
++yyCurLineNo; |
|
412 |
++uc; |
|
413 |
if (*uc == '\n') |
|
414 |
++uc; |
|
415 |
continue; |
|
416 |
} |
|
417 |
} |
|
418 |
if (c == '\r') { |
|
419 |
if (*uc == '\n') |
|
420 |
++uc; |
|
421 |
c = '\n'; |
|
422 |
++yyCurLineNo; |
|
423 |
yyAtNewline = true; |
|
424 |
} else if (c == '\n') { |
|
425 |
++yyCurLineNo; |
|
426 |
yyAtNewline = true; |
|
427 |
} else if (c != ' ' && c != '\t' && c != '#') { |
|
428 |
yyAtNewline = false; |
|
429 |
} |
|
430 |
yyInPtr = uc; |
|
431 |
return c; |
|
432 |
} |
|
433 |
} |
|
434 |
||
435 |
// This ignores commas, parens and comments. |
|
436 |
// IOW, it understands only a single, simple argument. |
|
437 |
bool CppParser::getMacroArgs() |
|
438 |
{ |
|
439 |
// Failing this assertion would mean losing the preallocated buffer. |
|
440 |
Q_ASSERT(yyWord.isDetached()); |
|
441 |
yyWord.resize(0); |
|
442 |
||
443 |
while (isspace(yyCh)) |
|
444 |
yyCh = getChar(); |
|
445 |
if (yyCh != '(') |
|
446 |
return false; |
|
447 |
do { |
|
448 |
yyCh = getChar(); |
|
449 |
} while (isspace(yyCh)); |
|
450 |
ushort *ptr = (ushort *)yyWord.unicode(); |
|
451 |
while (yyCh != ')') { |
|
452 |
if (yyCh == EOF) |
|
453 |
return false; |
|
454 |
*ptr++ = yyCh; |
|
455 |
yyCh = getChar(); |
|
456 |
} |
|
457 |
yyCh = getChar(); |
|
458 |
for (; ptr != (ushort *)yyWord.unicode() && isspace(*(ptr - 1)); --ptr) ; |
|
459 |
yyWord.resize(ptr - (ushort *)yyWord.unicode()); |
|
460 |
return true; |
|
461 |
} |
|
462 |
||
463 |
STRING(Q_OBJECT); |
|
464 |
STRING(Q_DECLARE_TR_FUNCTIONS); |
|
465 |
STRING(QT_TR_NOOP); |
|
466 |
STRING(QT_TRID_NOOP); |
|
467 |
STRING(QT_TRANSLATE_NOOP); |
|
468 |
STRING(QT_TRANSLATE_NOOP3); |
|
469 |
STRING(QT_TR_NOOP_UTF8); |
|
470 |
STRING(QT_TRANSLATE_NOOP_UTF8); |
|
471 |
STRING(QT_TRANSLATE_NOOP3_UTF8); |
|
472 |
STRING(class); |
|
473 |
// QTranslator::findMessage() has the same parameters as QApplication::translate() |
|
474 |
STRING(findMessage); |
|
475 |
STRING(friend); |
|
476 |
STRING(namespace); |
|
477 |
STRING(qtTrId); |
|
478 |
STRING(return); |
|
479 |
STRING(struct); |
|
480 |
STRING(TR); |
|
481 |
STRING(Tr); |
|
482 |
STRING(tr); |
|
483 |
STRING(trUtf8); |
|
484 |
STRING(translate); |
|
485 |
STRING(using); |
|
486 |
||
487 |
uint CppParser::getToken() |
|
488 |
{ |
|
489 |
restart: |
|
490 |
// Failing this assertion would mean losing the preallocated buffer. |
|
491 |
Q_ASSERT(yyWord.isDetached()); |
|
492 |
yyWord.resize(0); |
|
493 |
||
494 |
while (yyCh != EOF) { |
|
495 |
yyLineNo = yyCurLineNo; |
|
496 |
||
497 |
if (yyCh == '#' && yyAtNewline) { |
|
498 |
/* |
|
499 |
Early versions of lupdate complained about |
|
500 |
unbalanced braces in the following code: |
|
501 |
||
502 |
#ifdef ALPHA |
|
503 |
while (beta) { |
|
504 |
#else |
|
505 |
while (gamma) { |
|
506 |
#endif |
|
507 |
delta; |
|
508 |
} |
|
509 |
||
510 |
The code contains, indeed, two opening braces for |
|
511 |
one closing brace; yet there's no reason to panic. |
|
512 |
||
513 |
The solution is to remember yyBraceDepth as it was |
|
514 |
when #if, #ifdef or #ifndef was met, and to set |
|
515 |
yyBraceDepth to that value when meeting #elif or |
|
516 |
#else. |
|
517 |
*/ |
|
518 |
do { |
|
519 |
yyCh = getChar(); |
|
520 |
} while (isspace(yyCh) && yyCh != '\n'); |
|
521 |
||
522 |
switch (yyCh) { |
|
523 |
case 'd': // define |
|
524 |
// Skip over the name of the define to avoid it being interpreted as c++ code |
|
525 |
do { // Rest of "define" |
|
526 |
yyCh = getChar(); |
|
527 |
if (yyCh == EOF) |
|
528 |
return Tok_Eof; |
|
529 |
if (yyCh == '\n') |
|
530 |
goto restart; |
|
531 |
} while (!isspace(yyCh)); |
|
532 |
do { // Space beween "define" and macro name |
|
533 |
yyCh = getChar(); |
|
534 |
if (yyCh == EOF) |
|
535 |
return Tok_Eof; |
|
536 |
if (yyCh == '\n') |
|
537 |
goto restart; |
|
538 |
} while (isspace(yyCh)); |
|
539 |
do { // Macro name |
|
540 |
if (yyCh == '(') { |
|
541 |
// Argument list. Follows the name without a space, and no |
|
542 |
// paren nesting is possible. |
|
543 |
do { |
|
544 |
yyCh = getChar(); |
|
545 |
if (yyCh == EOF) |
|
546 |
return Tok_Eof; |
|
547 |
if (yyCh == '\n') |
|
548 |
goto restart; |
|
549 |
} while (yyCh != ')'); |
|
550 |
break; |
|
551 |
} |
|
552 |
yyCh = getChar(); |
|
553 |
if (yyCh == EOF) |
|
554 |
return Tok_Eof; |
|
555 |
if (yyCh == '\n') |
|
556 |
goto restart; |
|
557 |
} while (!isspace(yyCh)); |
|
558 |
do { // Shortcut the immediate newline case if no comments follow. |
|
559 |
yyCh = getChar(); |
|
560 |
if (yyCh == EOF) |
|
561 |
return Tok_Eof; |
|
562 |
if (yyCh == '\n') |
|
563 |
goto restart; |
|
564 |
} while (isspace(yyCh)); |
|
565 |
||
566 |
saveState(&savedState); |
|
567 |
yyMinBraceDepth = yyBraceDepth; |
|
568 |
inDefine = true; |
|
569 |
goto restart; |
|
570 |
case 'i': |
|
571 |
yyCh = getChar(); |
|
572 |
if (yyCh == 'f') { |
|
573 |
// if, ifdef, ifndef |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
574 |
yyIfdefStack.push(IfdefState(yyBracketDepth, yyBraceDepth, yyParenDepth)); |
0 | 575 |
yyCh = getChar(); |
576 |
} else if (yyCh == 'n') { |
|
577 |
// include |
|
578 |
do { |
|
579 |
yyCh = getChar(); |
|
580 |
} while (yyCh != EOF && !isspace(yyCh)); |
|
581 |
do { |
|
582 |
yyCh = getChar(); |
|
583 |
} while (isspace(yyCh)); |
|
584 |
int tChar; |
|
585 |
if (yyCh == '"') |
|
586 |
tChar = '"'; |
|
587 |
else if (yyCh == '<') |
|
588 |
tChar = '>'; |
|
589 |
else |
|
590 |
break; |
|
591 |
ushort *ptr = (ushort *)yyWord.unicode(); |
|
592 |
forever { |
|
593 |
yyCh = getChar(); |
|
594 |
if (yyCh == EOF || yyCh == '\n') |
|
595 |
break; |
|
596 |
if (yyCh == tChar) { |
|
597 |
yyCh = getChar(); |
|
598 |
break; |
|
599 |
} |
|
600 |
*ptr++ = yyCh; |
|
601 |
} |
|
602 |
yyWord.resize(ptr - (ushort *)yyWord.unicode()); |
|
603 |
return (tChar == '"') ? Tok_QuotedInclude : Tok_AngledInclude; |
|
604 |
} |
|
605 |
break; |
|
606 |
case 'e': |
|
607 |
yyCh = getChar(); |
|
608 |
if (yyCh == 'l') { |
|
609 |
// elif, else |
|
610 |
if (!yyIfdefStack.isEmpty()) { |
|
611 |
IfdefState &is = yyIfdefStack.top(); |
|
612 |
if (is.elseLine != -1) { |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
613 |
if (yyBracketDepth != is.bracketDepth1st |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
614 |
|| yyBraceDepth != is.braceDepth1st |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
615 |
|| yyParenDepth != is.parenDepth1st) |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
616 |
qWarning("%s:%d: Parenthesis/bracket/brace mismatch between " |
0 | 617 |
"#if and #else branches; using #if branch\n", |
618 |
qPrintable(yyFileName), is.elseLine); |
|
619 |
} else { |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
620 |
is.bracketDepth1st = yyBracketDepth; |
0 | 621 |
is.braceDepth1st = yyBraceDepth; |
622 |
is.parenDepth1st = yyParenDepth; |
|
623 |
saveState(&is.state); |
|
624 |
} |
|
625 |
is.elseLine = yyLineNo; |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
626 |
yyBracketDepth = is.bracketDepth; |
0 | 627 |
yyBraceDepth = is.braceDepth; |
628 |
yyParenDepth = is.parenDepth; |
|
629 |
} |
|
630 |
yyCh = getChar(); |
|
631 |
} else if (yyCh == 'n') { |
|
632 |
// endif |
|
633 |
if (!yyIfdefStack.isEmpty()) { |
|
634 |
IfdefState is = yyIfdefStack.pop(); |
|
635 |
if (is.elseLine != -1) { |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
636 |
if (yyBracketDepth != is.bracketDepth1st |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
637 |
|| yyBraceDepth != is.braceDepth1st |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
638 |
|| yyParenDepth != is.parenDepth1st) |
0 | 639 |
qWarning("%s:%d: Parenthesis/brace mismatch between " |
640 |
"#if and #else branches; using #if branch\n", |
|
641 |
qPrintable(yyFileName), is.elseLine); |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
642 |
yyBracketDepth = is.bracketDepth1st; |
0 | 643 |
yyBraceDepth = is.braceDepth1st; |
644 |
yyParenDepth = is.parenDepth1st; |
|
645 |
loadState(&is.state); |
|
646 |
} |
|
647 |
} |
|
648 |
yyCh = getChar(); |
|
649 |
} |
|
650 |
break; |
|
651 |
} |
|
652 |
// Optimization: skip over rest of preprocessor directive |
|
653 |
do { |
|
654 |
if (yyCh == '/') { |
|
655 |
yyCh = getChar(); |
|
656 |
if (yyCh == '/') { |
|
657 |
do { |
|
658 |
yyCh = getChar(); |
|
659 |
} while (yyCh != EOF && yyCh != '\n'); |
|
660 |
break; |
|
661 |
} else if (yyCh == '*') { |
|
662 |
bool metAster = false; |
|
663 |
||
664 |
forever { |
|
665 |
yyCh = getChar(); |
|
666 |
if (yyCh == EOF) { |
|
667 |
qWarning("%s:%d: Unterminated C++ comment\n", |
|
668 |
qPrintable(yyFileName), yyLineNo); |
|
669 |
break; |
|
670 |
} |
|
671 |
||
672 |
if (yyCh == '*') { |
|
673 |
metAster = true; |
|
674 |
} else if (metAster && yyCh == '/') { |
|
675 |
yyCh = getChar(); |
|
676 |
break; |
|
677 |
} else { |
|
678 |
metAster = false; |
|
679 |
} |
|
680 |
} |
|
681 |
} |
|
682 |
} else { |
|
683 |
yyCh = getChar(); |
|
684 |
} |
|
685 |
} while (yyCh != '\n' && yyCh != EOF); |
|
686 |
yyCh = getChar(); |
|
687 |
} else if ((yyCh >= 'A' && yyCh <= 'Z') || (yyCh >= 'a' && yyCh <= 'z') || yyCh == '_') { |
|
688 |
ushort *ptr = (ushort *)yyWord.unicode(); |
|
689 |
do { |
|
690 |
*ptr++ = yyCh; |
|
691 |
yyCh = getChar(); |
|
692 |
} while ((yyCh >= 'A' && yyCh <= 'Z') || (yyCh >= 'a' && yyCh <= 'z') |
|
693 |
|| (yyCh >= '0' && yyCh <= '9') || yyCh == '_'); |
|
694 |
yyWord.resize(ptr - (ushort *)yyWord.unicode()); |
|
695 |
||
696 |
//qDebug() << "IDENT: " << yyWord; |
|
697 |
||
698 |
switch (yyWord.unicode()[0].unicode()) { |
|
699 |
case 'Q': |
|
700 |
if (yyWord == strQ_OBJECT) |
|
701 |
return Tok_Q_OBJECT; |
|
702 |
if (yyWord == strQ_DECLARE_TR_FUNCTIONS) |
|
703 |
return Tok_Q_DECLARE_TR_FUNCTIONS; |
|
704 |
if (yyWord == strQT_TR_NOOP) |
|
705 |
return Tok_tr; |
|
706 |
if (yyWord == strQT_TRID_NOOP) |
|
707 |
return Tok_trid; |
|
708 |
if (yyWord == strQT_TRANSLATE_NOOP) |
|
709 |
return Tok_translate; |
|
710 |
if (yyWord == strQT_TRANSLATE_NOOP3) |
|
711 |
return Tok_translate; |
|
712 |
if (yyWord == strQT_TR_NOOP_UTF8) |
|
713 |
return Tok_trUtf8; |
|
714 |
if (yyWord == strQT_TRANSLATE_NOOP_UTF8) |
|
715 |
return Tok_translateUtf8; |
|
716 |
if (yyWord == strQT_TRANSLATE_NOOP3_UTF8) |
|
717 |
return Tok_translateUtf8; |
|
718 |
break; |
|
719 |
case 'T': |
|
720 |
// TR() for when all else fails |
|
721 |
if (yyWord == strTR || yyWord == strTr) |
|
722 |
return Tok_tr; |
|
723 |
break; |
|
724 |
case 'c': |
|
725 |
if (yyWord == strclass) |
|
726 |
return Tok_class; |
|
727 |
break; |
|
728 |
case 'f': |
|
729 |
/* |
|
730 |
QTranslator::findMessage() has the same parameters as |
|
731 |
QApplication::translate(). |
|
732 |
*/ |
|
733 |
if (yyWord == strfindMessage) |
|
734 |
return Tok_translate; |
|
735 |
if (yyWord == strfriend) |
|
736 |
return Tok_friend; |
|
737 |
break; |
|
738 |
case 'n': |
|
739 |
if (yyWord == strnamespace) |
|
740 |
return Tok_namespace; |
|
741 |
break; |
|
742 |
case 'q': |
|
743 |
if (yyWord == strqtTrId) |
|
744 |
return Tok_trid; |
|
745 |
break; |
|
746 |
case 'r': |
|
747 |
if (yyWord == strreturn) |
|
748 |
return Tok_return; |
|
749 |
break; |
|
750 |
case 's': |
|
751 |
if (yyWord == strstruct) |
|
752 |
return Tok_class; |
|
753 |
break; |
|
754 |
case 't': |
|
755 |
if (yyWord == strtr) |
|
756 |
return Tok_tr; |
|
757 |
if (yyWord == strtrUtf8) |
|
758 |
return Tok_trUtf8; |
|
759 |
if (yyWord == strtranslate) |
|
760 |
return Tok_translate; |
|
761 |
break; |
|
762 |
case 'u': |
|
763 |
if (yyWord == strusing) |
|
764 |
return Tok_using; |
|
765 |
break; |
|
766 |
} |
|
767 |
return Tok_Ident; |
|
768 |
} else { |
|
769 |
switch (yyCh) { |
|
770 |
case '\n': |
|
771 |
if (inDefine) { |
|
772 |
loadState(&savedState); |
|
773 |
prospectiveContext.clear(); |
|
774 |
yyBraceDepth = yyMinBraceDepth; |
|
775 |
yyMinBraceDepth = 0; |
|
776 |
inDefine = false; |
|
777 |
} |
|
778 |
yyCh = getChar(); |
|
779 |
break; |
|
780 |
case '/': |
|
781 |
yyCh = getChar(); |
|
782 |
if (yyCh == '/') { |
|
783 |
ushort *ptr = (ushort *)yyWord.unicode() + yyWord.length(); |
|
784 |
do { |
|
785 |
yyCh = getChar(); |
|
786 |
if (yyCh == EOF) |
|
787 |
break; |
|
788 |
*ptr++ = yyCh; |
|
789 |
} while (yyCh != '\n'); |
|
790 |
yyWord.resize(ptr - (ushort *)yyWord.unicode()); |
|
791 |
} else if (yyCh == '*') { |
|
792 |
bool metAster = false; |
|
793 |
ushort *ptr = (ushort *)yyWord.unicode() + yyWord.length(); |
|
794 |
||
795 |
forever { |
|
796 |
yyCh = getChar(); |
|
797 |
if (yyCh == EOF) { |
|
798 |
qWarning("%s:%d: Unterminated C++ comment\n", |
|
799 |
qPrintable(yyFileName), yyLineNo); |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
800 |
break; |
0 | 801 |
} |
802 |
*ptr++ = yyCh; |
|
803 |
||
804 |
if (yyCh == '*') |
|
805 |
metAster = true; |
|
806 |
else if (metAster && yyCh == '/') |
|
807 |
break; |
|
808 |
else |
|
809 |
metAster = false; |
|
810 |
} |
|
811 |
yyWord.resize(ptr - (ushort *)yyWord.unicode() - 2); |
|
812 |
||
813 |
yyCh = getChar(); |
|
814 |
} |
|
815 |
return Tok_Comment; |
|
816 |
case '"': { |
|
817 |
ushort *ptr = (ushort *)yyWord.unicode() + yyWord.length(); |
|
818 |
yyCh = getChar(); |
|
819 |
while (yyCh != EOF && yyCh != '\n' && yyCh != '"') { |
|
820 |
if (yyCh == '\\') { |
|
821 |
yyCh = getChar(); |
|
822 |
if (yyCh == EOF || yyCh == '\n') |
|
823 |
break; |
|
824 |
*ptr++ = '\\'; |
|
825 |
} |
|
826 |
*ptr++ = yyCh; |
|
827 |
yyCh = getChar(); |
|
828 |
} |
|
829 |
yyWord.resize(ptr - (ushort *)yyWord.unicode()); |
|
830 |
||
831 |
if (yyCh != '"') |
|
832 |
qWarning("%s:%d: Unterminated C++ string\n", |
|
833 |
qPrintable(yyFileName), yyLineNo); |
|
834 |
else |
|
835 |
yyCh = getChar(); |
|
836 |
return Tok_String; |
|
837 |
} |
|
838 |
case '-': |
|
839 |
yyCh = getChar(); |
|
840 |
if (yyCh == '>') { |
|
841 |
yyCh = getChar(); |
|
842 |
return Tok_Arrow; |
|
843 |
} |
|
844 |
break; |
|
845 |
case ':': |
|
846 |
yyCh = getChar(); |
|
847 |
if (yyCh == ':') { |
|
848 |
yyCh = getChar(); |
|
849 |
return Tok_ColonColon; |
|
850 |
} |
|
851 |
return Tok_Colon; |
|
852 |
// Incomplete: '<' might be part of '<=' or of template syntax. |
|
853 |
// The main intent of not completely ignoring it is to break |
|
854 |
// parsing of things like std::cout << QObject::tr() as |
|
855 |
// context std::cout::QObject (see Task 161106) |
|
856 |
case '=': |
|
857 |
yyCh = getChar(); |
|
858 |
return Tok_Equals; |
|
859 |
case '>': |
|
860 |
case '<': |
|
861 |
yyCh = getChar(); |
|
862 |
return Tok_Other; |
|
863 |
case '\'': |
|
864 |
yyCh = getChar(); |
|
865 |
if (yyCh == '\\') |
|
866 |
yyCh = getChar(); |
|
867 |
||
868 |
forever { |
|
869 |
if (yyCh == EOF || yyCh == '\n') { |
|
870 |
qWarning("%s:%d: Unterminated C++ character\n", |
|
871 |
qPrintable(yyFileName), yyLineNo); |
|
872 |
break; |
|
873 |
} |
|
874 |
yyCh = getChar(); |
|
875 |
if (yyCh == '\'') { |
|
876 |
yyCh = getChar(); |
|
877 |
break; |
|
878 |
} |
|
879 |
} |
|
880 |
break; |
|
881 |
case '{': |
|
882 |
if (yyBraceDepth == 0) |
|
883 |
yyBraceLineNo = yyCurLineNo; |
|
884 |
yyBraceDepth++; |
|
885 |
yyCh = getChar(); |
|
886 |
return Tok_LeftBrace; |
|
887 |
case '}': |
|
888 |
if (yyBraceDepth == yyMinBraceDepth) { |
|
889 |
if (!inDefine) |
|
890 |
qWarning("%s:%d: Excess closing brace in C++ code" |
|
891 |
" (or abuse of the C++ preprocessor)\n", |
|
892 |
qPrintable(yyFileName), yyCurLineNo); |
|
893 |
// Avoid things getting messed up even more |
|
894 |
yyCh = getChar(); |
|
895 |
return Tok_Semicolon; |
|
896 |
} |
|
897 |
yyBraceDepth--; |
|
898 |
yyCh = getChar(); |
|
899 |
return Tok_RightBrace; |
|
900 |
case '(': |
|
901 |
if (yyParenDepth == 0) |
|
902 |
yyParenLineNo = yyCurLineNo; |
|
903 |
yyParenDepth++; |
|
904 |
yyCh = getChar(); |
|
905 |
return Tok_LeftParen; |
|
906 |
case ')': |
|
907 |
if (yyParenDepth == 0) |
|
908 |
qWarning("%s:%d: Excess closing parenthesis in C++ code" |
|
909 |
" (or abuse of the C++ preprocessor)\n", |
|
910 |
qPrintable(yyFileName), yyCurLineNo); |
|
911 |
else |
|
912 |
yyParenDepth--; |
|
913 |
yyCh = getChar(); |
|
914 |
return Tok_RightParen; |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
915 |
case '[': |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
916 |
if (yyBracketDepth == 0) |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
917 |
yyBracketLineNo = yyCurLineNo; |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
918 |
yyBracketDepth++; |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
919 |
yyCh = getChar(); |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
920 |
return Tok_LeftBracket; |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
921 |
case ']': |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
922 |
if (yyBracketDepth == 0) |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
923 |
qWarning("%s:%d: Excess closing bracket in C++ code" |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
924 |
" (or abuse of the C++ preprocessor)\n", |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
925 |
qPrintable(yyFileName), yyCurLineNo); |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
926 |
else |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
927 |
yyBracketDepth--; |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
928 |
yyCh = getChar(); |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
929 |
return Tok_RightBracket; |
0 | 930 |
case ',': |
931 |
yyCh = getChar(); |
|
932 |
return Tok_Comma; |
|
933 |
case ';': |
|
934 |
yyCh = getChar(); |
|
935 |
return Tok_Semicolon; |
|
936 |
case '0': |
|
937 |
yyCh = getChar(); |
|
938 |
if (yyCh == 'x') { |
|
939 |
do { |
|
940 |
yyCh = getChar(); |
|
941 |
} while ((yyCh >= '0' && yyCh <= '9') |
|
942 |
|| (yyCh >= 'a' && yyCh <= 'f') || (yyCh >= 'A' && yyCh <= 'F')); |
|
943 |
return Tok_Integer; |
|
944 |
} |
|
945 |
if (yyCh < '0' || yyCh > '9') |
|
946 |
return Tok_Null; |
|
947 |
// Fallthrough |
|
948 |
case '1': |
|
949 |
case '2': |
|
950 |
case '3': |
|
951 |
case '4': |
|
952 |
case '5': |
|
953 |
case '6': |
|
954 |
case '7': |
|
955 |
case '8': |
|
956 |
case '9': |
|
957 |
do { |
|
958 |
yyCh = getChar(); |
|
959 |
} while (yyCh >= '0' && yyCh <= '9'); |
|
960 |
return Tok_Integer; |
|
961 |
default: |
|
962 |
yyCh = getChar(); |
|
963 |
break; |
|
964 |
} |
|
965 |
} |
|
966 |
} |
|
967 |
return Tok_Eof; |
|
968 |
} |
|
969 |
||
970 |
/* |
|
971 |
The second part of this source file are namespace/class related |
|
972 |
utilities for the third part. |
|
973 |
*/ |
|
974 |
||
975 |
void CppParser::saveState(SavedState *state) |
|
976 |
{ |
|
977 |
state->namespaces = namespaces; |
|
978 |
state->namespaceDepths = namespaceDepths; |
|
979 |
state->functionContext = functionContext; |
|
980 |
state->functionContextUnresolved = functionContextUnresolved; |
|
981 |
state->pendingContext = pendingContext; |
|
982 |
} |
|
983 |
||
984 |
void CppParser::loadState(const SavedState *state) |
|
985 |
{ |
|
986 |
namespaces = state->namespaces; |
|
987 |
namespaceDepths = state->namespaceDepths; |
|
988 |
functionContext = state->functionContext; |
|
989 |
functionContextUnresolved = state->functionContextUnresolved; |
|
990 |
pendingContext = state->pendingContext; |
|
991 |
} |
|
992 |
||
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
993 |
Namespace *CppParser::modifyNamespace(NamespaceList *namespaces, bool haveLast) |
0 | 994 |
{ |
995 |
Namespace *pns, *ns = &results->rootNamespace; |
|
996 |
for (int i = 1; i < namespaces->count(); ++i) { |
|
997 |
pns = ns; |
|
998 |
if (!(ns = pns->children.value(namespaces->at(i)))) { |
|
999 |
do { |
|
1000 |
ns = new Namespace; |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1001 |
if (haveLast || i < namespaces->count() - 1) |
0 | 1002 |
if (const Namespace *ons = findNamespace(*namespaces, i + 1)) |
1003 |
ns->classDef = ons->classDef; |
|
1004 |
pns->children.insert(namespaces->at(i), ns); |
|
1005 |
pns = ns; |
|
1006 |
} while (++i < namespaces->count()); |
|
1007 |
break; |
|
1008 |
} |
|
1009 |
} |
|
1010 |
return ns; |
|
1011 |
} |
|
1012 |
||
1013 |
QString CppParser::stringifyNamespace(const NamespaceList &namespaces) |
|
1014 |
{ |
|
1015 |
QString ret; |
|
1016 |
for (int i = 1; i < namespaces.count(); ++i) { |
|
1017 |
if (i > 1) |
|
1018 |
ret += QLatin1String("::"); |
|
1019 |
ret += namespaces.at(i).value(); |
|
1020 |
} |
|
1021 |
return ret; |
|
1022 |
} |
|
1023 |
||
1024 |
QStringList CppParser::stringListifyNamespace(const NamespaceList &namespaces) |
|
1025 |
{ |
|
1026 |
QStringList ret; |
|
1027 |
for (int i = 1; i < namespaces.count(); ++i) |
|
1028 |
ret << namespaces.at(i).value(); |
|
1029 |
return ret; |
|
1030 |
} |
|
1031 |
||
1032 |
bool CppParser::visitNamespace(const NamespaceList &namespaces, int nsCount, |
|
1033 |
VisitNamespaceCallback callback, void *context, |
|
1034 |
VisitRecorder &vr, const ParseResults *rslt) const |
|
1035 |
{ |
|
1036 |
const Namespace *ns = &rslt->rootNamespace; |
|
1037 |
for (int i = 1; i < nsCount; ++i) |
|
1038 |
if (!(ns = ns->children.value(namespaces.at(i)))) |
|
1039 |
goto supers; |
|
1040 |
if ((this->*callback)(ns, context)) |
|
1041 |
return true; |
|
1042 |
supers: |
|
1043 |
foreach (const ParseResults *sup, rslt->includes) |
|
1044 |
if (vr.tryVisit(sup->fileId) |
|
1045 |
&& visitNamespace(namespaces, nsCount, callback, context, vr, sup)) |
|
1046 |
return true; |
|
1047 |
return false; |
|
1048 |
} |
|
1049 |
||
1050 |
bool CppParser::visitNamespace(const NamespaceList &namespaces, int nsCount, |
|
1051 |
VisitNamespaceCallback callback, void *context) const |
|
1052 |
{ |
|
1053 |
VisitRecorder vr; |
|
1054 |
return visitNamespace(namespaces, nsCount, callback, context, vr, results); |
|
1055 |
} |
|
1056 |
||
1057 |
QStringList CppParser::stringListifySegments(const QList<HashString> &segments) |
|
1058 |
{ |
|
1059 |
QStringList ret; |
|
1060 |
for (int i = 0; i < segments.count(); ++i) |
|
1061 |
ret << segments.at(i).value(); |
|
1062 |
return ret; |
|
1063 |
} |
|
1064 |
||
1065 |
struct QualifyOneData { |
|
7
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
1066 |
QualifyOneData(const NamespaceList &ns, int nsc, const HashString &seg, NamespaceList *rslvd, |
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
1067 |
QSet<HashStringList> *visited) |
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
1068 |
: namespaces(ns), nsCount(nsc), segment(seg), resolved(rslvd), visitedUsings(visited) |
0 | 1069 |
{} |
1070 |
||
1071 |
const NamespaceList &namespaces; |
|
1072 |
int nsCount; |
|
1073 |
const HashString &segment; |
|
1074 |
NamespaceList *resolved; |
|
7
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
1075 |
QSet<HashStringList> *visitedUsings; |
0 | 1076 |
}; |
1077 |
||
1078 |
bool CppParser::qualifyOneCallbackOwn(const Namespace *ns, void *context) const |
|
1079 |
{ |
|
1080 |
QualifyOneData *data = (QualifyOneData *)context; |
|
1081 |
if (ns->children.contains(data->segment)) { |
|
1082 |
*data->resolved = data->namespaces.mid(0, data->nsCount); |
|
1083 |
*data->resolved << data->segment; |
|
1084 |
return true; |
|
1085 |
} |
|
1086 |
QHash<HashString, NamespaceList>::ConstIterator nsai = ns->aliases.constFind(data->segment); |
|
1087 |
if (nsai != ns->aliases.constEnd()) { |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1088 |
const NamespaceList &nsl = *nsai; |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1089 |
if (nsl.last().value().isEmpty()) { // Delayed alias resolution |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1090 |
NamespaceList &nslIn = *const_cast<NamespaceList *>(&nsl); |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1091 |
nslIn.removeLast(); |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1092 |
NamespaceList nslOut; |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1093 |
if (!fullyQualify(data->namespaces, data->nsCount, nslIn, false, &nslOut, 0)) { |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1094 |
const_cast<Namespace *>(ns)->aliases.remove(data->segment); |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1095 |
return false; |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1096 |
} |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1097 |
nslIn = nslOut; |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1098 |
} |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1099 |
*data->resolved = nsl; |
0 | 1100 |
return true; |
1101 |
} |
|
1102 |
return false; |
|
1103 |
} |
|
1104 |
||
1105 |
bool CppParser::qualifyOneCallbackUsing(const Namespace *ns, void *context) const |
|
1106 |
{ |
|
1107 |
QualifyOneData *data = (QualifyOneData *)context; |
|
1108 |
foreach (const HashStringList &use, ns->usings) |
|
7
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
1109 |
if (!data->visitedUsings->contains(use)) { |
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
1110 |
data->visitedUsings->insert(use); |
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
1111 |
if (qualifyOne(use.value(), use.value().count(), data->segment, data->resolved, |
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
1112 |
data->visitedUsings)) |
0 | 1113 |
return true; |
1114 |
} |
|
1115 |
return false; |
|
1116 |
} |
|
1117 |
||
1118 |
bool CppParser::qualifyOne(const NamespaceList &namespaces, int nsCnt, const HashString &segment, |
|
7
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
1119 |
NamespaceList *resolved, QSet<HashStringList> *visitedUsings) const |
0 | 1120 |
{ |
7
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
1121 |
QualifyOneData data(namespaces, nsCnt, segment, resolved, visitedUsings); |
0 | 1122 |
|
1123 |
if (visitNamespace(namespaces, nsCnt, &CppParser::qualifyOneCallbackOwn, &data)) |
|
1124 |
return true; |
|
1125 |
||
1126 |
return visitNamespace(namespaces, nsCnt, &CppParser::qualifyOneCallbackUsing, &data); |
|
1127 |
} |
|
1128 |
||
7
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
1129 |
bool CppParser::qualifyOne(const NamespaceList &namespaces, int nsCnt, const HashString &segment, |
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
1130 |
NamespaceList *resolved) const |
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
1131 |
{ |
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
1132 |
QSet<HashStringList> visitedUsings; |
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
1133 |
|
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
1134 |
return qualifyOne(namespaces, nsCnt, segment, resolved, &visitedUsings); |
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
1135 |
} |
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
1136 |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1137 |
bool CppParser::fullyQualify(const NamespaceList &namespaces, int nsCnt, |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1138 |
const QList<HashString> &segments, bool isDeclaration, |
0 | 1139 |
NamespaceList *resolved, QStringList *unresolved) const |
1140 |
{ |
|
1141 |
int nsIdx; |
|
1142 |
int initSegIdx; |
|
1143 |
||
1144 |
if (segments.first().value().isEmpty()) { |
|
1145 |
// fully qualified |
|
1146 |
if (segments.count() == 1) { |
|
1147 |
resolved->clear(); |
|
1148 |
*resolved << HashString(QString()); |
|
1149 |
return true; |
|
1150 |
} |
|
1151 |
initSegIdx = 1; |
|
1152 |
nsIdx = 0; |
|
1153 |
} else { |
|
1154 |
initSegIdx = 0; |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1155 |
nsIdx = nsCnt - 1; |
0 | 1156 |
} |
1157 |
||
1158 |
do { |
|
1159 |
if (qualifyOne(namespaces, nsIdx + 1, segments[initSegIdx], resolved)) { |
|
1160 |
int segIdx = initSegIdx; |
|
1161 |
while (++segIdx < segments.count()) { |
|
1162 |
if (!qualifyOne(*resolved, resolved->count(), segments[segIdx], resolved)) { |
|
1163 |
if (unresolved) |
|
1164 |
*unresolved = stringListifySegments(segments.mid(segIdx)); |
|
1165 |
return false; |
|
1166 |
} |
|
1167 |
} |
|
1168 |
return true; |
|
1169 |
} |
|
1170 |
} while (!isDeclaration && --nsIdx >= 0); |
|
1171 |
resolved->clear(); |
|
1172 |
*resolved << HashString(QString()); |
|
1173 |
if (unresolved) |
|
1174 |
*unresolved = stringListifySegments(segments.mid(initSegIdx)); |
|
1175 |
return false; |
|
1176 |
} |
|
1177 |
||
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1178 |
bool CppParser::fullyQualify(const NamespaceList &namespaces, |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1179 |
const QList<HashString> &segments, bool isDeclaration, |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1180 |
NamespaceList *resolved, QStringList *unresolved) const |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1181 |
{ |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1182 |
return fullyQualify(namespaces, namespaces.count(), |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1183 |
segments, isDeclaration, resolved, unresolved); |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1184 |
} |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1185 |
|
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1186 |
bool CppParser::fullyQualify(const NamespaceList &namespaces, |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1187 |
const QString &quali, bool isDeclaration, |
0 | 1188 |
NamespaceList *resolved, QStringList *unresolved) const |
1189 |
{ |
|
1190 |
static QString strColons(QLatin1String("::")); |
|
1191 |
||
1192 |
QList<HashString> segments; |
|
1193 |
foreach (const QString &str, quali.split(strColons)) // XXX slow, but needs to be fast(?) |
|
1194 |
segments << HashString(str); |
|
1195 |
return fullyQualify(namespaces, segments, isDeclaration, resolved, unresolved); |
|
1196 |
} |
|
1197 |
||
1198 |
bool CppParser::findNamespaceCallback(const Namespace *ns, void *context) const |
|
1199 |
{ |
|
1200 |
*((const Namespace **)context) = ns; |
|
1201 |
return true; |
|
1202 |
} |
|
1203 |
||
1204 |
const Namespace *CppParser::findNamespace(const NamespaceList &namespaces, int nsCount) const |
|
1205 |
{ |
|
1206 |
const Namespace *ns = 0; |
|
1207 |
if (nsCount == -1) |
|
1208 |
nsCount = namespaces.count(); |
|
1209 |
visitNamespace(namespaces, nsCount, &CppParser::findNamespaceCallback, &ns); |
|
1210 |
return ns; |
|
1211 |
} |
|
1212 |
||
1213 |
void CppParser::enterNamespace(NamespaceList *namespaces, const HashString &name) |
|
1214 |
{ |
|
1215 |
*namespaces << name; |
|
1216 |
if (!findNamespace(*namespaces)) |
|
1217 |
modifyNamespace(namespaces, false); |
|
1218 |
} |
|
1219 |
||
1220 |
void CppParser::truncateNamespaces(NamespaceList *namespaces, int length) |
|
1221 |
{ |
|
1222 |
if (namespaces->count() > length) |
|
1223 |
namespaces->erase(namespaces->begin() + length, namespaces->end()); |
|
1224 |
} |
|
1225 |
||
1226 |
/* |
|
1227 |
Functions for processing include files. |
|
1228 |
*/ |
|
1229 |
||
1230 |
ParseResultHash &CppFiles::parsedFiles() |
|
1231 |
{ |
|
1232 |
static ParseResultHash parsed; |
|
1233 |
||
1234 |
return parsed; |
|
1235 |
} |
|
1236 |
||
1237 |
TranslatorHash &CppFiles::translatedFiles() |
|
1238 |
{ |
|
1239 |
static TranslatorHash tors; |
|
1240 |
||
1241 |
return tors; |
|
1242 |
} |
|
1243 |
||
1244 |
QSet<QString> &CppFiles::blacklistedFiles() |
|
1245 |
{ |
|
1246 |
static QSet<QString> blacklisted; |
|
1247 |
||
1248 |
return blacklisted; |
|
1249 |
} |
|
1250 |
||
1251 |
const ParseResults *CppFiles::getResults(const QString &cleanFile) |
|
1252 |
{ |
|
1253 |
return parsedFiles().value(cleanFile); |
|
1254 |
} |
|
1255 |
||
1256 |
void CppFiles::setResults(const QString &cleanFile, const ParseResults *results) |
|
1257 |
{ |
|
1258 |
parsedFiles().insert(cleanFile, results); |
|
1259 |
} |
|
1260 |
||
1261 |
const Translator *CppFiles::getTranslator(const QString &cleanFile) |
|
1262 |
{ |
|
1263 |
return translatedFiles().value(cleanFile); |
|
1264 |
} |
|
1265 |
||
1266 |
void CppFiles::setTranslator(const QString &cleanFile, const Translator *tor) |
|
1267 |
{ |
|
1268 |
translatedFiles().insert(cleanFile, tor); |
|
1269 |
} |
|
1270 |
||
1271 |
bool CppFiles::isBlacklisted(const QString &cleanFile) |
|
1272 |
{ |
|
1273 |
return blacklistedFiles().contains(cleanFile); |
|
1274 |
} |
|
1275 |
||
1276 |
void CppFiles::setBlacklisted(const QString &cleanFile) |
|
1277 |
{ |
|
1278 |
blacklistedFiles().insert(cleanFile); |
|
1279 |
} |
|
1280 |
||
1281 |
static bool isHeader(const QString &name) |
|
1282 |
{ |
|
1283 |
QString fileExt = QFileInfo(name).suffix(); |
|
1284 |
return fileExt.isEmpty() || fileExt.startsWith(QLatin1Char('h'), Qt::CaseInsensitive); |
|
1285 |
} |
|
1286 |
||
1287 |
void CppParser::processInclude(const QString &file, ConversionData &cd, |
|
1288 |
QSet<QString> &inclusions) |
|
1289 |
{ |
|
1290 |
QString cleanFile = QDir::cleanPath(file); |
|
1291 |
||
1292 |
if (inclusions.contains(cleanFile)) { |
|
1293 |
qWarning("%s:%d: circular inclusion of %s\n", |
|
1294 |
qPrintable(yyFileName), yyLineNo, qPrintable(cleanFile)); |
|
1295 |
return; |
|
1296 |
} |
|
1297 |
||
1298 |
// If the #include is in any kind of namespace, has been blacklisted previously, |
|
1299 |
// or is not a header file (stdc++ extensionless or *.h*), then really include |
|
1300 |
// it. Otherwise it is safe to process it stand-alone and re-use the parsed |
|
1301 |
// namespace data for inclusion into other files. |
|
1302 |
bool isIndirect = false; |
|
1303 |
if (namespaces.count() == 1 && functionContext.count() == 1 |
|
1304 |
&& functionContextUnresolved.isEmpty() && pendingContext.isEmpty() |
|
1305 |
&& !CppFiles::isBlacklisted(cleanFile) |
|
1306 |
&& isHeader(cleanFile)) { |
|
1307 |
||
1308 |
if (const ParseResults *res = CppFiles::getResults(cleanFile)) { |
|
1309 |
results->includes.insert(res); |
|
1310 |
return; |
|
1311 |
} |
|
1312 |
||
1313 |
isIndirect = true; |
|
1314 |
} |
|
1315 |
||
1316 |
QFile f(cleanFile); |
|
1317 |
if (!f.open(QIODevice::ReadOnly)) { |
|
1318 |
qWarning("%s:%d: Cannot open %s: %s\n", |
|
1319 |
qPrintable(yyFileName), yyLineNo, |
|
1320 |
qPrintable(cleanFile), qPrintable(f.errorString())); |
|
1321 |
return; |
|
1322 |
} |
|
1323 |
||
1324 |
QTextStream ts(&f); |
|
1325 |
ts.setCodec(yySourceCodec); |
|
1326 |
ts.setAutoDetectUnicode(true); |
|
1327 |
||
1328 |
inclusions.insert(cleanFile); |
|
1329 |
if (isIndirect) { |
|
1330 |
CppParser parser; |
|
1331 |
foreach (const QString &projectRoot, cd.m_projectRoots) |
|
1332 |
if (cleanFile.startsWith(projectRoot)) { |
|
1333 |
parser.setTranslator(new Translator); |
|
1334 |
break; |
|
1335 |
} |
|
1336 |
parser.setInput(ts, cleanFile); |
|
1337 |
parser.parse(cd.m_defaultContext, cd, inclusions); |
|
1338 |
results->includes.insert(parser.recordResults(true)); |
|
1339 |
} else { |
|
1340 |
CppParser parser(results); |
|
1341 |
parser.namespaces = namespaces; |
|
1342 |
parser.functionContext = functionContext; |
|
1343 |
parser.functionContextUnresolved = functionContextUnresolved; |
|
1344 |
parser.pendingContext = pendingContext; |
|
1345 |
parser.setInput(ts, cleanFile); |
|
1346 |
parser.parseInternal(cd, inclusions); |
|
1347 |
// Avoid that messages obtained by direct scanning are used |
|
1348 |
CppFiles::setBlacklisted(cleanFile); |
|
1349 |
} |
|
1350 |
inclusions.remove(cleanFile); |
|
1351 |
} |
|
1352 |
||
1353 |
/* |
|
1354 |
The third part of this source file is the parser. It accomplishes |
|
1355 |
a very easy task: It finds all strings inside a tr() or translate() |
|
1356 |
call, and possibly finds out the context of the call. It supports |
|
1357 |
three cases: (1) the context is specified, as in |
|
1358 |
FunnyDialog::tr("Hello") or translate("FunnyDialog", "Hello"); |
|
1359 |
(2) the call appears within an inlined function; (3) the call |
|
1360 |
appears within a function defined outside the class definition. |
|
1361 |
*/ |
|
1362 |
||
1363 |
bool CppParser::match(uint t) |
|
1364 |
{ |
|
1365 |
bool matches = (yyTok == t); |
|
1366 |
if (matches) |
|
1367 |
yyTok = getToken(); |
|
1368 |
return matches; |
|
1369 |
} |
|
1370 |
||
1371 |
bool CppParser::matchString(QString *s) |
|
1372 |
{ |
|
1373 |
bool matches = false; |
|
1374 |
s->clear(); |
|
1375 |
forever { |
|
1376 |
while (yyTok == Tok_Comment) |
|
1377 |
yyTok = getToken(); |
|
1378 |
if (yyTok != Tok_String) |
|
1379 |
return matches; |
|
1380 |
matches = true; |
|
1381 |
*s += yyWord; |
|
1382 |
s->detach(); |
|
1383 |
yyTok = getToken(); |
|
1384 |
} |
|
1385 |
} |
|
1386 |
||
1387 |
STRING(QApplication); |
|
1388 |
STRING(QCoreApplication); |
|
1389 |
STRING(UnicodeUTF8); |
|
1390 |
STRING(DefaultCodec); |
|
1391 |
STRING(CodecForTr); |
|
1392 |
||
1393 |
bool CppParser::matchEncoding(bool *utf8) |
|
1394 |
{ |
|
1395 |
if (yyTok != Tok_Ident) |
|
1396 |
return false; |
|
1397 |
if (yyWord == strQApplication || yyWord == strQCoreApplication) { |
|
1398 |
yyTok = getToken(); |
|
1399 |
if (yyTok == Tok_ColonColon) |
|
1400 |
yyTok = getToken(); |
|
1401 |
} |
|
1402 |
if (yyWord == strUnicodeUTF8) { |
|
1403 |
*utf8 = true; |
|
1404 |
yyTok = getToken(); |
|
1405 |
return true; |
|
1406 |
} |
|
1407 |
if (yyWord == strDefaultCodec || yyWord == strCodecForTr) { |
|
1408 |
*utf8 = false; |
|
1409 |
yyTok = getToken(); |
|
1410 |
return true; |
|
1411 |
} |
|
1412 |
return false; |
|
1413 |
} |
|
1414 |
||
1415 |
bool CppParser::matchStringOrNull(QString *s) |
|
1416 |
{ |
|
1417 |
return matchString(s) || match(Tok_Null); |
|
1418 |
} |
|
1419 |
||
1420 |
/* |
|
1421 |
* match any expression that can return a number, which can be |
|
1422 |
* 1. Literal number (e.g. '11') |
|
1423 |
* 2. simple identifier (e.g. 'm_count') |
|
1424 |
* 3. simple function call (e.g. 'size()' ) |
|
1425 |
* 4. function call on an object (e.g. 'list.size()') |
|
1426 |
* 5. function call on an object (e.g. 'list->size()') |
|
1427 |
* |
|
1428 |
* Other cases: |
|
1429 |
* size(2,4) |
|
1430 |
* list().size() |
|
1431 |
* list(a,b).size(2,4) |
|
1432 |
* etc... |
|
1433 |
*/ |
|
1434 |
bool CppParser::matchExpression() |
|
1435 |
{ |
|
1436 |
if (match(Tok_Null) || match(Tok_Integer)) |
|
1437 |
return true; |
|
1438 |
||
1439 |
int parenlevel = 0; |
|
1440 |
while (match(Tok_Ident) || parenlevel > 0) { |
|
1441 |
if (yyTok == Tok_RightParen) { |
|
1442 |
if (parenlevel == 0) break; |
|
1443 |
--parenlevel; |
|
1444 |
yyTok = getToken(); |
|
1445 |
} else if (yyTok == Tok_LeftParen) { |
|
1446 |
yyTok = getToken(); |
|
1447 |
if (yyTok == Tok_RightParen) { |
|
1448 |
yyTok = getToken(); |
|
1449 |
} else { |
|
1450 |
++parenlevel; |
|
1451 |
} |
|
1452 |
} else if (yyTok == Tok_Ident) { |
|
1453 |
continue; |
|
1454 |
} else if (yyTok == Tok_Arrow) { |
|
1455 |
yyTok = getToken(); |
|
1456 |
} else if (parenlevel == 0) { |
|
1457 |
return false; |
|
1458 |
} |
|
1459 |
} |
|
1460 |
return true; |
|
1461 |
} |
|
1462 |
||
1463 |
QString CppParser::transcode(const QString &str, bool utf8) |
|
1464 |
{ |
|
1465 |
static const char tab[] = "abfnrtv"; |
|
1466 |
static const char backTab[] = "\a\b\f\n\r\t\v"; |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1467 |
// This function has to convert back to bytes, as C's \0* sequences work at that level. |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1468 |
const QByteArray in = yyForceUtf8 ? str.toUtf8() : tor->codec()->fromUnicode(str); |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1469 |
QByteArray out; |
0 | 1470 |
|
1471 |
out.reserve(in.length()); |
|
1472 |
for (int i = 0; i < in.length();) { |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1473 |
uchar c = in[i++]; |
0 | 1474 |
if (c == '\\') { |
1475 |
if (i >= in.length()) |
|
1476 |
break; |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1477 |
c = in[i++]; |
0 | 1478 |
|
1479 |
if (c == '\n') |
|
1480 |
continue; |
|
1481 |
||
1482 |
if (c == 'x') { |
|
1483 |
QByteArray hex; |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1484 |
while (i < in.length() && isxdigit((c = in[i]))) { |
0 | 1485 |
hex += c; |
1486 |
i++; |
|
1487 |
} |
|
1488 |
out += hex.toUInt(0, 16); |
|
1489 |
} else if (c >= '0' && c < '8') { |
|
1490 |
QByteArray oct; |
|
1491 |
int n = 0; |
|
1492 |
oct += c; |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1493 |
while (n < 2 && i < in.length() && (c = in[i]) >= '0' && c < '8') { |
0 | 1494 |
i++; |
1495 |
n++; |
|
1496 |
oct += c; |
|
1497 |
} |
|
1498 |
out += oct.toUInt(0, 8); |
|
1499 |
} else { |
|
1500 |
const char *p = strchr(tab, c); |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1501 |
out += !p ? c : backTab[p - tab]; |
0 | 1502 |
} |
1503 |
} else { |
|
1504 |
out += c; |
|
1505 |
} |
|
1506 |
} |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1507 |
return (utf8 || yyForceUtf8) ? QString::fromUtf8(out.constData(), out.length()) |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1508 |
: tor->codec()->toUnicode(out); |
0 | 1509 |
} |
1510 |
||
1511 |
void CppParser::recordMessage( |
|
1512 |
int line, const QString &context, const QString &text, const QString &comment, |
|
1513 |
const QString &extracomment, const QString &msgid, const TranslatorMessage::ExtraData &extra, |
|
1514 |
bool utf8, bool plural) |
|
1515 |
{ |
|
1516 |
TranslatorMessage msg( |
|
1517 |
transcode(context, utf8), transcode(text, utf8), transcode(comment, utf8), QString(), |
|
1518 |
yyFileName, line, QStringList(), |
|
1519 |
TranslatorMessage::Unfinished, plural); |
|
1520 |
msg.setExtraComment(transcode(extracomment.simplified(), utf8)); |
|
1521 |
msg.setId(msgid); |
|
1522 |
msg.setExtras(extra); |
|
1523 |
if ((utf8 || yyForceUtf8) && !yyCodecIsUtf8 && msg.needs8Bit()) |
|
1524 |
msg.setUtf8(true); |
|
1525 |
tor->append(msg); |
|
1526 |
} |
|
1527 |
||
1528 |
void CppParser::parse(const QString &initialContext, ConversionData &cd, |
|
1529 |
QSet<QString> &inclusions) |
|
1530 |
{ |
|
1531 |
if (tor) |
|
1532 |
yyCodecIsUtf8 = (tor->codecName() == "UTF-8"); |
|
1533 |
||
1534 |
namespaces << HashString(); |
|
1535 |
functionContext = namespaces; |
|
1536 |
functionContextUnresolved = initialContext; |
|
1537 |
||
1538 |
parseInternal(cd, inclusions); |
|
1539 |
} |
|
1540 |
||
1541 |
void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) |
|
1542 |
{ |
|
1543 |
static QString strColons(QLatin1String("::")); |
|
1544 |
||
1545 |
QString context; |
|
1546 |
QString text; |
|
1547 |
QString comment; |
|
1548 |
QString extracomment; |
|
1549 |
QString msgid; |
|
1550 |
QString sourcetext; |
|
1551 |
TranslatorMessage::ExtraData extra; |
|
1552 |
QString prefix; |
|
1553 |
#ifdef DIAGNOSE_RETRANSLATABILITY |
|
1554 |
QString functionName; |
|
1555 |
#endif |
|
1556 |
int line; |
|
1557 |
bool utf8; |
|
1558 |
bool yyTokColonSeen = false; // Start of c'tor's initializer list |
|
1559 |
||
1560 |
yyWord.reserve(yyInStr.size()); // Rather insane. That's because we do no length checking. |
|
1561 |
yyInPtr = (const ushort *)yyInStr.unicode(); |
|
1562 |
yyCh = getChar(); |
|
1563 |
yyTok = getToken(); |
|
1564 |
while (yyTok != Tok_Eof) { |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
1565 |
// these are array indexing operations. we ignore them entirely |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
1566 |
// so they don't confuse our scoping of static initializers. |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
1567 |
// we enter the loop by either reading a left bracket or by an |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
1568 |
// #else popping the state. |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
1569 |
while (yyBracketDepth) |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
1570 |
yyTok = getToken(); |
0 | 1571 |
//qDebug() << "TOKEN: " << yyTok; |
1572 |
switch (yyTok) { |
|
1573 |
case Tok_QuotedInclude: { |
|
1574 |
text = QDir(QFileInfo(yyFileName).absolutePath()).absoluteFilePath(yyWord); |
|
1575 |
text.detach(); |
|
1576 |
if (QFileInfo(text).isFile()) { |
|
1577 |
processInclude(text, cd, inclusions); |
|
1578 |
yyTok = getToken(); |
|
1579 |
break; |
|
1580 |
} |
|
1581 |
} |
|
1582 |
/* fall through */ |
|
1583 |
case Tok_AngledInclude: { |
|
1584 |
QStringList cSources = cd.m_allCSources.values(yyWord); |
|
1585 |
if (!cSources.isEmpty()) { |
|
1586 |
foreach (const QString &cSource, cSources) |
|
1587 |
processInclude(cSource, cd, inclusions); |
|
1588 |
goto incOk; |
|
1589 |
} |
|
1590 |
foreach (const QString &incPath, cd.m_includePath) { |
|
1591 |
text = QDir(incPath).absoluteFilePath(yyWord); |
|
1592 |
text.detach(); |
|
1593 |
if (QFileInfo(text).isFile()) { |
|
1594 |
processInclude(text, cd, inclusions); |
|
1595 |
goto incOk; |
|
1596 |
} |
|
1597 |
} |
|
1598 |
incOk: |
|
1599 |
yyTok = getToken(); |
|
1600 |
break; |
|
1601 |
} |
|
1602 |
case Tok_friend: |
|
1603 |
yyTok = getToken(); |
|
1604 |
// These are forward declarations, so ignore them. |
|
1605 |
if (yyTok == Tok_class) |
|
1606 |
yyTok = getToken(); |
|
1607 |
break; |
|
1608 |
case Tok_class: |
|
1609 |
yyTokColonSeen = false; |
|
1610 |
/* |
|
1611 |
Partial support for inlined functions. |
|
1612 |
*/ |
|
1613 |
yyTok = getToken(); |
|
1614 |
if (yyBraceDepth == namespaceDepths.count() && yyParenDepth == 0) { |
|
1615 |
QList<HashString> quali; |
|
1616 |
HashString fct; |
|
1617 |
do { |
|
1618 |
/* |
|
1619 |
This code should execute only once, but we play |
|
1620 |
safe with impure definitions such as |
|
1621 |
'class Q_EXPORT QMessageBox', in which case |
|
1622 |
'QMessageBox' is the class name, not 'Q_EXPORT'. |
|
1623 |
*/ |
|
1624 |
text = yyWord; |
|
1625 |
text.detach(); |
|
1626 |
fct.setValue(text); |
|
1627 |
yyTok = getToken(); |
|
1628 |
} while (yyTok == Tok_Ident); |
|
1629 |
while (yyTok == Tok_ColonColon) { |
|
1630 |
yyTok = getToken(); |
|
1631 |
if (yyTok != Tok_Ident) |
|
1632 |
break; // Oops ... |
|
1633 |
quali << fct; |
|
1634 |
text = yyWord; |
|
1635 |
text.detach(); |
|
1636 |
fct.setValue(text); |
|
1637 |
yyTok = getToken(); |
|
1638 |
} |
|
1639 |
while (yyTok == Tok_Comment) |
|
1640 |
yyTok = getToken(); |
|
1641 |
if (yyTok == Tok_Colon) { |
|
1642 |
// Skip any token until '{' since we might do things wrong if we find |
|
1643 |
// a '::' token here. |
|
1644 |
do { |
|
1645 |
yyTok = getToken(); |
|
1646 |
} while (yyTok != Tok_LeftBrace && yyTok != Tok_Eof); |
|
1647 |
} else { |
|
1648 |
if (yyTok != Tok_LeftBrace) { |
|
1649 |
// Obviously a forward declaration. We skip those, as they |
|
1650 |
// don't create actually usable namespaces. |
|
1651 |
break; |
|
1652 |
} |
|
1653 |
} |
|
1654 |
||
1655 |
if (!quali.isEmpty()) { |
|
1656 |
// Forward-declared class definitions can be namespaced. |
|
1657 |
NamespaceList nsl; |
|
1658 |
if (!fullyQualify(namespaces, quali, true, &nsl, 0)) { |
|
1659 |
qWarning("%s:%d: Ignoring definition of undeclared qualified class\n", |
|
1660 |
qPrintable(yyFileName), yyLineNo); |
|
1661 |
break; |
|
1662 |
} |
|
1663 |
namespaceDepths.push(namespaces.count()); |
|
1664 |
namespaces = nsl; |
|
1665 |
} else { |
|
1666 |
namespaceDepths.push(namespaces.count()); |
|
1667 |
} |
|
1668 |
enterNamespace(&namespaces, fct); |
|
1669 |
||
1670 |
functionContext = namespaces; |
|
1671 |
functionContextUnresolved.clear(); // Pointless |
|
1672 |
prospectiveContext.clear(); |
|
1673 |
pendingContext.clear(); |
|
1674 |
} |
|
1675 |
break; |
|
1676 |
case Tok_namespace: |
|
1677 |
yyTokColonSeen = false; |
|
1678 |
yyTok = getToken(); |
|
1679 |
if (yyTok == Tok_Ident) { |
|
1680 |
text = yyWord; |
|
1681 |
text.detach(); |
|
1682 |
HashString ns = HashString(text); |
|
1683 |
yyTok = getToken(); |
|
1684 |
if (yyTok == Tok_LeftBrace) { |
|
1685 |
namespaceDepths.push(namespaces.count()); |
|
1686 |
enterNamespace(&namespaces, ns); |
|
1687 |
yyTok = getToken(); |
|
1688 |
} else if (yyTok == Tok_Equals) { |
|
1689 |
// e.g. namespace Is = OuterSpace::InnerSpace; |
|
1690 |
QList<HashString> fullName; |
|
1691 |
yyTok = getToken(); |
|
1692 |
if (yyTok == Tok_ColonColon) |
|
1693 |
fullName.append(HashString(QString())); |
|
1694 |
while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { |
|
1695 |
if (yyTok == Tok_Ident) { |
|
1696 |
text = yyWord; |
|
1697 |
text.detach(); |
|
1698 |
fullName.append(HashString(text)); |
|
1699 |
} |
|
1700 |
yyTok = getToken(); |
|
1701 |
} |
|
1702 |
if (fullName.isEmpty()) |
|
1703 |
break; |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1704 |
fullName.append(HashString(QString())); // Mark as unresolved |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1705 |
modifyNamespace(&namespaces)->aliases[ns] = fullName; |
0 | 1706 |
} |
1707 |
} else if (yyTok == Tok_LeftBrace) { |
|
1708 |
// Anonymous namespace |
|
1709 |
namespaceDepths.push(namespaces.count()); |
|
1710 |
yyTok = getToken(); |
|
1711 |
} |
|
1712 |
break; |
|
1713 |
case Tok_using: |
|
1714 |
yyTok = getToken(); |
|
1715 |
// XXX this should affect only the current scope, not the entire current namespace |
|
1716 |
if (yyTok == Tok_namespace) { |
|
1717 |
QList<HashString> fullName; |
|
1718 |
yyTok = getToken(); |
|
1719 |
if (yyTok == Tok_ColonColon) |
|
1720 |
fullName.append(HashString(QString())); |
|
1721 |
while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { |
|
1722 |
if (yyTok == Tok_Ident) { |
|
1723 |
text = yyWord; |
|
1724 |
text.detach(); |
|
1725 |
fullName.append(HashString(text)); |
|
1726 |
} |
|
1727 |
yyTok = getToken(); |
|
1728 |
} |
|
1729 |
NamespaceList nsl; |
|
1730 |
if (fullyQualify(namespaces, fullName, false, &nsl, 0)) |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1731 |
modifyNamespace(&namespaces)->usings << HashStringList(nsl); |
0 | 1732 |
} else { |
1733 |
QList<HashString> fullName; |
|
1734 |
if (yyTok == Tok_ColonColon) |
|
1735 |
fullName.append(HashString(QString())); |
|
1736 |
while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { |
|
1737 |
if (yyTok == Tok_Ident) { |
|
1738 |
text = yyWord; |
|
1739 |
text.detach(); |
|
1740 |
fullName.append(HashString(text)); |
|
1741 |
} |
|
1742 |
yyTok = getToken(); |
|
1743 |
} |
|
1744 |
if (fullName.isEmpty()) |
|
1745 |
break; |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1746 |
// using-declarations cannot rename classes, so the last element of |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1747 |
// fullName is already the resolved name we actually want. |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1748 |
// As we do no resolution here, we'll collect useless usings of data |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1749 |
// members and methods as well. This is no big deal. |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1750 |
HashString &ns = fullName.last(); |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1751 |
fullName.append(HashString(QString())); // Mark as unresolved |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1752 |
modifyNamespace(&namespaces)->aliases[ns] = fullName; |
0 | 1753 |
} |
1754 |
break; |
|
1755 |
case Tok_tr: |
|
1756 |
case Tok_trUtf8: |
|
1757 |
if (!tor) |
|
1758 |
goto case_default; |
|
1759 |
if (!sourcetext.isEmpty()) |
|
1760 |
qWarning("%s:%d: //%% cannot be used with tr() / QT_TR_NOOP(). Ignoring\n", |
|
1761 |
qPrintable(yyFileName), yyLineNo); |
|
1762 |
utf8 = (yyTok == Tok_trUtf8); |
|
1763 |
line = yyLineNo; |
|
1764 |
yyTok = getToken(); |
|
1765 |
if (match(Tok_LeftParen) && matchString(&text) && !text.isEmpty()) { |
|
1766 |
comment.clear(); |
|
1767 |
bool plural = false; |
|
1768 |
||
1769 |
if (match(Tok_RightParen)) { |
|
1770 |
// no comment |
|
1771 |
} else if (match(Tok_Comma) && matchStringOrNull(&comment)) { //comment |
|
1772 |
if (match(Tok_RightParen)) { |
|
1773 |
// ok, |
|
1774 |
} else if (match(Tok_Comma)) { |
|
1775 |
plural = true; |
|
1776 |
} |
|
1777 |
} |
|
4
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
1778 |
if (!pendingContext.isEmpty() && !prefix.startsWith(strColons)) { |
0 | 1779 |
QStringList unresolved; |
1780 |
if (!fullyQualify(namespaces, pendingContext, true, &functionContext, &unresolved)) { |
|
1781 |
functionContextUnresolved = unresolved.join(strColons); |
|
1782 |
qWarning("%s:%d: Qualifying with unknown namespace/class %s::%s\n", |
|
1783 |
qPrintable(yyFileName), yyLineNo, |
|
1784 |
qPrintable(stringifyNamespace(functionContext)), |
|
1785 |
qPrintable(unresolved.first())); |
|
1786 |
} |
|
1787 |
pendingContext.clear(); |
|
1788 |
} |
|
1789 |
if (prefix.isEmpty()) { |
|
1790 |
if (functionContextUnresolved.isEmpty()) { |
|
1791 |
int idx = functionContext.length(); |
|
1792 |
if (idx < 2) { |
|
1793 |
qWarning("%s:%d: tr() cannot be called without context\n", |
|
1794 |
qPrintable(yyFileName), yyLineNo); |
|
1795 |
break; |
|
1796 |
} |
|
1797 |
Namespace *fctx; |
|
1798 |
while (!(fctx = findNamespace(functionContext, idx)->classDef)->hasTrFunctions) { |
|
1799 |
if (idx == 1) { |
|
1800 |
context = stringifyNamespace(functionContext); |
|
1801 |
fctx = findNamespace(functionContext)->classDef; |
|
1802 |
if (!fctx->complained) { |
|
1803 |
qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro\n", |
|
1804 |
qPrintable(yyFileName), yyLineNo, |
|
1805 |
qPrintable(context)); |
|
1806 |
fctx->complained = true; |
|
1807 |
} |
|
1808 |
goto gotctx; |
|
1809 |
} |
|
1810 |
--idx; |
|
1811 |
} |
|
1812 |
if (fctx->trQualification.isEmpty()) { |
|
1813 |
context.clear(); |
|
1814 |
for (int i = 1;;) { |
|
1815 |
context += functionContext.at(i).value(); |
|
1816 |
if (++i == idx) |
|
1817 |
break; |
|
1818 |
context += strColons; |
|
1819 |
} |
|
1820 |
fctx->trQualification = context; |
|
1821 |
} else { |
|
1822 |
context = fctx->trQualification; |
|
1823 |
} |
|
1824 |
} else { |
|
1825 |
context = (stringListifyNamespace(functionContext) |
|
1826 |
<< functionContextUnresolved).join(strColons); |
|
1827 |
} |
|
1828 |
} else { |
|
1829 |
#ifdef DIAGNOSE_RETRANSLATABILITY |
|
1830 |
int last = prefix.lastIndexOf(strColons); |
|
1831 |
QString className = prefix.mid(last == -1 ? 0 : last + 2); |
|
1832 |
if (!className.isEmpty() && className == functionName) { |
|
1833 |
qWarning("%s::%d: It is not recommended to call tr() from within a constructor '%s::%s' ", |
|
1834 |
qPrintable(yyFileName), yyLineNo, |
|
1835 |
className.constData(), functionName.constData()); |
|
1836 |
} |
|
1837 |
#endif |
|
1838 |
prefix.chop(2); |
|
1839 |
NamespaceList nsl; |
|
1840 |
QStringList unresolved; |
|
1841 |
if (fullyQualify(functionContext, prefix, false, &nsl, &unresolved)) { |
|
1842 |
Namespace *fctx = findNamespace(nsl)->classDef; |
|
1843 |
if (fctx->trQualification.isEmpty()) { |
|
1844 |
context = stringifyNamespace(nsl); |
|
1845 |
fctx->trQualification = context; |
|
1846 |
} else { |
|
1847 |
context = fctx->trQualification; |
|
1848 |
} |
|
1849 |
if (!fctx->hasTrFunctions && !fctx->complained) { |
|
1850 |
qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro\n", |
|
1851 |
qPrintable(yyFileName), yyLineNo, |
|
1852 |
qPrintable(context)); |
|
1853 |
fctx->complained = true; |
|
1854 |
} |
|
1855 |
} else { |
|
1856 |
context = (stringListifyNamespace(nsl) + unresolved).join(strColons); |
|
1857 |
} |
|
1858 |
prefix.clear(); |
|
1859 |
} |
|
1860 |
||
1861 |
gotctx: |
|
1862 |
recordMessage(line, context, text, comment, extracomment, msgid, extra, utf8, plural); |
|
1863 |
} |
|
1864 |
extracomment.clear(); |
|
1865 |
msgid.clear(); |
|
1866 |
extra.clear(); |
|
1867 |
break; |
|
1868 |
case Tok_translateUtf8: |
|
1869 |
case Tok_translate: |
|
1870 |
if (!tor) |
|
1871 |
goto case_default; |
|
1872 |
if (!sourcetext.isEmpty()) |
|
1873 |
qWarning("%s:%d: //%% cannot be used with translate() / QT_TRANSLATE_NOOP(). Ignoring\n", |
|
1874 |
qPrintable(yyFileName), yyLineNo); |
|
1875 |
utf8 = (yyTok == Tok_translateUtf8); |
|
1876 |
line = yyLineNo; |
|
1877 |
yyTok = getToken(); |
|
1878 |
if (match(Tok_LeftParen) |
|
1879 |
&& matchString(&context) |
|
1880 |
&& match(Tok_Comma) |
|
1881 |
&& matchString(&text) && !text.isEmpty()) |
|
1882 |
{ |
|
1883 |
comment.clear(); |
|
1884 |
bool plural = false; |
|
1885 |
if (!match(Tok_RightParen)) { |
|
1886 |
// look for comment |
|
1887 |
if (match(Tok_Comma) && matchStringOrNull(&comment)) { |
|
1888 |
if (!match(Tok_RightParen)) { |
|
1889 |
// look for encoding |
|
1890 |
if (match(Tok_Comma)) { |
|
1891 |
if (matchEncoding(&utf8)) { |
|
1892 |
if (!match(Tok_RightParen)) { |
|
1893 |
// look for the plural quantifier, |
|
1894 |
// this can be a number, an identifier or |
|
1895 |
// a function call, |
|
1896 |
// so for simplicity we mark it as plural if |
|
1897 |
// we know we have a comma instead of an |
|
1898 |
// right parentheses. |
|
1899 |
plural = match(Tok_Comma); |
|
1900 |
} |
|
1901 |
} else { |
|
1902 |
// This can be a QTranslator::translate("context", |
|
1903 |
// "source", "comment", n) plural translation |
|
1904 |
if (matchExpression() && match(Tok_RightParen)) { |
|
1905 |
plural = true; |
|
1906 |
} else { |
|
1907 |
break; |
|
1908 |
} |
|
1909 |
} |
|
1910 |
} else { |
|
1911 |
break; |
|
1912 |
} |
|
1913 |
} |
|
1914 |
} else { |
|
1915 |
break; |
|
1916 |
} |
|
1917 |
} |
|
1918 |
recordMessage(line, context, text, comment, extracomment, msgid, extra, utf8, plural); |
|
1919 |
} |
|
1920 |
extracomment.clear(); |
|
1921 |
msgid.clear(); |
|
1922 |
extra.clear(); |
|
1923 |
break; |
|
1924 |
case Tok_trid: |
|
1925 |
if (!tor) |
|
1926 |
goto case_default; |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1927 |
if (!msgid.isEmpty()) |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1928 |
qWarning("%s:%d: //= cannot be used with qtTrId() / QT_TRID_NOOP(). Ignoring\n", |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1929 |
qPrintable(yyFileName), yyLineNo); |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1930 |
//utf8 = false; // Maybe use //%% or something like that |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1931 |
line = yyLineNo; |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1932 |
yyTok = getToken(); |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1933 |
if (match(Tok_LeftParen) && matchString(&msgid) && !msgid.isEmpty()) { |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1934 |
bool plural = match(Tok_Comma); |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1935 |
recordMessage(line, QString(), sourcetext, QString(), extracomment, |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1936 |
msgid, extra, false, plural); |
0 | 1937 |
} |
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1938 |
sourcetext.clear(); |
0 | 1939 |
extracomment.clear(); |
1940 |
msgid.clear(); |
|
1941 |
extra.clear(); |
|
1942 |
break; |
|
1943 |
case Tok_Q_DECLARE_TR_FUNCTIONS: |
|
1944 |
if (getMacroArgs()) { |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1945 |
Namespace *ns = modifyNamespace(&namespaces); |
0 | 1946 |
ns->hasTrFunctions = true; |
1947 |
ns->trQualification = yyWord; |
|
1948 |
ns->trQualification.detach(); |
|
1949 |
} |
|
1950 |
yyTok = getToken(); |
|
1951 |
break; |
|
1952 |
case Tok_Q_OBJECT: |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1953 |
modifyNamespace(&namespaces)->hasTrFunctions = true; |
0 | 1954 |
yyTok = getToken(); |
1955 |
break; |
|
1956 |
case Tok_Ident: |
|
1957 |
prefix += yyWord; |
|
1958 |
prefix.detach(); |
|
1959 |
yyTok = getToken(); |
|
1960 |
if (yyTok != Tok_ColonColon) { |
|
1961 |
prefix.clear(); |
|
1962 |
if (yyTok == Tok_Ident && !yyParenDepth) |
|
1963 |
prospectiveContext.clear(); |
|
1964 |
} |
|
1965 |
break; |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1966 |
case Tok_Comment: { |
0 | 1967 |
if (!tor) |
1968 |
goto case_default; |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1969 |
const QChar *ptr = yyWord.unicode(); |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1970 |
if (*ptr == QLatin1Char(':') && ptr[1].isSpace()) { |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1971 |
yyWord.remove(0, 2); |
0 | 1972 |
extracomment += yyWord; |
1973 |
extracomment.detach(); |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1974 |
} else if (*ptr == QLatin1Char('=') && ptr[1].isSpace()) { |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1975 |
yyWord.remove(0, 2); |
0 | 1976 |
msgid = yyWord.simplified(); |
1977 |
msgid.detach(); |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1978 |
} else if (*ptr == QLatin1Char('~') && ptr[1].isSpace()) { |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1979 |
yyWord.remove(0, 2); |
0 | 1980 |
text = yyWord.trimmed(); |
1981 |
int k = text.indexOf(QLatin1Char(' ')); |
|
1982 |
if (k > -1) |
|
1983 |
extra.insert(text.left(k), text.mid(k + 1).trimmed()); |
|
1984 |
text.clear(); |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1985 |
} else if (*ptr == QLatin1Char('%') && ptr[1].isSpace()) { |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1986 |
sourcetext.reserve(sourcetext.length() + yyWord.length() - 2); |
0 | 1987 |
ushort *ptr = (ushort *)sourcetext.data() + sourcetext.length(); |
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1988 |
int p = 2, c; |
0 | 1989 |
forever { |
1990 |
if (p >= yyWord.length()) |
|
1991 |
break; |
|
1992 |
c = yyWord.unicode()[p++].unicode(); |
|
1993 |
if (isspace(c)) |
|
1994 |
continue; |
|
1995 |
if (c != '"') { |
|
1996 |
qWarning("%s:%d: Unexpected character in meta string\n", |
|
1997 |
qPrintable(yyFileName), yyLineNo); |
|
1998 |
break; |
|
1999 |
} |
|
2000 |
forever { |
|
2001 |
if (p >= yyWord.length()) { |
|
2002 |
whoops: |
|
2003 |
qWarning("%s:%d: Unterminated meta string\n", |
|
2004 |
qPrintable(yyFileName), yyLineNo); |
|
2005 |
break; |
|
2006 |
} |
|
2007 |
c = yyWord.unicode()[p++].unicode(); |
|
2008 |
if (c == '"') |
|
2009 |
break; |
|
2010 |
if (c == '\\') { |
|
2011 |
if (p >= yyWord.length()) |
|
2012 |
goto whoops; |
|
2013 |
c = yyWord.unicode()[p++].unicode(); |
|
2014 |
if (c == '\n') |
|
2015 |
goto whoops; |
|
2016 |
*ptr++ = '\\'; |
|
2017 |
} |
|
2018 |
*ptr++ = c; |
|
2019 |
} |
|
2020 |
} |
|
2021 |
sourcetext.resize(ptr - (ushort *)sourcetext.data()); |
|
2022 |
} else { |
|
2023 |
const ushort *uc = (const ushort *)yyWord.unicode(); // Is zero-terminated |
|
2024 |
int idx = 0; |
|
2025 |
ushort c; |
|
2026 |
while ((c = uc[idx]) == ' ' || c == '\t' || c == '\n') |
|
2027 |
++idx; |
|
2028 |
if (!memcmp(uc + idx, MagicComment.unicode(), MagicComment.length() * 2)) { |
|
2029 |
idx += MagicComment.length(); |
|
2030 |
comment = QString::fromRawData(yyWord.unicode() + idx, |
|
2031 |
yyWord.length() - idx).simplified(); |
|
2032 |
int k = comment.indexOf(QLatin1Char(' ')); |
|
2033 |
if (k == -1) { |
|
2034 |
context = comment; |
|
2035 |
} else { |
|
2036 |
context = comment.left(k); |
|
2037 |
comment.remove(0, k + 1); |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
2038 |
TranslatorMessage msg( |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
2039 |
transcode(context, false), QString(), |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
2040 |
transcode(comment, false), QString(), |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
2041 |
yyFileName, yyLineNo, QStringList(), |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
2042 |
TranslatorMessage::Finished, false); |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
2043 |
msg.setExtraComment(transcode(extracomment.simplified(), false)); |
0 | 2044 |
extracomment.clear(); |
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
2045 |
tor->append(msg); |
0 | 2046 |
tor->setExtras(extra); |
2047 |
extra.clear(); |
|
2048 |
} |
|
2049 |
} |
|
2050 |
} |
|
2051 |
yyTok = getToken(); |
|
2052 |
break; |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
2053 |
} |
0 | 2054 |
case Tok_Arrow: |
2055 |
yyTok = getToken(); |
|
2056 |
if (yyTok == Tok_tr || yyTok == Tok_trUtf8) |
|
2057 |
qWarning("%s:%d: Cannot invoke tr() like this\n", |
|
2058 |
qPrintable(yyFileName), yyLineNo); |
|
2059 |
break; |
|
2060 |
case Tok_ColonColon: |
|
2061 |
if (yyBraceDepth == namespaceDepths.count() && yyParenDepth == 0 && !yyTokColonSeen) |
|
2062 |
prospectiveContext = prefix; |
|
2063 |
prefix += strColons; |
|
2064 |
yyTok = getToken(); |
|
2065 |
#ifdef DIAGNOSE_RETRANSLATABILITY |
|
2066 |
if (yyTok == Tok_Ident && yyBraceDepth == namespaceDepths.count() && yyParenDepth == 0) { |
|
2067 |
functionName = yyWord; |
|
2068 |
functionName.detach(); |
|
2069 |
} |
|
2070 |
#endif |
|
2071 |
break; |
|
2072 |
case Tok_RightBrace: |
|
2073 |
if (yyBraceDepth + 1 == namespaceDepths.count()) // class or namespace |
|
2074 |
truncateNamespaces(&namespaces, namespaceDepths.pop()); |
|
2075 |
if (yyBraceDepth == namespaceDepths.count()) { |
|
2076 |
// function, class or namespace |
|
2077 |
if (!yyBraceDepth && !directInclude) { |
|
2078 |
truncateNamespaces(&functionContext, 1); |
|
2079 |
functionContextUnresolved = cd.m_defaultContext; |
|
2080 |
} else { |
|
2081 |
functionContext = namespaces; |
|
2082 |
functionContextUnresolved.clear(); |
|
2083 |
} |
|
2084 |
pendingContext.clear(); |
|
2085 |
} |
|
2086 |
// fallthrough |
|
2087 |
case Tok_Semicolon: |
|
2088 |
prospectiveContext.clear(); |
|
2089 |
prefix.clear(); |
|
2090 |
extracomment.clear(); |
|
2091 |
msgid.clear(); |
|
2092 |
extra.clear(); |
|
2093 |
yyTokColonSeen = false; |
|
2094 |
yyTok = getToken(); |
|
2095 |
break; |
|
2096 |
case Tok_Colon: |
|
2097 |
if (!prospectiveContext.isEmpty() |
|
2098 |
&& yyBraceDepth == namespaceDepths.count() && yyParenDepth == 0) |
|
2099 |
pendingContext = prospectiveContext; |
|
2100 |
yyTokColonSeen = true; |
|
2101 |
yyTok = getToken(); |
|
2102 |
break; |
|
2103 |
case Tok_LeftBrace: |
|
2104 |
if (!prospectiveContext.isEmpty() |
|
2105 |
&& yyBraceDepth == namespaceDepths.count() + 1 && yyParenDepth == 0) |
|
2106 |
pendingContext = prospectiveContext; |
|
2107 |
// fallthrough |
|
2108 |
case Tok_LeftParen: |
|
2109 |
case Tok_RightParen: |
|
2110 |
yyTokColonSeen = false; |
|
2111 |
yyTok = getToken(); |
|
2112 |
break; |
|
2113 |
default: |
|
2114 |
if (!yyParenDepth) |
|
2115 |
prospectiveContext.clear(); |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
2116 |
// fallthrough |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
2117 |
case Tok_Equals: // for static initializers; other cases make no difference |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
2118 |
case Tok_RightBracket: // ignoring indexing; same reason |
0 | 2119 |
case_default: |
2120 |
yyTok = getToken(); |
|
2121 |
break; |
|
2122 |
} |
|
2123 |
} |
|
2124 |
||
2125 |
if (yyBraceDepth != 0) |
|
2126 |
qWarning("%s:%d: Unbalanced opening brace in C++ code" |
|
2127 |
" (or abuse of the C++ preprocessor)\n", |
|
2128 |
qPrintable(yyFileName), yyBraceLineNo); |
|
2129 |
else if (yyParenDepth != 0) |
|
2130 |
qWarning("%s:%d: Unbalanced opening parenthesis in C++ code" |
|
2131 |
" (or abuse of the C++ preprocessor)\n", |
|
2132 |
qPrintable(yyFileName), yyParenLineNo); |
|
13
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
2133 |
else if (yyBracketDepth != 0) |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
2134 |
qWarning("%s:%d: Unbalanced opening bracket in C++ code" |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
2135 |
" (or abuse of the C++ preprocessor)\n", |
c0432d11811c
eb175c3290cd7ea85da4a590db9461504a4904bc
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
7
diff
changeset
|
2136 |
qPrintable(yyFileName), yyBracketLineNo); |
0 | 2137 |
} |
2138 |
||
2139 |
const ParseResults *CppParser::recordResults(bool isHeader) |
|
2140 |
{ |
|
2141 |
if (tor) { |
|
2142 |
if (tor->messageCount()) { |
|
2143 |
CppFiles::setTranslator(yyFileName, tor); |
|
2144 |
} else { |
|
2145 |
delete tor; |
|
2146 |
tor = 0; |
|
2147 |
} |
|
2148 |
} |
|
2149 |
if (isHeader) { |
|
2150 |
const ParseResults *pr; |
|
2151 |
if (!tor && results->includes.count() == 1 |
|
2152 |
&& results->rootNamespace.children.isEmpty() |
|
2153 |
&& results->rootNamespace.aliases.isEmpty() |
|
2154 |
&& results->rootNamespace.usings.isEmpty()) { |
|
2155 |
// This is a forwarding header. Slash it. |
|
2156 |
pr = *results->includes.begin(); |
|
2157 |
delete results; |
|
2158 |
} else { |
|
2159 |
results->fileId = nextFileId++; |
|
2160 |
pr = results; |
|
2161 |
} |
|
2162 |
CppFiles::setResults(yyFileName, pr); |
|
2163 |
return pr; |
|
2164 |
} else { |
|
2165 |
delete results; |
|
2166 |
return 0; |
|
2167 |
} |
|
2168 |
} |
|
2169 |
||
2170 |
/* |
|
2171 |
Fetches tr() calls in C++ code in UI files (inside "<function>" |
|
2172 |
tag). This mechanism is obsolete. |
|
2173 |
*/ |
|
2174 |
void fetchtrInlinedCpp(const QString &in, Translator &translator, const QString &context) |
|
2175 |
{ |
|
2176 |
CppParser parser; |
|
2177 |
parser.setInput(in); |
|
2178 |
ConversionData cd; |
|
2179 |
QSet<QString> inclusions; |
|
2180 |
parser.setTranslator(&translator); |
|
2181 |
parser.parse(context, cd, inclusions); |
|
2182 |
parser.deleteResults(); |
|
2183 |
} |
|
2184 |
||
2185 |
void loadCPP(Translator &translator, const QStringList &filenames, ConversionData &cd) |
|
2186 |
{ |
|
2187 |
QByteArray codecName = cd.m_codecForSource.isEmpty() |
|
2188 |
? translator.codecName() : cd.m_codecForSource; |
|
2189 |
QTextCodec *codec = QTextCodec::codecForName(codecName); |
|
2190 |
||
2191 |
foreach (const QString &filename, filenames) { |
|
2192 |
if (CppFiles::getResults(filename) || CppFiles::isBlacklisted(filename)) |
|
2193 |
continue; |
|
2194 |
||
2195 |
QFile file(filename); |
|
2196 |
if (!file.open(QIODevice::ReadOnly)) { |
|
2197 |
cd.appendError(QString::fromLatin1("Cannot open %1: %2") |
|
2198 |
.arg(filename, file.errorString())); |
|
2199 |
continue; |
|
2200 |
} |
|
2201 |
||
2202 |
CppParser parser; |
|
2203 |
QTextStream ts(&file); |
|
2204 |
ts.setCodec(codec); |
|
2205 |
ts.setAutoDetectUnicode(true); |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
2206 |
parser.setInput(ts, filename); |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
2207 |
if (cd.m_outputCodec.isEmpty() && ts.codec()->name() == "UTF-16") |
0 | 2208 |
translator.setCodecName("System"); |
2209 |
Translator *tor = new Translator; |
|
2210 |
tor->setCodecName(translator.codecName()); |
|
2211 |
parser.setTranslator(tor); |
|
2212 |
QSet<QString> inclusions; |
|
2213 |
parser.parse(cd.m_defaultContext, cd, inclusions); |
|
2214 |
parser.recordResults(isHeader(filename)); |
|
2215 |
} |
|
2216 |
||
2217 |
foreach (const QString &filename, filenames) |
|
2218 |
if (!CppFiles::isBlacklisted(filename)) |
|
2219 |
if (const Translator *tor = CppFiles::getTranslator(filename)) |
|
2220 |
foreach (const TranslatorMessage &msg, tor->messages()) |
|
2221 |
translator.extend(msg); |
|
2222 |
} |
|
2223 |
||
2224 |
QT_END_NAMESPACE |