diff --git a/setup.py b/setup.py old mode 100644 new mode 100755 index 973b826..3a65f2b --- a/setup.py +++ b/setup.py @@ -1,8 +1,7 @@ -#!/usr/bin/env/python +#!/usr/bin/python3 import os import platform - from setuptools import setup from setuptools.extension import Extension @@ -11,19 +10,18 @@ extra_compile_args = [] extra_link_args = [] -if platform.system() == "Linux": - extra_compile_args = ["-std=c++14"] - extra_link_args = ["-lstdc++fs"] +if platform.system() == "Linux" or platform.system() == "Darwin": + extra_compile_args = ["-std=c++11"] setup(name="ccscript", - version="1.338", - description="ccscript", - url="http://starmen.net/pkhack/ccscript", - ext_modules=[ - Extension("ccscript", - source_files, - language="c++", - extra_compile_args=extra_compile_args, - extra_link_args=extra_link_args - ) - ]) \ No newline at end of file + version="1.339", + description="ccscript", + url="http://starmen.net/pkhack/ccscript", + ext_modules=[ + Extension("ccscript", + source_files, + language="c++", + extra_compile_args=extra_compile_args, + extra_link_args=extra_link_args + ) + ]) diff --git a/src/Makefile b/src/Makefile index 7a94ecb..cd2ca17 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,13 +1,12 @@ # # Crappy makefile for ccscript compiler (ccc) # -CXXFLAGS = -c -Wall -O3 -std=c++14 +CXXFLAGS = -c -Wall -O3 -std=c++11 OBJDIR = obj BINDIR = bin OUTFILE = ccc SOURCES = ccc.cpp compiler.cpp module.cpp bytechunk.cpp lexer.cpp parser.cpp ast.cpp \ stringparser.cpp symboltable.cpp table.cpp value.cpp anchor.cpp -LIBS = -lstdc++fs OBJECTS = $(SOURCES:%.cpp=$(OBJDIR)/%.o) INSTALL_DIR = /usr/local @@ -39,13 +38,13 @@ endif # # Targets # - + all: ccc tests runtests # Builds the compiler ccc: mkdirs libsdir $(OBJECTS) - $(CXX) $(OBJECTS) $(LIBS) -o $(BINDIR)/$@ + $(CXX) $(OBJECTS) -o $(BINDIR)/$@ # Ensure that bin and obj directories exist @@ -111,5 +110,5 @@ $(OBJDIR)/table.o: table.h clean: -$(RM) $(OBJDIR)$(SEP)*.o $(BINDIR)$(SEP)$(OUTFILE) -$(MAKE) -C tests clean - + diff --git a/src/bytechunk.cpp b/src/bytechunk.cpp index b1367ff..25e3932 100644 --- a/src/bytechunk.cpp +++ b/src/bytechunk.cpp @@ -166,7 +166,7 @@ void ByteChunk::Truncate(unsigned int newsize) bytes.resize(newsize); pos = bytes.size(); - + cinfo.resize(newsize); } @@ -253,7 +253,7 @@ void ByteChunk::TranslateReferences(ByteChunk& destination, } } - + for(vector::const_iterator it = needed_refs.begin(); it != needed_refs.end(); ++it) { @@ -307,7 +307,7 @@ void ByteChunk::TranslateReferences(ByteChunk& destination, // how many total bytes of the reference are left? r.length = std::min(r.length, r.length - r.offset - overflow); } - + // Add the reference destination.AddReference(r.location + start - offset, r.offset, r.length, r.target); } @@ -442,7 +442,7 @@ unsigned char ByteChunk::ReadByte(unsigned int pos) const try { return bytes.at(pos); } - catch(std::exception e) {} + catch(std::exception&) {} return 0; } @@ -453,7 +453,7 @@ unsigned short ByteChunk::ReadShort(unsigned int pos) const result += bytes.at(pos); result += bytes.at(pos+1) << 8; } - catch(std::exception e) { + catch(std::exception&) { // just give incomplete results on exception } return result; @@ -468,7 +468,7 @@ unsigned int ByteChunk::ReadLong(unsigned int pos) const result += bytes.at(pos+2) << 16; result += bytes.at(pos+3) << 24; } - catch(std::exception e) { + catch(std::exception&) { } return result; } diff --git a/src/ccc.cpp b/src/ccc.cpp index 322e4ed..37ab511 100644 --- a/src/ccc.cpp +++ b/src/ccc.cpp @@ -7,11 +7,20 @@ #include #include -#include -namespace fs = std::experimental::filesystem::v1; +#ifdef _WIN32 + #include + #include + #include + namespace fs = std::experimental::filesystem::v1; +#else + #include "filesystem/filesystem_mini.h" + namespace fs = filesystem; +#endif +#include "ccc.h" #include "compiler.h" #include "module.h" +#include "util.h" using std::vector; using std::string; @@ -19,8 +28,6 @@ using std::stringstream; using std::cout; using std::endl; - - string getbasepath(const char* p) { string path = p; @@ -32,7 +39,7 @@ string getbasepath(const char* p) void printversion() { - cout << "ccc version 1.337 Duck Tape Edition" << endl; + cout << "ccc version 1.339 Duck Tape Edition" << endl; } void printusage() @@ -48,8 +55,6 @@ void printusage() << " --nostdlibs Do not include the default standard libraries" << endl << " --summary Writes a compilation summary to " << endl << " Useful if you want to know where stuff went." << endl - //<< " --shortpause Short pauses '/' are frames long (default 5)" << endl - //<< " --longpause Long pauses '|' are frames long (default 15)" << endl << " --printAST Prints the abstract syntax tree for each module" << endl << " --printRT Prints the root symbol table for each module" << endl << " --printJumps Prints the compiled addresses of all labels" << endl @@ -64,9 +69,8 @@ void printusage() << " put the resulting compiled text at $F20000 in the ROM Earthbound.smc" << endl; } -int main(int argc, char* argv[]) +int cccmain(int argc, const char* argv[]) { - // // Get the default libs path // @@ -89,8 +93,6 @@ int main(int argc, char* argv[]) vector libs; bool noreset = false; bool nostdlibs = false; - unsigned char shortpause; - unsigned char longpause; bool printAST = false; bool printRT = false; bool printJumps = false; @@ -105,8 +107,6 @@ int main(int argc, char* argv[]) // --libs look in for standard libraries // -h,--help print help message // --nostdlibs do not include default libraries - // --shortpause duration of short pauses ('/') - // --longpause duration of long pauses ('|') // --printAST print AST for each module // --printRT print root table for each module // --printJumps print a list of jumps and addresses @@ -183,14 +183,6 @@ int main(int argc, char* argv[]) } summaryfile = argv[p++]; } - else if(!strcmp(argv[p],"--shortpause")) { - p++; - shortpause = (unsigned char)strtoul(argv[p++], NULL, 10); - } - else if(!strcmp(argv[p],"--longpause")) { - p++; - longpause = (unsigned char)strtoul(argv[p++], NULL, 10); - } else if(!strcmp(argv[p],"--printAST")) { p++; printAST = true; @@ -269,7 +261,7 @@ int main(int argc, char* argv[]) if(!summaryfile.empty()) { std::fstream file; - file.open(summaryfile.c_str(), std::ios_base::out|std::ios_base::trunc); + file.open(ConvertToNativeString(summaryfile).c_str(), std::ios_base::out|std::ios_base::trunc); if(file.fail()) { std::cerr << "Couldn't open " << summaryfile << " to write summary file." << std::endl; @@ -279,4 +271,32 @@ int main(int argc, char* argv[]) } return compiler.Failed(); -} \ No newline at end of file +} + +#ifdef _WIN32 +int wmain(int argc, const wchar_t* argv[]) +{ + std::vector utf8Args; + std::vector utf8Argv; + utf8Args.reserve(argc); + utf8Args.reserve(argc); + + { + std::wstring_convert, wchar_t> converter; + + // Convert the utf-16 args to utf-8... + // and expose the std::strings as a vector of const char*s + for(int i = 0; i < argc; ++i) { + utf8Args.emplace_back(converter.to_bytes(argv[i])); + utf8Argv.emplace_back(utf8Args[i].c_str()); + } + } + + return cccmain(argc, utf8Argv.data()); +} +#else +int main(int argc, const char* argv[]) +{ + return cccmain(argc, argv); +} +#endif diff --git a/src/ccc.h b/src/ccc.h index 3556e31..a96d848 100644 --- a/src/ccc.h +++ b/src/ccc.h @@ -1 +1,2 @@ -int main(int argc, char* argv[]); +extern "C" int cccmain(int argc, const char* argv[]); +extern "C" int main(int argc, const char* argv[]); diff --git a/src/compiler.cpp b/src/compiler.cpp index 1125c08..b0cdd41 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -9,8 +9,13 @@ #include #include -#include -namespace fs = std::experimental::filesystem::v1; +#ifdef _WIN32 + #include + namespace fs = std::experimental::filesystem::v1; +#else + #include "filesystem/filesystem_mini.h" + namespace fs = filesystem; +#endif #include "module.h" @@ -20,6 +25,7 @@ namespace fs = std::experimental::filesystem::v1; #include "module.h" #include "symboltable.h" #include "exception.h" +#include "util.h" using namespace std; @@ -60,7 +66,7 @@ Compiler::Compiler(const string& romfile, unsigned int adr, unsigned int endadr) nostdlibs = false; // Open the file - ifstream file(filename.c_str(), ifstream::binary); + ifstream file(ConvertToNativeString(filename), ifstream::binary); if(file.fail()) { Error("failed to open file " + filename + " for reading."); @@ -84,7 +90,7 @@ Compiler::Compiler(const string& romfile, unsigned int adr, unsigned int endadr) file.seekg(0, ifstream::end); filesize = file.tellg(); file.seekg(0); - filebuffer = new char[filesize]; + filebuffer = new char[(unsigned int) filesize]; file.read(filebuffer, filesize); file.close(); @@ -130,7 +136,7 @@ Compiler::~Compiler() void Compiler::WriteOutput() { if(failed) return; - ofstream file(filename.c_str(), ofstream::binary); + ofstream file(ConvertToNativeString(filename), ofstream::binary); if(file.fail()) { Error("failed to open file " + filename + " for writing."); @@ -165,7 +171,7 @@ Module* Compiler::LoadModule(const std::string &filename) // instead of SetLibTable, we should use m->Include(othermodule). //m->SetLibTable(libtable); string name = m->GetName(); - + if(GetModule(name) != NULL) { Error("attempt to redefine module " + name + "; module names must be unique"); return NULL; @@ -192,7 +198,7 @@ string Compiler::FindModule(const string& name, const string& filedir) { // Complete paths aren't looked for in include directories if (fs::path(name).is_absolute()) - return fs::exists( name )? name : ""; + return fs::exists( name ) ? name : ""; // First, try in the provided file directory. fs::path base(filedir); @@ -414,8 +420,8 @@ void Compiler::AssignModuleAddresses() bool found = false; for(i = sorted.begin(); i != sorted.end(); ++i) { - unsigned int size = (*i)->GetCodeSize(); - if((base & 0xFFFF) + size <= 0x10000) + unsigned int size = (*i)->GetCodeSize(); + if((base & 0xFFFF) + size <= 0x10000) { // Check for overwriting maximum address if((endadr > 0) && (base + size >= endadr)) @@ -471,7 +477,7 @@ void Compiler::OutputModules() throw Exception(ss.str()); } - m->WriteCode(filebuffer, MapVirtualAddress(m->GetBaseAddress()), filesize); + m->WriteCode(filebuffer, MapVirtualAddress(m->GetBaseAddress()), (int) filesize); if(printJumps && m->GetName().substr(0,3) != "std") m->PrintJumps(); @@ -554,7 +560,7 @@ void Compiler::DoDelayedWrites() << romwrites[i]->GetVirtualAddress(); throw Exception(ss.str()); } - romwrites[i]->DoWrite(filebuffer, padr, filesize); + romwrites[i]->DoWrite(filebuffer, padr, (int) filesize); } } @@ -576,7 +582,7 @@ void Compiler::DoDelayedWrites() */ void Compiler::WriteResetInfo(const std::string &filename) { - ofstream file(filename.c_str()); + ofstream file(ConvertToNativeString(filename)); if(file.fail()) throw Exception("couldn't create info file '" + filename + "'"); @@ -621,7 +627,7 @@ void Compiler::WriteResetInfo(const std::string &filename) void Compiler::ApplyResetInfo(const std::string& filename) { - ifstream file(filename.c_str()); + ifstream file(ConvertToNativeString(filename)); if(file.fail()) return; diff --git a/src/compiler.h b/src/compiler.h index 6382bd0..8a3796f 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -80,7 +80,7 @@ class Compiler // File info std::string filename; char* filebuffer; - int filesize; + std::streamoff filesize; int actual_start; int actual_end; int totalfrag; diff --git a/src/filesystem/LICENSE b/src/filesystem/LICENSE new file mode 100644 index 0000000..ccf4e97 --- /dev/null +++ b/src/filesystem/LICENSE @@ -0,0 +1,36 @@ +Copyright (c) 2016 Wenzel Jakob , All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +You are under no obligation whatsoever to provide any bug fixes, patches, or +upgrades to the features, functionality or performance of the source code +("Enhancements") to anyone; however, if you choose to make your Enhancements +available either publicly, or directly to the author of this software, without +imposing a separate written license agreement for such Enhancements, then you +hereby grant the following license: a non-exclusive, royalty-free perpetual +license to install, use, modify, prepare derivative works, incorporate into +other computer software, distribute, and sublicense such enhancements or +derivative works thereof, in binary and source code form. diff --git a/src/filesystem/filesystem_mini.h b/src/filesystem/filesystem_mini.h new file mode 100644 index 0000000..5b3e23d --- /dev/null +++ b/src/filesystem/filesystem_mini.h @@ -0,0 +1,211 @@ +#ifndef FILESYSTEM_PATH_H_ +#define FILESYSTEM_PATH_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__linux) + #include +#endif + +namespace filesystem { + /** + * \brief Simple class for manipulating paths on POSIX systems + */ + class path { + public: + path() : m_absolute(false) {} + path(const path &path) : m_path(path.m_path), m_absolute(path.m_absolute) {} + path(const char *string) { set(string); } + path(const std::string &string) { set(string); } + size_t length() const { return m_path.size(); } + bool empty() const { return m_path.empty(); } + bool is_absolute() const { return m_absolute; } + + path make_absolute() const { + char temp[PATH_MAX]; + + if (realpath(string().c_str(), temp) == NULL) + throw std::runtime_error("Internal error in realpath(): " + std::string(strerror(errno))); + + return path(temp); + } + + bool exists() const { + struct stat sb; + return stat(string().c_str(), &sb) == 0; + } + + size_t file_size() const { + struct stat sb; + + if (stat(string().c_str(), &sb) != 0) + throw std::runtime_error("path::file_size(): cannot stat file \"" + string() + "\"!"); + + return (size_t) sb.st_size; + } + + bool is_directory() const { + struct stat sb; + + if (stat(string().c_str(), &sb)) + return false; + + return S_ISDIR(sb.st_mode); + } + + bool is_file() const { + struct stat sb; + + if (stat(string().c_str(), &sb)) + return false; + + return S_ISREG(sb.st_mode); + } + + std::string extension() const { + const std::string &name = filename(); + size_t pos = name.find_last_of("."); + + if (pos == std::string::npos) + return ""; + + return name.substr(pos+1); + } + + std::string filename() const { + if (empty()) + return ""; + + const std::string &last = m_path[m_path.size()-1]; + return last; + } + + path parent_path() const { + path result; + result.m_absolute = m_absolute; + + if (m_path.empty()) { + if (!m_absolute) + result.m_path.push_back(".."); + } else { + size_t until = m_path.size() - 1; + + for (size_t i = 0; i < until; ++i) + result.m_path.push_back(m_path[i]); + } + + return result; + } + + path& operator/=(const path &other) { + if (other.m_absolute) + throw std::runtime_error("path::operator/(): expected a relative path!"); + + for (size_t i=0; i tokenize(const std::string &string, const std::string &delim) { + std::string::size_type lastPos = 0, pos = string.find_first_of(delim, lastPos); + std::vector tokens; + + while (lastPos != std::string::npos) { + if (pos != lastPos) + tokens.push_back(string.substr(lastPos, pos - lastPos)); + + lastPos = pos; + + if (lastPos == std::string::npos || lastPos + 1 == string.length()) + break; + + pos = string.find_first_of(delim, ++lastPos); + } + + return tokens; + } + + protected: + std::vector m_path; + bool m_absolute; + }; + + inline bool exists(const path& p) { + return p.exists(); + } + + inline bool equivalent(const path& p1, const path& p2) { + return p1.make_absolute() == p2.make_absolute(); + } +} +#endif \ No newline at end of file diff --git a/src/module.cpp b/src/module.cpp index 2f62866..eba305b 100644 --- a/src/module.cpp +++ b/src/module.cpp @@ -16,6 +16,7 @@ #include "symboltable.h" #include "bytechunk.h" #include "exception.h" +#include "util.h" using namespace std; @@ -68,9 +69,8 @@ void Module::Load(const string& filename) failed = true; return; } - ifstream in(filename.c_str()); - + ifstream in(ConvertToNativeString(filename)); if(in.fail()) { parent->Error("couldn't open " + filename); diff --git a/src/pythonlib.cpp b/src/pythonlib.cpp index 57fd936..c96a7b6 100644 --- a/src/pythonlib.cpp +++ b/src/pythonlib.cpp @@ -19,7 +19,7 @@ static PyObject* ccc(PyObject* self, PyObject* args) { return nullptr; } - std::vector argv; + std::vector argv; argv.reserve(argc+1); argv.push_back(CCC_BASENAME); for (int i = 0; i < argc; ++i) { @@ -39,7 +39,7 @@ static PyObject* ccc(PyObject* self, PyObject* args) { std::stringstream buffer; std::streambuf* old_cout = std::cout.rdbuf(buffer.rdbuf()); std::streambuf* old_cerr = std::cerr.rdbuf(buffer.rdbuf()); - int return_value = main(argc + 1, &argv[0]); + int return_value = cccmain(argc + 1, argv.data()); std::cout.rdbuf(old_cout); std::cerr.rdbuf(old_cerr); diff --git a/src/tests/src/main.cpp b/src/tests/src/main.cpp index bae552a..d945166 100644 --- a/src/tests/src/main.cpp +++ b/src/tests/src/main.cpp @@ -75,17 +75,17 @@ int main(int argc, char** argv) log.open(logfile.c_str(), ios::app); log << endl << "==========================" << endl; log << endl << "BEGIN TESTS" << endl << endl; - + // // Try to run all tests specified in the test list file // - try + try { ifstream file(tests_file.c_str()); if(file.fail()) throw runtime_error(string("couldn't open test list file '") + tests_file + "'"); - + while(!file.eof()) { string testfilename; @@ -109,7 +109,7 @@ int main(int argc, char** argv) // // NOTE: this assumes that all the paths in the test list file // are relative, which is fine for our purposes. For anything - // more general, we should just use std::experimental::filesystem::v1::path... + // more general, we should just use the standard library's filesystem path... string test_dir( testfilename ); string::size_type lastsep = test_dir.find_last_of("\\/"); if(lastsep == string::npos) diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..176eccb --- /dev/null +++ b/src/util.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +#ifdef _WIN32 +#include + +inline std::wstring ConvertToNativeString(const std::string str) { + std::wstring_convert> converter; + std::wstring wstr = converter.from_bytes(str); + return wstr; +} +#else +inline std::string ConvertToNativeString(const std::string str) { + return str; +} +#endif \ No newline at end of file