Bump simplecpp
This commit is contained in:
parent
d376201cb4
commit
0725aa3f8b
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* simplecpp - A simple and high-fidelity C/C++ preprocessor library
|
* simplecpp - A simple and high-fidelity C/C++ preprocessor library
|
||||||
* Copyright (C) 2016 Daniel Marjamäki.
|
* Copyright (C) 2016-2022 Daniel Marjamäki.
|
||||||
*
|
*
|
||||||
* This library is free software: you can redistribute it and/or
|
* This library is free software: you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -24,16 +24,18 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <ctime>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <fstream> // IWYU pragma: keep
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <sstream> // IWYU pragma: keep
|
#include <sstream>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <type_traits>
|
#if __cplusplus >= 201103L
|
||||||
|
#include <unordered_map>
|
||||||
|
#endif
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#ifdef SIMPLECPP_WINDOWS
|
#ifdef SIMPLECPP_WINDOWS
|
||||||
|
@ -42,6 +44,10 @@
|
||||||
#undef TRUE
|
#undef TRUE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (__cplusplus < 201103L) && !defined(__APPLE__)
|
||||||
|
#define nullptr NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
static bool isHex(const std::string &s)
|
static bool isHex(const std::string &s)
|
||||||
{
|
{
|
||||||
return s.size()>2 && (s.compare(0,2,"0x")==0 || s.compare(0,2,"0X")==0);
|
return s.size()>2 && (s.compare(0,2,"0x")==0 || s.compare(0,2,"0X")==0);
|
||||||
|
@ -52,6 +58,19 @@ static bool isOct(const std::string &s)
|
||||||
return s.size()>1 && (s[0]=='0') && (s[1] >= '0') && (s[1] < '8');
|
return s.size()>1 && (s[0]=='0') && (s[1] >= '0') && (s[1] < '8');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: added an undercore since this conflicts with a function of the same name in utils.h from Cppcheck source when building Cppcheck with MSBuild
|
||||||
|
static bool isStringLiteral_(const std::string &s)
|
||||||
|
{
|
||||||
|
return s.size() > 1 && (s[0]=='\"') && (*s.rbegin()=='\"');
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: added an undercore since this conflicts with a function of the same name in utils.h from Cppcheck source when building Cppcheck with MSBuild
|
||||||
|
static bool isCharLiteral_(const std::string &s)
|
||||||
|
{
|
||||||
|
// char literal patterns can include 'a', '\t', '\000', '\xff', 'abcd', and maybe ''
|
||||||
|
// This only checks for the surrounding '' but doesn't parse the content.
|
||||||
|
return s.size() > 1 && (s[0]=='\'') && (*s.rbegin()=='\'');
|
||||||
|
}
|
||||||
|
|
||||||
static const simplecpp::TokenString DEFINE("define");
|
static const simplecpp::TokenString DEFINE("define");
|
||||||
static const simplecpp::TokenString UNDEF("undef");
|
static const simplecpp::TokenString UNDEF("undef");
|
||||||
|
@ -152,7 +171,7 @@ const std::string simplecpp::Location::emptyFileName;
|
||||||
|
|
||||||
void simplecpp::Location::adjust(const std::string &str)
|
void simplecpp::Location::adjust(const std::string &str)
|
||||||
{
|
{
|
||||||
if (str.find_first_of("\r\n") == std::string::npos) {
|
if (strpbrk(str.c_str(), "\r\n") == nullptr) {
|
||||||
col += str.size();
|
col += str.size();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -170,17 +189,17 @@ void simplecpp::Location::adjust(const std::string &str)
|
||||||
|
|
||||||
bool simplecpp::Token::isOneOf(const char ops[]) const
|
bool simplecpp::Token::isOneOf(const char ops[]) const
|
||||||
{
|
{
|
||||||
return (op != '\0') && (std::strchr(ops, op) != NULL);
|
return (op != '\0') && (std::strchr(ops, op) != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool simplecpp::Token::startsWithOneOf(const char c[]) const
|
bool simplecpp::Token::startsWithOneOf(const char c[]) const
|
||||||
{
|
{
|
||||||
return std::strchr(c, string[0]) != NULL;
|
return std::strchr(c, string[0]) != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool simplecpp::Token::endsWithOneOf(const char c[]) const
|
bool simplecpp::Token::endsWithOneOf(const char c[]) const
|
||||||
{
|
{
|
||||||
return std::strchr(c, string[string.size() - 1U]) != NULL;
|
return std::strchr(c, string[string.size() - 1U]) != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void simplecpp::Token::printAll() const
|
void simplecpp::Token::printAll() const
|
||||||
|
@ -208,21 +227,21 @@ void simplecpp::Token::printOut() const
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
simplecpp::TokenList::TokenList(std::vector<std::string> &filenames) : frontToken(NULL), backToken(NULL), files(filenames) {}
|
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, OutputList *outputList)
|
||||||
: frontToken(NULL), backToken(NULL), files(filenames)
|
: frontToken(nullptr), backToken(nullptr), files(filenames)
|
||||||
{
|
{
|
||||||
readfile(istr,filename,outputList);
|
readfile(istr,filename,outputList);
|
||||||
}
|
}
|
||||||
|
|
||||||
simplecpp::TokenList::TokenList(const TokenList &other) : frontToken(NULL), backToken(NULL), files(other.files)
|
simplecpp::TokenList::TokenList(const TokenList &other) : frontToken(nullptr), backToken(nullptr), files(other.files)
|
||||||
{
|
{
|
||||||
*this = other;
|
*this = other;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __cplusplus >= 201103L
|
#if __cplusplus >= 201103L
|
||||||
simplecpp::TokenList::TokenList(TokenList &&other) : frontToken(NULL), backToken(NULL), files(other.files)
|
simplecpp::TokenList::TokenList(TokenList &&other) : TokenList(other)
|
||||||
{
|
{
|
||||||
*this = std::move(other);
|
*this = std::move(other);
|
||||||
}
|
}
|
||||||
|
@ -237,6 +256,7 @@ simplecpp::TokenList &simplecpp::TokenList::operator=(const TokenList &other)
|
||||||
{
|
{
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
clear();
|
clear();
|
||||||
|
files = other.files;
|
||||||
for (const Token *tok = other.cfront(); tok; tok = tok->next)
|
for (const Token *tok = other.cfront(); tok; tok = tok->next)
|
||||||
push_back(new Token(*tok));
|
push_back(new Token(*tok));
|
||||||
sizeOfType = other.sizeOfType;
|
sizeOfType = other.sizeOfType;
|
||||||
|
@ -249,10 +269,11 @@ simplecpp::TokenList &simplecpp::TokenList::operator=(TokenList &&other)
|
||||||
{
|
{
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
clear();
|
clear();
|
||||||
backToken = other.backToken;
|
|
||||||
other.backToken = NULL;
|
|
||||||
frontToken = other.frontToken;
|
frontToken = other.frontToken;
|
||||||
other.frontToken = NULL;
|
other.frontToken = nullptr;
|
||||||
|
backToken = other.backToken;
|
||||||
|
other.backToken = nullptr;
|
||||||
|
files = other.files;
|
||||||
sizeOfType = std::move(other.sizeOfType);
|
sizeOfType = std::move(other.sizeOfType);
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -261,7 +282,7 @@ simplecpp::TokenList &simplecpp::TokenList::operator=(TokenList &&other)
|
||||||
|
|
||||||
void simplecpp::TokenList::clear()
|
void simplecpp::TokenList::clear()
|
||||||
{
|
{
|
||||||
backToken = NULL;
|
backToken = nullptr;
|
||||||
while (frontToken) {
|
while (frontToken) {
|
||||||
Token *next = frontToken->next;
|
Token *next = frontToken->next;
|
||||||
delete frontToken;
|
delete frontToken;
|
||||||
|
@ -313,20 +334,20 @@ std::string simplecpp::TokenList::stringify() const
|
||||||
|
|
||||||
static unsigned char readChar(std::istream &istr, unsigned int bom)
|
static unsigned char readChar(std::istream &istr, unsigned int bom)
|
||||||
{
|
{
|
||||||
unsigned char ch = (unsigned char)istr.get();
|
unsigned char ch = static_cast<unsigned char>(istr.get());
|
||||||
|
|
||||||
// For UTF-16 encoded files the BOM is 0xfeff/0xfffe. If the
|
// For UTF-16 encoded files the BOM is 0xfeff/0xfffe. If the
|
||||||
// character is non-ASCII character then replace it with 0xff
|
// character is non-ASCII character then replace it with 0xff
|
||||||
if (bom == 0xfeff || bom == 0xfffe) {
|
if (bom == 0xfeff || bom == 0xfffe) {
|
||||||
const unsigned char ch2 = (unsigned char)istr.get();
|
const unsigned char ch2 = static_cast<unsigned char>(istr.get());
|
||||||
const int ch16 = (bom == 0xfeff) ? (ch<<8 | ch2) : (ch2<<8 | ch);
|
const int ch16 = (bom == 0xfeff) ? (ch<<8 | ch2) : (ch2<<8 | ch);
|
||||||
ch = (unsigned char)((ch16 >= 0x80) ? 0xff : ch16);
|
ch = static_cast<unsigned char>(((ch16 >= 0x80) ? 0xff : ch16));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handling of newlines..
|
// Handling of newlines..
|
||||||
if (ch == '\r') {
|
if (ch == '\r') {
|
||||||
ch = '\n';
|
ch = '\n';
|
||||||
if (bom == 0 && (char)istr.peek() == '\n')
|
if (bom == 0 && static_cast<char>(istr.peek()) == '\n')
|
||||||
(void)istr.get();
|
(void)istr.get();
|
||||||
else if (bom == 0xfeff || bom == 0xfffe) {
|
else if (bom == 0xfeff || bom == 0xfffe) {
|
||||||
int c1 = istr.get();
|
int c1 = istr.get();
|
||||||
|
@ -344,16 +365,16 @@ static unsigned char readChar(std::istream &istr, unsigned int bom)
|
||||||
|
|
||||||
static unsigned char peekChar(std::istream &istr, unsigned int bom)
|
static unsigned char peekChar(std::istream &istr, unsigned int bom)
|
||||||
{
|
{
|
||||||
unsigned char ch = (unsigned char)istr.peek();
|
unsigned char ch = static_cast<unsigned char>(istr.peek());
|
||||||
|
|
||||||
// For UTF-16 encoded files the BOM is 0xfeff/0xfffe. If the
|
// For UTF-16 encoded files the BOM is 0xfeff/0xfffe. If the
|
||||||
// character is non-ASCII character then replace it with 0xff
|
// character is non-ASCII character then replace it with 0xff
|
||||||
if (bom == 0xfeff || bom == 0xfffe) {
|
if (bom == 0xfeff || bom == 0xfffe) {
|
||||||
(void)istr.get();
|
(void)istr.get();
|
||||||
const unsigned char ch2 = (unsigned char)istr.peek();
|
const unsigned char ch2 = static_cast<unsigned char>(istr.peek());
|
||||||
istr.unget();
|
istr.unget();
|
||||||
const int ch16 = (bom == 0xfeff) ? (ch<<8 | ch2) : (ch2<<8 | ch);
|
const int ch16 = (bom == 0xfeff) ? (ch<<8 | ch2) : (ch2<<8 | ch);
|
||||||
ch = (unsigned char)((ch16 >= 0x80) ? 0xff : ch16);
|
ch = static_cast<unsigned char>(((ch16 >= 0x80) ? 0xff : ch16));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handling of newlines..
|
// Handling of newlines..
|
||||||
|
@ -376,9 +397,9 @@ static unsigned short getAndSkipBOM(std::istream &istr)
|
||||||
|
|
||||||
// The UTF-16 BOM is 0xfffe or 0xfeff.
|
// The UTF-16 BOM is 0xfffe or 0xfeff.
|
||||||
if (ch1 >= 0xfe) {
|
if (ch1 >= 0xfe) {
|
||||||
unsigned short bom = ((unsigned char)istr.get() << 8);
|
unsigned short bom = (static_cast<unsigned char>(istr.get()) << 8);
|
||||||
if (istr.peek() >= 0xfe)
|
if (istr.peek() >= 0xfe)
|
||||||
return bom | (unsigned char)istr.get();
|
return bom | static_cast<unsigned char>(istr.get());
|
||||||
istr.unget();
|
istr.unget();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -450,13 +471,15 @@ void simplecpp::TokenList::lineDirective(unsigned int fileIndex, unsigned int li
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const std::string COMMENT_END("*/");
|
||||||
|
|
||||||
void simplecpp::TokenList::readfile(std::istream &istr, const std::string &filename, OutputList *outputList)
|
void simplecpp::TokenList::readfile(std::istream &istr, const std::string &filename, OutputList *outputList)
|
||||||
{
|
{
|
||||||
std::stack<simplecpp::Location> loc;
|
std::stack<simplecpp::Location> loc;
|
||||||
|
|
||||||
unsigned int multiline = 0U;
|
unsigned int multiline = 0U;
|
||||||
|
|
||||||
const Token *oldLastToken = NULL;
|
const Token *oldLastToken = nullptr;
|
||||||
|
|
||||||
const unsigned short bom = getAndSkipBOM(istr);
|
const unsigned short bom = getAndSkipBOM(istr);
|
||||||
|
|
||||||
|
@ -477,7 +500,7 @@ void simplecpp::TokenList::readfile(std::istream &istr, const std::string &filen
|
||||||
err.type = simplecpp::Output::UNHANDLED_CHAR_ERROR;
|
err.type = simplecpp::Output::UNHANDLED_CHAR_ERROR;
|
||||||
err.location = location;
|
err.location = location;
|
||||||
std::ostringstream s;
|
std::ostringstream s;
|
||||||
s << (int)ch;
|
s << static_cast<int>(ch);
|
||||||
err.msg = "The code contains unhandled character(s) (character code=" + s.str() + "). Neither unicode nor extended ascii is supported.";
|
err.msg = "The code contains unhandled character(s) (character code=" + s.str() + "). Neither unicode nor extended ascii is supported.";
|
||||||
outputList->push_back(err);
|
outputList->push_back(err);
|
||||||
}
|
}
|
||||||
|
@ -500,6 +523,8 @@ void simplecpp::TokenList::readfile(std::istream &istr, const std::string &filen
|
||||||
|
|
||||||
if (oldLastToken != cback()) {
|
if (oldLastToken != cback()) {
|
||||||
oldLastToken = cback();
|
oldLastToken = cback();
|
||||||
|
if (!isLastLinePreprocessor())
|
||||||
|
continue;
|
||||||
const std::string lastline(lastLine());
|
const std::string lastline(lastLine());
|
||||||
if (lastline == "# file %str%") {
|
if (lastline == "# file %str%") {
|
||||||
const Token *strtok = cback();
|
const Token *strtok = cback();
|
||||||
|
@ -590,7 +615,7 @@ void simplecpp::TokenList::readfile(std::istream &istr, const std::string &filen
|
||||||
ch = readChar(istr,bom);
|
ch = readChar(istr,bom);
|
||||||
while (istr.good()) {
|
while (istr.good()) {
|
||||||
currentToken += ch;
|
currentToken += ch;
|
||||||
if (currentToken.size() >= 4U && endsWith(currentToken, "*/"))
|
if (currentToken.size() >= 4U && endsWith(currentToken, COMMENT_END))
|
||||||
break;
|
break;
|
||||||
ch = readChar(istr,bom);
|
ch = readChar(istr,bom);
|
||||||
}
|
}
|
||||||
|
@ -1194,19 +1219,42 @@ std::string simplecpp::TokenList::lastLine(int maxsize) const
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (const Token *tok = cback(); sameline(tok,cback()); tok = tok->previous) {
|
for (const Token *tok = cback(); ; tok = tok->previous) {
|
||||||
|
if (!sameline(tok, cback())) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (tok->comment)
|
if (tok->comment)
|
||||||
continue;
|
continue;
|
||||||
if (!ret.empty())
|
|
||||||
ret.insert(0, 1, ' ');
|
|
||||||
ret.insert(0, tok->str()[0] == '\"' ? std::string("%str%")
|
|
||||||
: tok->number ? std::string("%num%") : tok->str());
|
|
||||||
if (++count > maxsize)
|
if (++count > maxsize)
|
||||||
return "";
|
return "";
|
||||||
|
if (!ret.empty())
|
||||||
|
ret.insert(0, 1, ' ');
|
||||||
|
if (tok->str()[0] == '\"')
|
||||||
|
ret.insert(0, "%str%");
|
||||||
|
else if (tok->number)
|
||||||
|
ret.insert(0, "%num%");
|
||||||
|
else
|
||||||
|
ret.insert(0, tok->str());
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool simplecpp::TokenList::isLastLinePreprocessor(int maxsize) const
|
||||||
|
{
|
||||||
|
const Token* prevTok = nullptr;
|
||||||
|
int count = 0;
|
||||||
|
for (const Token *tok = cback(); ; tok = tok->previous) {
|
||||||
|
if (!sameline(tok, cback()))
|
||||||
|
break;
|
||||||
|
if (tok->comment)
|
||||||
|
continue;
|
||||||
|
if (++count > maxsize)
|
||||||
|
return false;
|
||||||
|
prevTok = tok;
|
||||||
|
}
|
||||||
|
return prevTok && prevTok->str()[0] == '#';
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int simplecpp::TokenList::fileIndex(const std::string &filename)
|
unsigned int simplecpp::TokenList::fileIndex(const std::string &filename)
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < files.size(); ++i) {
|
for (unsigned int i = 0; i < files.size(); ++i) {
|
||||||
|
@ -1219,11 +1267,18 @@ unsigned int simplecpp::TokenList::fileIndex(const std::string &filename)
|
||||||
|
|
||||||
|
|
||||||
namespace simplecpp {
|
namespace simplecpp {
|
||||||
|
class Macro;
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
using MacroMap = std::unordered_map<TokenString,Macro>;
|
||||||
|
#else
|
||||||
|
typedef std::map<TokenString,Macro> MacroMap;
|
||||||
|
#endif
|
||||||
|
|
||||||
class Macro {
|
class Macro {
|
||||||
public:
|
public:
|
||||||
explicit Macro(std::vector<std::string> &f) : nameTokDef(NULL), variadic(false), valueToken(NULL), endToken(NULL), files(f), tokenListDefine(f), valueDefinedInCode_(false) {}
|
explicit Macro(std::vector<std::string> &f) : nameTokDef(nullptr), variadic(false), valueToken(nullptr), endToken(nullptr), files(f), tokenListDefine(f), valueDefinedInCode_(false) {}
|
||||||
|
|
||||||
Macro(const Token *tok, std::vector<std::string> &f) : nameTokDef(NULL), files(f), tokenListDefine(f), valueDefinedInCode_(true) {
|
Macro(const Token *tok, std::vector<std::string> &f) : nameTokDef(nullptr), files(f), tokenListDefine(f), valueDefinedInCode_(true) {
|
||||||
if (sameline(tok->previous, tok))
|
if (sameline(tok->previous, tok))
|
||||||
throw std::runtime_error("bad macro syntax");
|
throw std::runtime_error("bad macro syntax");
|
||||||
if (tok->op != '#')
|
if (tok->op != '#')
|
||||||
|
@ -1239,7 +1294,7 @@ namespace simplecpp {
|
||||||
throw std::runtime_error("bad macro syntax");
|
throw std::runtime_error("bad macro syntax");
|
||||||
}
|
}
|
||||||
|
|
||||||
Macro(const std::string &name, const std::string &value, std::vector<std::string> &f) : nameTokDef(NULL), files(f), tokenListDefine(f), valueDefinedInCode_(false) {
|
Macro(const std::string &name, const std::string &value, std::vector<std::string> &f) : nameTokDef(nullptr), files(f), tokenListDefine(f), valueDefinedInCode_(false) {
|
||||||
const std::string def(name + ' ' + value);
|
const std::string def(name + ' ' + value);
|
||||||
std::istringstream istr(def);
|
std::istringstream istr(def);
|
||||||
tokenListDefine.readfile(istr);
|
tokenListDefine.readfile(istr);
|
||||||
|
@ -1247,20 +1302,22 @@ namespace simplecpp {
|
||||||
throw std::runtime_error("bad macro syntax. macroname=" + name + " value=" + value);
|
throw std::runtime_error("bad macro syntax. macroname=" + name + " value=" + value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Macro(const Macro ¯o) : nameTokDef(NULL), files(macro.files), tokenListDefine(macro.files), valueDefinedInCode_(macro.valueDefinedInCode_) {
|
Macro(const Macro &other) : nameTokDef(nullptr), files(other.files), tokenListDefine(other.files), valueDefinedInCode_(other.valueDefinedInCode_) {
|
||||||
*this = macro;
|
*this = other;
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator=(const Macro ¯o) {
|
Macro &operator=(const Macro &other) {
|
||||||
if (this != ¯o) {
|
if (this != &other) {
|
||||||
valueDefinedInCode_ = macro.valueDefinedInCode_;
|
files = other.files;
|
||||||
if (macro.tokenListDefine.empty())
|
valueDefinedInCode_ = other.valueDefinedInCode_;
|
||||||
parseDefine(macro.nameTokDef);
|
if (other.tokenListDefine.empty())
|
||||||
|
parseDefine(other.nameTokDef);
|
||||||
else {
|
else {
|
||||||
tokenListDefine = macro.tokenListDefine;
|
tokenListDefine = other.tokenListDefine;
|
||||||
parseDefine(tokenListDefine.cfront());
|
parseDefine(tokenListDefine.cfront());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool valueDefinedInCode() const {
|
bool valueDefinedInCode() const {
|
||||||
|
@ -1278,7 +1335,7 @@ namespace simplecpp {
|
||||||
*/
|
*/
|
||||||
const Token * expand(TokenList * const output,
|
const Token * expand(TokenList * const output,
|
||||||
const Token * rawtok,
|
const Token * rawtok,
|
||||||
const std::map<TokenString,Macro> ¯os,
|
const MacroMap ¯os,
|
||||||
std::vector<std::string> &inputFiles) const {
|
std::vector<std::string> &inputFiles) const {
|
||||||
std::set<TokenString> expandedmacros;
|
std::set<TokenString> expandedmacros;
|
||||||
|
|
||||||
|
@ -1332,7 +1389,7 @@ namespace simplecpp {
|
||||||
break;
|
break;
|
||||||
if (output2.cfront() != output2.cback() && macro2tok->str() == this->name())
|
if (output2.cfront() != output2.cback() && macro2tok->str() == this->name())
|
||||||
break;
|
break;
|
||||||
const std::map<TokenString,Macro>::const_iterator macro = macros.find(macro2tok->str());
|
const MacroMap::const_iterator macro = macros.find(macro2tok->str());
|
||||||
if (macro == macros.end() || !macro->second.functionLike())
|
if (macro == macros.end() || !macro->second.functionLike())
|
||||||
break;
|
break;
|
||||||
TokenList rawtokens2(inputFiles);
|
TokenList rawtokens2(inputFiles);
|
||||||
|
@ -1357,7 +1414,7 @@ namespace simplecpp {
|
||||||
}
|
}
|
||||||
if (!rawtok2 || par != 1U)
|
if (!rawtok2 || par != 1U)
|
||||||
break;
|
break;
|
||||||
if (macro->second.expand(&output2, rawtok->location, rawtokens2.cfront(), macros, expandedmacros) != NULL)
|
if (macro->second.expand(&output2, rawtok->location, rawtokens2.cfront(), macros, expandedmacros) != nullptr)
|
||||||
break;
|
break;
|
||||||
rawtok = rawtok2->next;
|
rawtok = rawtok2->next;
|
||||||
}
|
}
|
||||||
|
@ -1391,8 +1448,8 @@ namespace simplecpp {
|
||||||
/** base class for errors */
|
/** base class for errors */
|
||||||
struct Error {
|
struct Error {
|
||||||
Error(const Location &loc, const std::string &s) : location(loc), what(s) {}
|
Error(const Location &loc, const std::string &s) : location(loc), what(s) {}
|
||||||
Location location;
|
const Location location;
|
||||||
std::string what;
|
const std::string what;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Struct that is thrown when macro is expanded with wrong number of parameters */
|
/** Struct that is thrown when macro is expanded with wrong number of parameters */
|
||||||
|
@ -1402,11 +1459,28 @@ namespace simplecpp {
|
||||||
|
|
||||||
/** Struct that is thrown when there is invalid ## usage */
|
/** Struct that is thrown when there is invalid ## usage */
|
||||||
struct invalidHashHash : public Error {
|
struct invalidHashHash : public Error {
|
||||||
invalidHashHash(const Location &loc, const std::string ¯oName) : Error(loc, "Invalid ## usage when expanding \'" + macroName + "\'.") {}
|
static inline std::string format(const std::string ¯oName, const std::string &message) {
|
||||||
|
return "Invalid ## usage when expanding \'" + macroName + "\': " + message;
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidHashHash(const Location &loc, const std::string ¯oName, const std::string &message)
|
||||||
|
: Error(loc, format(macroName, message)) { }
|
||||||
|
|
||||||
|
static inline invalidHashHash unexpectedToken(const Location &loc, const std::string ¯oName, const Token *tokenA) {
|
||||||
|
return invalidHashHash(loc, macroName, "Unexpected token '"+ tokenA->str()+"'");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline invalidHashHash cannotCombine(const Location &loc, const std::string ¯oName, const Token *tokenA, const Token *tokenB) {
|
||||||
|
return invalidHashHash(loc, macroName, "Pasting '"+ tokenA->str()+ "' and '"+ tokenB->str() + "' yields an invalid token.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline invalidHashHash unexpectedNewline(const Location &loc, const std::string ¯oName) {
|
||||||
|
return invalidHashHash(loc, macroName, "Unexpected newline");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
/** Create new token where Token::macro is set for replaced tokens */
|
/** Create new token where Token::macro is set for replaced tokens */
|
||||||
Token *newMacroToken(const TokenString &str, const Location &loc, bool replaced, const Token *expandedFromToken=NULL) const {
|
Token *newMacroToken(const TokenString &str, const Location &loc, bool replaced, const Token *expandedFromToken=nullptr) const {
|
||||||
Token *tok = new Token(str,loc);
|
Token *tok = new Token(str,loc);
|
||||||
if (replaced)
|
if (replaced)
|
||||||
tok->macro = nameTokDef->str();
|
tok->macro = nameTokDef->str();
|
||||||
|
@ -1419,7 +1493,7 @@ namespace simplecpp {
|
||||||
nameTokDef = nametoken;
|
nameTokDef = nametoken;
|
||||||
variadic = false;
|
variadic = false;
|
||||||
if (!nameTokDef) {
|
if (!nameTokDef) {
|
||||||
valueToken = endToken = NULL;
|
valueToken = endToken = nullptr;
|
||||||
args.clear();
|
args.clear();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1443,17 +1517,17 @@ namespace simplecpp {
|
||||||
}
|
}
|
||||||
if (!sameline(nametoken, argtok)) {
|
if (!sameline(nametoken, argtok)) {
|
||||||
endToken = argtok ? argtok->previous : argtok;
|
endToken = argtok ? argtok->previous : argtok;
|
||||||
valueToken = NULL;
|
valueToken = nullptr;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
valueToken = argtok ? argtok->next : NULL;
|
valueToken = argtok ? argtok->next : nullptr;
|
||||||
} else {
|
} else {
|
||||||
args.clear();
|
args.clear();
|
||||||
valueToken = nameTokDef->next;
|
valueToken = nameTokDef->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sameline(valueToken, nameTokDef))
|
if (!sameline(valueToken, nameTokDef))
|
||||||
valueToken = NULL;
|
valueToken = nullptr;
|
||||||
endToken = valueToken;
|
endToken = valueToken;
|
||||||
while (sameline(endToken, nameTokDef))
|
while (sameline(endToken, nameTokDef))
|
||||||
endToken = endToken->next;
|
endToken = endToken->next;
|
||||||
|
@ -1477,7 +1551,7 @@ namespace simplecpp {
|
||||||
std::vector<const Token *> parametertokens;
|
std::vector<const Token *> parametertokens;
|
||||||
parametertokens.push_back(nameTokInst->next);
|
parametertokens.push_back(nameTokInst->next);
|
||||||
unsigned int par = 0U;
|
unsigned int par = 0U;
|
||||||
for (const Token *tok = nameTokInst->next->next; calledInDefine ? sameline(tok, nameTokInst) : (tok != NULL); tok = tok->next) {
|
for (const Token *tok = nameTokInst->next->next; calledInDefine ? sameline(tok, nameTokInst) : (tok != nullptr); tok = tok->next) {
|
||||||
if (tok->op == '(')
|
if (tok->op == '(')
|
||||||
++par;
|
++par;
|
||||||
else if (tok->op == ')') {
|
else if (tok->op == ')') {
|
||||||
|
@ -1495,11 +1569,11 @@ namespace simplecpp {
|
||||||
const Token *appendTokens(TokenList *tokens,
|
const Token *appendTokens(TokenList *tokens,
|
||||||
const Location &rawloc,
|
const Location &rawloc,
|
||||||
const Token * const lpar,
|
const Token * const lpar,
|
||||||
const std::map<TokenString,Macro> ¯os,
|
const MacroMap ¯os,
|
||||||
const std::set<TokenString> &expandedmacros,
|
const std::set<TokenString> &expandedmacros,
|
||||||
const std::vector<const Token*> ¶metertokens) const {
|
const std::vector<const Token*> ¶metertokens) const {
|
||||||
if (!lpar || lpar->op != '(')
|
if (!lpar || lpar->op != '(')
|
||||||
return NULL;
|
return nullptr;
|
||||||
unsigned int par = 0;
|
unsigned int par = 0;
|
||||||
const Token *tok = lpar;
|
const Token *tok = lpar;
|
||||||
while (sameline(lpar, tok)) {
|
while (sameline(lpar, tok)) {
|
||||||
|
@ -1511,7 +1585,7 @@ namespace simplecpp {
|
||||||
} else {
|
} else {
|
||||||
if (!expandArg(tokens, tok, rawloc, macros, expandedmacros, parametertokens)) {
|
if (!expandArg(tokens, tok, rawloc, macros, expandedmacros, parametertokens)) {
|
||||||
bool expanded = false;
|
bool expanded = false;
|
||||||
const std::map<TokenString, Macro>::const_iterator it = macros.find(tok->str());
|
const MacroMap::const_iterator it = macros.find(tok->str());
|
||||||
if (it != macros.end() && expandedmacros.find(tok->str()) == expandedmacros.end()) {
|
if (it != macros.end() && expandedmacros.find(tok->str()) == expandedmacros.end()) {
|
||||||
const Macro &m = it->second;
|
const Macro &m = it->second;
|
||||||
if (!m.functionLike()) {
|
if (!m.functionLike()) {
|
||||||
|
@ -1538,10 +1612,10 @@ namespace simplecpp {
|
||||||
}
|
}
|
||||||
for (Token *tok2 = tokens->front(); tok2; tok2 = tok2->next)
|
for (Token *tok2 = tokens->front(); tok2; tok2 = tok2->next)
|
||||||
tok2->location = lpar->location;
|
tok2->location = lpar->location;
|
||||||
return sameline(lpar,tok) ? tok : NULL;
|
return sameline(lpar,tok) ? tok : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Token * expand(TokenList * const output, const Location &loc, const Token * const nameTokInst, const std::map<TokenString,Macro> ¯os, std::set<TokenString> expandedmacros, bool first=false) const {
|
const Token * expand(TokenList * const output, const Location &loc, const Token * const nameTokInst, const MacroMap ¯os, std::set<TokenString> expandedmacros, bool first=false) const {
|
||||||
|
|
||||||
if (!first)
|
if (!first)
|
||||||
expandedmacros.insert(nameTokInst->str());
|
expandedmacros.insert(nameTokInst->str());
|
||||||
|
@ -1596,7 +1670,7 @@ namespace simplecpp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<TokenString,Macro>::const_iterator m = macros.find("__COUNTER__");
|
const MacroMap::const_iterator m = macros.find("__COUNTER__");
|
||||||
|
|
||||||
if (!counter || m == macros.end())
|
if (!counter || m == macros.end())
|
||||||
parametertokens2.swap(parametertokens1);
|
parametertokens2.swap(parametertokens1);
|
||||||
|
@ -1626,7 +1700,7 @@ namespace simplecpp {
|
||||||
// A##B => AB
|
// A##B => AB
|
||||||
if (sameline(tok, tok->next) && tok->next && tok->next->op == '#' && tok->next->next && tok->next->next->op == '#') {
|
if (sameline(tok, tok->next) && tok->next && tok->next->op == '#' && tok->next->next && tok->next->next->op == '#') {
|
||||||
if (!sameline(tok, tok->next->next->next))
|
if (!sameline(tok, tok->next->next->next))
|
||||||
throw invalidHashHash(tok->location, name());
|
throw invalidHashHash::unexpectedNewline(tok->location, name());
|
||||||
TokenList new_output(files);
|
TokenList new_output(files);
|
||||||
if (!expandArg(&new_output, tok, parametertokens2))
|
if (!expandArg(&new_output, tok, parametertokens2))
|
||||||
output->push_back(newMacroToken(tok->str(), loc, isReplaced(expandedmacros), tok));
|
output->push_back(newMacroToken(tok->str(), loc, isReplaced(expandedmacros), tok));
|
||||||
|
@ -1687,7 +1761,7 @@ namespace simplecpp {
|
||||||
return functionLike() ? parametertokens2.back()->next : nameTokInst->next;
|
return functionLike() ? parametertokens2.back()->next : nameTokInst->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Token *recursiveExpandToken(TokenList *output, TokenList &temp, const Location &loc, const Token *tok, const std::map<TokenString,Macro> ¯os, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> ¶metertokens) const {
|
const Token *recursiveExpandToken(TokenList *output, TokenList &temp, const Location &loc, const Token *tok, const MacroMap ¯os, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> ¶metertokens) const {
|
||||||
if (!(temp.cback() && temp.cback()->name && tok->next && tok->next->op == '(')) {
|
if (!(temp.cback() && temp.cback()->name && tok->next && tok->next->op == '(')) {
|
||||||
output->takeTokens(temp);
|
output->takeTokens(temp);
|
||||||
return tok->next;
|
return tok->next;
|
||||||
|
@ -1698,7 +1772,7 @@ namespace simplecpp {
|
||||||
return tok->next;
|
return tok->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<TokenString, Macro>::const_iterator it = macros.find(temp.cback()->str());
|
const MacroMap::const_iterator it = macros.find(temp.cback()->str());
|
||||||
if (it == macros.end() || expandedmacros.find(temp.cback()->str()) != expandedmacros.end()) {
|
if (it == macros.end() || expandedmacros.find(temp.cback()->str()) != expandedmacros.end()) {
|
||||||
output->takeTokens(temp);
|
output->takeTokens(temp);
|
||||||
return tok->next;
|
return tok->next;
|
||||||
|
@ -1722,7 +1796,7 @@ namespace simplecpp {
|
||||||
return tok2->next;
|
return tok2->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Token *expandToken(TokenList *output, const Location &loc, const Token *tok, const std::map<TokenString,Macro> ¯os, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> ¶metertokens) const {
|
const Token *expandToken(TokenList *output, const Location &loc, const Token *tok, const MacroMap ¯os, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> ¶metertokens) const {
|
||||||
// Not name..
|
// Not name..
|
||||||
if (!tok->name) {
|
if (!tok->name) {
|
||||||
output->push_back(newMacroToken(tok->str(), loc, true, tok));
|
output->push_back(newMacroToken(tok->str(), loc, true, tok));
|
||||||
|
@ -1737,7 +1811,7 @@ namespace simplecpp {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Macro..
|
// Macro..
|
||||||
const std::map<TokenString, Macro>::const_iterator it = macros.find(tok->str());
|
const MacroMap::const_iterator it = macros.find(tok->str());
|
||||||
if (it != macros.end() && expandedmacros.find(tok->str()) == expandedmacros.end()) {
|
if (it != macros.end() && expandedmacros.find(tok->str()) == expandedmacros.end()) {
|
||||||
std::set<std::string> expandedmacros2(expandedmacros);
|
std::set<std::string> expandedmacros2(expandedmacros);
|
||||||
expandedmacros2.insert(tok->str());
|
expandedmacros2.insert(tok->str());
|
||||||
|
@ -1766,10 +1840,10 @@ namespace simplecpp {
|
||||||
|
|
||||||
else if (tok->str() == DEFINED) {
|
else if (tok->str() == DEFINED) {
|
||||||
const Token *tok2 = tok->next;
|
const Token *tok2 = tok->next;
|
||||||
const Token *tok3 = tok2 ? tok2->next : NULL;
|
const Token *tok3 = tok2 ? tok2->next : nullptr;
|
||||||
const Token *tok4 = tok3 ? tok3->next : NULL;
|
const Token *tok4 = tok3 ? tok3->next : nullptr;
|
||||||
const Token *defToken = NULL;
|
const Token *defToken = nullptr;
|
||||||
const Token *lastToken = NULL;
|
const Token *lastToken = nullptr;
|
||||||
if (sameline(tok, tok4) && tok2->op == '(' && tok3->name && tok4->op == ')') {
|
if (sameline(tok, tok4) && tok2->op == '(' && tok3->name && tok4->op == ')') {
|
||||||
defToken = tok3;
|
defToken = tok3;
|
||||||
lastToken = tok4;
|
lastToken = tok4;
|
||||||
|
@ -1816,7 +1890,7 @@ namespace simplecpp {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool expandArg(TokenList *output, const Token *tok, const Location &loc, const std::map<TokenString, Macro> ¯os, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> ¶metertokens) const {
|
bool expandArg(TokenList *output, const Token *tok, const Location &loc, const MacroMap ¯os, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> ¶metertokens) const {
|
||||||
if (!tok->name)
|
if (!tok->name)
|
||||||
return false;
|
return false;
|
||||||
const unsigned int argnr = getArgNum(tok->str());
|
const unsigned int argnr = getArgNum(tok->str());
|
||||||
|
@ -1825,7 +1899,7 @@ namespace simplecpp {
|
||||||
if (variadic && argnr + 1U >= parametertokens.size()) // empty variadic parameter
|
if (variadic && argnr + 1U >= parametertokens.size()) // empty variadic parameter
|
||||||
return true;
|
return true;
|
||||||
for (const Token *partok = parametertokens[argnr]->next; partok != parametertokens[argnr + 1U];) {
|
for (const Token *partok = parametertokens[argnr]->next; partok != parametertokens[argnr + 1U];) {
|
||||||
const std::map<TokenString, Macro>::const_iterator it = macros.find(partok->str());
|
const MacroMap::const_iterator it = macros.find(partok->str());
|
||||||
if (it != macros.end() && !partok->isExpandedFrom(&it->second) && (partok->str() == name() || expandedmacros.find(partok->str()) == expandedmacros.end()))
|
if (it != macros.end() && !partok->isExpandedFrom(&it->second) && (partok->str() == name() || expandedmacros.find(partok->str()) == expandedmacros.end()))
|
||||||
partok = it->second.expand(output, loc, partok, macros, expandedmacros);
|
partok = it->second.expand(output, loc, partok, macros, expandedmacros);
|
||||||
else {
|
else {
|
||||||
|
@ -1847,7 +1921,7 @@ namespace simplecpp {
|
||||||
* @param parametertokens parameters given when expanding this macro
|
* @param parametertokens parameters given when expanding this macro
|
||||||
* @return token after the X
|
* @return token after the X
|
||||||
*/
|
*/
|
||||||
const Token *expandHash(TokenList *output, const Location &loc, const Token *tok, const std::map<TokenString, Macro> ¯os, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> ¶metertokens) const {
|
const Token *expandHash(TokenList *output, const Location &loc, const Token *tok, const MacroMap ¯os, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> ¶metertokens) const {
|
||||||
TokenList tokenListHash(files);
|
TokenList tokenListHash(files);
|
||||||
tok = expandToken(&tokenListHash, loc, tok->next, macros, expandedmacros, parametertokens);
|
tok = expandToken(&tokenListHash, loc, tok->next, macros, expandedmacros, parametertokens);
|
||||||
std::ostringstream ostr;
|
std::ostringstream ostr;
|
||||||
|
@ -1870,74 +1944,93 @@ namespace simplecpp {
|
||||||
* @param parametertokens parameters given when expanding this macro
|
* @param parametertokens parameters given when expanding this macro
|
||||||
* @return token after B
|
* @return token after B
|
||||||
*/
|
*/
|
||||||
const Token *expandHashHash(TokenList *output, const Location &loc, const Token *tok, const std::map<TokenString, Macro> ¯os, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> ¶metertokens) const {
|
const Token *expandHashHash(TokenList *output, const Location &loc, const Token *tok, const MacroMap ¯os, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> ¶metertokens) const {
|
||||||
Token *A = output->back();
|
Token *A = output->back();
|
||||||
if (!A)
|
if (!A)
|
||||||
throw invalidHashHash(tok->location, name());
|
throw invalidHashHash(tok->location, name(), "Missing first argument");
|
||||||
if (!sameline(tok, tok->next) || !sameline(tok, tok->next->next))
|
if (!sameline(tok, tok->next) || !sameline(tok, tok->next->next))
|
||||||
throw invalidHashHash(tok->location, name());
|
throw invalidHashHash::unexpectedNewline(tok->location, name());
|
||||||
|
|
||||||
bool canBeConcatenatedWithEqual = A->isOneOf("+-*/%&|^") || A->str() == "<<" || A->str() == ">>";
|
bool canBeConcatenatedWithEqual = A->isOneOf("+-*/%&|^") || A->str() == "<<" || A->str() == ">>";
|
||||||
if (!A->name && !A->number && A->op != ',' && !A->str().empty() && !canBeConcatenatedWithEqual)
|
bool canBeConcatenatedStringOrChar = isStringLiteral_(A->str()) || isCharLiteral_(A->str());
|
||||||
throw invalidHashHash(tok->location, name());
|
if (!A->name && !A->number && A->op != ',' && !A->str().empty() && !canBeConcatenatedWithEqual && !canBeConcatenatedStringOrChar)
|
||||||
|
throw invalidHashHash::unexpectedToken(tok->location, name(), A);
|
||||||
|
|
||||||
Token *B = tok->next->next;
|
Token *B = tok->next->next;
|
||||||
if (!B->name && !B->number && B->op && !B->isOneOf("#="))
|
if (!B->name && !B->number && B->op && !B->isOneOf("#="))
|
||||||
throw invalidHashHash(tok->location, name());
|
throw invalidHashHash::unexpectedToken(tok->location, name(), B);
|
||||||
|
|
||||||
if ((canBeConcatenatedWithEqual && B->op != '=') ||
|
if ((canBeConcatenatedWithEqual && B->op != '=') ||
|
||||||
(!canBeConcatenatedWithEqual && B->op == '='))
|
(!canBeConcatenatedWithEqual && B->op == '='))
|
||||||
throw invalidHashHash(tok->location, name());
|
throw invalidHashHash::cannotCombine(tok->location, name(), A, B);
|
||||||
|
|
||||||
std::string strAB;
|
// Superficial check; more in-depth would in theory be possible _after_ expandArg
|
||||||
|
if (canBeConcatenatedStringOrChar && (B->number || !B->name))
|
||||||
const bool varargs = variadic && args.size() >= 1U && B->str() == args[args.size()-1U];
|
throw invalidHashHash::cannotCombine(tok->location, name(), A, B);
|
||||||
|
|
||||||
TokenList tokensB(files);
|
TokenList tokensB(files);
|
||||||
if (expandArg(&tokensB, B, parametertokens)) {
|
|
||||||
if (tokensB.empty())
|
|
||||||
strAB = A->str();
|
|
||||||
else if (varargs && A->op == ',') {
|
|
||||||
strAB = ",";
|
|
||||||
} else {
|
|
||||||
strAB = A->str() + tokensB.cfront()->str();
|
|
||||||
tokensB.deleteToken(tokensB.front());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
strAB = A->str() + B->str();
|
|
||||||
}
|
|
||||||
|
|
||||||
const Token *nextTok = B->next;
|
const Token *nextTok = B->next;
|
||||||
if (varargs && tokensB.empty() && tok->previous->str() == ",")
|
|
||||||
output->deleteToken(A);
|
if (canBeConcatenatedStringOrChar) {
|
||||||
else if (strAB != "," && macros.find(strAB) == macros.end()) {
|
// It seems clearer to handle this case separately even though the code is similar-ish, but we don't want to merge here.
|
||||||
A->setstr(strAB);
|
// TODO The question is whether the ## or varargs may still apply, and how to provoke?
|
||||||
for (Token *b = tokensB.front(); b; b = b->next)
|
if (expandArg(&tokensB, B, parametertokens)) {
|
||||||
b->location = loc;
|
for (Token *b = tokensB.front(); b; b = b->next)
|
||||||
output->takeTokens(tokensB);
|
b->location = loc;
|
||||||
} else if (nextTok->op == '#' && nextTok->next->op == '#') {
|
} else {
|
||||||
TokenList output2(files);
|
tokensB.push_back(new Token(*B));
|
||||||
output2.push_back(new Token(strAB, tok->location));
|
tokensB.back()->location = loc;
|
||||||
nextTok = expandHashHash(&output2, loc, nextTok, macros, expandedmacros, parametertokens);
|
|
||||||
output->deleteToken(A);
|
|
||||||
output->takeTokens(output2);
|
|
||||||
} else {
|
|
||||||
output->deleteToken(A);
|
|
||||||
TokenList tokens(files);
|
|
||||||
tokens.push_back(new Token(strAB, tok->location));
|
|
||||||
// for function like macros, push the (...)
|
|
||||||
if (tokensB.empty() && sameline(B,B->next) && B->next->op=='(') {
|
|
||||||
const std::map<TokenString,Macro>::const_iterator it = macros.find(strAB);
|
|
||||||
if (it != macros.end() && expandedmacros.find(strAB) == expandedmacros.end() && it->second.functionLike()) {
|
|
||||||
const Token *tok2 = appendTokens(&tokens, loc, B->next, macros, expandedmacros, parametertokens);
|
|
||||||
if (tok2)
|
|
||||||
nextTok = tok2->next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
expandToken(output, loc, tokens.cfront(), macros, expandedmacros, parametertokens);
|
|
||||||
for (Token *b = tokensB.front(); b; b = b->next)
|
|
||||||
b->location = loc;
|
|
||||||
output->takeTokens(tokensB);
|
output->takeTokens(tokensB);
|
||||||
|
} else {
|
||||||
|
std::string strAB;
|
||||||
|
|
||||||
|
const bool varargs = variadic && args.size() >= 1U && B->str() == args[args.size()-1U];
|
||||||
|
|
||||||
|
if (expandArg(&tokensB, B, parametertokens)) {
|
||||||
|
if (tokensB.empty())
|
||||||
|
strAB = A->str();
|
||||||
|
else if (varargs && A->op == ',') {
|
||||||
|
strAB = ",";
|
||||||
|
} else {
|
||||||
|
strAB = A->str() + tokensB.cfront()->str();
|
||||||
|
tokensB.deleteToken(tokensB.front());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
strAB = A->str() + B->str();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (varargs && tokensB.empty() && tok->previous->str() == ",")
|
||||||
|
output->deleteToken(A);
|
||||||
|
else if (strAB != "," && macros.find(strAB) == macros.end()) {
|
||||||
|
A->setstr(strAB);
|
||||||
|
for (Token *b = tokensB.front(); b; b = b->next)
|
||||||
|
b->location = loc;
|
||||||
|
output->takeTokens(tokensB);
|
||||||
|
} else if (nextTok->op == '#' && nextTok->next->op == '#') {
|
||||||
|
TokenList output2(files);
|
||||||
|
output2.push_back(new Token(strAB, tok->location));
|
||||||
|
nextTok = expandHashHash(&output2, loc, nextTok, macros, expandedmacros, parametertokens);
|
||||||
|
output->deleteToken(A);
|
||||||
|
output->takeTokens(output2);
|
||||||
|
} else {
|
||||||
|
output->deleteToken(A);
|
||||||
|
TokenList tokens(files);
|
||||||
|
tokens.push_back(new Token(strAB, tok->location));
|
||||||
|
// for function like macros, push the (...)
|
||||||
|
if (tokensB.empty() && sameline(B,B->next) && B->next->op=='(') {
|
||||||
|
const MacroMap::const_iterator it = macros.find(strAB);
|
||||||
|
if (it != macros.end() && expandedmacros.find(strAB) == expandedmacros.end() && it->second.functionLike()) {
|
||||||
|
const Token *tok2 = appendTokens(&tokens, loc, B->next, macros, expandedmacros, parametertokens);
|
||||||
|
if (tok2)
|
||||||
|
nextTok = tok2->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expandToken(output, loc, tokens.cfront(), macros, expandedmacros, parametertokens);
|
||||||
|
for (Token *b = tokensB.front(); b; b = b->next)
|
||||||
|
b->location = loc;
|
||||||
|
output->takeTokens(tokensB);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nextTok;
|
return nextTok;
|
||||||
|
@ -2220,14 +2313,19 @@ namespace simplecpp {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// get previous subpath
|
// get previous subpath
|
||||||
const std::string::size_type pos1 = path.rfind('/', pos - 1U) + 1U;
|
std::string::size_type pos1 = path.rfind('/', pos - 1U);
|
||||||
const std::string previousSubPath = path.substr(pos1, pos-pos1);
|
if (pos1 == std::string::npos) {
|
||||||
|
pos1 = 0;
|
||||||
|
} else {
|
||||||
|
pos1 += 1U;
|
||||||
|
}
|
||||||
|
const std::string previousSubPath = path.substr(pos1, pos - pos1);
|
||||||
if (previousSubPath == "..") {
|
if (previousSubPath == "..") {
|
||||||
// don't simplify
|
// don't simplify
|
||||||
++pos;
|
++pos;
|
||||||
} else {
|
} else {
|
||||||
// remove previous subpath and ".."
|
// remove previous subpath and ".."
|
||||||
path.erase(pos1,pos-pos1+4);
|
path.erase(pos1, pos - pos1 + 4);
|
||||||
if (path.empty())
|
if (path.empty())
|
||||||
path = ".";
|
path = ".";
|
||||||
// update pos
|
// update pos
|
||||||
|
@ -2623,7 +2721,7 @@ static NonExistingFilesCache nonExistingFilesCache;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static std::string _openHeader(std::ifstream &f, const std::string &path)
|
static std::string openHeader(std::ifstream &f, const std::string &path)
|
||||||
{
|
{
|
||||||
#ifdef SIMPLECPP_WINDOWS
|
#ifdef SIMPLECPP_WINDOWS
|
||||||
std::string simplePath = simplecpp::simplifyPath(path);
|
std::string simplePath = simplecpp::simplifyPath(path);
|
||||||
|
@ -2652,7 +2750,7 @@ static std::string getRelativeFileName(const std::string &sourcefile, const std:
|
||||||
|
|
||||||
static std::string openHeaderRelative(std::ifstream &f, const std::string &sourcefile, const std::string &header)
|
static std::string openHeaderRelative(std::ifstream &f, const std::string &sourcefile, const std::string &header)
|
||||||
{
|
{
|
||||||
return _openHeader(f, getRelativeFileName(sourcefile, header));
|
return openHeader(f, getRelativeFileName(sourcefile, header));
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string getIncludePathFileName(const std::string &includePath, const std::string &header)
|
static std::string getIncludePathFileName(const std::string &includePath, const std::string &header)
|
||||||
|
@ -2666,7 +2764,7 @@ static std::string getIncludePathFileName(const std::string &includePath, const
|
||||||
static std::string openHeaderIncludePath(std::ifstream &f, const simplecpp::DUI &dui, const std::string &header)
|
static std::string openHeaderIncludePath(std::ifstream &f, const simplecpp::DUI &dui, const std::string &header)
|
||||||
{
|
{
|
||||||
for (std::list<std::string>::const_iterator it = dui.includePaths.begin(); it != dui.includePaths.end(); ++it) {
|
for (std::list<std::string>::const_iterator it = dui.includePaths.begin(); it != dui.includePaths.end(); ++it) {
|
||||||
std::string simplePath = _openHeader(f, getIncludePathFileName(*it, header));
|
std::string simplePath = openHeader(f, getIncludePathFileName(*it, header));
|
||||||
if (!simplePath.empty())
|
if (!simplePath.empty())
|
||||||
return simplePath;
|
return simplePath;
|
||||||
}
|
}
|
||||||
|
@ -2676,7 +2774,7 @@ static std::string openHeaderIncludePath(std::ifstream &f, const simplecpp::DUI
|
||||||
static std::string openHeader(std::ifstream &f, const simplecpp::DUI &dui, const std::string &sourcefile, const std::string &header, bool systemheader)
|
static std::string openHeader(std::ifstream &f, const simplecpp::DUI &dui, const std::string &sourcefile, const std::string &header, bool systemheader)
|
||||||
{
|
{
|
||||||
if (isAbsolutePath(header))
|
if (isAbsolutePath(header))
|
||||||
return _openHeader(f, header);
|
return openHeader(f, header);
|
||||||
|
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
|
@ -2754,8 +2852,8 @@ std::map<std::string, simplecpp::TokenList*> simplecpp::load(const simplecpp::To
|
||||||
filelist.push_back(tokenlist->front());
|
filelist.push_back(tokenlist->front());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const Token *rawtok = rawtokens.cfront(); rawtok || !filelist.empty(); rawtok = rawtok ? rawtok->next : NULL) {
|
for (const Token *rawtok = rawtokens.cfront(); rawtok || !filelist.empty(); rawtok = rawtok ? rawtok->next : nullptr) {
|
||||||
if (rawtok == NULL) {
|
if (rawtok == nullptr) {
|
||||||
rawtok = filelist.back();
|
rawtok = filelist.back();
|
||||||
filelist.pop_back();
|
filelist.pop_back();
|
||||||
}
|
}
|
||||||
|
@ -2792,10 +2890,10 @@ std::map<std::string, simplecpp::TokenList*> simplecpp::load(const simplecpp::To
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool preprocessToken(simplecpp::TokenList &output, const simplecpp::Token **tok1, std::map<std::string, simplecpp::Macro> ¯os, std::vector<std::string> &files, simplecpp::OutputList *outputList)
|
static bool preprocessToken(simplecpp::TokenList &output, const simplecpp::Token **tok1, simplecpp::MacroMap ¯os, std::vector<std::string> &files, simplecpp::OutputList *outputList)
|
||||||
{
|
{
|
||||||
const simplecpp::Token *tok = *tok1;
|
const simplecpp::Token *tok = *tok1;
|
||||||
const std::map<std::string,simplecpp::Macro>::const_iterator it = macros.find(tok->str());
|
const simplecpp::MacroMap::const_iterator it = macros.find(tok->str());
|
||||||
if (it != macros.end()) {
|
if (it != macros.end()) {
|
||||||
simplecpp::TokenList value(files);
|
simplecpp::TokenList value(files);
|
||||||
try {
|
try {
|
||||||
|
@ -2819,6 +2917,28 @@ static bool preprocessToken(simplecpp::TokenList &output, const simplecpp::Token
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void getLocaltime(struct tm <ime) {
|
||||||
|
time_t t;
|
||||||
|
time(&t);
|
||||||
|
#ifndef _WIN32
|
||||||
|
localtime_r(&t, <ime);
|
||||||
|
#else
|
||||||
|
localtime_s(<ime, &t);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string getDateDefine(struct tm *timep) {
|
||||||
|
char buf[] = "??? ?? ????";
|
||||||
|
strftime(buf, sizeof(buf), "%b %d %Y", timep);
|
||||||
|
return std::string("\"").append(buf).append("\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string getTimeDefine(struct tm *timep) {
|
||||||
|
char buf[] = "??:??:??";
|
||||||
|
strftime(buf, sizeof(buf), "%T", timep);
|
||||||
|
return std::string("\"").append(buf).append("\"");
|
||||||
|
}
|
||||||
|
|
||||||
void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenList &rawtokens, std::vector<std::string> &files, std::map<std::string, simplecpp::TokenList *> &filedata, const simplecpp::DUI &dui, simplecpp::OutputList *outputList, std::list<simplecpp::MacroUsage> *macroUsage, std::list<simplecpp::IfCond> *ifCond)
|
void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenList &rawtokens, std::vector<std::string> &files, std::map<std::string, simplecpp::TokenList *> &filedata, const simplecpp::DUI &dui, simplecpp::OutputList *outputList, std::list<simplecpp::MacroUsage> *macroUsage, std::list<simplecpp::IfCond> *ifCond)
|
||||||
{
|
{
|
||||||
std::map<std::string, std::size_t> sizeOfType(rawtokens.sizeOfType);
|
std::map<std::string, std::size_t> sizeOfType(rawtokens.sizeOfType);
|
||||||
|
@ -2844,7 +2964,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
|
||||||
sizeOfType.insert(std::make_pair("long double *", sizeof(long double *)));
|
sizeOfType.insert(std::make_pair("long double *", sizeof(long double *)));
|
||||||
|
|
||||||
const bool hasInclude = (dui.std.size() == 5 && dui.std.compare(0,3,"c++") == 0 && dui.std >= "c++17");
|
const bool hasInclude = (dui.std.size() == 5 && dui.std.compare(0,3,"c++") == 0 && dui.std >= "c++17");
|
||||||
std::map<TokenString, Macro> macros;
|
MacroMap macros;
|
||||||
for (std::list<std::string>::const_iterator it = dui.defines.begin(); it != dui.defines.end(); ++it) {
|
for (std::list<std::string>::const_iterator it = dui.defines.begin(); it != dui.defines.end(); ++it) {
|
||||||
const std::string ¯ostr = *it;
|
const std::string ¯ostr = *it;
|
||||||
const std::string::size_type eq = macrostr.find('=');
|
const std::string::size_type eq = macrostr.find('=');
|
||||||
|
@ -2861,15 +2981,21 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
|
||||||
macros.insert(std::make_pair("__FILE__", Macro("__FILE__", "__FILE__", files)));
|
macros.insert(std::make_pair("__FILE__", Macro("__FILE__", "__FILE__", files)));
|
||||||
macros.insert(std::make_pair("__LINE__", Macro("__LINE__", "__LINE__", files)));
|
macros.insert(std::make_pair("__LINE__", Macro("__LINE__", "__LINE__", files)));
|
||||||
macros.insert(std::make_pair("__COUNTER__", Macro("__COUNTER__", "__COUNTER__", files)));
|
macros.insert(std::make_pair("__COUNTER__", Macro("__COUNTER__", "__COUNTER__", files)));
|
||||||
|
struct tm ltime = {};
|
||||||
|
getLocaltime(ltime);
|
||||||
|
macros.insert(std::make_pair("__DATE__", Macro("__DATE__", getDateDefine(<ime), files)));
|
||||||
|
macros.insert(std::make_pair("__TIME__", Macro("__TIME__", getTimeDefine(<ime), files)));
|
||||||
|
|
||||||
if (dui.std == "c++11")
|
if (!dui.std.empty()) {
|
||||||
macros.insert(std::make_pair("__cplusplus", Macro("__cplusplus", "201103L", files)));
|
std::string std_def = simplecpp::getCStdString(dui.std);
|
||||||
else if (dui.std == "c++14")
|
if (!std_def.empty()) {
|
||||||
macros.insert(std::make_pair("__cplusplus", Macro("__cplusplus", "201402L", files)));
|
macros.insert(std::make_pair("__STDC_VERSION__", Macro("__STDC_VERSION__", std_def, files)));
|
||||||
else if (dui.std == "c++17")
|
} else {
|
||||||
macros.insert(std::make_pair("__cplusplus", Macro("__cplusplus", "201703L", files)));
|
std_def = simplecpp::getCppStdString(dui.std);
|
||||||
else if (dui.std == "c++20")
|
if (!std_def.empty())
|
||||||
macros.insert(std::make_pair("__cplusplus", Macro("__cplusplus", "202002L", files)));
|
macros.insert(std::make_pair("__cplusplus", Macro("__cplusplus", std_def, files)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TRUE => code in current #if block should be kept
|
// TRUE => code in current #if block should be kept
|
||||||
// ELSE_IS_TRUE => code in current #if block should be dropped. the code in the #else should be kept.
|
// ELSE_IS_TRUE => code in current #if block should be dropped. the code in the #else should be kept.
|
||||||
|
@ -2889,8 +3015,10 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
|
||||||
includetokenstack.push(f->second->cfront());
|
includetokenstack.push(f->second->cfront());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const Token *rawtok = NULL; rawtok || !includetokenstack.empty();) {
|
std::map<std::string, std::list<Location> > maybeUsedMacros;
|
||||||
if (rawtok == NULL) {
|
|
||||||
|
for (const Token *rawtok = nullptr; rawtok || !includetokenstack.empty();) {
|
||||||
|
if (rawtok == nullptr) {
|
||||||
rawtok = includetokenstack.top();
|
rawtok = includetokenstack.top();
|
||||||
includetokenstack.pop();
|
includetokenstack.pop();
|
||||||
continue;
|
continue;
|
||||||
|
@ -2944,7 +3072,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
|
||||||
try {
|
try {
|
||||||
const Macro ¯o = Macro(rawtok->previous, files);
|
const Macro ¯o = Macro(rawtok->previous, files);
|
||||||
if (dui.undefined.find(macro.name()) == dui.undefined.end()) {
|
if (dui.undefined.find(macro.name()) == dui.undefined.end()) {
|
||||||
std::map<TokenString, Macro>::iterator it = macros.find(macro.name());
|
MacroMap::iterator it = macros.find(macro.name());
|
||||||
if (it == macros.end())
|
if (it == macros.end())
|
||||||
macros.insert(std::pair<TokenString, Macro>(macro.name(), macro));
|
macros.insert(std::pair<TokenString, Macro>(macro.name(), macro));
|
||||||
else
|
else
|
||||||
|
@ -3035,7 +3163,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
|
||||||
} else if (pragmaOnce.find(header2) == pragmaOnce.end()) {
|
} else if (pragmaOnce.find(header2) == pragmaOnce.end()) {
|
||||||
includetokenstack.push(gotoNextLine(rawtok));
|
includetokenstack.push(gotoNextLine(rawtok));
|
||||||
const TokenList *includetokens = filedata.find(header2)->second;
|
const TokenList *includetokens = filedata.find(header2)->second;
|
||||||
rawtok = includetokens ? includetokens->cfront() : NULL;
|
rawtok = includetokens ? includetokens->cfront() : nullptr;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else if (rawtok->str() == IF || rawtok->str() == IFDEF || rawtok->str() == IFNDEF || rawtok->str() == ELIF) {
|
} else if (rawtok->str() == IF || rawtok->str() == IFDEF || rawtok->str() == IFNDEF || rawtok->str() == ELIF) {
|
||||||
|
@ -3054,11 +3182,13 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
|
||||||
bool conditionIsTrue;
|
bool conditionIsTrue;
|
||||||
if (ifstates.top() == ALWAYS_FALSE || (ifstates.top() == ELSE_IS_TRUE && rawtok->str() != ELIF))
|
if (ifstates.top() == ALWAYS_FALSE || (ifstates.top() == ELSE_IS_TRUE && rawtok->str() != ELIF))
|
||||||
conditionIsTrue = false;
|
conditionIsTrue = false;
|
||||||
else if (rawtok->str() == IFDEF)
|
else if (rawtok->str() == IFDEF) {
|
||||||
conditionIsTrue = (macros.find(rawtok->next->str()) != macros.end() || (hasInclude && rawtok->next->str() == HAS_INCLUDE));
|
conditionIsTrue = (macros.find(rawtok->next->str()) != macros.end() || (hasInclude && rawtok->next->str() == HAS_INCLUDE));
|
||||||
else if (rawtok->str() == IFNDEF)
|
maybeUsedMacros[rawtok->next->str()].push_back(rawtok->next->location);
|
||||||
|
} else if (rawtok->str() == IFNDEF) {
|
||||||
conditionIsTrue = (macros.find(rawtok->next->str()) == macros.end() && !(hasInclude && rawtok->next->str() == HAS_INCLUDE));
|
conditionIsTrue = (macros.find(rawtok->next->str()) == macros.end() && !(hasInclude && rawtok->next->str() == HAS_INCLUDE));
|
||||||
else { /*if (rawtok->str() == IF || rawtok->str() == ELIF)*/
|
maybeUsedMacros[rawtok->next->str()].push_back(rawtok->next->location);
|
||||||
|
} else { /*if (rawtok->str() == IF || rawtok->str() == ELIF)*/
|
||||||
TokenList expr(files);
|
TokenList expr(files);
|
||||||
for (const Token *tok = rawtok->next; tok && tok->location.sameline(rawtok->location); tok = tok->next) {
|
for (const Token *tok = rawtok->next; tok && tok->location.sameline(rawtok->location); tok = tok->next) {
|
||||||
if (!tok->name) {
|
if (!tok->name) {
|
||||||
|
@ -3071,6 +3201,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
|
||||||
const bool par = (tok && tok->op == '(');
|
const bool par = (tok && tok->op == '(');
|
||||||
if (par)
|
if (par)
|
||||||
tok = tok->next;
|
tok = tok->next;
|
||||||
|
maybeUsedMacros[rawtok->next->str()].push_back(rawtok->next->location);
|
||||||
if (tok) {
|
if (tok) {
|
||||||
if (macros.find(tok->str()) != macros.end())
|
if (macros.find(tok->str()) != macros.end())
|
||||||
expr.push_back(new Token("1", tok->location));
|
expr.push_back(new Token("1", tok->location));
|
||||||
|
@ -3080,7 +3211,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
|
||||||
expr.push_back(new Token("0", tok->location));
|
expr.push_back(new Token("0", tok->location));
|
||||||
}
|
}
|
||||||
if (par)
|
if (par)
|
||||||
tok = tok ? tok->next : NULL;
|
tok = tok ? tok->next : nullptr;
|
||||||
if (!tok || !sameline(rawtok,tok) || (par && tok->op != ')')) {
|
if (!tok || !sameline(rawtok,tok) || (par && tok->op != ')')) {
|
||||||
if (outputList) {
|
if (outputList) {
|
||||||
Output out(rawtok->location.files);
|
Output out(rawtok->location.files);
|
||||||
|
@ -3109,7 +3240,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
|
||||||
expr.push_back(new Token(header2.empty() ? "0" : "1", tok->location));
|
expr.push_back(new Token(header2.empty() ? "0" : "1", tok->location));
|
||||||
}
|
}
|
||||||
if (par)
|
if (par)
|
||||||
tok = tok ? tok->next : NULL;
|
tok = tok ? tok->next : nullptr;
|
||||||
if (!tok || !sameline(rawtok,tok) || (par && tok->op != ')')) {
|
if (!tok || !sameline(rawtok,tok) || (par && tok->op != ')')) {
|
||||||
if (outputList) {
|
if (outputList) {
|
||||||
Output out(rawtok->location.files);
|
Output out(rawtok->location.files);
|
||||||
|
@ -3124,6 +3255,8 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
maybeUsedMacros[rawtok->next->str()].push_back(rawtok->next->location);
|
||||||
|
|
||||||
const Token *tmp = tok;
|
const Token *tmp = tok;
|
||||||
if (!preprocessToken(expr, &tmp, macros, files, outputList)) {
|
if (!preprocessToken(expr, &tmp, macros, files, outputList)) {
|
||||||
output.clear();
|
output.clear();
|
||||||
|
@ -3231,9 +3364,11 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
|
||||||
}
|
}
|
||||||
|
|
||||||
if (macroUsage) {
|
if (macroUsage) {
|
||||||
for (std::map<TokenString, simplecpp::Macro>::const_iterator macroIt = macros.begin(); macroIt != macros.end(); ++macroIt) {
|
for (simplecpp::MacroMap::const_iterator macroIt = macros.begin(); macroIt != macros.end(); ++macroIt) {
|
||||||
const Macro ¯o = macroIt->second;
|
const Macro ¯o = macroIt->second;
|
||||||
const std::list<Location> &usage = macro.usage();
|
std::list<Location> usage = macro.usage();
|
||||||
|
const std::list<Location>& temp = maybeUsedMacros[macro.name()];
|
||||||
|
usage.insert(usage.end(), temp.begin(), temp.end());
|
||||||
for (std::list<Location>::const_iterator usageIt = usage.begin(); usageIt != usage.end(); ++usageIt) {
|
for (std::list<Location>::const_iterator usageIt = usage.begin(); usageIt != usage.end(); ++usageIt) {
|
||||||
MacroUsage mu(usageIt->files, macro.valueDefinedInCode());
|
MacroUsage mu(usageIt->files, macro.valueDefinedInCode());
|
||||||
mu.macroName = macro.name();
|
mu.macroName = macro.name();
|
||||||
|
@ -3251,3 +3386,48 @@ void simplecpp::cleanup(std::map<std::string, TokenList*> &filedata)
|
||||||
delete it->second;
|
delete it->second;
|
||||||
filedata.clear();
|
filedata.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string simplecpp::getCStdString(const std::string &std)
|
||||||
|
{
|
||||||
|
if (std == "c90" || std == "c89" || std == "iso9899:1990" || std == "iso9899:199409" || std == "gnu90" || std == "gnu89") {
|
||||||
|
// __STDC_VERSION__ is not set for C90 although the macro was added in the 1994 amendments
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (std == "c99" || std == "c9x" || std == "iso9899:1999" || std == "iso9899:199x" || std == "gnu99"|| std == "gnu9x")
|
||||||
|
return "199901L";
|
||||||
|
if (std == "c11" || std == "c1x" || std == "iso9899:2011" || std == "gnu11" || std == "gnu1x")
|
||||||
|
return "201112L";
|
||||||
|
if (std == "c17" || std == "c18" || std == "iso9899:2017" || std == "iso9899:2018" || std == "gnu17"|| std == "gnu18")
|
||||||
|
return "201710L";
|
||||||
|
if (std == "c2x" || std == "gnu2x") {
|
||||||
|
// Clang 11 returns "201710L"
|
||||||
|
return "202000L";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string simplecpp::getCppStdString(const std::string &std)
|
||||||
|
{
|
||||||
|
if (std == "c++98" || std == "c++03" || std == "gnu++98" || std == "gnu++03")
|
||||||
|
return "199711L";
|
||||||
|
if (std == "c++11" || std == "gnu++11" || std == "c++0x" || std == "gnu++0x")
|
||||||
|
return "201103L";
|
||||||
|
if (std == "c++14" || std == "c++1y" || std == "gnu++14" || std == "gnu++1y")
|
||||||
|
return "201402L";
|
||||||
|
if (std == "c++17" || std == "c++1z" || std == "gnu++17" || std == "gnu++1z")
|
||||||
|
return "201703L";
|
||||||
|
if (std == "c++20" || std == "c++2a" || std == "gnu++20" || std == "gnu++2a") {
|
||||||
|
// GCC 10 returns "201703L"
|
||||||
|
return "202002L";
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
if (std == "c++23" || std == "c++2b" || std == "gnu++23" || std == "gnu++2b") {
|
||||||
|
// supported by GCC 11+
|
||||||
|
return "";
|
||||||
|
} */
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (__cplusplus < 201103L) && !defined(__APPLE__)
|
||||||
|
#undef nullptr
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* simplecpp - A simple and high-fidelity C/C++ preprocessor library
|
* simplecpp - A simple and high-fidelity C/C++ preprocessor library
|
||||||
* Copyright (C) 2016 Daniel Marjamäki.
|
* Copyright (C) 2016-2022 Daniel Marjamäki.
|
||||||
*
|
*
|
||||||
* This library is free software: you can redistribute it and/or
|
* This library is free software: you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <cstring>
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -40,10 +41,14 @@
|
||||||
# define SIMPLECPP_LIB
|
# define SIMPLECPP_LIB
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (__cplusplus < 201103L) && !defined(__APPLE__)
|
||||||
|
#define nullptr NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace simplecpp {
|
namespace simplecpp {
|
||||||
|
|
||||||
typedef std::string TokenString;
|
typedef std::string TokenString;
|
||||||
|
class Macro;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Location in source code
|
* Location in source code
|
||||||
|
@ -97,20 +102,19 @@ namespace simplecpp {
|
||||||
class SIMPLECPP_LIB Token {
|
class SIMPLECPP_LIB Token {
|
||||||
public:
|
public:
|
||||||
Token(const TokenString &s, const Location &loc) :
|
Token(const TokenString &s, const Location &loc) :
|
||||||
location(loc), previous(NULL), next(NULL), string(s) {
|
location(loc), previous(nullptr), next(nullptr), string(s) {
|
||||||
flags();
|
flags();
|
||||||
}
|
}
|
||||||
|
|
||||||
Token(const Token &tok) :
|
Token(const Token &tok) :
|
||||||
macro(tok.macro), location(tok.location), previous(NULL), next(NULL), string(tok.string) {
|
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) {
|
||||||
flags();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void flags() {
|
void flags() {
|
||||||
name = (std::isalpha((unsigned char)string[0]) || string[0] == '_' || string[0] == '$')
|
name = (std::isalpha(static_cast<unsigned char>(string[0])) || string[0] == '_' || string[0] == '$')
|
||||||
&& (string.find('\'') == string.npos);
|
&& (std::memchr(string.c_str(), '\'', string.size()) == nullptr);
|
||||||
comment = string.size() > 1U && string[0] == '/' && (string[1] == '/' || string[1] == '*');
|
comment = string.size() > 1U && string[0] == '/' && (string[1] == '/' || string[1] == '*');
|
||||||
number = std::isdigit((unsigned char)string[0]) || (string.size() > 1U && string[0] == '-' && std::isdigit((unsigned char)string[1]));
|
number = std::isdigit(static_cast<unsigned char>(string[0])) || (string.size() > 1U && string[0] == '-' && std::isdigit(static_cast<unsigned char>(string[1])));
|
||||||
op = (string.size() == 1U) ? string[0] : '\0';
|
op = (string.size() == 1U) ? string[0] : '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,11 +153,11 @@ namespace simplecpp {
|
||||||
return tok;
|
return tok;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setExpandedFrom(const Token *tok, const void* m) {
|
void setExpandedFrom(const Token *tok, const Macro* m) {
|
||||||
mExpandedFrom = tok->mExpandedFrom;
|
mExpandedFrom = tok->mExpandedFrom;
|
||||||
mExpandedFrom.insert(m);
|
mExpandedFrom.insert(m);
|
||||||
}
|
}
|
||||||
bool isExpandedFrom(const void* m) const {
|
bool isExpandedFrom(const Macro* m) const {
|
||||||
return mExpandedFrom.find(m) != mExpandedFrom.end();
|
return mExpandedFrom.find(m) != mExpandedFrom.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +166,7 @@ namespace simplecpp {
|
||||||
private:
|
private:
|
||||||
TokenString string;
|
TokenString string;
|
||||||
|
|
||||||
std::set<const void*> mExpandedFrom;
|
std::set<const Macro*> mExpandedFrom;
|
||||||
|
|
||||||
// Not implemented - prevent assignment
|
// Not implemented - prevent assignment
|
||||||
Token &operator=(const Token &tok);
|
Token &operator=(const Token &tok);
|
||||||
|
@ -191,7 +195,7 @@ namespace simplecpp {
|
||||||
class SIMPLECPP_LIB TokenList {
|
class SIMPLECPP_LIB TokenList {
|
||||||
public:
|
public:
|
||||||
explicit TokenList(std::vector<std::string> &filenames);
|
explicit TokenList(std::vector<std::string> &filenames);
|
||||||
TokenList(std::istream &istr, std::vector<std::string> &filenames, const std::string &filename=std::string(), OutputList *outputList = NULL);
|
TokenList(std::istream &istr, std::vector<std::string> &filenames, const std::string &filename=std::string(), OutputList *outputList = nullptr);
|
||||||
TokenList(const TokenList &other);
|
TokenList(const TokenList &other);
|
||||||
#if __cplusplus >= 201103L
|
#if __cplusplus >= 201103L
|
||||||
TokenList(TokenList &&other);
|
TokenList(TokenList &&other);
|
||||||
|
@ -211,7 +215,7 @@ namespace simplecpp {
|
||||||
void dump() const;
|
void dump() const;
|
||||||
std::string stringify() const;
|
std::string stringify() const;
|
||||||
|
|
||||||
void readfile(std::istream &istr, const std::string &filename=std::string(), OutputList *outputList = NULL);
|
void readfile(std::istream &istr, const std::string &filename=std::string(), OutputList *outputList = nullptr);
|
||||||
void constFold();
|
void constFold();
|
||||||
|
|
||||||
void removeComments();
|
void removeComments();
|
||||||
|
@ -258,7 +262,7 @@ namespace simplecpp {
|
||||||
other.frontToken->previous = backToken;
|
other.frontToken->previous = backToken;
|
||||||
}
|
}
|
||||||
backToken = other.backToken;
|
backToken = other.backToken;
|
||||||
other.frontToken = other.backToken = NULL;
|
other.frontToken = other.backToken = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** sizeof(T) */
|
/** sizeof(T) */
|
||||||
|
@ -280,6 +284,7 @@ namespace simplecpp {
|
||||||
void lineDirective(unsigned int fileIndex, unsigned int line, Location *location);
|
void lineDirective(unsigned int fileIndex, unsigned int line, Location *location);
|
||||||
|
|
||||||
std::string lastLine(int maxsize=100000) const;
|
std::string lastLine(int maxsize=100000) const;
|
||||||
|
bool isLastLinePreprocessor(int maxsize=100000) const;
|
||||||
|
|
||||||
unsigned int fileIndex(const std::string &filename);
|
unsigned int fileIndex(const std::string &filename);
|
||||||
|
|
||||||
|
@ -320,7 +325,7 @@ namespace simplecpp {
|
||||||
|
|
||||||
SIMPLECPP_LIB long long characterLiteralToLL(const std::string& str);
|
SIMPLECPP_LIB long long characterLiteralToLL(const std::string& str);
|
||||||
|
|
||||||
SIMPLECPP_LIB std::map<std::string, TokenList*> load(const TokenList &rawtokens, std::vector<std::string> &filenames, const DUI &dui, OutputList *outputList = NULL);
|
SIMPLECPP_LIB std::map<std::string, TokenList*> load(const TokenList &rawtokens, std::vector<std::string> &filenames, const DUI &dui, OutputList *outputList = nullptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preprocess
|
* Preprocess
|
||||||
|
@ -334,7 +339,7 @@ namespace simplecpp {
|
||||||
* @param macroUsage output: macro usage
|
* @param macroUsage output: macro usage
|
||||||
* @param ifCond output: #if/#elif expressions
|
* @param ifCond output: #if/#elif expressions
|
||||||
*/
|
*/
|
||||||
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 = NULL, std::list<MacroUsage> *macroUsage = NULL, std::list<IfCond> *ifCond = NULL);
|
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
|
* Deallocate data
|
||||||
|
@ -346,6 +351,16 @@ namespace simplecpp {
|
||||||
|
|
||||||
/** Convert Cygwin path to Windows path */
|
/** Convert Cygwin path to Windows path */
|
||||||
SIMPLECPP_LIB std::string convertCygwinToWindowsPath(const std::string &cygwinPath);
|
SIMPLECPP_LIB std::string convertCygwinToWindowsPath(const std::string &cygwinPath);
|
||||||
|
|
||||||
|
/** 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (__cplusplus < 201103L) && !defined(__APPLE__)
|
||||||
|
#undef nullptr
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue