]> git.localhorst.tv Git - l2e.git/blob - src/loader/Compiler.cpp
new language, new compiler
[l2e.git] / src / loader / Compiler.cpp
1 #include "Compiler.h"
2
3 #include "Interpreter.h"
4 #include "TypeDescription.h"
5 #include "../common/Script.h"
6
7 #include <climits>
8 #include <cstring>
9 #include <iostream>
10 #include <map>
11 #include <ostream>
12 #include <set>
13 #include <stdexcept>
14 #include <string>
15 #include <utility>
16 #include <vector>
17
18 using std::iostream;
19 using std::make_pair;
20 using std::map;
21 using std::ostream;
22 using std::pair;
23 using std::runtime_error;
24 using std::set;
25 using std::string;
26 using std::strlen;
27 using std::vector;
28
29 namespace loader {
30
31 Compiler::Compiler(const Interpreter &intp)
32 : intp(intp) {
33         int headerSize(sizeof(ObjectFileHeader));
34
35         fileHeader.exportsBegin = headerSize;
36         fileHeader.exportsEnd = fileHeader.exportsBegin
37                         + (intp.ExportedIdentifiers().size() * sizeof(Export));
38
39         fileHeader.externalsBegin = fileHeader.exportsEnd;
40         fileHeader.externalsEnd = fileHeader.externalsBegin
41                         + (intp.PostponedDefinitions().size() * sizeof(External));
42
43         fileHeader.objectsBegin = fileHeader.externalsEnd
44                         + Remaining(fileHeader.externalsEnd, 16);
45 }
46
47 void Compiler::Write(iostream &out) {
48         ReserveHeader(out);
49         WriteObjects(out);
50         WriteOwnStrings(out);
51         fileHeader.objectsEnd = out.tellp();
52         Pad(out, 16);
53         fileHeader.arraysBegin = out.tellp();
54         WriteArrays(out);
55         fileHeader.arraysEnd = out.tellp();
56         fileHeader.scriptsBegin = out.tellp();
57         WriteScripts(out);
58         fileHeader.scriptsEnd = out.tellp();
59         out.seekp(0);
60         WriteHeader(out);
61         WriteExports(out);
62         WriteExternals(out);
63         out.seekg(fileHeader.objectsBegin);
64         out.clear();
65         Relocate(out);
66         fileHeader.imagesBegin = out.tellp();
67         WriteImages(out);
68         fileHeader.imagesEnd = out.tellp();
69         out.seekp(0);
70         WriteHeader(out);
71 }
72
73 void Compiler::ReserveHeader(ostream &out) {
74         Fill(out, fileHeader.objectsBegin);
75 }
76
77 void Compiler::WriteHeader(ostream &out) {
78         Write(out, &fileHeader, sizeof(ObjectFileHeader));
79 }
80
81 void Compiler::WriteOwnStrings(ostream &out) {
82         for (set<string>::const_iterator
83                         i(intp.ExportedIdentifiers().begin()),
84                         end(intp.ExportedIdentifiers().end());
85                         i != end; ++i) {
86                 Object object;
87                 object.typeId = Interpreter::STRING_ID;
88                 object.size = i->size() + 1;
89                 Write(out, &object, sizeof(Object));
90                 addressMap.insert(make_pair(i->c_str(), out.tellp()));
91                 Write(out, i->c_str(), object.size);
92         }
93         for(vector<Interpreter::PostponedDefinition>::const_iterator
94                         i(intp.PostponedDefinitions().begin()),
95                         end(intp.PostponedDefinitions().end());
96                         i != end; ++i) {
97                 Object object;
98                 object.typeId = Interpreter::STRING_ID;
99                 object.size = i->identifier.size() + 1;
100                 Write(out, &object, sizeof(Object));
101                 addressMap.insert(make_pair(
102                                 i->identifier.c_str(), out.tellp()));
103                 Write(out, i->identifier.c_str(), object.size);
104         }
105         for (std::map<std::string, SDL_Surface *>::const_iterator
106                         i(intp.Images().begin()), end(intp.Images().end());
107                         i != end; ++i) {
108                 addressMap.insert(make_pair(
109                                 i->second, 0));
110                 Object object;
111                 object.typeId = Interpreter::STRING_ID;
112                 object.size = i->first.size() + 1;
113                 Write(out, &object, sizeof(Object));
114                 addressMap.insert(make_pair(
115                                 i->first.c_str(), out.tellp()));
116                 Write(out, i->first.c_str(), object.size);
117         }
118 }
119
120 void Compiler::WriteExports(ostream &out) {
121         for (set<string>::const_iterator
122                         i(intp.ExportedIdentifiers().begin()),
123                         end(intp.ExportedIdentifiers().end());
124                         i != end; ++i) {
125                 Export exp;
126                 PrepareExport(exp, *i);
127                 Write(out, &exp, sizeof(Export));
128         }
129 }
130
131 void Compiler::WriteExternals(ostream &out) {
132         for(vector<Interpreter::PostponedDefinition>::const_iterator
133                         i(intp.PostponedDefinitions().begin()),
134                         end(intp.PostponedDefinitions().end());
135                         i != end; ++i) {
136                 External ext;
137                 PrepareExternal(ext, *i);
138                 Write(out, &ext, sizeof(External));
139         }
140 }
141
142 void Compiler::WriteObjects(ostream &out) {
143         Pad(out, 16);
144         for (map<int, vector<void *> >::const_iterator
145                         i(intp.Values().begin()), end(intp.Values().end());
146                         i != end; ++i) {
147                 const TypeDescription &td(TypeDescription::Get(i->first));
148                 for (vector<void *>::const_iterator
149                                 j(i->second.begin()), jend(i->second.end());
150                                 j != jend; ++j) {
151                         Object object;
152                         PrepareObject(object, td, *j);
153                         Write(out, &object, sizeof(Object));
154                         addressMap.insert(make_pair(*j, out.tellp()));
155                         Write(out, *j, object.size);
156
157                         if (td.TypeId() == Interpreter::SCRIPT_ID) {
158                                 common::Script *script = reinterpret_cast<common::Script *>(*j);
159                                 scripts.push_back(make_pair(const_cast<char *>(script->text), script->textlen));
160                         }
161                 }
162         }
163 }
164
165 void Compiler::WriteArrays(ostream &out) {
166         Pad(out, 16);
167         for (vector<Interpreter::Array>::const_iterator
168                         i(intp.Arrays().begin()), end(intp.Arrays().end());
169                         i != end; ++i) {
170                 Array array;
171                 array.typeId = i->typeId;
172                 array.size = i->size;
173                 array.ref = i->ref;
174                 Write(out, &array, sizeof(Array));
175                 addressMap.insert(make_pair(i->data, out.tellp()));
176                 Write(out, i->data, array.size);
177         }
178 }
179
180 void Compiler::WriteImages(ostream &out) {
181         for (std::map<unsigned int, void *>::const_iterator
182                         i(images.begin()), end(images.end());
183                         i != end; ++i) {
184                 const string &path = intp.FindImage(
185                                 reinterpret_cast<SDL_Surface *>(i->second));
186                 Image img;
187                 img.pathOffset = addressMap.at(path.c_str());
188                 img.destOffset = i->first;
189                 Write(out, &img, sizeof(Image));
190         }
191 }
192
193 void Compiler::WriteScripts(ostream &out) {
194         for (vector<pair<const char *, unsigned int> >::const_iterator
195                         i(scripts.begin()), end(scripts.end());
196                         i != end; ++i) {
197                 Script s;
198                 s.size = i->second;
199                 Write(out, &s, sizeof(Script));
200                 addressMap.insert(make_pair(i->first, out.tellp()));
201                 Write(out, i->first, s.size);
202         }
203 }
204
205
206 void Compiler::PrepareExport(Export &exp, const string &str) {
207         const Interpreter::ParsedDefinition &dfn
208                         = intp.GetDefinition(str);
209         exp.nameOffset = addressMap[str.c_str()];
210         exp.typeId = dfn.type;
211         exp.dataOffset = addressMap[intp.GetObject(dfn.type, str)];
212 }
213
214 void Compiler::PrepareExternal(
215                 External &ext,
216                 const Interpreter::PostponedDefinition &def) {
217         ext.nameOffset = addressMap[def.identifier.c_str()];
218         ext.referenceOffset = addressMap[def.object] + (def.dest - def.object);
219         ext.typeId = def.type;
220         ext.inlined = 0;
221         if (def.inlined) ext.inlined |= 1;
222         if (def.aggregate) ext.inlined |= 2;
223 }
224
225 void Compiler::PrepareObject(
226                 Object &object,
227                 const TypeDescription &td,
228                 void *data) {
229         object.typeId = td.TypeId();
230         switch (td.TypeId()) {
231                 case Interpreter::STRING_ID:
232                         object.size = strlen(
233                                         reinterpret_cast<char *>(data)) + 1;
234                         break;
235                 default:
236                         object.size = td.Size();
237                         break;
238         }
239 }
240
241 void Compiler::Relocate(iostream &out) {
242         int bufferSize = TypeDescription::GetMaxSize();
243         char *buffer = new char[bufferSize];
244         for (;out && out.tellg() < fileHeader.objectsEnd;) {
245                 Object object;
246                 out.read(reinterpret_cast<char *>(&object), sizeof(Object));
247                 const TypeDescription &td = TypeDescription::Get(object.typeId);
248                 unsigned int pos = out.tellg();
249
250                 out.read(buffer, object.size);
251                 Relocate(pos, buffer, td);
252                 out.seekp(pos);
253                 out.write(buffer, object.size);
254                 out.seekg(out.tellp());
255         }
256         delete[] buffer;
257         out.seekg(fileHeader.arraysBegin);
258         Array array;
259         for (; out && out.tellg() < fileHeader.arraysEnd;) {
260                 out.read(reinterpret_cast<char *>(&array), sizeof(Array));
261                 buffer = new char[array.size];
262                 unsigned int pos = out.tellg();
263                 out.read(buffer, array.size);
264                 if (array.ref) {
265                         RelocateArray(buffer, array.size);
266                 } else {
267                         const TypeDescription &td = TypeDescription::Get(array.typeId);
268                         for (char *i = buffer, *end = buffer + array.size;
269                                         i < end; i += td.Size()) {
270                                 Relocate(pos + (i - buffer), i, td);
271                         }
272                 }
273                 out.seekp(pos);
274                 out.write(buffer, array.size);
275                 out.seekg(out.tellp());
276                 delete[] buffer;
277         }
278         Script script;
279         for (; out && out.tellg() < fileHeader.scriptsEnd;) {
280                 out.read(reinterpret_cast<char *>(&script), sizeof(Script));
281                 buffer = new char[script.size];
282                 unsigned int pos = out.tellg();
283                 out.read(buffer, script.size);
284                 RelocateScript(buffer, script.size);
285                 out.seekp(pos);
286                 out.write(buffer, script.size);
287                 out.seekg(out.tellp());
288                 delete[] buffer;
289         }
290 }
291
292 void Compiler::RelocateArray(char *array, int size) {
293         for (char *i = array, *end = array + size;
294                         i < end; i += sizeof(void *)) {
295                 char **dest = reinterpret_cast<char **>(i);
296                 if (!*dest) {
297                         continue;
298                 }
299                 map<const void *, unsigned int>::const_iterator
300                                 entry(addressMap.find(*dest));
301                 if (entry == addressMap.end()) {
302                         throw runtime_error("unable to relocate array member");
303                 }
304                 unsigned int destOffset = entry->second;
305                 *dest = reinterpret_cast<char *>(destOffset);
306         }
307 }
308
309 void Compiler::Relocate(
310                 unsigned int pos,
311                 char *object,
312                 const TypeDescription &td) {
313         for (TypeDescription::FieldIterator
314                         i(td.FieldsBegin()), end(td.FieldsEnd());
315                         i != end; ++i) {
316                 const FieldDescription &fd = i->second;
317                 if (fd.IsAggregate() || fd.IsReferenced()) {
318                         char **dest = reinterpret_cast<char **>(
319                                         object + fd.Offset());
320                         if (!(*dest)) {
321                                 continue;
322                         }
323                         if (fd.TypeId() == Interpreter::IMAGE_ID) {
324                                 images.insert(make_pair(
325                                                 pos + fd.Offset(), *dest));
326                         }
327                         map<const void *, unsigned int>::const_iterator
328                                         entry(addressMap.find(*dest));
329                         if (entry == addressMap.end()) {
330                                 throw runtime_error(string("unable to relocate field ")
331                                                 + i->first + " in object of type " + td.TypeName());
332                         }
333                         unsigned int destOffset = entry->second;
334                         *dest = reinterpret_cast<char *>(destOffset);
335                 } else {
336                         const TypeDescription &nestedType
337                                         = TypeDescription::Get(fd.TypeId());
338                         Relocate(pos + fd.Offset(), object + fd.Offset(), nestedType);
339                 }
340         }
341 }
342
343 void Compiler::RelocateScript(char *text, unsigned int textlen) {
344         for (char *i = text, *end = text + textlen; i < end;) {
345                 common::Script::Code *code =
346                                 reinterpret_cast<common::Script::Code *>(i);
347                 if (code->type == common::Script::TYPE_ADDRESS && code->numParams > 0) {
348                         if (code->reg1 == 7) {
349                                 char *addr = i + sizeof(common::Script::Code);
350                                 std::map<const void *, unsigned int>::const_iterator
351                                                 found(addressMap.find(*reinterpret_cast<void **>(addr)));
352                                 if (found == addressMap.end()) {
353                                         throw std::runtime_error("unable to relocate script code");
354                                 }
355                                 *reinterpret_cast<unsigned int *>(addr) = found->second;
356                         }
357
358                         if (code->numParams > 1 && code->reg2 == 7) {
359                                 char *addr = i + sizeof(common::Script::Code);
360                                 if (code->reg1 == 7) {
361                                         addr += sizeof(void *);
362                                 }
363                                 std::map<const void *, unsigned int>::const_iterator
364                                                 found(addressMap.find(*reinterpret_cast<void **>(addr)));
365                                 if (found == addressMap.end()) {
366                                         throw std::runtime_error("unable to relocate script code");
367                                 }
368                                 *reinterpret_cast<unsigned int *>(addr) = found->second;
369                         }
370                 }
371                 i += code->Size();
372         }
373 }
374
375
376 void Compiler::Write(ostream &out, const void *data, int amount) {
377         out.write(reinterpret_cast<const char *>(data), amount);
378 }
379
380 void Compiler::Pad(ostream &out, int to) {
381         Fill(out, Remaining(out.tellp(), to));
382 }
383
384 void Compiler::Fill(ostream &out, int count, char c) {
385         for (int remaining(count); remaining > 0; --remaining) {
386                 out.put(c);
387         }
388 }
389
390 int Compiler::Remaining(int value, int alignment) {
391         int have(value % alignment);
392         return (have > 0) ? (16 - have) : 0;
393 }
394
395 }