📄 preprocessor.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.**** This file is part of the tools applications of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://www.trolltech.com/products/qt/opensource.html**** If you are unsure which license is appropriate for your use, please** review the following information:** http://www.trolltech.com/products/qt/licensing.html or contact the** sales department at sales@trolltech.com.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "preprocessor.h"#include "utils.h"#include "ppkeywords.cpp"#include <QStringList>#include <QFile>#include <QDir>#include <QFileInfo>QList<QByteArray> Preprocessor::includes;Macros Preprocessor::macros;bool Preprocessor::onlyPreprocess = false;QByteArray Preprocessor::protocol;QSet<QByteArray> Preprocessor::preprocessedIncludes;static inline bool hasNext(const Symbols &symbols, int i){ return (i < symbols.size()); }static inline const Symbol &next(const Symbols &symbols, int &i){ return symbols.at(i++); }static void skipUntilEndif(const Symbols &symbols, int &i){ while(i < symbols.size() - 1 && symbols.at(i).pp_token != PP_ENDIF){ switch (symbols.at(i).pp_token) { case PP_IF: case PP_IFDEF: case PP_IFNDEF: ++i; skipUntilEndif(symbols, i); break; default: ; } ++i; }}static bool skipBranch(const Symbols &symbols, int &i){ while(i < symbols.size() - 1 && (symbols.at(i).pp_token != PP_ENDIF && symbols.at(i).pp_token != PP_ELIF && symbols.at(i).pp_token != PP_ELSE) ){ switch (symbols.at(i).pp_token) { case PP_IF: case PP_IFDEF: case PP_IFNDEF: ++i; skipUntilEndif(symbols, i); break; default: ; } ++i; } return (i < symbols.size() - 1);}static QByteArray cleaned(const QByteArray &input){ QByteArray result; result.reserve(input.size()); const char *data = input; char *output = result.data(); int newlines = 0; while (*data) { while (*data && is_space(*data)) ++data; bool takeLine = (*data == '#'); if (*data == '%' && *(data+1) == ':') { takeLine = true; ++data; } if (takeLine) { *output = '#'; ++output; do ++data; while (*data && is_space(*data)); } while (*data) { if (*data == '\\' && *(data+1) == '\n') { ++newlines; data += 2; continue; } *output = *data; ++output; if (*data == '\n') { while (newlines) { *output = '\n'; ++output; --newlines; } ++data; break; } ++data; } } result.resize(output - result.constData()); return result;}enum TokenizeMode { TokenizeFile, TokenizeLine };static Symbols tokenize(const QByteArray &input, int lineNum = 1, TokenizeMode mode = TokenizeFile){ Symbols symbols; const char *begin = input; const char *data = begin; while (*data) { const char *lexem = data; int state = 0; PP_Token token = PP_NOTOKEN; for (;;) { if (static_cast<signed char>(*data) < 0) { ++data; continue; } int nextindex = pp_keywords[state].next; int next = 0; if (*data == pp_keywords[state].defchar) next = pp_keywords[state].defnext; else if (!state || nextindex) next = pp_keyword_trans[nextindex][(int)*data]; if (!next) break; state = next; token = pp_keywords[state].token; ++data; } // suboptimal, is_ident_char should use a table if (pp_keywords[state].ident && is_ident_char(*data)) token = pp_keywords[state].ident; switch (token) { case NOTOKEN: ++data; break; case PP_IFDEF: symbols += Symbol(lineNum, PP_IF, QByteArray()); symbols += Symbol(lineNum, PP_DEFINED, QByteArray()); continue; case PP_IFNDEF: symbols += Symbol(lineNum, PP_IF, QByteArray()); symbols += Symbol(lineNum, PP_NOT, QByteArray()); symbols += Symbol(lineNum, PP_DEFINED, QByteArray()); continue; case PP_QUOTE: data = skipQuote(data); token = PP_STRING_LITERAL; break; case PP_SINGLEQUOTE: while (*data && (*data != '\'' || (*(data-1)=='\\' && *(data-2)!='\\'))) ++data; if (*data) ++data; token = PP_CHARACTER_LITERAL; break; case PP_DIGIT: while (is_digit_char(*data)) ++data; if (!*data || *data != '.') { token = PP_INTEGER_LITERAL; if (data - lexem == 1 && (*data == 'x' || *data == 'X') && *lexem == '0') { ++data; while (is_hex_char(*data)) ++data; } break; } token = PP_FLOATING_LITERAL; ++data; // fall through case PP_FLOATING_LITERAL: while (is_digit_char(*data)) ++data; if (*data == '+' || *data == '-') ++data; if (*data == 'e' || *data == 'E') { ++data; while (is_digit_char(*data)) ++data; } if (*data == 'f' || *data == 'F' || *data == 'l' || *data == 'L') ++data; break; case PP_CHARACTER: while (is_ident_char(*data)) ++data; token = PP_IDENTIFIER; break; case PP_C_COMMENT: while (*data && (*(data-1) != '/' || *(data-2) != '*')) { if (*data == '\n') ++lineNum; ++data; } token = PP_WHITESPACE; // one comment, one whitespace // fall through; case PP_WHITESPACE: while (*data && (*data == ' ' || *data == '\t')) ++data; break; case PP_CPP_COMMENT: while (*data && *data != '\n') ++data; continue; // ignore safly, the newline is a seperator case PP_NEWLINE: if (mode == TokenizeLine) goto exit; ++lineNum; break; default: break; } symbols += Symbol(lineNum, token, input, lexem-begin, data-lexem); }exit: symbols += Symbol(); // eof symbol return symbols;}//static Symbols tokenize(const Symbol &symbol)//{ return tokenize(symbol.lexem(), symbol.lineNum, TokenizeLine); }static Symbols substitute(const Macros ¯os, const Symbols& symbols, int &i, bool discardWhitespace = false, QList<QByteArray> safeset = QList<QByteArray>()){ QByteArray lexem = symbols.at(i-1).lexem(); if (!macros.contains(lexem) || safeset.contains(lexem)) return Symbols(1, symbols.at(i-1)); QByteArray macro = macros.value(lexem); // ### cannot do parameters yet, TODO if (macro.size() && macro.at(0) == '(') return Symbols(1, symbols.at(i-1)); safeset += lexem; Symbols syms = tokenize(macro, symbols.at(i-1).lineNum, TokenizeLine); Symbols result; int j = 0; bool skip = false; while (hasNext(syms, j+1)) { const Symbol &sym = next(syms, j); if (discardWhitespace && sym.pp_token == PP_WHITESPACE) continue; if (sym.pp_token == PP_IDENTIFIER && !skip) result += substitute(macros, syms, j, discardWhitespace, safeset); else result += sym; skip = (sym.pp_token == PP_DEFINED || skip && sym.pp_token == PP_LPAREN); } return result;}struct PP_Expression{ PP_Expression():i(0){} Macros macros; Symbols symbols; int i; int value() { i = 0; return unary_expression_lookup() ? conditional_expression() : 0; } inline bool hasNext() const { return (i <= symbols.size()); } inline PP_Token next() { return symbols.at(i++).pp_token; } bool test(PP_Token); inline void prev() {--i;} PP_Token lookup(int k = 1); inline PP_Token token() { return symbols.at(i-1).pp_token;} inline QByteArray lexem() { return symbols.at(i-1).lexem();} int conditional_expression(); int logical_OR_expression(); int logical_AND_expression(); int inclusive_OR_expression(); int exclusive_OR_expression(); int AND_expression(); int equality_expression(); int relational_expression(); int shift_expression(); int additive_expression(); int multiplicative_expression(); int unary_expression(); bool unary_expression_lookup(); int primary_expression(); bool primary_expression_lookup();};inline bool PP_Expression::test(PP_Token token){ if (i < symbols.size() && symbols.at(i).pp_token == token) { ++i; return true; } return false;}inline PP_Token PP_Expression::lookup(int k){ const int l = i - 1 + k; return l < symbols.size() ? symbols.at(l).pp_token : PP_NOTOKEN;}int PP_Expression::conditional_expression(){ int value = logical_OR_expression(); if (test(PP_QUESTION)) { int alt1 = conditional_expression(); int alt2 = test(PP_COLON) ? conditional_expression() : 0; return value ? alt1 : alt2; } return value;}int PP_Expression::logical_OR_expression(){ int value = logical_AND_expression(); if (test(PP_OROR)) return logical_OR_expression() || value; return value;}int PP_Expression::logical_AND_expression(){ int value = inclusive_OR_expression(); if (test(PP_ANDAND)) return logical_AND_expression() && value; return value;}int PP_Expression::inclusive_OR_expression(){ int value = exclusive_OR_expression(); if (test(PP_OR)) return value | inclusive_OR_expression(); return value;}int PP_Expression::exclusive_OR_expression(){ int value = AND_expression(); if (test(PP_HAT)) return value ^ exclusive_OR_expression(); return value;}int PP_Expression::AND_expression(){ int value = equality_expression(); if (test(PP_AND)) return value & AND_expression(); return value;}int PP_Expression::equality_expression(){ int value = relational_expression(); switch (next()) { case PP_EQEQ: return value == equality_expression(); case PP_NE: return value != equality_expression(); default: prev(); return value; }}int PP_Expression::relational_expression(){ int value = shift_expression(); switch (next()) { case PP_LANGLE: return value < relational_expression(); case PP_RANGLE: return value > relational_expression(); case PP_LE: return value <= relational_expression(); case PP_GE: return value >= relational_expression(); default: prev(); return value; }}int PP_Expression::shift_expression(){ int value = additive_expression(); switch (next()) { case PP_LTLT: return value << shift_expression(); case PP_GTGT:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -