bump simplecpp

This commit is contained in:
Daniel Marjamäki 2017-06-21 12:09:50 +02:00
parent 170cfc24a2
commit 18c97c5456
2 changed files with 271 additions and 175 deletions

View File

@ -16,6 +16,9 @@
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
#define NOMINMAX
#endif
#include "simplecpp.h"
#include <algorithm>
@ -31,7 +34,6 @@
#include <utility>
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
#define NOMINMAX
#include <windows.h>
#undef ERROR
#undef TRUE
@ -134,7 +136,7 @@ void simplecpp::Location::adjust(const std::string &str)
for (std::size_t i = 0U; i < str.size(); ++i) {
col++;
if (str[i] == '\n' || str[i] == '\r') {
col = 0;
col = 1;
line++;
if (str[i] == '\r' && (i+1)<str.size() && str[i+1]=='\n')
++i;
@ -520,7 +522,11 @@ void simplecpp::TokenList::readfile(std::istream &istr, const std::string &filen
return;
currentToken.erase(currentToken.size() - endOfRawString.size(), endOfRawString.size() - 1U);
back()->setstr(escapeString(currentToken));
location.col += currentToken.size() + 2U + 2 * delim.size();
location.adjust(currentToken);
if (currentToken.find_first_of("\r\n") == std::string::npos)
location.col += 2 + 2 * delim.size();
else
location.col += 1 + delim.size();
continue;
}
@ -1673,48 +1679,106 @@ namespace simplecpp {
namespace simplecpp {
#ifdef SIMPLECPP_WINDOWS
static bool realFileName(const std::vector<CHAR> &buf, std::ostream &ostr)
bool realFileName(const std::string &f, std::string *result)
{
// Detect root directory, see simplecpp:realFileName returns the wrong root path #45
if ((buf.size()==2 || (buf.size()>2 && buf[2]=='\0'))
&& std::isalpha(buf[0]) && buf[1]==':') {
ostr << (char)buf[0];
ostr << (char)buf[1];
// If path is a drive letter, uppercase it
if (f.size() == 2 && std::isalpha((unsigned char)f[0]) && f[1] == ':') {
*result = (char)std::toupper((unsigned char)f[0]) + std::string(":");
return true;
}
// are there alpha characters in last subpath?
bool alpha = false;
for (std::string::size_type pos = 1; pos < f.size(); ++pos) {
unsigned char c = f[f.size() - pos];
if (c=='/' || c=='\\')
break;
if (std::isalpha(c)) {
alpha = true;
break;
}
}
// do not convert this path if there are no alpha characters (either pointless or cause wrong results for . and ..)
if (!alpha)
return false;
// Convert char path to CHAR path
std::vector<CHAR> buf(f.size()+1U, 0);
for (unsigned int i = 0; i < f.size(); ++i)
buf[i] = f[i];
// Lookup filename or foldername on file system
WIN32_FIND_DATAA FindFileData;
HANDLE hFind = FindFirstFileA(&buf[0], &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
return false;
ostr << FindFileData.cFileName;
*result = FindFileData.cFileName;
FindClose(hFind);
return true;
}
/** Change case in given path to match filesystem */
std::string realFilename(const std::string &f)
{
std::vector<CHAR> buf(f.size()+1U, 0);
for (unsigned int i = 0; i < f.size(); ++i)
buf[i] = f[i];
std::ostringstream ostr;
std::string::size_type sep = 0;
while ((sep = f.find_first_of("\\/", sep + 1U)) != std::string::npos) {
if (sep >= 2 && f.compare(sep-2,2,"..",0,2) == 0) {
ostr << "../";
continue;
std::string ret;
ret.reserve(f.size()); // this will be the final size
// Current subpath
std::string subpath;
for (std::string::size_type pos = 0; pos < f.size(); ++pos) {
unsigned char c = f[pos];
// Separator.. add subpath and separator
if (c == '/' || c == '\\') {
// if subpath is empty just add separator
if (subpath.empty()) {
ret += c;
continue;
}
// Append real filename (proper case)
std::string f2;
if (realFileName(f.substr(0,pos),&f2))
ret += f2;
else
ret += subpath;
subpath.clear();
// Append separator
ret += c;
} else {
subpath += c;
}
buf[sep] = 0;
if (!realFileName(buf,ostr))
return f;
ostr << '/';
buf[sep] = '/';
}
if (!realFileName(buf, ostr))
return f;
return ostr.str();
if (!subpath.empty()) {
std::string f2;
if (realFileName(f,&f2))
ret += f2;
else
ret += subpath;
}
return ret;
}
bool isAbsolutePath(const std::string &path)
{
if (path.length() >= 3 && path[0] > 0 && std::isalpha(path[0]) && path[1] == ':' && (path[2] == '\\' || path[2] == '/'))
return true;
return path.length() > 1U && (path[0] == '/' || path[0] == '/');
}
#else
#define realFilename(f) f
bool isAbsolutePath(const std::string &path)
{
return path.length() > 1U && path[0] == '/';
}
#endif
/**
@ -1727,6 +1791,14 @@ namespace simplecpp {
// replace backslash separators
std::replace(path.begin(), path.end(), '\\', '/');
const bool unc(path.compare(0,2,"//") == 0);
// replace "//" with "/"
pos = 0;
while ((pos = path.find("//",pos)) != std::string::npos) {
path.erase(pos,1);
}
// remove "./"
pos = 0;
while ((pos = path.find("./",pos)) != std::string::npos) {
@ -1736,184 +1808,207 @@ namespace simplecpp {
pos += 2;
}
// remove "xyz/../"
pos = 1U;
while ((pos = path.find("/../", pos)) != std::string::npos) {
const std::string::size_type pos1 = path.rfind('/', pos - 1U);
if (pos1 == std::string::npos) {
path.erase(0,pos+4);
pos = 0;
// remove trailing dot if path ends with "/."
if (endsWith(path,"/."))
path.erase(path.size()-1);
// simplify ".."
pos = 1; // don't simplify ".." if path starts with that
while ((pos = path.find("/..", pos)) != std::string::npos) {
// not end of path, then string must be "/../"
if (pos + 3 < path.size() && path[pos + 3] != '/') {
++pos;
continue;
}
// get previous subpath
const std::string::size_type pos1 = path.rfind('/', pos - 1U) + 1U;
const std::string previousSubPath = path.substr(pos1, pos-pos1);
if (previousSubPath == "..") {
// don't simplify
++pos;
} else {
path.erase(pos1,pos-pos1+3);
pos = std::min((std::string::size_type)1, pos1);
// remove previous subpath and ".."
path.erase(pos1,pos-pos1+4);
if (path.empty())
path = ".";
// update pos
pos = (pos1 == 0) ? 1 : (pos1 - 1);
}
}
// Remove trailing '/'?
//if (path.size() > 1 && endsWith(path, "/"))
// path.erase(path.size()-1);
if (unc)
path = '/' + path;
return realFilename(path);
}
}
namespace {
/** Evaluate sizeof(type) */
void simplifySizeof(simplecpp::TokenList &expr, const std::map<std::string, std::size_t> &sizeOfType)
{
for (simplecpp::Token *tok = expr.front(); tok; tok = tok->next) {
if (tok->str != "sizeof")
continue;
simplecpp::Token *tok1 = tok->next;
if (!tok1) {
throw std::runtime_error("missed sizeof argument");
}
simplecpp::Token *tok2 = tok1->next;
if (!tok2) {
throw std::runtime_error("missed sizeof argument");
}
if (tok1->op == '(') {
tok1 = tok1->next;
while (tok2->op != ')')
tok2 = tok2->next;
}
std::string type;
for (simplecpp::Token *typeToken = tok1; typeToken != tok2; typeToken = typeToken->next) {
if ((typeToken->str == "unsigned" || typeToken->str == "signed") && typeToken->next->name)
continue;
if (typeToken->str == "*" && type.find('*') != std::string::npos)
continue;
if (!type.empty())
type += ' ';
type += typeToken->str;
}
const std::map<std::string, std::size_t>::const_iterator it = sizeOfType.find(type);
if (it != sizeOfType.end())
tok->setstr(toString(it->second));
else
continue;
tok2 = tok2->next;
while (tok->next != tok2)
expr.deleteToken(tok->next);
/** Evaluate sizeof(type) */
static void simplifySizeof(simplecpp::TokenList &expr, const std::map<std::string, std::size_t> &sizeOfType)
{
for (simplecpp::Token *tok = expr.front(); tok; tok = tok->next) {
if (tok->str != "sizeof")
continue;
simplecpp::Token *tok1 = tok->next;
if (!tok1) {
throw std::runtime_error("missed sizeof argument");
}
simplecpp::Token *tok2 = tok1->next;
if (!tok2) {
throw std::runtime_error("missed sizeof argument");
}
if (tok1->op == '(') {
tok1 = tok1->next;
while (tok2->op != ')')
tok2 = tok2->next;
}
}
void simplifyName(simplecpp::TokenList &expr)
{
std::set<std::string> altop;
altop.insert("and");
altop.insert("or");
altop.insert("bitand");
altop.insert("bitor");
altop.insert("not");
altop.insert("not_eq");
altop.insert("xor");
for (simplecpp::Token *tok = expr.front(); tok; tok = tok->next) {
if (tok->name) {
if (altop.find(tok->str) != altop.end()) {
bool alt;
if (tok->str == "not") {
alt = isAlternativeUnaryOp(tok,tok->str);
} else {
alt = isAlternativeBinaryOp(tok,tok->str);
}
if (alt)
continue;
std::string type;
for (simplecpp::Token *typeToken = tok1; typeToken != tok2; typeToken = typeToken->next) {
if ((typeToken->str == "unsigned" || typeToken->str == "signed") && typeToken->next->name)
continue;
if (typeToken->str == "*" && type.find('*') != std::string::npos)
continue;
if (!type.empty())
type += ' ';
type += typeToken->str;
}
const std::map<std::string, std::size_t>::const_iterator it = sizeOfType.find(type);
if (it != sizeOfType.end())
tok->setstr(toString(it->second));
else
continue;
tok2 = tok2->next;
while (tok->next != tok2)
expr.deleteToken(tok->next);
}
}
static const char * const altopData[] = {"and","or","bitand","bitor","not","not_eq","xor"};
static const std::set<std::string> altop(&altopData[0], &altopData[7]);
static void simplifyName(simplecpp::TokenList &expr)
{
for (simplecpp::Token *tok = expr.front(); tok; tok = tok->next) {
if (tok->name) {
if (altop.find(tok->str) != altop.end()) {
bool alt;
if (tok->str == "not") {
alt = isAlternativeUnaryOp(tok,tok->str);
} else {
alt = isAlternativeBinaryOp(tok,tok->str);
}
tok->setstr("0");
if (alt)
continue;
}
tok->setstr("0");
}
}
}
void simplifyNumbers(simplecpp::TokenList &expr)
{
for (simplecpp::Token *tok = expr.front(); tok; tok = tok->next) {
if (tok->str.size() == 1U)
continue;
if (tok->str.compare(0,2,"0x") == 0)
tok->setstr(toString(stringToULL(tok->str)));
else if (tok->str[0] == '\'')
tok->setstr(toString(tok->str[1] & 0xffU));
}
static void simplifyNumbers(simplecpp::TokenList &expr)
{
for (simplecpp::Token *tok = expr.front(); tok; tok = tok->next) {
if (tok->str.size() == 1U)
continue;
if (tok->str.compare(0,2,"0x") == 0)
tok->setstr(toString(stringToULL(tok->str)));
else if (tok->str[0] == '\'')
tok->setstr(toString(tok->str[1] & 0xffU));
}
}
static long long evaluate(simplecpp::TokenList &expr, const std::map<std::string, std::size_t> &sizeOfType)
{
simplifySizeof(expr, sizeOfType);
simplifyName(expr);
simplifyNumbers(expr);
expr.constFold();
// TODO: handle invalid expressions
return expr.cfront() && expr.cfront() == expr.cback() && expr.cfront()->number ? stringToLL(expr.cfront()->str) : 0LL;
}
static const simplecpp::Token *gotoNextLine(const simplecpp::Token *tok)
{
const unsigned int line = tok->location.line;
const unsigned int file = tok->location.fileIndex;
while (tok && tok->location.line == line && tok->location.fileIndex == file)
tok = tok->next;
return tok;
}
static std::string openHeader(std::ifstream &f, const simplecpp::DUI &dui, const std::string &sourcefile, const std::string &header, bool systemheader)
{
if (simplecpp::isAbsolutePath(header)) {
f.open(header.c_str());
return f.is_open() ? simplecpp::simplifyPath(header) : "";
}
long long evaluate(simplecpp::TokenList &expr, const std::map<std::string, std::size_t> &sizeOfType)
{
simplifySizeof(expr, sizeOfType);
simplifyName(expr);
simplifyNumbers(expr);
expr.constFold();
// TODO: handle invalid expressions
return expr.cfront() && expr.cfront() == expr.cback() && expr.cfront()->number ? stringToLL(expr.cfront()->str) : 0LL;
}
const simplecpp::Token *gotoNextLine(const simplecpp::Token *tok)
{
const unsigned int line = tok->location.line;
const unsigned int file = tok->location.fileIndex;
while (tok && tok->location.line == line && tok->location.fileIndex == file)
tok = tok->next;
return tok;
}
std::string openHeader(std::ifstream &f, const simplecpp::DUI &dui, const std::string &sourcefile, const std::string &header, bool systemheader)
{
if (!systemheader) {
if (sourcefile.find_first_of("\\/") != std::string::npos) {
const std::string s = sourcefile.substr(0, sourcefile.find_last_of("\\/") + 1U) + header;
f.open(s.c_str());
if (f.is_open())
return simplecpp::simplifyPath(s);
} else {
f.open(header.c_str());
if (f.is_open())
return simplecpp::simplifyPath(header);
}
}
for (std::list<std::string>::const_iterator it = dui.includePaths.begin(); it != dui.includePaths.end(); ++it) {
std::string s = *it;
if (!s.empty() && s[s.size()-1U]!='/' && s[s.size()-1U]!='\\')
s += '/';
s += header;
if (!systemheader) {
if (sourcefile.find_first_of("\\/") != std::string::npos) {
const std::string s = sourcefile.substr(0, sourcefile.find_last_of("\\/") + 1U) + header;
f.open(s.c_str());
if (f.is_open())
return simplecpp::simplifyPath(s);
} else {
f.open(header.c_str());
if (f.is_open())
return simplecpp::simplifyPath(header);
}
return "";
}
std::string getFileName(const std::map<std::string, simplecpp::TokenList *> &filedata, const std::string &sourcefile, const std::string &header, const simplecpp::DUI &dui, bool systemheader)
{
if (!systemheader) {
if (sourcefile.find_first_of("\\/") != std::string::npos) {
const std::string s(simplecpp::simplifyPath(sourcefile.substr(0, sourcefile.find_last_of("\\/") + 1U) + header));
if (filedata.find(s) != filedata.end())
return s;
} else {
std::string s = simplecpp::simplifyPath(header);
if (filedata.find(s) != filedata.end())
return s;
}
}
for (std::list<std::string>::const_iterator it = dui.includePaths.begin(); it != dui.includePaths.end(); ++it) {
std::string s = *it;
if (!s.empty() && s[s.size()-1U]!='/' && s[s.size()-1U]!='\\')
s += '/';
s += header;
f.open(s.c_str());
if (f.is_open())
return simplecpp::simplifyPath(s);
}
for (std::list<std::string>::const_iterator it = dui.includePaths.begin(); it != dui.includePaths.end(); ++it) {
std::string s = *it;
if (!s.empty() && s[s.size()-1U]!='/' && s[s.size()-1U]!='\\')
s += '/';
s += header;
s = simplecpp::simplifyPath(s);
return "";
}
static std::string getFileName(const std::map<std::string, simplecpp::TokenList *> &filedata, const std::string &sourcefile, const std::string &header, const simplecpp::DUI &dui, bool systemheader)
{
if (simplecpp::isAbsolutePath(header)) {
return (filedata.find(header) != filedata.end()) ? simplecpp::simplifyPath(header) : "";
}
if (!systemheader) {
if (sourcefile.find_first_of("\\/") != std::string::npos) {
const std::string s(simplecpp::simplifyPath(sourcefile.substr(0, sourcefile.find_last_of("\\/") + 1U) + header));
if (filedata.find(s) != filedata.end())
return s;
} else {
std::string s = simplecpp::simplifyPath(header);
if (filedata.find(s) != filedata.end())
return s;
}
return "";
}
bool hasFile(const std::map<std::string, simplecpp::TokenList *> &filedata, const std::string &sourcefile, const std::string &header, const simplecpp::DUI &dui, bool systemheader)
{
return !getFileName(filedata, sourcefile, header, dui, systemheader).empty();
for (std::list<std::string>::const_iterator it = dui.includePaths.begin(); it != dui.includePaths.end(); ++it) {
std::string s = *it;
if (!s.empty() && s[s.size()-1U]!='/' && s[s.size()-1U]!='\\')
s += '/';
s += header;
s = simplecpp::simplifyPath(s);
if (filedata.find(s) != filedata.end())
return s;
}
return "";
}
static bool hasFile(const std::map<std::string, simplecpp::TokenList *> &filedata, const std::string &sourcefile, const std::string &header, const simplecpp::DUI &dui, bool systemheader)
{
return !getFileName(filedata, sourcefile, header, dui, systemheader).empty();
}
std::map<std::string, simplecpp::TokenList*> simplecpp::load(const simplecpp::TokenList &rawtokens, std::vector<std::string> &fileNumbers, const simplecpp::DUI &dui, simplecpp::OutputList *outputList)

View File

@ -268,6 +268,7 @@ namespace simplecpp {
};
struct SIMPLECPP_LIB DUI {
DUI() {}
std::list<std::string> defines;
std::set<std::string> undefined;
std::list<std::string> includePaths;