📄 preprocessor.cpp
字号:
return value >> shift_expression(); default: prev(); return value; }}int PP_Expression::additive_expression(){ int value = multiplicative_expression(); switch (next()) { case PP_PLUS: return value + additive_expression(); case PP_MINUS: return value - additive_expression(); default: prev(); return value; }}int PP_Expression::multiplicative_expression(){ int value = unary_expression(); switch (next()) { case PP_STAR: return value * multiplicative_expression(); case PP_PERCENT: { int remainder = multiplicative_expression(); return remainder ? value % remainder : 0; } case PP_SLASH: { int div = multiplicative_expression(); return div ? value / div : 0; } default: prev(); return value; };}int PP_Expression::unary_expression(){ switch (next()) { case PP_PLUS: return unary_expression(); case PP_MINUS: return -unary_expression(); case PP_NOT: return !unary_expression(); case PP_TILDE: return ~unary_expression(); case PP_DEFINED: { QByteArray identifier; if (test(PP_IDENTIFIER)) { identifier = lexem(); } else if (test(PP_LPAREN)) { if (test(PP_IDENTIFIER)) identifier = lexem(); test(PP_RPAREN); } return macros.contains(identifier); } default: prev(); return primary_expression(); }}bool PP_Expression::unary_expression_lookup(){ PP_Token t = lookup(); return (primary_expression_lookup() || t == PP_PLUS || t == PP_MINUS || t == PP_NOT || t == PP_TILDE || t == PP_DEFINED);}int PP_Expression::primary_expression(){ int value; if (test(PP_LPAREN)) { value = conditional_expression(); test(PP_RPAREN); } else { next(); value = QString(lexem()).toInt(0, 0); } return value;}bool PP_Expression::primary_expression_lookup(){ PP_Token t = lookup(); return (t == PP_IDENTIFIER || t == PP_INTEGER_LITERAL || t == PP_FLOATING_LITERAL || t == PP_LPAREN);}static int evaluateCondition(const Macros ¯os, const Symbols &symbols, int &i){ PP_Expression expression; expression.macros = macros; bool skip = false; while (hasNext(symbols, i)) { const Symbol &sym = next(symbols, i); if (sym.pp_token == PP_WHITESPACE) continue; if (sym.pp_token == PP_IDENTIFIER && macros.contains(sym.lexem()) && !skip) expression.symbols += substitute(macros, symbols, i, true); else expression.symbols += sym; if (sym.pp_token == PP_NEWLINE) break; skip = (sym.pp_token == PP_DEFINED || skip && sym.pp_token == PP_LPAREN); } return expression.value();}static inline QByteArray lexemUntil(const Symbols &symbols, int i, PP_Token token){ QByteArray s; while (i < symbols.size() && symbols.at(i).pp_token != token) { s += symbols.at(i).lexem(); ++i; } return s;}static inline void until(const Symbols &symbols, int &i, PP_Token token){ while (i < symbols.size() && symbols.at(i).pp_token != token) { ++i; }}static void preprocess(const QByteArray &filename, const Symbols &symbols, Macros ¯os, Symbols &preprocessed);static Symbols preprocess(const QByteArray &filename, const Symbols &symbols, Macros ¯os){ Symbols preprocessed; preprocess(filename, symbols, macros, preprocessed); return preprocessed;}static void preprocess(const QByteArray &filename, const Symbols &symbols, Macros ¯os, Symbols &preprocessed){ static int depth = 0; preprocessed.reserve(preprocessed.size() + symbols.size()); int i = 0; bool skipUntilNewLine = false; while (hasNext(symbols,i)) { if (skipUntilNewLine) { until(symbols, i, PP_NEWLINE); // skip the newline token if (hasNext(symbols, i)) ++i; skipUntilNewLine = false; continue; } Symbol sym = next(symbols, i); // preprocessor statements always end with a PP_NEWLINE. Some of the // statement handlers operate on the actual lexical elements until the // newline and others (like evaluationCondition) operate on the tokens // directly. That's why we can't skip to PP_NEWLINE here but we have to // do it in the next loop iteration, using skipUntilNewLine. QByteArray statementLexem; if (sym.pp_token >= PP_FIRST_STATEMENT && sym.pp_token <= PP_LAST_STATEMENT) { int lexemIndex = i; if (hasNext(symbols, lexemIndex) && symbols.at(lexemIndex).pp_token == PP_WHITESPACE) ++lexemIndex; statementLexem = lexemUntil(symbols, lexemIndex, PP_NEWLINE); skipUntilNewLine = true; } switch (sym.pp_token) { case PP_INCLUDE: { QByteArray include = statementLexem; const char *data = include.constData(); while (*data && is_whitespace(*data)) ++data; const char *name = data++; if (*name == '\"') while (*data && *data != '\"') ++data; else if (*name == '<') while (*data && *data != '>') ++data; else continue; bool local = (*name == '\"'); include = QByteArray(name + 1, data - name - 1); // #### stringery QFileInfo fi; if (local) fi.setFile(QFileInfo(QString::fromLocal8Bit(filename)).dir(), QString::fromLocal8Bit(include)); for (int j = 0; j < Preprocessor::includes.size() && !fi.exists(); ++j) fi.setFile(QString::fromLocal8Bit(Preprocessor::includes.at(j)), QString::fromLocal8Bit(include)); if (!fi.exists()) continue; include = fi.filePath().toLocal8Bit(); if (Preprocessor::preprocessedIncludes.contains(include)) continue; Preprocessor::preprocessedIncludes.insert(include); QFile file(QString::fromLocal8Bit(include)); if (!file.open(QFile::ReadOnly|QFile::Text)) continue; if (Preprocessor::onlyPreprocess) { Preprocessor::protocol += "#"; Preprocessor::protocol += QByteArray(depth * 2, ' '); Preprocessor::protocol += "include \""; Preprocessor::protocol += include; Preprocessor::protocol += "\"\n"; }// qDebug("... include %s", include.constData()); QByteArray input = file.readAll(); file.close(); if (input.isEmpty()) continue; // phase 1: get rid of backslash-newlines QByteArray phase1 = cleaned(input); // phase 2: tokenize for the preprocessor Symbols symbols = tokenize(phase1); // phase 3: preprocess conditions and substitute macros ++depth; Symbol includeSym; includeSym.lexem_data = "\n#moc_include_begin \""; includeSym.lexem_data += include; includeSym.lexem_data += "\"\n"; preprocessed += includeSym; preprocess(include, symbols, macros, preprocessed); includeSym.lexem_data = "\n#moc_include_end "; includeSym.lexem_data += QByteArray::number(sym.lineNum); includeSym.lineNum = sym.lineNum; includeSym.pp_token = PP_MOC_INCLUDE_END; preprocessed += includeSym; --depth; continue; } case PP_DEFINE: { QByteArray macro = statementLexem; const char *data = macro.constData(); while (*data && is_whitespace(*data)) ++data; if (!is_ident_start(*data)) continue; const char *ident = data++; while (*data && is_ident_char(*data)) ++data; QByteArray name(ident, data - ident); macros[name] = data; if (Preprocessor::onlyPreprocess) { Preprocessor::protocol += "#"; Preprocessor::protocol += QByteArray(depth * 2, ' '); Preprocessor::protocol += "define "; Preprocessor::protocol += name; Preprocessor::protocol += "\n"; } continue; } case PP_UNDEF: { QByteArray macro = statementLexem; const char *data = macro.constData(); while (*data && is_whitespace(*data)) ++data; if (!is_ident_start(*data)) continue; const char *ident = data++; while (*data && is_ident_char(*data)) ++data; QByteArray name(ident, data - ident); macros.remove(name); if (Preprocessor::onlyPreprocess) { Preprocessor::protocol += "#"; Preprocessor::protocol += QByteArray(depth * 2, ' '); Preprocessor::protocol += "undef "; Preprocessor::protocol += name; Preprocessor::protocol += "\n"; } continue; } case PP_IDENTIFIER: // we _could_ easily substitute macros by the following // four lines, but we choose not to. /* if (macros.contains(sym.lexem())) { preprocessed += substitute(macros, symbols, i); continue; } */ break; case PP_QT_SIGNALS: case PP_QT_SLOTS: if (macros.contains("QT_NO_KEYWORDS")) { Symbol treatIdentSym; treatIdentSym.lexem_data = "#moc_next_is_identifier "; preprocessed += treatIdentSym; } break; case PP_HASH: continue; // skip unknown preprocessor statement case PP_IFDEF: case PP_IFNDEF: case PP_IF: while (!evaluateCondition(macros, symbols, i)) { if (!skipBranch(symbols, i)) break; sym = next(symbols, i); if (sym.pp_token != PP_ELIF) break; } // evaluateCondition already does the job of skipping // over the newline, so don't do it twice and accidentially // lose tokens by that skipUntilNewLine = false; continue; case PP_ELIF: case PP_ELSE: skipUntilEndif(symbols, i); // fall through case PP_ENDIF: continue; default: break; } preprocessed += sym; }}QByteArray Preprocessor::preprocessed(const QByteArray &filename, FILE *file){ QByteArray output; QFile qfile; qfile.open(file, QFile::ReadOnly|QFile::Text); QByteArray input = qfile.readAll(); if (input.isEmpty()) return output; // phase 1: get rid of backslash-newlines QByteArray phase1 = cleaned(input); // phase 2: tokenize for the preprocessor Symbols symbols = tokenize(phase1);#if 0 for (int j = 0; j < symbols.size(); ++j) qDebug("line %d: %s(%d)", symbols[j].lineNum, symbols[j].lexem().constData(), symbols[j].token);#endif // phase 3: preprocess conditions and substitute macros symbols = preprocess(filename, symbols, macros); // final phase: compose string for the C++ scanner int lineNum = 1; PP_Token last = PP_NOTOKEN; PP_Token secondlast = last; int i = 0; while (hasNext(symbols, i)) { Symbol sym = next(symbols, i); switch (sym.pp_token) { case PP_NEWLINE: case PP_WHITESPACE: if (last != PP_WHITESPACE) { secondlast = last; last = PP_WHITESPACE; output += ' '; } continue; case PP_STRING_LITERAL: if (last == PP_STRING_LITERAL) output.chop(1); else if (secondlast == PP_STRING_LITERAL && last == PP_WHITESPACE) output.chop(2); else break; output += sym.lexem().mid(1); secondlast = last; last = PP_STRING_LITERAL; continue; case PP_MOC_INCLUDE_END: lineNum = sym.lineNum; break; default: break; } secondlast = last; last = sym.pp_token; const int padding = sym.lineNum - lineNum; if (padding > 0) { output.resize(output.size() + padding); qMemSet(output.data() + output.size() - padding, '\n', padding); lineNum = sym.lineNum; } output += sym.lexem(); } return output;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -