⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 preprocessor.cpp

📁 cppcheck is a static C/C++ code analyzer that checks for memory leaks, mismatching allocation-deallo
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* * Cppcheck - A tool for static C/C++ code analysis * Copyright (C) 2007-2009 Daniel Marjamäki, Reijo Tomperi, Nicolas Le Cam, * Leandro Penz, Kimmo Varis, Vesa Pikki * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program.  If not, see <http://www.gnu.org/licenses/ */#include "preprocessor.h"#include "tokenize.h"#include "token.h"#include <algorithm>#include <sstream>#include <fstream>#include <iostream>#include <cstdlib>#include <cctype>Preprocessor::Preprocessor(){}static char readChar(std::istream &istr){    char ch = (char)istr.get();    // Handling of newlines..    if (ch == '\r')    {        ch = '\n';        if ((char)istr.peek() == '\n')            (void)istr.get();    }    return ch;}/** Just read the code into a string. Perform simple cleanup of the code */std::string Preprocessor::read(std::istream &istr){    // Get filedata from stream..    bool ignoreSpace = true;    // need space.. #if( => #if (    bool needSpace = false;    // For the error report    int lineno = 1;    // handling <backspace><newline>    // when this is encountered the <backspace><newline> will be "skipped".    // on the next <newline>, extra newlines will be added    unsigned int newlines = 0;    std::ostringstream code;    for (char ch = readChar(istr); istr.good(); ch = readChar(istr))    {        if (ch < 0)            continue;        if (ch == '\n')            ++lineno;        // Replace assorted special chars with spaces..        if ((ch != '\n') && (std::isspace(ch) || std::iscntrl(ch)))            ch = ' ';        // Skip spaces after ' ' and after '#'        if (ch == ' ' && ignoreSpace)            continue;        ignoreSpace = bool(ch == ' ' || ch == '#' || ch == '/');        if (needSpace)        {            if (ch == '(')                code << " ";            else if (! std::isalpha(ch))                needSpace = false;        }        if (ch == '#')            needSpace = true;        // Remove comments..        if (ch == '/')        {            char chNext = readChar(istr);            if (chNext == '/')            {                while (istr.good() && ch != '\n')                    ch = readChar(istr);                code << "\n";                ++lineno;            }            else if (chNext == '*')            {                char chPrev = 0;                while (istr.good() && (chPrev != '*' || ch != '/'))                {                    chPrev = ch;                    ch = readChar(istr);                    if (ch == '\n')                    {                        code << "\n";                        ++lineno;                    }                }            }            else            {                if (chNext == '\n')                    ++lineno;                code << std::string(1, ch) << std::string(1, chNext);            }        }        // String or char constants..        else if (ch == '\"' || ch == '\'')        {            code << std::string(1, ch);            char chNext;            do            {                chNext = (char)istr.get();                if (chNext == '\\')                {                    char chSeq = readChar(istr);                    if (chSeq == '\n')                        ++newlines;                    else                    {                        code << std::string(1, chNext);                        code << std::string(1, chSeq);                    }                }                else                    code << std::string(1, chNext);            }            while (istr.good() && chNext != ch);        }        // <backspace><newline>..        else if (ch == '\\')        {            char chNext = (char)istr.peek();            if (chNext == '\n' || chNext == '\r')            {                ++newlines;                (void)readChar(istr);   // Skip the "<backspace><newline>"            }            else                code << "\\";        }        // Just some code..        else        {            code << std::string(1, ch);            // if there has been <backspace><newline> sequences, add extra newlines..            if (ch == '\n' && newlines > 0)            {                code << std::string(newlines, '\n');                newlines = 0;            }        }    }    return code.str();}void Preprocessor::preprocess(std::istream &istr, std::map<std::string, std::string> &result, const std::string &filename, const std::list<std::string> &includePaths){    std::list<std::string> configs;    std::string data;    preprocess(istr, data, configs, filename, includePaths);    for (std::list<std::string>::const_iterator it = configs.begin(); it != configs.end(); ++it)        result[ *it ] = Preprocessor::getcode(data, *it);}std::string Preprocessor::removeSpaceNearNL(const std::string &str){    std::string tmp;    int prev = -1;    for (unsigned int i = 0; i < str.size(); i++)    {        if (str[i] == ' ' &&            ((i > 0 && tmp[prev] == '\n') ||             (i + 1 < str.size() && str[i+1] == '\n')            )           )        {            // Ignore space that has new line in either side of it        }        else        {            tmp.append(1, str[i]);            ++prev;        }    }    return tmp;}std::string Preprocessor::replaceIfDefined(const std::string &str){    std::string ret(str);    std::string::size_type pos = 0;    while ((pos = ret.find("#if defined(", pos)) != std::string::npos)    {        std::string::size_type pos2 = ret.find(")", pos + 9);        if (pos2 > ret.length() - 1)            break;        if (ret[pos2+1] == '\n')        {            ret.erase(pos2, 1);            ret.erase(pos + 3, 9);            ret.insert(pos + 3, "def ");        }        ++pos;    }    return ret;}void Preprocessor::preprocess(std::istream &istr, std::string &processedFile, std::list<std::string> &resultConfigurations, const std::string &filename, const std::list<std::string> &includePaths){    processedFile = read(istr);    // Replace all tabs with spaces..    std::replace(processedFile.begin(), processedFile.end(), '\t', ' ');    // Remove all indentation..    if (!processedFile.empty() && processedFile[0] == ' ')        processedFile.erase(0, processedFile.find_first_not_of(" "));    // Remove space characters that are after or before new line character    processedFile = removeSpaceNearNL(processedFile);    handleIncludes(processedFile, filename, includePaths);    processedFile = replaceIfDefined(processedFile);    // Get all possible configurations..    resultConfigurations = getcfgs(processedFile);}// Get the DEF in this line: "#ifdef DEF"std::string Preprocessor::getdef(std::string line, bool def){    // If def is true, the line must start with "#ifdef"    if (def && line.find("#ifdef ") != 0 && line.find("#if ") != 0 && line.find("#elif ") != 0)    {        return "";    }    // If def is false, the line must start with "#ifndef"    if (!def && line.find("#ifndef ") != 0)    {        return "";    }    // Remove the "#ifdef" or "#ifndef"    line.erase(0, line.find(" "));    // Remove all spaces.    while (line.find(" ") != std::string::npos)        line.erase(line.find(" "), 1);    // The remaining string is our result.    return line;}std::list<std::string> Preprocessor::getcfgs(const std::string &filedata){    std::list<std::string> ret;    ret.push_back("");    std::list<std::string> deflist;    // How deep into included files are we currently parsing?    // 0=>Source file, 1=>Included by source file, 2=>included by header that was included by source file, etc    int filelevel = 0;    std::istringstream istr(filedata);    std::string line;    while (getline(istr, line))    {        if (line.substr(0, 6) == "#file ")        {            ++filelevel;            continue;        }        else if (line == "#endfile")        {            if (filelevel > 0)                --filelevel;            continue;        }        if (filelevel > 0)            continue;        std::string def = getdef(line, true) + getdef(line, false);        if (!def.empty())        {            if (! deflist.empty() && line.find("#elif ") == 0)                deflist.pop_back();            deflist.push_back(def);            def = "";            for (std::list<std::string>::const_iterator it = deflist.begin(); it != deflist.end(); ++it)            {                if (*it == "0")                    break;                if (*it == "1")                    continue;                if (! def.empty())                    def += ";";                def += *it;            }            if (std::find(ret.begin(), ret.end(), def) == ret.end())                ret.push_back(def);        }        if (line.find("#else") == 0 && ! deflist.empty())        {            std::string def((deflist.back() == "1") ? "0" : "1");            deflist.pop_back();            deflist.push_back(def);        }        if (line.find("#endif") == 0 && ! deflist.empty())            deflist.pop_back();    }    return ret;}bool Preprocessor::match_cfg_def(std::string cfg, const std::string &def){    if (def == "0")        return false;    if (def == "1")        return true;    if (cfg.empty())        return false;    while (! cfg.empty())    {        if (cfg.find(";") == std::string::npos)            return bool(cfg == def);        std::string _cfg = cfg.substr(0, cfg.find(";"));        if (_cfg == def)            return true;        cfg.erase(0, cfg.find(";") + 1);    }    return false;}std::string Preprocessor::getcode(const std::string &filedata, std::string cfg){    std::ostringstream ret;    bool match = true;    std::list<bool> matching_ifdef;    std::list<bool> matched_ifdef;    std::istringstream istr(filedata);    std::string line;    while (getline(istr, line))    {        std::string def = getdef(line, true);        std::string ndef = getdef(line, false);        if (line.find("#elif ") == 0)        {            if (matched_ifdef.back())            {                matching_ifdef.back() = false;            }            else            {                if (match_cfg_def(cfg, def))                {                    matching_ifdef.back() = true;                    matched_ifdef.back() = true;                }            }        }        else if (! def.empty())        {            matching_ifdef.push_back(match_cfg_def(cfg, def));            matched_ifdef.push_back(matching_ifdef.back());        }        else if (! ndef.empty())        {            matching_ifdef.push_back(! match_cfg_def(cfg, ndef));            matched_ifdef.push_back(matching_ifdef.back());        }        else if (line == "#else")        {            if (! matched_ifdef.empty())                matching_ifdef.back() = ! matched_ifdef.back();        }        else if (line == "#endif")        {            if (! matched_ifdef.empty())                matched_ifdef.pop_back();            if (! matching_ifdef.empty())                matching_ifdef.pop_back();        }        if (!line.empty() && line[0] == '#')        {            match = true;            for (std::list<bool>::const_iterator it = matching_ifdef.begin(); it != matching_ifdef.end(); ++it)                match &= bool(*it);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -