[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/baltth/simplecpp/master/simplecpp.cpp [Back]  [Original]

/*
 * simplecpp - A simple and high-fidelity C/C++ preprocessor library
 * Copyright (C) 2016 Daniel Marjamki.
 *
 * This library is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation, either
 * version 3 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see .
 */

#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
#define SIMPLECPP_WINDOWS
#define NOMINMAX
#endif
#include "simplecpp.h"

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#ifdef SIMPLECPP_WINDOWS
#include 
#undef ERROR
#undef TRUE
#endif

static bool isHex(const std::string &s)
{
    return s.size()>2 && (s.compare(0,2,"0x")==0 || s.compare(0,2,"0X")==0);
}


static const simplecpp::TokenString DEFINE("define");
static const simplecpp::TokenString UNDEF("undef");

static const simplecpp::TokenString INCLUDE("include");

static const simplecpp::TokenString ERROR("error");
static const simplecpp::TokenString WARNING("warning");

static const simplecpp::TokenString IF("if");
static const simplecpp::TokenString IFDEF("ifdef");
static const simplecpp::TokenString IFNDEF("ifndef");
static const simplecpp::TokenString DEFINED("defined");
static const simplecpp::TokenString ELSE("else");
static const simplecpp::TokenString ELIF("elif");
static const simplecpp::TokenString ENDIF("endif");

static const simplecpp::TokenString PRAGMA("pragma");
static const simplecpp::TokenString ONCE("once");

template static std::string toString(T t)
{
    std::ostringstream ostr;
    ostr > std::hex;
    istr >> ret;
    return ret;
}

static unsigned long long stringToULL(const std::string &s)
{
    unsigned long long ret;
    const bool hex = isHex(s);
    std::istringstream istr(hex ? s.substr(2) : s);
    if (hex)
        istr >> std::hex;
    istr >> ret;
    return ret;
}

static bool startsWith(const std::string &str, const std::string &s)
{
    return (str.size() >= s.size() && str.compare(0, s.size(), s) == 0);
}

static bool endsWith(const std::string &s, const std::string &e)
{
    return (s.size() >= e.size() && s.compare(s.size() - e.size(), e.size(), e) == 0);
}

static bool sameline(const simplecpp::Token *tok1, const simplecpp::Token *tok2)
{
    return tok1 && tok2 && tok1->location.sameline(tok2->location);
}

static bool isAlternativeBinaryOp(const simplecpp::Token *tok, const std::string &alt)
{
    return (tok->name &&
            tok->str == alt &&
            tok->previous &&
            tok->next &&
            (tok->previous->number || tok->previous->name || tok->previous->op == ')') &&
            (tok->next->number || tok->next->name || tok->next->op == '('));
}

static bool isAlternativeUnaryOp(const simplecpp::Token *tok, const std::string &alt)
{
    return ((tok->name && tok->str == alt) &&
            (!tok->previous || tok->previous->op == '(') &&
            (tok->next && (tok->next->name || tok->next->number)));
}

void simplecpp::Location::adjust(const std::string &str)
{
    if (str.find_first_of("\r\n") == std::string::npos) {
        col += str.size();
        return;
    }

    for (std::size_t i = 0U; i < str.size(); ++i) {
        col++;
        if (str[i] == '\n' || str[i] == '\r') {
            col = 1;
            line++;
            if (str[i] == '\r' && (i+1)previous)
        tok = tok->previous;
    for (; tok; tok = tok->next) {
        if (tok->previous) {
            std::cout previous) ? ' ' : '\n');
        }
        std::cout str;
    }
    std::cout next) {
        if (tok != this) {
            std::cout previous) ? ' ' : '\n');
        }
        std::cout str;
    }
    std::cout next)
            push_back(new Token(*tok));
        sizeOfType = other.sizeOfType;
    }
    return *this;
}

void simplecpp::TokenList::clear()
{
    backToken = NULL;
    while (frontToken) {
        Token *next = frontToken->next;
        delete frontToken;
        frontToken = next;
    }
    sizeOfType.clear();
}

void simplecpp::TokenList::push_back(Token *tok)
{
    if (!frontToken)
        frontToken = tok;
    else
        backToken->next = tok;
    tok->previous = backToken;
    backToken = tok;
}

void simplecpp::TokenList::dump() const
{
    std::cout location.line < loc.line || tok->location.fileIndex != loc.fileIndex) {
            ret location;
        }

        while (tok->location.line > loc.line) {
            ret previous, tok))
            ret str);
    }

    return ret.str();
}

static unsigned char readChar(std::istream &istr, unsigned int bom)
{
    unsigned char ch = (unsigned char)istr.get();

    // For UTF-16 encoded files the BOM is 0xfeff/0xfffe. If the
    // character is non-ASCII character then replace it with 0xff
    if (bom == 0xfeff || bom == 0xfffe) {
        const unsigned char ch2 = (unsigned char)istr.get();
        const int ch16 = (bom == 0xfeff) ? (chop == 'R') {
                std::string delim;
                ch = readChar(istr,bom);
                while (istr.good() && ch != '(' && ch != '\n') {
                    delim += ch;
                    ch = readChar(istr,bom);
                }
                if (!istr.good() || ch == '\n')
                    // TODO report
                    return;
                currentToken = '\"';
                const std::string endOfRawString(')' + delim + '\"');
                while (istr.good() && !endsWith(currentToken, endOfRawString))
                    currentToken += readChar(istr,bom);
                if (!endsWith(currentToken, endOfRawString))
                    // TODO report
                    return;
                currentToken.erase(currentToken.size() - endOfRawString.size(), endOfRawString.size() - 1U);
                back()->setstr(escapeString(currentToken));
                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;
            }

            currentToken = readUntil(istr,location,ch,ch,outputList);
            if (currentToken.size() < 2U)
                // TODO report
                return;

            std::string s = currentToken;
            std::string::size_type pos;
            while ((pos = s.find_first_of("\r\n")) != std::string::npos) {
                s.erase(pos,1);
            }

            push_back(new Token(s, location)); // push string without newlines

            location.adjust(currentToken);

            continue;
        }

        else {
            currentToken += ch;
        }

        if (currentToken == ">")
            result = stringToLL(tok->previous->str) >> stringToLL(tok->next->str);
        else
            continue;

        tok = tok->previous;
        tok->setstr(toString(result));
        deleteToken(tok->next);
        deleteToken(tok->next);
    }
}

static const std::string NOTEQ("not_eq");
void simplecpp::TokenList::constFoldComparison(Token *tok)
{
    for (; tok && tok->op != ')'; tok = tok->next) {
        if (isAlternativeBinaryOp(tok,NOTEQ))
            tok->setstr("!=");

        if (!tok->startsWithOneOf("=!"))
            continue;
        if (!tok->previous || !tok->previous->number)
            continue;
        if (!tok->next || !tok->next->number)
            continue;

        int result;
        if (tok->str == "==")
            result = (stringToLL(tok->previous->str) == stringToLL(tok->next->str));
        else if (tok->str == "!=")
            result = (stringToLL(tok->previous->str) != stringToLL(tok->next->str));
        else if (tok->str == ">")
            result = (stringToLL(tok->previous->str) > stringToLL(tok->next->str));
        else if (tok->str == ">=")
            result = (stringToLL(tok->previous->str) >= stringToLL(tok->next->str));
        else if (tok->str == "setstr(toString(tok->str[1] & 0xffU));
    }
}

static long long evaluate(simplecpp::TokenList &expr, const std::map &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 (isAbsolutePath(header)) {
        f.open(header.c_str());
        return f.is_open() ? simplecpp::simplifyPath(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);
        }
    }

    for (std::list::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);
    }

    return "";
}

static std::string getFileName(const std::map &filedata, const std::string &sourcefile, const std::string &header, const simplecpp::DUI &dui, bool systemheader)
{
	if (filedata.empty()) {
		return "";
	}
    if (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;
        }
    }

    for (std::list::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 &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 simplecpp::load(const simplecpp::TokenList &rawtokens, std::vector &fileNumbers, const simplecpp::DUI &dui, simplecpp::OutputList *outputList)
{
    std::map ret;

    std::list filelist;

    // -include files
    for (std::list::const_iterator it = dui.includes.begin(); it != dui.includes.end(); ++it) {
        const std::string &filename = realFilename(*it);

        if (ret.find(filename) != ret.end())
            continue;

        std::ifstream fin(filename.c_str());
        if (!fin.is_open())
            continue;

        TokenList *tokenlist = new TokenList(fin, fileNumbers, filename, outputList);
        if (!tokenlist->front()) {
            delete tokenlist;
            continue;
        }

        ret[filename] = tokenlist;
        filelist.push_back(tokenlist->front());
    }

    for (const Token *rawtok = rawtokens.cfront(); rawtok || !filelist.empty(); rawtok = rawtok ? rawtok->next : NULL) {
        if (rawtok == NULL) {
            rawtok = filelist.back();
            filelist.pop_back();
        }

        if (rawtok->op != '#' || sameline(rawtok->previousSkipComments(), rawtok))
            continue;

        rawtok = rawtok->nextSkipComments();
        if (!rawtok || rawtok->str != INCLUDE)
            continue;

        const std::string &sourcefile = rawtok->location.file();

        const Token *htok = rawtok->nextSkipComments();
        if (!sameline(rawtok, htok))
            continue;

        bool systemheader = (htok->str[0] == '

Web Proxy Viewer  |  New URL  |  Original Page