compiler.cpp

Engine/source/console/compiler.cpp

More...

Namespaces:

namespace

Detailed Description

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "console/console.h"
 26#include "console/telnetDebugger.h"
 27
 28#include "console/ast.h"
 29#include "core/tAlgorithm.h"
 30
 31#include "core/strings/findMatch.h"
 32#include "console/consoleInternal.h"
 33#include "core/stream/fileStream.h"
 34#include "console/compiler.h"
 35
 36#include "console/simBase.h"
 37
 38namespace Compiler
 39{
 40
 41   F64 consoleStringToNumber(const char *str, StringTableEntry file, U32 line)
 42   {
 43      F64 val = dAtof(str);
 44      if (val != 0)
 45         return val;
 46      else if (!dStricmp(str, "true"))
 47         return 1;
 48      else if (!dStricmp(str, "false"))
 49         return 0;
 50      else if (file)
 51      {
 52         Con::warnf(ConsoleLogEntry::General, "%s (%d): string always evaluates to 0.", file, line);
 53         return 0;
 54      }
 55      return 0;
 56   }
 57
 58   //------------------------------------------------------------
 59
 60   CompilerStringTable *gCurrentStringTable, gGlobalStringTable, gFunctionStringTable;
 61   CompilerFloatTable  *gCurrentFloatTable, gGlobalFloatTable, gFunctionFloatTable;
 62   DataChunker          gConsoleAllocator;
 63   CompilerIdentTable   gIdentTable;
 64
 65   //------------------------------------------------------------
 66
 67   void evalSTEtoCode(StringTableEntry ste, U32 ip, U32 *ptr)
 68   {
 69#ifdef TORQUE_CPU_X64
 70      *(U64*)(ptr) = (U64)ste;
 71#else
 72      *ptr = (U32)ste;
 73#endif
 74   }
 75
 76   void compileSTEtoCode(StringTableEntry ste, U32 ip, U32 *ptr)
 77   {
 78      if (ste)
 79         getIdentTable().add(ste, ip);
 80      *ptr = 0;
 81      *(ptr + 1) = 0;
 82   }
 83
 84   void(*STEtoCode)(StringTableEntry ste, U32 ip, U32 *ptr) = evalSTEtoCode;
 85
 86   //------------------------------------------------------------
 87
 88   bool gSyntaxError = false;
 89
 90   //------------------------------------------------------------
 91
 92   CompilerStringTable *getCurrentStringTable() { return gCurrentStringTable; }
 93   CompilerStringTable &getGlobalStringTable() { return gGlobalStringTable; }
 94   CompilerStringTable &getFunctionStringTable() { return gFunctionStringTable; }
 95
 96   void setCurrentStringTable(CompilerStringTable* cst) { gCurrentStringTable = cst; }
 97
 98   CompilerFloatTable *getCurrentFloatTable() { return gCurrentFloatTable; }
 99   CompilerFloatTable &getGlobalFloatTable() { return gGlobalFloatTable; }
100   CompilerFloatTable &getFunctionFloatTable() { return gFunctionFloatTable; }
101
102   void setCurrentFloatTable(CompilerFloatTable* cst) { gCurrentFloatTable = cst; }
103
104   CompilerIdentTable &getIdentTable() { return gIdentTable; }
105
106   void precompileIdent(StringTableEntry ident)
107   {
108      if (ident)
109         gGlobalStringTable.add(ident);
110   }
111
112   void resetTables()
113   {
114      setCurrentStringTable(&gGlobalStringTable);
115      setCurrentFloatTable(&gGlobalFloatTable);
116      getGlobalFloatTable().reset();
117      getGlobalStringTable().reset();
118      getFunctionFloatTable().reset();
119      getFunctionStringTable().reset();
120      getIdentTable().reset();
121   }
122
123   void *consoleAlloc(U32 size) { return gConsoleAllocator.alloc(size); }
124   void consoleAllocReset() { gConsoleAllocator.freeBlocks(); }
125
126}
127
128//-------------------------------------------------------------------------
129
130using namespace Compiler;
131
132//-------------------------------------------------------------------------
133
134
135U32 CompilerStringTable::add(const char *str, bool caseSens, bool tag)
136{
137   // Is it already in?
138   Entry **walk;
139   for (walk = &list; *walk; walk = &((*walk)->next))
140   {
141      if ((*walk)->tag != tag)
142         continue;
143
144      if (caseSens)
145      {
146         if (!String::compare((*walk)->string, str))
147            return (*walk)->start;
148      }
149      else
150      {
151         if (!dStricmp((*walk)->string, str))
152            return (*walk)->start;
153      }
154   }
155
156   // Write it out.
157   Entry *newStr = (Entry *)consoleAlloc(sizeof(Entry));
158   *walk = newStr;
159   newStr->next = NULL;
160   newStr->start = totalLen;
161   U32 len = dStrlen(str) + 1;
162   if (tag && len < 7) // alloc space for the numeric tag 1 for tag, 5 for # and 1 for nul
163      len = 7;
164   totalLen += len;
165   newStr->string = (char *)consoleAlloc(len);
166   newStr->len = len;
167   newStr->tag = tag;
168   dStrcpy(newStr->string, str, len);
169
170   // Put into the hash table.
171   hashTable[str] = newStr;
172
173   return newStr->start;
174}
175
176U32 CompilerStringTable::addIntString(U32 value)
177{
178   dSprintf(buf, sizeof(buf), "%d", value);
179   return add(buf);
180}
181
182U32 CompilerStringTable::addFloatString(F64 value)
183{
184   dSprintf(buf, sizeof(buf), "%g", value);
185   return add(buf);
186}
187
188void CompilerStringTable::reset()
189{
190   list = NULL;
191   totalLen = 0;
192}
193
194char *CompilerStringTable::build()
195{
196   char *ret = new char[totalLen];
197   dMemset(ret, 0, totalLen);
198   for (Entry *walk = list; walk; walk = walk->next)
199      dStrcpy(ret + walk->start, walk->string, totalLen - walk->start);
200   return ret;
201}
202
203void CompilerStringTable::write(Stream &st)
204{
205   st.write(totalLen);
206   for (Entry *walk = list; walk; walk = walk->next)
207      st.write(walk->len, walk->string);
208}
209
210//------------------------------------------------------------
211
212U32 CompilerFloatTable::add(F64 value)
213{
214   Entry **walk;
215   U32 i = 0;
216   for (walk = &list; *walk; walk = &((*walk)->next), i++)
217      if (value == (*walk)->val)
218         return i;
219   Entry *newFloat = (Entry *)consoleAlloc(sizeof(Entry));
220   newFloat->val = value;
221   newFloat->next = NULL;
222   count++;
223   *walk = newFloat;
224   return count - 1;
225}
226void CompilerFloatTable::reset()
227{
228   list = NULL;
229   count = 0;
230}
231F64 *CompilerFloatTable::build()
232{
233   F64 *ret = new F64[count];
234   U32 i = 0;
235   for (Entry *walk = list; walk; walk = walk->next, i++)
236      ret[i] = walk->val;
237   return ret;
238}
239
240void CompilerFloatTable::write(Stream &st)
241{
242   st.write(count);
243   for (Entry *walk = list; walk; walk = walk->next)
244      st.write(walk->val);
245}
246
247//------------------------------------------------------------
248
249void CompilerIdentTable::reset()
250{
251   list = NULL;
252}
253
254void CompilerIdentTable::add(StringTableEntry ste, U32 ip)
255{
256   U32 index = gGlobalStringTable.add(ste, false);
257   Entry *newEntry = (Entry *)consoleAlloc(sizeof(Entry));
258   newEntry->offset = index;
259   newEntry->ip = ip;
260   for (Entry *walk = list; walk; walk = walk->next)
261   {
262      if (walk->offset == index)
263      {
264         newEntry->nextIdent = walk->nextIdent;
265         walk->nextIdent = newEntry;
266         return;
267      }
268   }
269   newEntry->next = list;
270   list = newEntry;
271   newEntry->nextIdent = NULL;
272}
273
274void CompilerIdentTable::write(Stream &st)
275{
276   U32 count = 0;
277   Entry * walk;
278   for (walk = list; walk; walk = walk->next)
279      count++;
280   st.write(count);
281   for (walk = list; walk; walk = walk->next)
282   {
283      U32 ec = 0;
284      Entry * el;
285      for (el = walk; el; el = el->nextIdent)
286         ec++;
287      st.write(walk->offset);
288      st.write(ec);
289      for (el = walk; el; el = el->nextIdent)
290         st.write(el->ip);
291   }
292}
293
294//-------------------------------------------------------------------------
295
296U8 *CodeStream::allocCode(U32 sz)
297{
298   U8 *ptr = NULL;
299   if (mCodeHead)
300   {
301      const U32 bytesLeft = BlockSize - mCodeHead->size;
302      if (bytesLeft > sz)
303      {
304         ptr = mCodeHead->data + mCodeHead->size;
305         mCodeHead->size += sz;
306         return ptr;
307      }
308   }
309
310   CodeData *data = new CodeData;
311   data->data = (U8*)dMalloc(BlockSize);
312   data->size = sz;
313   data->next = NULL;
314
315   if (mCodeHead)
316      mCodeHead->next = data;
317   mCodeHead = data;
318   if (mCode == NULL)
319      mCode = data;
320   return data->data;
321}
322
323//-------------------------------------------------------------------------
324
325void CodeStream::fixLoop(U32 loopBlockStart, U32 breakPoint, U32 continuePoint)
326{
327   AssertFatal(mFixStack.size() > 0, "Fix stack mismatch");
328
329   U32 fixStart = mFixStack[mFixStack.size() - 1];
330   for (U32 i = fixStart; i<mFixList.size(); i += 2)
331   {
332      FixType type = (FixType)mFixList[i + 1];
333
334      U32 fixedIp = 0;
335      bool valid = true;
336
337      switch (type)
338      {
339         case FIXTYPE_LOOPBLOCKSTART:
340            fixedIp = loopBlockStart;
341            break;
342         case FIXTYPE_BREAK:
343            fixedIp = breakPoint;
344            break;
345         case FIXTYPE_CONTINUE:
346            fixedIp = continuePoint;
347            break;
348         default:
349            //Con::warnf("Address %u fixed as %u", mFixList[i], mFixList[i+1]);
350            valid = false;
351            break;
352      }
353
354      if (valid)
355      {
356         patch(mFixList[i], fixedIp);
357      }
358   }
359}
360
361//-------------------------------------------------------------------------
362
363void CodeStream::emitCodeStream(U32 *size, U32 **stream, U32 **lineBreaks)
364{
365   // Alloc stream
366   U32 numLineBreaks = getNumLineBreaks();
367   *stream = new U32[mCodePos + (numLineBreaks * 2)];
368   dMemset(*stream, '\0', mCodePos + (numLineBreaks * 2));
369   *size = mCodePos;
370
371   // Dump chunks & line breaks
372   U32 outBytes = mCodePos * sizeof(U32);
373   U8 *outPtr = *((U8**)stream);
374   for (CodeData *itr = mCode; itr != NULL; itr = itr->next)
375   {
376      U32 bytesToCopy = itr->size > outBytes ? outBytes : itr->size;
377      dMemcpy(outPtr, itr->data, bytesToCopy);
378      outPtr += bytesToCopy;
379      outBytes -= bytesToCopy;
380   }
381
382   *lineBreaks = *stream + mCodePos;
383   dMemcpy(*lineBreaks, mBreakLines.address(), sizeof(U32) * mBreakLines.size());
384
385   // Apply patches on top
386   for (U32 i = 0; i<mPatchList.size(); i++)
387   {
388      PatchEntry &e = mPatchList[i];
389      (*stream)[e.addr] = e.value;
390   }
391}
392
393//-------------------------------------------------------------------------
394
395void CodeStream::reset()
396{
397   mCodePos = 0;
398   mFixStack.clear();
399   mFixLoopStack.clear();
400   mFixList.clear();
401   mBreakLines.clear();
402
403   // Pop down to one code block
404   CodeData *itr = mCode ? mCode->next : NULL;
405   while (itr != NULL)
406   {
407      CodeData *next = itr->next;
408      dFree(itr->data);
409      delete(itr);
410      itr = next;
411   }
412
413   if (mCode)
414   {
415      mCode->size = 0;
416      mCode->next = NULL;
417      mCodeHead = mCode;
418   }
419}
420
421