cppcheck/externals/simplecpp/simplecpp.h

383 lines
12 KiB
C
Raw Normal View History

2016-07-20 12:21:00 +02:00
/*
* simplecpp - A simple and high-fidelity C/C++ preprocessor library
2022-03-22 21:14:48 +01:00
* Copyright (C) 2016-2022 Daniel Marjamäki.
2016-07-20 12:21:00 +02:00
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef simplecppH
#define simplecppH
#include <cctype>
2022-03-22 21:14:48 +01:00
#include <cstring>
2016-07-20 12:21:00 +02:00
#include <istream>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#ifdef _WIN32
# ifdef SIMPLECPP_EXPORT
# define SIMPLECPP_LIB __declspec(dllexport)
# elif defined(SIMPLECPP_IMPORT)
# define SIMPLECPP_LIB __declspec(dllimport)
# else
# define SIMPLECPP_LIB
# endif
#else
# define SIMPLECPP_LIB
#endif
2022-03-22 21:14:48 +01:00
#if (__cplusplus < 201103L) && !defined(__APPLE__)
#define nullptr NULL
#endif
2023-09-13 10:30:42 +02:00
#if defined(_MSC_VER)
# pragma warning(push)
// suppress warnings about "conversion from 'type1' to 'type2', possible loss of data"
# pragma warning(disable : 4267)
# pragma warning(disable : 4244)
#endif
2016-07-20 12:21:00 +02:00
namespace simplecpp {
typedef std::string TokenString;
2022-03-22 21:14:48 +01:00
class Macro;
/**
* Location in source code
*/
class SIMPLECPP_LIB Location {
public:
explicit Location(const std::vector<std::string> &f) : files(f), fileIndex(0), line(1U), col(0U) {}
2017-08-13 13:59:09 +02:00
Location(const Location &loc) : files(loc.files), fileIndex(loc.fileIndex), line(loc.line), col(loc.col) {}
Location &operator=(const Location &other) {
if (this != &other) {
fileIndex = other.fileIndex;
line = other.line;
col = other.col;
}
return *this;
}
2016-07-20 12:21:00 +02:00
/** increment this location by string */
void adjust(const std::string &str);
bool operator<(const Location &rhs) const {
if (fileIndex != rhs.fileIndex)
return fileIndex < rhs.fileIndex;
if (line != rhs.line)
return line < rhs.line;
return col < rhs.col;
2016-07-20 12:21:00 +02:00
}
bool sameline(const Location &other) const {
return fileIndex == other.fileIndex && line == other.line;
2016-07-23 09:26:06 +02:00
}
2016-07-31 20:48:55 +02:00
const std::string& file() const {
2017-08-13 13:59:09 +02:00
return fileIndex < files.size() ? files[fileIndex] : emptyFileName;
}
const std::vector<std::string> &files;
unsigned int fileIndex;
unsigned int line;
unsigned int col;
2017-08-13 13:59:09 +02:00
private:
2018-05-14 13:00:22 +02:00
static const std::string emptyFileName;
};
/**
* token class.
* @todo don't use std::string representation - for both memory and performance reasons
*/
class SIMPLECPP_LIB Token {
public:
Token(const TokenString &s, const Location &loc) :
2022-03-22 21:14:48 +01:00
location(loc), previous(nullptr), next(nullptr), string(s) {
flags();
}
Token(const Token &tok) :
2022-03-22 21:14:48 +01:00
macro(tok.macro), op(tok.op), comment(tok.comment), name(tok.name), number(tok.number), location(tok.location), previous(nullptr), next(nullptr), string(tok.string), mExpandedFrom(tok.mExpandedFrom) {
}
void flags() {
2022-03-22 21:14:48 +01:00
name = (std::isalpha(static_cast<unsigned char>(string[0])) || string[0] == '_' || string[0] == '$')
&& (std::memchr(string.c_str(), '\'', string.size()) == nullptr);
2019-05-03 18:49:48 +02:00
comment = string.size() > 1U && string[0] == '/' && (string[1] == '/' || string[1] == '*');
2023-03-13 16:11:46 +01:00
number = std::isdigit(static_cast<unsigned char>(string[0])) || (string.size() > 1U && (string[0] == '-' || string[0] == '+') && std::isdigit(static_cast<unsigned char>(string[1])));
op = (string.size() == 1U && !name && !comment && !number) ? string[0] : '\0';
}
2018-10-09 21:17:38 +02:00
const TokenString& str() const {
return string;
}
void setstr(const std::string &s) {
string = s;
flags();
}
bool isOneOf(const char ops[]) const;
bool startsWithOneOf(const char c[]) const;
bool endsWithOneOf(const char c[]) const;
TokenString macro;
char op;
bool comment;
bool name;
bool number;
Location location;
Token *previous;
Token *next;
const Token *previousSkipComments() const {
const Token *tok = this->previous;
while (tok && tok->comment)
tok = tok->previous;
return tok;
}
const Token *nextSkipComments() const {
const Token *tok = this->next;
while (tok && tok->comment)
tok = tok->next;
return tok;
}
2022-03-22 21:14:48 +01:00
void setExpandedFrom(const Token *tok, const Macro* m) {
2021-12-16 21:18:05 +01:00
mExpandedFrom = tok->mExpandedFrom;
mExpandedFrom.insert(m);
}
2022-03-22 21:14:48 +01:00
bool isExpandedFrom(const Macro* m) const {
2021-12-16 21:18:05 +01:00
return mExpandedFrom.find(m) != mExpandedFrom.end();
}
void printAll() const;
void printOut() const;
private:
TokenString string;
2017-08-13 13:59:09 +02:00
2022-03-22 21:14:48 +01:00
std::set<const Macro*> mExpandedFrom;
2021-12-16 21:18:05 +01:00
2017-08-13 13:59:09 +02:00
// Not implemented - prevent assignment
Token &operator=(const Token &tok);
};
/** Output from preprocessor */
struct SIMPLECPP_LIB Output {
explicit Output(const std::vector<std::string> &files) : type(ERROR), location(files) {}
enum Type {
ERROR, /* #error */
WARNING, /* #warning */
MISSING_HEADER,
INCLUDE_NESTED_TOO_DEEPLY,
SYNTAX_ERROR,
2017-09-12 22:42:10 +02:00
PORTABILITY_BACKSLASH,
UNHANDLED_CHAR_ERROR,
EXPLICIT_INCLUDE_NOT_FOUND
} type;
Location location;
std::string msg;
};
typedef std::list<Output> OutputList;
/** List of tokens. */
class SIMPLECPP_LIB TokenList {
public:
2023-03-13 16:11:46 +01:00
class Stream;
explicit TokenList(std::vector<std::string> &filenames);
2023-03-13 16:11:46 +01:00
/** generates a token list from the given std::istream parameter */
2022-03-22 21:14:48 +01:00
TokenList(std::istream &istr, std::vector<std::string> &filenames, const std::string &filename=std::string(), OutputList *outputList = nullptr);
2023-03-13 16:11:46 +01:00
/** generates a token list from the given filename parameter */
TokenList(const std::string &filename, std::vector<std::string> &filenames, OutputList *outputList = nullptr);
TokenList(const TokenList &other);
2019-05-03 18:49:48 +02:00
#if __cplusplus >= 201103L
TokenList(TokenList &&other);
#endif
~TokenList();
2017-08-13 13:59:09 +02:00
TokenList &operator=(const TokenList &other);
2019-05-03 18:49:48 +02:00
#if __cplusplus >= 201103L
TokenList &operator=(TokenList &&other);
#endif
void clear();
bool empty() const {
return !frontToken;
}
2017-08-13 13:59:09 +02:00
void push_back(Token *tok);
void dump() const;
std::string stringify() const;
2023-03-13 16:11:46 +01:00
void readfile(Stream &stream, const std::string &filename=std::string(), OutputList *outputList = nullptr);
void constFold();
void removeComments();
Token *front() {
return frontToken;
}
const Token *cfront() const {
return frontToken;
}
Token *back() {
return backToken;
}
const Token *cback() const {
return backToken;
}
void deleteToken(Token *tok) {
if (!tok)
return;
2022-09-30 07:26:48 +02:00
Token * const prev = tok->previous;
Token * const next = tok->next;
if (prev)
prev->next = next;
if (next)
next->previous = prev;
if (frontToken == tok)
frontToken = next;
if (backToken == tok)
backToken = prev;
delete tok;
}
void takeTokens(TokenList &other) {
if (!other.frontToken)
return;
if (!frontToken) {
frontToken = other.frontToken;
} else {
backToken->next = other.frontToken;
other.frontToken->previous = backToken;
}
backToken = other.backToken;
2022-03-22 21:14:48 +01:00
other.frontToken = other.backToken = nullptr;
}
/** sizeof(T) */
std::map<std::string, std::size_t> sizeOfType;
private:
void combineOperators();
void constFoldUnaryNotPosNeg(Token *tok);
void constFoldMulDivRem(Token *tok);
void constFoldAddSub(Token *tok);
2017-09-08 23:20:39 +02:00
void constFoldShift(Token *tok);
void constFoldComparison(Token *tok);
void constFoldBitwise(Token *tok);
void constFoldLogicalOp(Token *tok);
2017-08-13 13:59:09 +02:00
void constFoldQuestionOp(Token **tok1);
2023-03-13 16:11:46 +01:00
std::string readUntil(Stream &stream, const Location &location, char start, char end, OutputList *outputList);
2019-05-03 18:49:48 +02:00
void lineDirective(unsigned int fileIndex, unsigned int line, Location *location);
2023-09-13 10:30:42 +02:00
std::string lastLine(int maxsize=1000) const;
2022-03-22 21:14:48 +01:00
bool isLastLinePreprocessor(int maxsize=100000) const;
unsigned int fileIndex(const std::string &filename);
Token *frontToken;
Token *backToken;
std::vector<std::string> &files;
};
/** Tracking how macros are used */
struct SIMPLECPP_LIB MacroUsage {
explicit MacroUsage(const std::vector<std::string> &f, bool macroValueKnown_) : macroLocation(f), useLocation(f), macroValueKnown(macroValueKnown_) {}
std::string macroName;
Location macroLocation;
Location useLocation;
bool macroValueKnown;
};
2021-07-21 20:29:00 +02:00
/** Tracking #if/#elif expressions */
struct SIMPLECPP_LIB IfCond {
explicit IfCond(const Location& location, const std::string &E, long long result) : location(location), E(E), result(result) {}
Location location; // location of #if/#elif
std::string E; // preprocessed condition
long long result; // condition result
};
2018-01-13 18:08:23 +01:00
/**
* Command line preprocessor settings.
2021-04-26 16:25:39 +02:00
* On the command line these are configured by -D, -U, -I, --include, -std
2018-01-13 18:08:23 +01:00
*/
struct SIMPLECPP_LIB DUI {
DUI() : clearIncludeCache(false) {}
std::list<std::string> defines;
std::set<std::string> undefined;
std::list<std::string> includePaths;
std::list<std::string> includes;
2021-04-26 16:25:39 +02:00
std::string std;
bool clearIncludeCache;
};
2021-04-30 17:41:59 +02:00
SIMPLECPP_LIB long long characterLiteralToLL(const std::string& str);
2022-03-22 21:14:48 +01:00
SIMPLECPP_LIB std::map<std::string, TokenList*> load(const TokenList &rawtokens, std::vector<std::string> &filenames, const DUI &dui, OutputList *outputList = nullptr);
/**
* Preprocess
* @todo simplify interface
* @param output TokenList that receives the preprocessing output
* @param rawtokens Raw tokenlist for top sourcefile
* @param files internal data of simplecpp
* @param filedata output from simplecpp::load()
* @param dui defines, undefs, and include paths
* @param outputList output: list that will receive output messages
* @param macroUsage output: macro usage
2021-07-21 20:29:00 +02:00
* @param ifCond output: #if/#elif expressions
*/
2022-03-22 21:14:48 +01:00
SIMPLECPP_LIB void preprocess(TokenList &output, const TokenList &rawtokens, std::vector<std::string> &files, std::map<std::string, TokenList*> &filedata, const DUI &dui, OutputList *outputList = nullptr, std::list<MacroUsage> *macroUsage = nullptr, std::list<IfCond> *ifCond = nullptr);
/**
* Deallocate data
*/
SIMPLECPP_LIB void cleanup(std::map<std::string, TokenList*> &filedata);
2017-06-21 14:27:08 +02:00
/** Simplify path */
SIMPLECPP_LIB std::string simplifyPath(std::string path);
2019-03-10 08:47:27 +01:00
/** Convert Cygwin path to Windows path */
SIMPLECPP_LIB std::string convertCygwinToWindowsPath(const std::string &cygwinPath);
2022-03-22 21:14:48 +01:00
/** Returns the __STDC_VERSION__ value for a given standard */
SIMPLECPP_LIB std::string getCStdString(const std::string &std);
/** Returns the __cplusplus value for a given standard */
SIMPLECPP_LIB std::string getCppStdString(const std::string &std);
2016-07-20 12:21:00 +02:00
}
2023-09-13 10:30:42 +02:00
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
2022-03-22 21:14:48 +01:00
#if (__cplusplus < 201103L) && !defined(__APPLE__)
#undef nullptr
#endif
2016-07-20 12:21:00 +02:00
#endif