]> git.localhorst.tv Git - l2e.git/blobdiff - src/loader/Compiler.cpp
new language, new compiler
[l2e.git] / src / loader / Compiler.cpp
index bb96b28728ecf82e1abb03fbb195722eb02dec83..13f3dfc24ba0b1416ef87bfdd2976b9f9c8003dd 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "Interpreter.h"
 #include "TypeDescription.h"
+#include "../common/Script.h"
 
 #include <climits>
 #include <cstring>
@@ -18,6 +19,7 @@ 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;
@@ -27,8 +29,7 @@ using std::vector;
 namespace loader {
 
 Compiler::Compiler(const Interpreter &intp)
-: intp(intp)
-, cursor(0) {
+: intp(intp) {
        int headerSize(sizeof(ObjectFileHeader));
 
        fileHeader.exportsBegin = headerSize;
@@ -47,19 +48,26 @@ void Compiler::Write(iostream &out) {
        ReserveHeader(out);
        WriteObjects(out);
        WriteOwnStrings(out);
-       fileHeader.objectsEnd = cursor;
+       fileHeader.objectsEnd = out.tellp();
        Pad(out, 16);
-       fileHeader.arraysBegin = cursor;
+       fileHeader.arraysBegin = out.tellp();
        WriteArrays(out);
-       fileHeader.arraysEnd = cursor;
+       fileHeader.arraysEnd = out.tellp();
+       fileHeader.scriptsBegin = out.tellp();
+       WriteScripts(out);
+       fileHeader.scriptsEnd = out.tellp();
        out.seekp(0);
-       cursor = 0;
        WriteHeader(out);
        WriteExports(out);
        WriteExternals(out);
        out.seekg(fileHeader.objectsBegin);
        out.clear();
        Relocate(out);
+       fileHeader.imagesBegin = out.tellp();
+       WriteImages(out);
+       fileHeader.imagesEnd = out.tellp();
+       out.seekp(0);
+       WriteHeader(out);
 }
 
 void Compiler::ReserveHeader(ostream &out) {
@@ -79,21 +87,34 @@ void Compiler::WriteOwnStrings(ostream &out) {
                object.typeId = Interpreter::STRING_ID;
                object.size = i->size() + 1;
                Write(out, &object, sizeof(Object));
-               addressMap.insert(make_pair(i->c_str(), cursor));
+               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) {
-               addressMap.insert(make_pair(
-                               i->identifier.c_str(), cursor));
                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);
+       }
 }
 
 void Compiler::WriteExports(ostream &out) {
@@ -130,7 +151,13 @@ void Compiler::WriteObjects(ostream &out) {
                        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));
+                       }
                }
        }
 }
@@ -141,14 +168,40 @@ void Compiler::WriteArrays(ostream &out) {
                        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, cursor));
+               addressMap.insert(make_pair(i->data, out.tellp()));
                Write(out, i->data, array.size);
        }
 }
 
+void Compiler::WriteImages(ostream &out) {
+       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::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::PrepareExport(Export &exp, const string &str) {
        const Interpreter::ParsedDefinition &dfn
@@ -163,6 +216,7 @@ void Compiler::PrepareExternal(
                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;
@@ -172,7 +226,6 @@ void Compiler::PrepareObject(
                Object &object,
                const TypeDescription &td,
                void *data) {
-       addressMap.insert(make_pair(data, cursor + sizeof(Object)));
        object.typeId = td.TypeId();
        switch (td.TypeId()) {
                case Interpreter::STRING_ID:
@@ -189,18 +242,13 @@ void Compiler::Relocate(iostream &out) {
        int bufferSize = TypeDescription::GetMaxSize();
        char *buffer = new char[bufferSize];
        for (;out && out.tellg() < fileHeader.objectsEnd;) {
-               // 20785
                Object object;
                out.read(reinterpret_cast<char *>(&object), sizeof(Object));
                const TypeDescription &td = TypeDescription::Get(object.typeId);
-               if (td.NeedsLinking()) {
-                       out.seekg(object.size, iostream::cur);
-                       continue;
-               }
                unsigned int pos = out.tellg();
-               out.seekg(pos);
+
                out.read(buffer, object.size);
-               Relocate(buffer, td);
+               Relocate(pos, buffer, td);
                out.seekp(pos);
                out.write(buffer, object.size);
                out.seekg(out.tellp());
@@ -210,26 +258,44 @@ void Compiler::Relocate(iostream &out) {
        Array array;
        for (; out && out.tellg() < fileHeader.arraysEnd;) {
                out.read(reinterpret_cast<char *>(&array), sizeof(Array));
-               if (!array.ref) {
-                       out.seekg(array.size);
-                       continue;
-               }
                buffer = new char[array.size];
                unsigned int pos = out.tellg();
-               out.seekg(pos);
                out.read(buffer, array.size);
-               RelocateArray(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()) {
@@ -240,44 +306,84 @@ void Compiler::RelocateArray(char *array, int size) {
        }
 }
 
-void Compiler::Relocate(char *object, const TypeDescription &td) {
+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()) {
-                       continue;
+               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);
                }
-               char **dest = reinterpret_cast<char **>(
-                               object + fd.Offset());
-               if (!(*dest)) {
-                       continue;
-               }
-               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());
+       }
+}
+
+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;
+                       }
                }
-               unsigned int destOffset = entry->second;
-               *dest = reinterpret_cast<char *>(destOffset);
+               i += code->Size();
        }
 }
 
 
 void Compiler::Write(ostream &out, const void *data, int amount) {
        out.write(reinterpret_cast<const char *>(data), amount);
-       cursor += amount;
 }
 
 void Compiler::Pad(ostream &out, int to) {
-       Fill(out, Remaining(cursor, to));
+       Fill(out, Remaining(out.tellp(), to));
 }
 
 void Compiler::Fill(ostream &out, int count, char c) {
        for (int remaining(count); remaining > 0; --remaining) {
                out.put(c);
-               ++cursor;
        }
 }