-/*
- * Compiler.cpp
- *
- * Created on: Sep 11, 2012
- * Author: holy
- */
-
#include "Compiler.h"
#include "Interpreter.h"
+#include "TypeDescription.h"
+#include "../common/Script.h"
#include <climits>
#include <cstring>
+#include <iostream>
#include <map>
#include <ostream>
#include <set>
+#include <stdexcept>
#include <string>
+#include <utility>
#include <vector>
+using std::iostream;
+using std::make_pair;
using std::map;
using std::ostream;
+using std::pair;
+using std::runtime_error;
using std::set;
using std::string;
+using std::strlen;
using std::vector;
namespace loader {
Compiler::Compiler(const Interpreter &intp)
-: intp(intp)
-, cursor(0) {
- int headerSize(sizeof(ObjectFileHeader) + (intp.Values().size() * sizeof(TypeOffset)));
-
- fileHeader.exportsBegin = headerSize + Remaining(headerSize, 16);
- fileHeader.exportsEnd = fileHeader.exportsBegin + (intp.ExportedIdentifiers().size() * sizeof(Export));
+: intp(intp) {
+ int headerSize(sizeof(ObjectFileHeader));
- fileHeader.externalsBegin = fileHeader.exportsEnd + Remaining(fileHeader.exportsEnd, 16);
- fileHeader.externalsEnd = fileHeader.externalsBegin + (intp.PostponedDefinitions().size() * sizeof(External));
+ fileHeader.exportsBegin = headerSize;
+ fileHeader.exportsEnd = fileHeader.exportsBegin
+ + (intp.ExportedIdentifiers().size() * sizeof(Export));
- fileHeader.exportStringsBegin = fileHeader.externalsEnd + Remaining(fileHeader.externalsEnd, 16);
- fileHeader.exportStringsEnd = fileHeader.exportStringsBegin;
- for (set<string>::const_iterator i(intp.ExportedIdentifiers().begin()), end(intp.ExportedIdentifiers().end()); i != end; ++i) {
- fileHeader.exportStringsEnd += i->size() + 1;
- }
-
- fileHeader.externalStringsBegin = fileHeader.exportStringsEnd + Remaining(fileHeader.exportStringsEnd, 16);
- fileHeader.externalStringsEnd = fileHeader.externalStringsBegin;
- for(vector<Interpreter::PostponedDefinition>::const_iterator i(intp.PostponedDefinitions().begin()), end(intp.PostponedDefinitions().end()); i != end; ++i) {
- fileHeader.externalStringsEnd += std::strlen(i->identifier) + 1;
- }
+ fileHeader.externalsBegin = fileHeader.exportsEnd;
+ fileHeader.externalsEnd = fileHeader.externalsBegin
+ + (intp.PostponedDefinitions().size() * sizeof(External));
- fileHeader.imagesBegin = fileHeader.externalStringsEnd + Remaining(fileHeader.externalStringsEnd, 16);
- fileHeader.imagesEnd = fileHeader.imagesBegin + (intp.Images().size() * sizeof(ImageProperties));
- for (map<string, SDL_Surface *>::const_iterator i(intp.Images().begin()), end(intp.Images().end()); i != end; ++i) {
- fileHeader.imagesEnd += i->second->w * i->second->h * i->second->format->BytesPerPixel;
- }
-
- fileHeader.objectsBegin = fileHeader.imagesEnd + Remaining(fileHeader.imagesEnd, 16);
- fileHeader.objectsEnd = fileHeader.objectsBegin;
- for (map<int, vector<void *> >::const_iterator i(intp.Values().begin()), end(intp.Values().end()); i != end; ++i) {
- const TypeDescription &td(TypeDescription::Get(i->first));
- objectOffsets[i->first] = fileHeader.objectsEnd;
- fileHeader.objectsEnd += td.Size() * i->second.size();
- fileHeader.objectsEnd += Remaining(fileHeader.objectsEnd, 16);
- }
+ fileHeader.objectsBegin = fileHeader.externalsEnd
+ + Remaining(fileHeader.externalsEnd, 16);
}
-void Compiler::Write(ostream &out) {
- WriteHeader(out);
+void Compiler::Write(iostream &out) {
+ ReserveHeader(out);
+ WriteObjects(out);
+ WriteOwnStrings(out);
+ fileHeader.objectsEnd = out.tellp();
Pad(out, 16);
+ fileHeader.arraysBegin = out.tellp();
+ WriteArrays(out);
+ fileHeader.arraysEnd = out.tellp();
+ fileHeader.scriptsBegin = out.tellp();
+ WriteScripts(out);
+ fileHeader.scriptsEnd = out.tellp();
+ out.seekp(0);
+ WriteHeader(out);
WriteExports(out);
- Pad(out, 16);
WriteExternals(out);
- Pad(out, 16);
- WriteExportStrings(out);
- Pad(out, 16);
- WriteExternalStrings(out);
- Pad(out, 16);
+ out.seekg(fileHeader.objectsBegin);
+ out.clear();
+ Relocate(out);
+ fileHeader.imagesBegin = out.tellp();
WriteImages(out);
- Pad(out, 16);
- WriteObjects(out);
+ fileHeader.imagesEnd = out.tellp();
+ out.seekp(0);
+ WriteHeader(out);
}
+void Compiler::ReserveHeader(ostream &out) {
+ Fill(out, fileHeader.objectsBegin);
+}
void Compiler::WriteHeader(ostream &out) {
- Write(out, reinterpret_cast<const char *>(&fileHeader), sizeof(ObjectFileHeader));
- for(map<int, vector<void *> >::const_iterator i(intp.Values().begin()), end(intp.Values().end()); i != end; ++i) {
- TypeOffset to;
- to.typeId = i->first;
- to.begin = GetTypeOffset(i->first);
- to.end = to.begin + (i->second.size() * TypeDescription::Get(i->first).Size());
- Write(out, reinterpret_cast<const char *>(&to), sizeof(TypeOffset));
+ Write(out, &fileHeader, sizeof(ObjectFileHeader));
+}
+
+void Compiler::WriteOwnStrings(ostream &out) {
+ for (set<string>::const_iterator
+ i(intp.ExportedIdentifiers().begin()),
+ end(intp.ExportedIdentifiers().end());
+ i != end; ++i) {
+ Object object;
+ object.typeId = Interpreter::STRING_ID;
+ object.size = i->size() + 1;
+ Write(out, &object, sizeof(Object));
+ addressMap.insert(make_pair(i->c_str(), out.tellp()));
+ Write(out, i->c_str(), object.size);
+ }
+ for(vector<Interpreter::PostponedDefinition>::const_iterator
+ i(intp.PostponedDefinitions().begin()),
+ end(intp.PostponedDefinitions().end());
+ i != end; ++i) {
+ Object object;
+ object.typeId = Interpreter::STRING_ID;
+ object.size = i->identifier.size() + 1;
+ Write(out, &object, sizeof(Object));
+ addressMap.insert(make_pair(
+ i->identifier.c_str(), out.tellp()));
+ Write(out, i->identifier.c_str(), object.size);
+ }
+ for (std::map<std::string, SDL_Surface *>::const_iterator
+ i(intp.Images().begin()), end(intp.Images().end());
+ i != end; ++i) {
+ addressMap.insert(make_pair(
+ i->second, 0));
+ Object object;
+ object.typeId = Interpreter::STRING_ID;
+ object.size = i->first.size() + 1;
+ Write(out, &object, sizeof(Object));
+ addressMap.insert(make_pair(
+ i->first.c_str(), out.tellp()));
+ Write(out, i->first.c_str(), object.size);
}
- TypeOffset to;
- to.typeId = 0;
- to.begin = 0;
- to.end = 0;
- Write(out, reinterpret_cast<const char *>(&to), sizeof(TypeOffset));
}
void Compiler::WriteExports(ostream &out) {
- int nameOffset(fileHeader.externalStringsBegin);
- for (set<string>::const_iterator i(intp.ExportedIdentifiers().begin()), end(intp.ExportedIdentifiers().end()); i != end; ++i) {
- const Interpreter::ParsedDefinition &dfn(intp.GetDefinition(*i));
+ for (set<string>::const_iterator
+ i(intp.ExportedIdentifiers().begin()),
+ end(intp.ExportedIdentifiers().end());
+ i != end; ++i) {
Export exp;
- exp.nameOffset = nameOffset;
- exp.typeId = dfn.type;
- exp.dataOffset = ObjectOffset(dfn.type, dfn.id);
- Write(out, reinterpret_cast<char *>(&exp), sizeof(Export));
- nameOffset += i->size() + 1;
+ PrepareExport(exp, *i);
+ Write(out, &exp, sizeof(Export));
}
}
void Compiler::WriteExternals(ostream &out) {
- int nameOffset(fileHeader.exportStringsBegin);
- for(vector<Interpreter::PostponedDefinition>::const_iterator i(intp.PostponedDefinitions().begin()), end(intp.PostponedDefinitions().end()); i != end; ++i) {
+ for(vector<Interpreter::PostponedDefinition>::const_iterator
+ i(intp.PostponedDefinitions().begin()),
+ end(intp.PostponedDefinitions().end());
+ i != end; ++i) {
External ext;
- ext.nameOffset = nameOffset;
- ext.referenceOffset = ReferenceOffset(i->type, i->id, i->offset);
- ext.inlined = i->inlined ? 1 : 0;
- Write(out, reinterpret_cast<char *>(&ext), sizeof(External));
- nameOffset += std::strlen(i->identifier) + 1;
+ PrepareExternal(ext, *i);
+ Write(out, &ext, sizeof(External));
}
}
-void Compiler::WriteExportStrings(ostream &out) {
- for (set<string>::const_iterator i(intp.ExportedIdentifiers().begin()), end(intp.ExportedIdentifiers().end()); i != end; ++i) {
- Write(out, i->c_str(), i->size() + 1);
+void Compiler::WriteObjects(ostream &out) {
+ Pad(out, 16);
+ for (map<int, vector<void *> >::const_iterator
+ i(intp.Values().begin()), end(intp.Values().end());
+ i != end; ++i) {
+ const TypeDescription &td(TypeDescription::Get(i->first));
+ for (vector<void *>::const_iterator
+ j(i->second.begin()), jend(i->second.end());
+ j != jend; ++j) {
+ Object object;
+ PrepareObject(object, td, *j);
+ Write(out, &object, sizeof(Object));
+ addressMap.insert(make_pair(*j, out.tellp()));
+ Write(out, *j, object.size);
+
+ if (td.TypeId() == Interpreter::SCRIPT_ID) {
+ common::Script *script = reinterpret_cast<common::Script *>(*j);
+ scripts.push_back(make_pair(const_cast<char *>(script->text), script->textlen));
+ }
+ }
}
}
-void Compiler::WriteExternalStrings(ostream &out) {
- for(vector<Interpreter::PostponedDefinition>::const_iterator i(intp.PostponedDefinitions().begin()), end(intp.PostponedDefinitions().end()); i != end; ++i) {
- Write(out, i->identifier, std::strlen(i->identifier) + 1);
+void Compiler::WriteArrays(ostream &out) {
+ Pad(out, 16);
+ for (vector<Interpreter::Array>::const_iterator
+ i(intp.Arrays().begin()), end(intp.Arrays().end());
+ i != end; ++i) {
+ Array array;
+ array.typeId = i->typeId;
+ array.size = i->size;
+ array.ref = i->ref;
+ Write(out, &array, sizeof(Array));
+ addressMap.insert(make_pair(i->data, out.tellp()));
+ Write(out, i->data, array.size);
}
}
void Compiler::WriteImages(ostream &out) {
- for (map<string, SDL_Surface *>::const_iterator i(intp.Images().begin()), end(intp.Images().end()); i != end; ++i) {
- ImageProperties ip;
- ip.flags = i->second->flags;
- ip.width = i->second->w;
- ip.height = i->second->h;
- ip.depth = i->second->format->BitsPerPixel;
- ip.pitch = i->second->pitch;
- ip.rmask = i->second->format->Rmask;
- ip.gmask = i->second->format->Gmask;
- ip.bmask = i->second->format->Bmask;
- ip.amask = i->second->format->Amask;
- Write(out, reinterpret_cast<char *>(&ip), sizeof(ImageProperties));
- SDL_LockSurface(i->second);
- Write(out, reinterpret_cast<char *>(i->second->pixels), ip.width * ip.height * (ip.depth / CHAR_BIT + (ip.depth % CHAR_BIT ? 1 : 0)));
- // TODO: store palette too?
- SDL_UnlockSurface(i->second);
+ for (std::map<unsigned int, void *>::const_iterator
+ i(images.begin()), end(images.end());
+ i != end; ++i) {
+ const string &path = intp.FindImage(
+ reinterpret_cast<SDL_Surface *>(i->second));
+ Image img;
+ img.pathOffset = addressMap.at(path.c_str());
+ img.destOffset = i->first;
+ Write(out, &img, sizeof(Image));
}
}
-void Compiler::WriteObjects(ostream &out) {
- for (map<int, vector<void *> >::const_iterator i(intp.Values().begin()), end(intp.Values().end()); i != end; ++i) {
- const TypeDescription &td(TypeDescription::Get(i->first));
- for (vector<void *>::const_iterator j(i->second.begin()), jend(i->second.end()); j != jend; ++j) {
- Write(out, reinterpret_cast<char *>(*j), td.Size());
- }
- Pad(out, 16);
+void Compiler::WriteScripts(ostream &out) {
+ for (vector<pair<const char *, unsigned int> >::const_iterator
+ i(scripts.begin()), end(scripts.end());
+ i != end; ++i) {
+ Script s;
+ s.size = i->second;
+ Write(out, &s, sizeof(Script));
+ addressMap.insert(make_pair(i->first, out.tellp()));
+ Write(out, i->first, s.size);
}
}
-void Compiler::Write(ostream &out, const char *data, int amount) {
- out.write(data, amount);
- cursor += amount;
+void Compiler::PrepareExport(Export &exp, const string &str) {
+ const Interpreter::ParsedDefinition &dfn
+ = intp.GetDefinition(str);
+ exp.nameOffset = addressMap[str.c_str()];
+ exp.typeId = dfn.type;
+ exp.dataOffset = addressMap[intp.GetObject(dfn.type, str)];
}
-void Compiler::Pad(ostream &out, int to) {
- for (int remaining(Remaining(cursor, to)); remaining > 0; --remaining) {
- out.put(0);
- ++cursor;
+void Compiler::PrepareExternal(
+ External &ext,
+ const Interpreter::PostponedDefinition &def) {
+ ext.nameOffset = addressMap[def.identifier.c_str()];
+ ext.referenceOffset = addressMap[def.object] + (def.dest - def.object);
+ ext.typeId = def.type;
+ ext.inlined = 0;
+ if (def.inlined) ext.inlined |= 1;
+ if (def.aggregate) ext.inlined |= 2;
+}
+
+void Compiler::PrepareObject(
+ Object &object,
+ const TypeDescription &td,
+ void *data) {
+ object.typeId = td.TypeId();
+ switch (td.TypeId()) {
+ case Interpreter::STRING_ID:
+ object.size = strlen(
+ reinterpret_cast<char *>(data)) + 1;
+ break;
+ default:
+ object.size = td.Size();
+ break;
}
}
-int Compiler::Remaining(int value, int alignment) {
- int have(value % alignment);
- return (have > 0) ? (16 - have) : 0;
+void Compiler::Relocate(iostream &out) {
+ int bufferSize = TypeDescription::GetMaxSize();
+ char *buffer = new char[bufferSize];
+ for (;out && out.tellg() < fileHeader.objectsEnd;) {
+ Object object;
+ out.read(reinterpret_cast<char *>(&object), sizeof(Object));
+ const TypeDescription &td = TypeDescription::Get(object.typeId);
+ unsigned int pos = out.tellg();
+
+ out.read(buffer, object.size);
+ Relocate(pos, buffer, td);
+ out.seekp(pos);
+ out.write(buffer, object.size);
+ out.seekg(out.tellp());
+ }
+ delete[] buffer;
+ out.seekg(fileHeader.arraysBegin);
+ Array array;
+ for (; out && out.tellg() < fileHeader.arraysEnd;) {
+ out.read(reinterpret_cast<char *>(&array), sizeof(Array));
+ buffer = new char[array.size];
+ unsigned int pos = out.tellg();
+ out.read(buffer, array.size);
+ if (array.ref) {
+ RelocateArray(buffer, array.size);
+ } else {
+ const TypeDescription &td = TypeDescription::Get(array.typeId);
+ for (char *i = buffer, *end = buffer + array.size;
+ i < end; i += td.Size()) {
+ Relocate(pos + (i - buffer), i, td);
+ }
+ }
+ out.seekp(pos);
+ out.write(buffer, array.size);
+ out.seekg(out.tellp());
+ delete[] buffer;
+ }
+ Script script;
+ for (; out && out.tellg() < fileHeader.scriptsEnd;) {
+ out.read(reinterpret_cast<char *>(&script), sizeof(Script));
+ buffer = new char[script.size];
+ unsigned int pos = out.tellg();
+ out.read(buffer, script.size);
+ RelocateScript(buffer, script.size);
+ out.seekp(pos);
+ out.write(buffer, script.size);
+ out.seekg(out.tellp());
+ delete[] buffer;
+ }
+}
+
+void Compiler::RelocateArray(char *array, int size) {
+ for (char *i = array, *end = array + size;
+ i < end; i += sizeof(void *)) {
+ char **dest = reinterpret_cast<char **>(i);
+ if (!*dest) {
+ continue;
+ }
+ map<const void *, unsigned int>::const_iterator
+ entry(addressMap.find(*dest));
+ if (entry == addressMap.end()) {
+ throw runtime_error("unable to relocate array member");
+ }
+ unsigned int destOffset = entry->second;
+ *dest = reinterpret_cast<char *>(destOffset);
+ }
}
+void Compiler::Relocate(
+ unsigned int pos,
+ char *object,
+ const TypeDescription &td) {
+ for (TypeDescription::FieldIterator
+ i(td.FieldsBegin()), end(td.FieldsEnd());
+ i != end; ++i) {
+ const FieldDescription &fd = i->second;
+ if (fd.IsAggregate() || fd.IsReferenced()) {
+ char **dest = reinterpret_cast<char **>(
+ object + fd.Offset());
+ if (!(*dest)) {
+ continue;
+ }
+ if (fd.TypeId() == Interpreter::IMAGE_ID) {
+ images.insert(make_pair(
+ pos + fd.Offset(), *dest));
+ }
+ map<const void *, unsigned int>::const_iterator
+ entry(addressMap.find(*dest));
+ if (entry == addressMap.end()) {
+ throw runtime_error(string("unable to relocate field ")
+ + i->first + " in object of type " + td.TypeName());
+ }
+ unsigned int destOffset = entry->second;
+ *dest = reinterpret_cast<char *>(destOffset);
+ } else {
+ const TypeDescription &nestedType
+ = TypeDescription::Get(fd.TypeId());
+ Relocate(pos + fd.Offset(), object + fd.Offset(), nestedType);
+ }
+ }
+}
+
+void Compiler::RelocateScript(char *text, unsigned int textlen) {
+ for (char *i = text, *end = text + textlen; i < end;) {
+ common::Script::Code *code =
+ reinterpret_cast<common::Script::Code *>(i);
+ if (code->type == common::Script::TYPE_ADDRESS && code->numParams > 0) {
+ if (code->reg1 == 7) {
+ char *addr = i + sizeof(common::Script::Code);
+ std::map<const void *, unsigned int>::const_iterator
+ found(addressMap.find(*reinterpret_cast<void **>(addr)));
+ if (found == addressMap.end()) {
+ throw std::runtime_error("unable to relocate script code");
+ }
+ *reinterpret_cast<unsigned int *>(addr) = found->second;
+ }
+
+ if (code->numParams > 1 && code->reg2 == 7) {
+ char *addr = i + sizeof(common::Script::Code);
+ if (code->reg1 == 7) {
+ addr += sizeof(void *);
+ }
+ std::map<const void *, unsigned int>::const_iterator
+ found(addressMap.find(*reinterpret_cast<void **>(addr)));
+ if (found == addressMap.end()) {
+ throw std::runtime_error("unable to relocate script code");
+ }
+ *reinterpret_cast<unsigned int *>(addr) = found->second;
+ }
+ }
+ i += code->Size();
+ }
+}
-int Compiler::ReferenceOffset(int typeId, int objectId, std::ptrdiff_t fieldOffset) const {
- return ObjectOffset(typeId, objectId) + fieldOffset;
+
+void Compiler::Write(ostream &out, const void *data, int amount) {
+ out.write(reinterpret_cast<const char *>(data), amount);
+}
+
+void Compiler::Pad(ostream &out, int to) {
+ Fill(out, Remaining(out.tellp(), to));
}
-int Compiler::ObjectOffset(int typeId, int objectId) const {
- const TypeDescription &td(TypeDescription::Get(typeId));
- return GetTypeOffset(typeId) + (td.Size() * objectId);
+void Compiler::Fill(ostream &out, int count, char c) {
+ for (int remaining(count); remaining > 0; --remaining) {
+ out.put(c);
+ }
}
-int Compiler::GetTypeOffset(int typeId) const {
- return objectOffsets.at(typeId);
+int Compiler::Remaining(int value, int alignment) {
+ int have(value % alignment);
+ return (have > 0) ? (16 - have) : 0;
}
}