Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ int main(int argc, char **argv)
{
simplecpp::TokenList *rawtokens;
if (toklist_inf == Fstream) {
rawtokens = new simplecpp::TokenList(f,files,filename,&outputList);
rawtokens = new simplecpp::TokenList(f,files,filename,dui,&outputList);
}
else if (toklist_inf == Sstream || toklist_inf == CharBuffer) {
std::ostringstream oss;
Expand All @@ -233,14 +233,14 @@ int main(int argc, char **argv)
const std::string s = oss.str();
if (toklist_inf == Sstream) {
std::istringstream iss(s);
rawtokens = new simplecpp::TokenList(iss,files,filename,&outputList);
rawtokens = new simplecpp::TokenList(iss,files,filename,dui,&outputList);
}
else {
rawtokens = new simplecpp::TokenList({s.data(),s.size()},files,filename,&outputList);
rawtokens = new simplecpp::TokenList({s.data(),s.size()},files,filename,dui,&outputList);
}
} else {
f.close();
rawtokens = new simplecpp::TokenList(filename,files,&outputList);
rawtokens = new simplecpp::TokenList(filename,files,dui,&outputList);
}
rawtokens->removeComments();
simplecpp::FileDataCache filedata;
Expand Down Expand Up @@ -276,6 +276,7 @@ int main(int argc, char **argv)
std::cerr << "directive as macro parameter: ";
break;
case simplecpp::Output::PORTABILITY_BACKSLASH:
case simplecpp::Output::PORTABILITY_LINE_DIRECTIVE:
std::cerr << "portability: ";
break;
case simplecpp::Output::PORTABILITY_NO_EOF_NEWLINE:
Expand Down
102 changes: 89 additions & 13 deletions simplecpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -475,26 +475,26 @@ namespace {

simplecpp::TokenList::TokenList(std::vector<std::string> &filenames) : frontToken(nullptr), backToken(nullptr), files(filenames) {}

simplecpp::TokenList::TokenList(std::istream &istr, std::vector<std::string> &filenames, const std::string &filename, OutputList *outputList)
simplecpp::TokenList::TokenList(std::istream &istr, std::vector<std::string> &filenames, const std::string &filename, const DUI &dui, OutputList *outputList)
: frontToken(nullptr), backToken(nullptr), files(filenames)
{
StdIStream stream(istr);
readfile(stream,filename,outputList);
readfile(stream,filename,dui,outputList);
}

simplecpp::TokenList::TokenList(const unsigned char* data, std::size_t size, std::vector<std::string> &filenames, const std::string &filename, OutputList *outputList, int /*unused*/)
simplecpp::TokenList::TokenList(const unsigned char* data, std::size_t size, std::vector<std::string> &filenames, const std::string &filename, const DUI &dui, OutputList *outputList, int /*unused*/)
: frontToken(nullptr), backToken(nullptr), files(filenames)
{
StdCharBufStream stream(data, size);
readfile(stream,filename,outputList);
readfile(stream,filename,dui,outputList);
}

simplecpp::TokenList::TokenList(const std::string &filename, std::vector<std::string> &filenames, OutputList *outputList)
simplecpp::TokenList::TokenList(const std::string &filename, std::vector<std::string> &filenames, const DUI &dui, OutputList *outputList)
: frontToken(nullptr), backToken(nullptr), files(filenames)
{
try {
FileStream stream(filename, filenames);
readfile(stream,filename,outputList);
readfile(stream,filename,dui,outputList);
} catch (const simplecpp::Output & e) {
outputList->emplace_back(e);
}
Expand Down Expand Up @@ -659,13 +659,23 @@ void simplecpp::TokenList::lineDirective(unsigned int fileIndex_, unsigned int l

static const std::string COMMENT_END("*/");

void simplecpp::TokenList::readfile(Stream &stream, const std::string &filename, OutputList *outputList)
void simplecpp::TokenList::readfile(Stream &stream, const std::string &filename, const DUI &dui, OutputList *outputList)
{
unsigned int multiline = 0U;
bool trailing_nl = true;

const Token *oldLastToken = nullptr;

const cstd_t cstd = getCStd(dui.std);
const bool std_is_c = cstd != CUnknown;
const cppstd_t cppstd = getCppStd(dui.std, std_is_c ? CPPUnknown : CPP26); // use C++26 by default

unsigned long maxline;
if ((cstd != CUnknown && cstd < C99) || (cppstd != CPPUnknown && cppstd < CPP11))
maxline = 32767;
else
maxline = 2147483647;

Location location(fileIndex(filename), 1, 1);
while (stream.good()) {
unsigned char ch = stream.readChar();
Expand Down Expand Up @@ -727,10 +737,47 @@ void simplecpp::TokenList::readfile(Stream &stream, const std::string &filename,
if (ppTok->str() == "line")
ppTok = advanceAndSkipComments(ppTok);

if (ppTok && (ppTok->str()[0] == '-' || ppTok->str()[0] == '+')) {
if (outputList) {
simplecpp::Output err{
simplecpp::Output::SYNTAX_ERROR,
location,
"Invalid character in line directive: '" + ppTok->str() + "'."
};
outputList->emplace_back(std::move(err));
}
clear();
return;
}

if (!ppTok || !ppTok->number)
continue;

const unsigned int line = std::atol(ppTok->str().c_str());
unsigned long line;
try {
line = std::stoul(ppTok->str());
} catch (...) {
line = std::numeric_limits<unsigned long>::max();
}

if (line == 0 || line > maxline) {
if (outputList) {
std::string msg = "Line number out of range: " + ppTok->str() + ". ";
if (line == 0) {
msg += "Line number zero is undefined behavior.";
} else {
msg += "Line numbers above " + std::to_string(maxline) + " are " +
(cppstd == CPP26 ? "conditionally supported" : "undefined behavior") +
" in " + (std_is_c ? getCStdName(cstd) : getCppStdName(cppstd)) + ".";
}
simplecpp::Output err{
simplecpp::Output::PORTABILITY_LINE_DIRECTIVE,
location, msg
};
outputList->emplace_back(std::move(err));
}
}

ppTok = advanceAndSkipComments(ppTok);

unsigned int fileindex;
Expand Down Expand Up @@ -3163,7 +3210,7 @@ std::pair<simplecpp::FileData *, bool> simplecpp::FileDataCache::tryload(FileDat
return {id_it->second, false};
}

auto *const data = new FileData {path, TokenList(path, filenames, outputList)};
auto *const data = new FileData {path, TokenList(path, filenames, {}, outputList)};

if (dui.removeComments)
data->tokens.removeComments();
Expand Down Expand Up @@ -3970,7 +4017,7 @@ void simplecpp::cleanup(FileDataCache &cache)
cache.clear();
}

simplecpp::cstd_t simplecpp::getCStd(const std::string &std)
simplecpp::cstd_t simplecpp::getCStd(const std::string &std, cstd_t dflt)
{
if (std == "c90" || std == "c89" || std == "iso9899:1990" || std == "iso9899:199409" || std == "gnu90" || std == "gnu89")
return C89;
Expand All @@ -3984,7 +4031,21 @@ simplecpp::cstd_t simplecpp::getCStd(const std::string &std)
return C23;
if (std == "c2y" || std == "gnu2y")
return C2Y;
return CUnknown;
return dflt;
}

const char *simplecpp::getCStdName(cstd_t std)
{
switch (std) {
case CUnknown: return "C";
case C89: return "C89";
case C99: return "C99";
case C11: return "C11";
case C17: return "C17";
case C23: return "C23";
case C2Y: return "C2Y";
}
return "";
}

std::string simplecpp::getCStdString(cstd_t std)
Expand Down Expand Up @@ -4020,7 +4081,7 @@ std::string simplecpp::getCStdString(const std::string &std)
return getCStdString(getCStd(std));
}

simplecpp::cppstd_t simplecpp::getCppStd(const std::string &std)
simplecpp::cppstd_t simplecpp::getCppStd(const std::string &std, cppstd_t dflt)
{
if (std == "c++98" || std == "c++03" || std == "gnu++98" || std == "gnu++03")
return CPP03;
Expand All @@ -4036,7 +4097,22 @@ simplecpp::cppstd_t simplecpp::getCppStd(const std::string &std)
return CPP23;
if (std == "c++26" || std == "c++2c" || std == "gnu++26" || std == "gnu++2c")
return CPP26;
return CPPUnknown;
return dflt;
}

const char *simplecpp::getCppStdName(cppstd_t std)
{
switch (std) {
case CPPUnknown: return "C++";
case CPP03: return "C++03";
case CPP11: return "C++11";
case CPP14: return "C++14";
case CPP17: return "C++17";
case CPP20: return "C++20";
case CPP23: return "C++23";
case CPP26: return "C++26";
}
return "";
}

std::string simplecpp::getCppStdString(cppstd_t std)
Expand Down
77 changes: 42 additions & 35 deletions simplecpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ namespace simplecpp {
SYNTAX_ERROR,
DIRECTIVE_AS_MACRO_PARAMETER,
PORTABILITY_BACKSLASH,
PORTABILITY_LINE_DIRECTIVE,
PORTABILITY_NO_EOF_NEWLINE,
UNHANDLED_CHAR_ERROR,
EXPLICIT_INCLUDE_NOT_FOUND,
Expand All @@ -262,52 +263,67 @@ namespace simplecpp {

using OutputList = std::list<Output>;

/**
* Command line preprocessor settings.
* On the command line these are configured by -D, -U, -I, --include, -std
*/
struct SIMPLECPP_LIB DUI {
DUI() = default;
std::list<std::string> defines;
std::set<std::string> undefined;
std::list<std::string> includePaths;
std::list<std::string> includes;
std::string std;
bool clearIncludeCache{};
bool removeComments{}; /** remove comment tokens from included files */
};

/** List of tokens. */
class SIMPLECPP_LIB TokenList {
public:
class Stream;

explicit TokenList(std::vector<std::string> &filenames);
/** generates a token list from the given std::istream parameter */
TokenList(std::istream &istr, std::vector<std::string> &filenames, const std::string &filename=std::string(), OutputList *outputList = nullptr);
TokenList(std::istream &istr, std::vector<std::string> &filenames, const std::string &filename=std::string(), const DUI &dui = {}, OutputList *outputList = nullptr);
/** generates a token list from the given buffer */
template<size_t size>
TokenList(const char (&data)[size], std::vector<std::string> &filenames, const std::string &filename=std::string(), OutputList *outputList = nullptr)
: TokenList(reinterpret_cast<const unsigned char*>(data), size-1, filenames, filename, outputList, 0)
TokenList(const char (&data)[size], std::vector<std::string> &filenames, const std::string &filename=std::string(), const DUI &dui = {}, OutputList *outputList = nullptr)
: TokenList(reinterpret_cast<const unsigned char*>(data), size-1, filenames, filename, dui, outputList, 0)
{}
/** generates a token list from the given buffer */
template<size_t size>
TokenList(const unsigned char (&data)[size], std::vector<std::string> &filenames, const std::string &filename=std::string(), OutputList *outputList = nullptr)
: TokenList(data, size-1, filenames, filename, outputList, 0)
TokenList(const unsigned char (&data)[size], std::vector<std::string> &filenames, const std::string &filename=std::string(), const DUI &dui = {}, OutputList *outputList = nullptr)
: TokenList(data, size-1, filenames, filename, dui, outputList, 0)
{}
#if SIMPLECPP_TOKENLIST_ALLOW_PTR
/** generates a token list from the given buffer */
TokenList(const unsigned char* data, std::size_t size, std::vector<std::string> &filenames, const std::string &filename=std::string(), OutputList *outputList = nullptr)
: TokenList(data, size, filenames, filename, outputList, 0)
TokenList(const unsigned char* data, std::size_t size, std::vector<std::string> &filenames, const std::string &filename=std::string(), const DUI &dui = {}, OutputList *outputList = nullptr)
: TokenList(data, size, filenames, filename, dui, outputList, 0)
{}
/** generates a token list from the given buffer */
TokenList(const char* data, std::size_t size, std::vector<std::string> &filenames, const std::string &filename=std::string(), OutputList *outputList = nullptr)
: TokenList(reinterpret_cast<const unsigned char*>(data), size, filenames, filename, outputList, 0)
TokenList(const char* data, std::size_t size, std::vector<std::string> &filenames, const std::string &filename=std::string(), const DUI &dui = {}, OutputList *outputList = nullptr)
: TokenList(reinterpret_cast<const unsigned char*>(data), size, filenames, filename, dui, outputList, 0)
{}
#endif // SIMPLECPP_TOKENLIST_ALLOW_PTR
/** generates a token list from the given buffer */
TokenList(View data, std::vector<std::string> &filenames, const std::string &filename=std::string(), OutputList *outputList = nullptr)
: TokenList(reinterpret_cast<const unsigned char*>(data.data()), data.size(), filenames, filename, outputList, 0)
TokenList(View data, std::vector<std::string> &filenames, const std::string &filename=std::string(), const DUI &dui = {}, OutputList *outputList = nullptr)
: TokenList(reinterpret_cast<const unsigned char*>(data.data()), data.size(), filenames, filename, dui, outputList, 0)
{}
#ifdef __cpp_lib_span
/** generates a token list from the given buffer */
TokenList(std::span<const char> data, std::vector<std::string> &filenames, const std::string &filename=std::string(), OutputList *outputList = nullptr)
: TokenList(reinterpret_cast<const unsigned char*>(data.data()), data.size(), filenames, filename, outputList, 0)
TokenList(std::span<const char> data, std::vector<std::string> &filenames, const std::string &filename=std::string(), const DUI &dui = {}, OutputList *outputList = nullptr)
: TokenList(reinterpret_cast<const unsigned char*>(data.data()), data.size(), filenames, filename, dui, outputList, 0)
{}

/** generates a token list from the given buffer */
TokenList(std::span<const unsigned char> data, std::vector<std::string> &filenames, const std::string &filename=std::string(), OutputList *outputList = nullptr)
: TokenList(data.data(), data.size(), filenames, filename, outputList, 0)
TokenList(std::span<const unsigned char> data, std::vector<std::string> &filenames, const std::string &filename=std::string(), const DUI &dui = {}, OutputList *outputList = nullptr)
: TokenList(data.data(), data.size(), filenames, filename, dui, outputList, 0)
{}
#endif // __cpp_lib_span

/** generates a token list from the given filename parameter */
TokenList(const std::string &filename, std::vector<std::string> &filenames, OutputList *outputList = nullptr);
TokenList(const std::string &filename, std::vector<std::string> &filenames, const DUI &dui = {}, OutputList *outputList = nullptr);
TokenList(const TokenList &other);
TokenList(TokenList &&other);
~TokenList();
Expand All @@ -323,7 +339,7 @@ namespace simplecpp {
void dump(bool linenrs = false) const;
std::string stringify(bool linenrs = false) const;

void readfile(Stream &stream, const std::string &filename=std::string(), OutputList *outputList = nullptr);
void readfile(Stream &stream, const std::string &filename=std::string(), const DUI &dui = {}, OutputList *outputList = nullptr);
/**
* @throws std::overflow_error thrown on overflow or division by zero
* @throws std::runtime_error thrown on invalid expressions
Expand Down Expand Up @@ -387,7 +403,7 @@ namespace simplecpp {
const std::string& file(const Location& loc) const;

private:
TokenList(const unsigned char* data, std::size_t size, std::vector<std::string> &filenames, const std::string &filename, OutputList *outputList, int /*unused*/);
TokenList(const unsigned char* data, std::size_t size, std::vector<std::string> &filenames, const std::string &filename, const DUI &dui, OutputList *outputList, int /*unused*/);

void combineOperators();

Expand Down Expand Up @@ -436,21 +452,6 @@ namespace simplecpp {
long long result; // condition result
};

/**
* Command line preprocessor settings.
* On the command line these are configured by -D, -U, -I, --include, -std
*/
struct SIMPLECPP_LIB DUI {
DUI() = default;
std::list<std::string> defines;
std::set<std::string> undefined;
std::list<std::string> includePaths;
std::list<std::string> includes;
std::string std;
bool clearIncludeCache{};
bool removeComments{}; /** remove comment tokens from included files */
};

struct SIMPLECPP_LIB FileData {
/** The canonical filename associated with this data */
std::string filename;
Expand Down Expand Up @@ -587,10 +588,16 @@ namespace simplecpp {
SIMPLECPP_LIB std::string convertCygwinToWindowsPath(const std::string &cygwinPath);

/** Returns the C version a given standard */
SIMPLECPP_LIB cstd_t getCStd(const std::string &std);
SIMPLECPP_LIB cstd_t getCStd(const std::string &std, cstd_t dflt = CUnknown);

/** Returns the name of a C standard */
SIMPLECPP_LIB const char *getCStdName(cstd_t std);

/** Returns the C++ version a given standard */
SIMPLECPP_LIB cppstd_t getCppStd(const std::string &std);
SIMPLECPP_LIB cppstd_t getCppStd(const std::string &std, cppstd_t dflt = CPPUnknown);

/** Returns the name of a C++ standard */
SIMPLECPP_LIB const char *getCppStdName(cppstd_t std);

/** Returns the __STDC_VERSION__ value for a given standard */
SIMPLECPP_LIB std::string getCStdString(const std::string &std);
Expand Down
Loading
Loading