63 |
63 |
64 //#define DIAGNOSE_RETRANSLATABILITY // FIXME: should make a runtime option of this |
64 //#define DIAGNOSE_RETRANSLATABILITY // FIXME: should make a runtime option of this |
65 |
65 |
66 class HashString { |
66 class HashString { |
67 public: |
67 public: |
68 HashString() : m_hashed(false) {} |
68 HashString() : m_hash(0x80000000) {} |
69 explicit HashString(const QString &str) : m_str(str), m_hashed(false) {} |
69 explicit HashString(const QString &str) : m_str(str), m_hash(0x80000000) {} |
70 void setValue(const QString &str) { m_str = str; m_hashed = false; } |
70 void setValue(const QString &str) { m_str = str; m_hash = 0x80000000; } |
71 const QString &value() const { return m_str; } |
71 const QString &value() const { return m_str; } |
72 bool operator==(const HashString &other) const { return m_str == other.m_str; } |
72 bool operator==(const HashString &other) const { return m_str == other.m_str; } |
73 private: |
73 private: |
74 QString m_str; |
74 QString m_str; |
|
75 // qHash() of a QString is only 28 bits wide, so we can use |
|
76 // the highest bit(s) as the "hash valid" flag. |
75 mutable uint m_hash; |
77 mutable uint m_hash; |
76 mutable bool m_hashed; |
|
77 friend uint qHash(const HashString &str); |
78 friend uint qHash(const HashString &str); |
78 }; |
79 }; |
79 |
80 |
80 uint qHash(const HashString &str) |
81 uint qHash(const HashString &str) |
81 { |
82 { |
82 if (!str.m_hashed) { |
83 if (str.m_hash & 0x80000000) |
83 str.m_hashed = true; |
|
84 str.m_hash = qHash(str.m_str); |
84 str.m_hash = qHash(str.m_str); |
85 } |
|
86 return str.m_hash; |
85 return str.m_hash; |
87 } |
86 } |
88 |
87 |
89 class HashStringList { |
88 class HashStringList { |
90 public: |
89 public: |
91 explicit HashStringList(const QList<HashString> &list) : m_list(list), m_hashed(false) {} |
90 explicit HashStringList(const QList<HashString> &list) : m_list(list), m_hash(0x80000000) {} |
92 const QList<HashString> &value() const { return m_list; } |
91 const QList<HashString> &value() const { return m_list; } |
93 bool operator==(const HashStringList &other) const { return m_list == other.m_list; } |
92 bool operator==(const HashStringList &other) const { return m_list == other.m_list; } |
94 private: |
93 private: |
95 QList<HashString> m_list; |
94 QList<HashString> m_list; |
96 mutable uint m_hash; |
95 mutable uint m_hash; |
97 mutable bool m_hashed; |
|
98 friend uint qHash(const HashStringList &list); |
96 friend uint qHash(const HashStringList &list); |
99 }; |
97 }; |
100 |
98 |
101 uint qHash(const HashStringList &list) |
99 uint qHash(const HashStringList &list) |
102 { |
100 { |
103 if (!list.m_hashed) { |
101 if (list.m_hash & 0x80000000) { |
104 list.m_hashed = true; |
|
105 uint hash = 0; |
102 uint hash = 0; |
106 foreach (const HashString &qs, list.m_list) { |
103 foreach (const HashString &qs, list.m_list) { |
107 hash ^= qHash(qs) ^ 0xa09df22f; |
104 hash ^= qHash(qs) ^ 0x0ad9f526; |
108 hash = (hash << 13) | (hash >> 19); |
105 hash = ((hash << 13) & 0x0fffffff) | (hash >> 15); |
109 } |
106 } |
110 list.m_hash = hash; |
107 list.m_hash = hash; |
111 } |
108 } |
112 return list.m_hash; |
109 return list.m_hash; |
113 } |
110 } |
213 }; |
210 }; |
214 |
211 |
215 private: |
212 private: |
216 struct IfdefState { |
213 struct IfdefState { |
217 IfdefState() {} |
214 IfdefState() {} |
218 IfdefState(int _braceDepth, int _parenDepth) : |
215 IfdefState(int _bracketDepth, int _braceDepth, int _parenDepth) : |
|
216 bracketDepth(_bracketDepth), |
219 braceDepth(_braceDepth), |
217 braceDepth(_braceDepth), |
220 parenDepth(_parenDepth), |
218 parenDepth(_parenDepth), |
221 elseLine(-1) |
219 elseLine(-1) |
222 {} |
220 {} |
223 |
221 |
224 SavedState state; |
222 SavedState state; |
|
223 int bracketDepth, bracketDepth1st; |
225 int braceDepth, braceDepth1st; |
224 int braceDepth, braceDepth1st; |
226 int parenDepth, parenDepth1st; |
225 int parenDepth, parenDepth1st; |
227 int elseLine; |
226 int elseLine; |
228 }; |
227 }; |
229 |
228 |
278 void truncateNamespaces(NamespaceList *namespaces, int lenght); |
277 void truncateNamespaces(NamespaceList *namespaces, int lenght); |
279 Namespace *modifyNamespace(NamespaceList *namespaces, bool haveLast = true); |
278 Namespace *modifyNamespace(NamespaceList *namespaces, bool haveLast = true); |
280 |
279 |
281 enum { |
280 enum { |
282 Tok_Eof, Tok_class, Tok_friend, Tok_namespace, Tok_using, Tok_return, |
281 Tok_Eof, Tok_class, Tok_friend, Tok_namespace, Tok_using, Tok_return, |
283 Tok_tr = 10, Tok_trUtf8, Tok_translate, Tok_translateUtf8, Tok_trid, |
282 Tok_tr, Tok_trUtf8, Tok_translate, Tok_translateUtf8, Tok_trid, |
284 Tok_Q_OBJECT = 20, Tok_Q_DECLARE_TR_FUNCTIONS, |
283 Tok_Q_OBJECT, Tok_Q_DECLARE_TR_FUNCTIONS, |
285 Tok_Ident, Tok_Comment, Tok_String, Tok_Arrow, Tok_Colon, Tok_ColonColon, |
284 Tok_Ident, Tok_Comment, Tok_String, Tok_Arrow, Tok_Colon, Tok_ColonColon, |
286 Tok_Equals, |
285 Tok_Equals, Tok_LeftBracket, Tok_RightBracket, |
287 Tok_LeftBrace = 30, Tok_RightBrace, Tok_LeftParen, Tok_RightParen, Tok_Comma, Tok_Semicolon, |
286 Tok_LeftBrace, Tok_RightBrace, Tok_LeftParen, Tok_RightParen, Tok_Comma, Tok_Semicolon, |
288 Tok_Null = 40, Tok_Integer, |
287 Tok_Null, Tok_Integer, |
289 Tok_QuotedInclude = 50, Tok_AngledInclude, |
288 Tok_QuotedInclude, Tok_AngledInclude, |
290 Tok_Other = 99 |
289 Tok_Other |
291 }; |
290 }; |
292 |
291 |
293 // Tokenizer state |
292 // Tokenizer state |
294 QString yyFileName; |
293 QString yyFileName; |
295 int yyCh; |
294 int yyCh; |
605 if (yyCh == 'l') { |
608 if (yyCh == 'l') { |
606 // elif, else |
609 // elif, else |
607 if (!yyIfdefStack.isEmpty()) { |
610 if (!yyIfdefStack.isEmpty()) { |
608 IfdefState &is = yyIfdefStack.top(); |
611 IfdefState &is = yyIfdefStack.top(); |
609 if (is.elseLine != -1) { |
612 if (is.elseLine != -1) { |
610 if (yyBraceDepth != is.braceDepth1st || yyParenDepth != is.parenDepth1st) |
613 if (yyBracketDepth != is.bracketDepth1st |
611 qWarning("%s:%d: Parenthesis/brace mismatch between " |
614 || yyBraceDepth != is.braceDepth1st |
|
615 || yyParenDepth != is.parenDepth1st) |
|
616 qWarning("%s:%d: Parenthesis/bracket/brace mismatch between " |
612 "#if and #else branches; using #if branch\n", |
617 "#if and #else branches; using #if branch\n", |
613 qPrintable(yyFileName), is.elseLine); |
618 qPrintable(yyFileName), is.elseLine); |
614 } else { |
619 } else { |
|
620 is.bracketDepth1st = yyBracketDepth; |
615 is.braceDepth1st = yyBraceDepth; |
621 is.braceDepth1st = yyBraceDepth; |
616 is.parenDepth1st = yyParenDepth; |
622 is.parenDepth1st = yyParenDepth; |
617 saveState(&is.state); |
623 saveState(&is.state); |
618 } |
624 } |
619 is.elseLine = yyLineNo; |
625 is.elseLine = yyLineNo; |
|
626 yyBracketDepth = is.bracketDepth; |
620 yyBraceDepth = is.braceDepth; |
627 yyBraceDepth = is.braceDepth; |
621 yyParenDepth = is.parenDepth; |
628 yyParenDepth = is.parenDepth; |
622 } |
629 } |
623 yyCh = getChar(); |
630 yyCh = getChar(); |
624 } else if (yyCh == 'n') { |
631 } else if (yyCh == 'n') { |
625 // endif |
632 // endif |
626 if (!yyIfdefStack.isEmpty()) { |
633 if (!yyIfdefStack.isEmpty()) { |
627 IfdefState is = yyIfdefStack.pop(); |
634 IfdefState is = yyIfdefStack.pop(); |
628 if (is.elseLine != -1) { |
635 if (is.elseLine != -1) { |
629 if (yyBraceDepth != is.braceDepth1st || yyParenDepth != is.parenDepth1st) |
636 if (yyBracketDepth != is.bracketDepth1st |
|
637 || yyBraceDepth != is.braceDepth1st |
|
638 || yyParenDepth != is.parenDepth1st) |
630 qWarning("%s:%d: Parenthesis/brace mismatch between " |
639 qWarning("%s:%d: Parenthesis/brace mismatch between " |
631 "#if and #else branches; using #if branch\n", |
640 "#if and #else branches; using #if branch\n", |
632 qPrintable(yyFileName), is.elseLine); |
641 qPrintable(yyFileName), is.elseLine); |
|
642 yyBracketDepth = is.bracketDepth1st; |
633 yyBraceDepth = is.braceDepth1st; |
643 yyBraceDepth = is.braceDepth1st; |
634 yyParenDepth = is.parenDepth1st; |
644 yyParenDepth = is.parenDepth1st; |
635 loadState(&is.state); |
645 loadState(&is.state); |
636 } |
646 } |
637 } |
647 } |
900 qPrintable(yyFileName), yyCurLineNo); |
910 qPrintable(yyFileName), yyCurLineNo); |
901 else |
911 else |
902 yyParenDepth--; |
912 yyParenDepth--; |
903 yyCh = getChar(); |
913 yyCh = getChar(); |
904 return Tok_RightParen; |
914 return Tok_RightParen; |
|
915 case '[': |
|
916 if (yyBracketDepth == 0) |
|
917 yyBracketLineNo = yyCurLineNo; |
|
918 yyBracketDepth++; |
|
919 yyCh = getChar(); |
|
920 return Tok_LeftBracket; |
|
921 case ']': |
|
922 if (yyBracketDepth == 0) |
|
923 qWarning("%s:%d: Excess closing bracket in C++ code" |
|
924 " (or abuse of the C++ preprocessor)\n", |
|
925 qPrintable(yyFileName), yyCurLineNo); |
|
926 else |
|
927 yyBracketDepth--; |
|
928 yyCh = getChar(); |
|
929 return Tok_RightBracket; |
905 case ',': |
930 case ',': |
906 yyCh = getChar(); |
931 yyCh = getChar(); |
907 return Tok_Comma; |
932 return Tok_Comma; |
908 case ';': |
933 case ';': |
909 yyCh = getChar(); |
934 yyCh = getChar(); |
1535 yyWord.reserve(yyInStr.size()); // Rather insane. That's because we do no length checking. |
1560 yyWord.reserve(yyInStr.size()); // Rather insane. That's because we do no length checking. |
1536 yyInPtr = (const ushort *)yyInStr.unicode(); |
1561 yyInPtr = (const ushort *)yyInStr.unicode(); |
1537 yyCh = getChar(); |
1562 yyCh = getChar(); |
1538 yyTok = getToken(); |
1563 yyTok = getToken(); |
1539 while (yyTok != Tok_Eof) { |
1564 while (yyTok != Tok_Eof) { |
|
1565 // these are array indexing operations. we ignore them entirely |
|
1566 // so they don't confuse our scoping of static initializers. |
|
1567 // we enter the loop by either reading a left bracket or by an |
|
1568 // #else popping the state. |
|
1569 while (yyBracketDepth) |
|
1570 yyTok = getToken(); |
1540 //qDebug() << "TOKEN: " << yyTok; |
1571 //qDebug() << "TOKEN: " << yyTok; |
1541 switch (yyTok) { |
1572 switch (yyTok) { |
1542 case Tok_QuotedInclude: { |
1573 case Tok_QuotedInclude: { |
1543 text = QDir(QFileInfo(yyFileName).absolutePath()).absoluteFilePath(yyWord); |
1574 text = QDir(QFileInfo(yyFileName).absolutePath()).absoluteFilePath(yyWord); |
1544 text.detach(); |
1575 text.detach(); |
2002 if (k == -1) { |
2033 if (k == -1) { |
2003 context = comment; |
2034 context = comment; |
2004 } else { |
2035 } else { |
2005 context = comment.left(k); |
2036 context = comment.left(k); |
2006 comment.remove(0, k + 1); |
2037 comment.remove(0, k + 1); |
2007 recordMessage(yyLineNo, context, QString(), comment, extracomment, |
2038 TranslatorMessage msg( |
2008 QString(), TranslatorMessage::ExtraData(), false, false); |
2039 transcode(context, false), QString(), |
|
2040 transcode(comment, false), QString(), |
|
2041 yyFileName, yyLineNo, QStringList(), |
|
2042 TranslatorMessage::Finished, false); |
|
2043 msg.setExtraComment(transcode(extracomment.simplified(), false)); |
2009 extracomment.clear(); |
2044 extracomment.clear(); |
|
2045 tor->append(msg); |
2010 tor->setExtras(extra); |
2046 tor->setExtras(extra); |
2011 extra.clear(); |
2047 extra.clear(); |
2012 } |
2048 } |
2013 } |
2049 } |
2014 } |
2050 } |
2089 qPrintable(yyFileName), yyBraceLineNo); |
2128 qPrintable(yyFileName), yyBraceLineNo); |
2090 else if (yyParenDepth != 0) |
2129 else if (yyParenDepth != 0) |
2091 qWarning("%s:%d: Unbalanced opening parenthesis in C++ code" |
2130 qWarning("%s:%d: Unbalanced opening parenthesis in C++ code" |
2092 " (or abuse of the C++ preprocessor)\n", |
2131 " (or abuse of the C++ preprocessor)\n", |
2093 qPrintable(yyFileName), yyParenLineNo); |
2132 qPrintable(yyFileName), yyParenLineNo); |
|
2133 else if (yyBracketDepth != 0) |
|
2134 qWarning("%s:%d: Unbalanced opening bracket in C++ code" |
|
2135 " (or abuse of the C++ preprocessor)\n", |
|
2136 qPrintable(yyFileName), yyBracketLineNo); |
2094 } |
2137 } |
2095 |
2138 |
2096 const ParseResults *CppParser::recordResults(bool isHeader) |
2139 const ParseResults *CppParser::recordResults(bool isHeader) |
2097 { |
2140 { |
2098 if (tor) { |
2141 if (tor) { |