9#include <QtCore/qfile.h>
10#include <QtCore/qhash.h>
11#include <QtCore/qregularexpression.h>
12#include <QtCore/qstring.h>
13#include <QtCore/qstringconverter.h>
21#define LANGUAGE_CPP "Cpp"
26
27
28static const char *
kwords[] = {
"char",
67 "Q_DECLARE_SEQUENTIAL_ITERATOR",
68 "Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR",
69 "Q_DECLARE_ASSOCIATIVE_ITERATOR",
70 "Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR",
75 "QT_COMPAT_CONSTRUCTOR",
80 "QT3_SUPPORT_CONSTRUCTOR",
90static QRegularExpression *
comment =
nullptr;
94static QRegularExpression *
defines =
nullptr;
100
101
102
103
106 return (((uchar)s[0]) + (((uchar)s[2]) << 5) + (((uchar)s[len - 1]) << 3)) % KwordHashTableSize;
142 token_too_long_warning_was_issued =
false;
148 while (m_ch != EOF) {
155 }
while (isspace(m_ch));
156 }
else if (isalpha(m_ch) || m_ch ==
'_') {
159 }
while (isalnum(m_ch) || m_ch ==
'_');
161 int k = hashKword(m_lex,
int(m_lexLen));
166 }
else if (i == -1) {
167 if (!m_parsingMacro && ignoredTokensAndDirectives->contains(m_lex)) {
170 while (m_ch != EOF && (m_ch !=
')' || parenDepth > 1)) {
173 else if (m_ch ==
')')
182 }
else if (strcmp(m_lex, kwords[i - 1]) == 0) {
192 }
else if (isdigit(m_ch)) {
195 }
while (isalnum(m_ch) || m_ch ==
'.' || m_ch ==
'+' || m_ch ==
'-');
208 while (m_ch != EOF && m_ch !=
'"') {
217 QStringLiteral(
"Unterminated C++ string literal"),
218 QStringLiteral(
"Maybe you forgot '/*!' at the beginning of the file?"));
223 return getTokenAfterPreprocessor();
227
228
229
239
240
249 }
while (m_ch != EOF && m_ch !=
'\'');
252 m_tokLoc.warning(QStringLiteral(
"Unterminated C++ character literal"));
260 if (m_numPreprocessorSkipping == 0)
265 }
while (isspace(m_ch));
276 if (m_numPreprocessorSkipping == 0)
297 if (m_ch ==
'+' || m_ch ==
'=')
305 if (m_ch ==
'-' || m_ch ==
'=') {
307 }
else if (m_ch ==
'>') {
317 }
else if (m_ch ==
'.') {
320 }
while (m_ch ==
'.');
322 }
else if (isdigit(m_ch)) {
325 }
while (isalnum(m_ch) || m_ch ==
'.' || m_ch ==
'+' || m_ch ==
'-');
334 }
while (m_ch != EOF && m_ch !=
'\n');
335 }
else if (m_ch ==
'*') {
337 bool metSlashAsterBang =
false;
338 bool metAster =
false;
339 bool metAsterSlash =
false;
343 metSlashAsterBang =
true;
345 while (!metAsterSlash) {
347 m_tokLoc.warning(QStringLiteral(
"Unterminated C++ comment"));
352 }
else if (metAster && m_ch ==
'/') {
353 metAsterSlash =
true;
362 if (metSlashAsterBang && metDoc)
364 else if (m_parenDepth > 0)
390 }
else if (m_ch ==
'=') {
411 }
else if (m_ch ==
'=') {
422 if (m_numPreprocessorSkipping == 0)
431 if (m_numPreprocessorSkipping == 0)
436 if (m_numPreprocessorSkipping == 0)
441 if (m_numPreprocessorSkipping == 0)
446 if (m_ch ==
'|' || m_ch ==
'=')
458 if (m_numPreprocessorSkipping == 0
459 && !(m_tokLoc.fileName().endsWith(
".qdoc")
460 || m_tokLoc.fileName().endsWith(
".js"))) {
461 m_tokLoc.warning(QStringLiteral(
"Hostile character 0x%1 in C++ source")
462 .arg((uchar)m_ch, 1, 16));
469 if (m_preprocessorSkipping.size() > 1) {
470 m_tokLoc.warning(QStringLiteral(
"Expected #endif before end of file"));
472 while (!m_preprocessorSkipping.isEmpty()) {
477 strcpy(m_lex,
"end-of-input");
478 m_lexLen = strlen(m_lex);
484 Config &config = Config::instance();
486 const QLatin1String defaultEncoding(
"UTF-8");
489 if (!QStringConverter::encodingForName(sourceEncoding.toUtf8().constData())) {
490 Location().warning(QStringLiteral(
"Source encoding '%1' not supported, using '%2' as default.")
491 .arg(sourceEncoding, defaultEncoding));
492 sourceEncoding = defaultEncoding;
494 sourceDecoder = QStringDecoder(sourceEncoding.toUtf8().constData());
495 Q_ASSERT(sourceDecoder.isValid());
497 comment =
new QRegularExpression(
"/(?:\\*.*\\*/|/.*\n|/[^\n]*$)", QRegularExpression::InvertedGreedinessOption);
498 versionX =
new QRegularExpression(
"$cannot possibly match^");
499 if (!versionSym.isEmpty())
500 versionX->setPattern(
"^[ \t]*(?:" + QRegularExpression::escape(versionSym)
501 +
")[ \t]+\"([^\"]*)\"[ \t]*$");
502 definedX =
new QRegularExpression(
"^defined ?\\(?([A-Z_0-9a-z]+) ?\\)?$");
506 defines =
new QRegularExpression(QRegularExpression::anchoredPattern(d.join(
'|')));
507 falsehoods =
new QRegularExpression(QRegularExpression::anchoredPattern(
511
512
515 insertKwordIntoHash(kwords[i], i + 1);
517 ignoredTokensAndDirectives =
new QHash<QByteArray,
bool>;
522 for (
const auto &token : tokens) {
523 const QByteArray tb = token.toLatin1();
524 ignoredTokensAndDirectives->insert(tb,
false);
525 insertKwordIntoHash(tb.data(), -1);
531 for (
const auto &directive : directives) {
532 const QByteArray db = directive.toLatin1();
533 ignoredTokensAndDirectives->insert(db,
true);
534 insertKwordIntoHash(db.data(), -1);
539
540
541
542
555 delete ignoredTokensAndDirectives;
561 m_lexBuf1 =
new char[(
int)yyLexBufSize];
562 m_lexBuf2 =
new char[(
int)yyLexBufSize];
563 m_prevLex = m_lexBuf1;
568 m_preprocessorSkipping.push(
false);
569 m_numPreprocessorSkipping = 0;
574 m_parsingMacro =
false;
582 strcpy(m_prevLex,
"beginning-of-input");
583 strcpy(m_lex,
"beginning-of-input");
584 m_lexLen = strlen(m_lex);
593
594
595
596
597int Tokenizer::getTokenAfterPreprocessor()
600 while (isspace(m_ch) && m_ch !=
'\n')
604
605
609 while (isalpha(m_ch)) {
610 directive += QChar(m_ch);
613 if (!directive.isEmpty()) {
614 while (m_ch != EOF && m_ch !=
'\n') {
620 condition += QChar(m_ch);
624 condition = condition.simplified();
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643 if (directive[0] == QChar(
'i')) {
644 if (directive == QString(
"if"))
645 pushSkipping(!isTrue(condition));
646 else if (directive == QString(
"ifdef"))
647 pushSkipping(!
defines->match(condition).hasMatch());
648 else if (directive == QString(
"ifndef"))
649 pushSkipping(
defines->match(condition).hasMatch());
650 }
else if (directive[0] == QChar(
'e')) {
651 if (directive == QString(
"elif")) {
652 bool old = popSkipping();
654 pushSkipping(!isTrue(condition));
657 }
else if (directive == QString(
"else")) {
658 pushSkipping(!popSkipping());
659 }
else if (directive == QString(
"endif")) {
662 }
else if (directive == QString(
"define")) {
663 auto match =
versionX->match(condition);
664 if (match.hasMatch())
665 m_version = match.captured(1);
672
673
674
675
676 qstrcpy(m_lex, m_prevLex);
679
680
681
682
683
684
686 }
while (m_numPreprocessorSkipping > 0 && tok !=
Tok_Eoi);
691
692
693
696 m_preprocessorSkipping.push(skip);
698 m_numPreprocessorSkipping++;
702
703
706 if (m_preprocessorSkipping.isEmpty()) {
707 m_tokLoc.warning(QStringLiteral(
"Unexpected #elif, #else or #endif"));
711 bool skip = m_preprocessorSkipping.pop();
713 m_numPreprocessorSkipping--;
718
719
720
721
722
730
731
732
733
734
735
736
737
738
739 for (
int i = 0; i < condition.size() - 1; i++) {
740 QChar ch = condition[i];
741 if (ch == QChar(
'(')) {
743 }
else if (ch == QChar(
')')) {
745 }
else if (parenDepth == 0) {
746 if (condition[i + 1] == ch) {
747 if (ch == QChar(
'|')) {
750 }
else if (ch == QChar(
'&')) {
758 return isTrue(condition.left(firstOr)) || isTrue(condition.mid(firstOr + 2));
760 return isTrue(condition.left(firstAnd)) && isTrue(condition.mid(firstAnd + 2));
762 QString t = condition.simplified();
766 if (t[0] == QChar(
'!'))
767 return !isTrue(t.mid(1));
768 if (t[0] == QChar(
'(') && t.endsWith(QChar(
')')))
769 return isTrue(t.mid(1, t.size() - 2));
772 if (match.hasMatch())
773 return defines->match(match.captured(1)).hasMatch();
780 return sourceDecoder(m_lex);
785 return sourceDecoder(m_prevLex);
The Config class contains the configuration variables for controlling how qdoc produces documentation...
The Location class provides a way to mark a location in a file.
Location()
Constructs an empty location.
QString previousLexeme() const
static void terminate()
The heap allocated variables are freed here.
Tokenizer(const Location &loc, QFile &file)
Tokenizer(const Location &loc, QByteArray in)
#define CONFIG_FALSEHOODS
#define CONFIG_IGNOREDIRECTIVES
#define CONFIG_VERSIONSYM
#define CONFIG_IGNORETOKENS
#define CONFIG_SOURCEENCODING
static int kwordHashTable[KwordHashTableSize]
static QHash< QByteArray, bool > * ignoredTokensAndDirectives
static QRegularExpression * defines
static const int KwordHashTableSize
static QRegularExpression * falsehoods
static const char * kwords[]
static QRegularExpression * definedX
static QRegularExpression * comment
static QStringDecoder sourceDecoder
static int hashKword(const char *s, int len)
static void insertKwordIntoHash(const char *s, int number)
static QRegularExpression * versionX