compiler.h

Engine/source/console/compiler.h

More...

Classes:

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
 25#ifndef _COMPILER_H_
 26#define _COMPILER_H_
 27
 28//#define DEBUG_CODESTREAM
 29
 30#ifdef DEBUG_CODESTREAM
 31#include <stdio.h>
 32#endif
 33
 34#include <string>
 35#include <unordered_map>
 36
 37class Stream;
 38class DataChunker;
 39
 40#include "platform/platform.h"
 41#include "console/ast.h"
 42#include "console/codeBlock.h"
 43
 44#ifndef _TVECTOR_H_
 45#include "core/util/tVector.h"
 46#endif
 47
 48namespace Compiler
 49{
 50   /// The opcodes for the TorqueScript VM.
 51   enum CompiledInstructions
 52   {
 53      OP_FUNC_DECL,
 54      OP_CREATE_OBJECT,
 55      OP_ADD_OBJECT,
 56      OP_END_OBJECT,
 57      // Added to fix the stack issue [7/9/2007 Black]
 58      OP_FINISH_OBJECT,
 59
 60      OP_JMPIFFNOT,
 61      OP_JMPIFNOT,
 62      OP_JMPIFF,
 63      OP_JMPIF,
 64      OP_JMPIFNOT_NP,
 65      OP_JMPIF_NP,    // 10
 66      OP_JMP,
 67      OP_RETURN,
 68      // fixes a bug when not explicitly returning a value
 69      OP_RETURN_VOID,
 70      OP_RETURN_FLT,
 71      OP_RETURN_UINT,
 72
 73      OP_CMPEQ,
 74      OP_CMPGR,
 75      OP_CMPGE,
 76      OP_CMPLT,
 77      OP_CMPLE,
 78      OP_CMPNE,
 79      OP_XOR,         // 20
 80      OP_MOD,
 81      OP_BITAND,
 82      OP_BITOR,
 83      OP_NOT,
 84      OP_NOTF,
 85      OP_ONESCOMPLEMENT,
 86
 87      OP_SHR,
 88      OP_SHL,
 89      OP_AND,
 90      OP_OR,          // 30
 91
 92      OP_ADD,
 93      OP_SUB,
 94      OP_MUL,
 95      OP_DIV,
 96      OP_NEG,
 97
 98      OP_INC,
 99      OP_DEC,
100
101      OP_SETCURVAR,
102      OP_SETCURVAR_CREATE,
103      OP_SETCURVAR_ARRAY,
104      OP_SETCURVAR_ARRAY_VARLOOKUP,
105      OP_SETCURVAR_ARRAY_CREATE,
106      OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP,
107
108      OP_LOADVAR_UINT,// 40
109      OP_LOADVAR_FLT,
110      OP_LOADVAR_STR,
111      OP_LOADVAR_VAR,
112
113      OP_SAVEVAR_UINT,
114      OP_SAVEVAR_FLT,
115      OP_SAVEVAR_STR,
116      OP_SAVEVAR_VAR,
117
118      OP_SETCUROBJECT,
119      OP_SETCUROBJECT_NEW,
120      OP_SETCUROBJECT_INTERNAL,
121
122      OP_SETCURFIELD,
123      OP_SETCURFIELD_ARRAY, // 50
124      OP_SETCURFIELD_TYPE,
125      OP_SETCURFIELD_ARRAY_VAR,
126      OP_SETCURFIELD_THIS,
127
128      OP_LOADFIELD_UINT,
129      OP_LOADFIELD_FLT,
130      OP_LOADFIELD_STR,
131
132      OP_SAVEFIELD_UINT,
133      OP_SAVEFIELD_FLT,
134      OP_SAVEFIELD_STR,
135
136      OP_STR_TO_UINT,
137      OP_STR_TO_FLT,
138      OP_STR_TO_NONE,  // 60
139      OP_FLT_TO_UINT,
140      OP_FLT_TO_STR,
141      OP_FLT_TO_NONE,
142      OP_UINT_TO_FLT,
143      OP_UINT_TO_STR,
144      OP_UINT_TO_NONE,
145      OP_COPYVAR_TO_NONE,
146
147      OP_LOADIMMED_UINT,
148      OP_LOADIMMED_FLT,
149      OP_TAG_TO_STR,
150      OP_LOADIMMED_STR, // 70
151      OP_DOCBLOCK_STR,
152      OP_LOADIMMED_IDENT,
153
154      OP_CALLFUNC_RESOLVE,
155      OP_CALLFUNC,
156      OP_CALLFUNC_POINTER,
157      OP_CALLFUNC_THIS,
158
159      OP_ADVANCE_STR,
160      OP_ADVANCE_STR_APPENDCHAR,
161      OP_ADVANCE_STR_COMMA,
162      OP_ADVANCE_STR_NUL,
163      OP_REWIND_STR,
164      OP_TERMINATE_REWIND_STR,  // 80
165      OP_COMPARE_STR,
166
167      OP_PUSH,          // String
168      OP_PUSH_UINT,     // Integer
169      OP_PUSH_FLT,      // Float
170      OP_PUSH_VAR,      // Variable
171      OP_PUSH_THIS,     // This pointer
172      OP_PUSH_FRAME,    // Frame
173
174      OP_ASSERT,
175      OP_BREAK,
176
177      OP_ITER_BEGIN,       ///< Prepare foreach iterator.
178      OP_ITER_BEGIN_STR,   ///< Prepare foreach$ iterator.
179      OP_ITER,             ///< Enter foreach loop.
180      OP_ITER_END,         ///< End foreach loop.
181
182      OP_INVALID,   // 90
183
184      MAX_OP_CODELEN ///< The amount of op codes.
185   };
186
187   //------------------------------------------------------------
188
189   F64 consoleStringToNumber(const char *str, StringTableEntry file = 0, U32 line = 0);
190
191   U32 compileBlock(StmtNode *block, CodeStream &codeStream, U32 ip);
192
193   //------------------------------------------------------------
194
195   struct CompilerIdentTable
196   {
197      struct Entry
198      {
199         U32 offset;
200         U32 ip;
201         Entry *next;
202         Entry *nextIdent;
203      };
204      Entry *list;
205      void add(StringTableEntry ste, U32 ip);
206      void reset();
207      void write(Stream &st);
208   };
209
210   //------------------------------------------------------------
211
212   struct CompilerStringTable
213   {
214      U32 totalLen;
215      struct Entry
216      {
217         char *string;
218         U32 start;
219         U32 len;
220         bool tag;
221         Entry *next;
222      };
223      Entry *list;
224
225      char buf[256];
226      std::unordered_map<std::string, Entry*> hashTable;
227
228      U32 add(const char *str, bool caseSens = true, bool tag = false);
229      U32 addIntString(U32 value);
230      U32 addFloatString(F64 value);
231      void reset();
232      char *build();
233      void write(Stream &st);
234   };
235
236   //------------------------------------------------------------
237
238   struct CompilerFloatTable
239   {
240      struct Entry
241      {
242         F64 val;
243         Entry *next;
244      };
245      U32 count;
246      Entry *list;
247
248      U32 add(F64 value);
249      void reset();
250      F64 *build();
251      void write(Stream &st);
252   };
253
254   //------------------------------------------------------------
255
256   inline StringTableEntry CodeToSTE(U32 *code, U32 ip)
257   {
258#ifdef TORQUE_CPU_X64
259      return (StringTableEntry)(*((U64*)(code + ip)));
260#else
261      return (StringTableEntry)(*(code + ip));
262#endif
263   }
264
265   extern void(*STEtoCode)(StringTableEntry ste, U32 ip, U32 *ptr);
266
267   void evalSTEtoCode(StringTableEntry ste, U32 ip, U32 *ptr);
268   void compileSTEtoCode(StringTableEntry ste, U32 ip, U32 *ptr);
269
270   CompilerStringTable *getCurrentStringTable();
271   CompilerStringTable &getGlobalStringTable();
272   CompilerStringTable &getFunctionStringTable();
273
274   void setCurrentStringTable(CompilerStringTable* cst);
275
276   CompilerFloatTable *getCurrentFloatTable();
277   CompilerFloatTable &getGlobalFloatTable();
278   CompilerFloatTable &getFunctionFloatTable();
279
280   void setCurrentFloatTable(CompilerFloatTable* cst);
281
282   CompilerIdentTable &getIdentTable();
283
284   void precompileIdent(StringTableEntry ident);
285
286   /// Helper function to reset the float, string, and ident tables to a base
287   /// starting state.
288   void resetTables();
289
290   void *consoleAlloc(U32 size);
291   void consoleAllocReset();
292
293   extern bool gSyntaxError;
294};
295
296/// Utility class to emit and patch bytecode
297class CodeStream
298{
299public:
300
301   enum FixType
302   {
303      // For loops
304      FIXTYPE_LOOPBLOCKSTART,
305      FIXTYPE_BREAK,
306      FIXTYPE_CONTINUE
307   };
308
309   enum Constants
310   {
311      BlockSize = 16384,
312   };
313
314protected:
315
316   typedef struct PatchEntry
317   {
318      U32 addr;  ///< Address to patch
319      U32 value; ///< Value to place at addr
320
321      PatchEntry(): addr(0), value(0) { ; }
322      PatchEntry(U32 a, U32 v) : addr(a), value(v) { ; }
323   } PatchEntry;
324
325   typedef struct CodeData
326   {
327      U8 *data;       ///< Allocated data (size is BlockSize)
328      U32 size;       ///< Bytes used in data
329      CodeData *next; ///< Next block
330   } CodeData;
331
332   /// @name Emitted code
333   /// {
334   CodeData *mCode;
335   CodeData *mCodeHead;
336   U32 mCodePos;
337   /// }
338
339   /// @name Code fixing stacks
340   /// {
341   Vector<U32> mFixList;
342   Vector<U32> mFixStack;
343   Vector<bool> mFixLoopStack;
344   Vector<PatchEntry> mPatchList;
345   /// }
346
347   Vector<U32> mBreakLines; ///< Line numbers
348
349public:
350
351   CodeStream() : mCode(0), mCodeHead(NULL), mCodePos(0)
352   {
353   }
354
355   ~CodeStream()
356   {
357      reset();
358
359      if (mCode)
360      {
361         dFree(mCode->data);
362         delete mCode;
363      }
364   }
365
366   U8 *allocCode(U32 sz);
367
368   inline U32 emit(U32 code)
369   {
370      U32 *ptr = (U32*)allocCode(4);
371      *ptr = code;
372#ifdef DEBUG_CODESTREAM
373      printf("code[%u] = %u\n", mCodePos, code);
374#endif
375      return mCodePos++;
376   }
377
378   inline void patch(U32 addr, U32 code)
379   {
380#ifdef DEBUG_CODESTREAM
381      printf("patch[%u] = %u\n", addr, code);
382#endif
383      mPatchList.push_back(PatchEntry(addr, code));
384   }
385
386   inline U32 emitSTE(const char *code)
387   {
388      U64 *ptr = (U64*)allocCode(8);
389      *ptr = 0;
390      Compiler::STEtoCode(code, mCodePos, (U32*)ptr);
391#ifdef DEBUG_CODESTREAM
392      printf("code[%u] = %s\n", mCodePos, code);
393#endif
394      mCodePos += 2;
395      return mCodePos - 2;
396   }
397
398   inline U32 tell()
399   {
400      return mCodePos;
401   }
402
403   inline bool inLoop()
404   {
405      for (U32 i = 0; i<mFixLoopStack.size(); i++)
406      {
407         if (mFixLoopStack[i])
408            return true;
409      }
410      return false;
411   }
412
413   inline U32 emitFix(FixType type)
414   {
415      U32 *ptr = (U32*)allocCode(4);
416      *ptr = (U32)type;
417
418#ifdef DEBUG_CODESTREAM
419      printf("code[%u] = [FIX:%u]\n", mCodePos, (U32)type);
420#endif
421
422      mFixList.push_back(mCodePos);
423      mFixList.push_back((U32)type);
424      return mCodePos++;
425   }
426
427   inline void pushFixScope(bool isLoop)
428   {
429      mFixStack.push_back(mFixList.size());
430      mFixLoopStack.push_back(isLoop);
431   }
432
433   inline void popFixScope()
434   {
435      AssertFatal(mFixStack.size() > 0, "Fix stack mismatch");
436
437      U32 newSize = mFixStack[mFixStack.size() - 1];
438      while (mFixList.size() > newSize)
439         mFixList.pop_back();
440      mFixStack.pop_back();
441      mFixLoopStack.pop_back();
442   }
443
444   void fixLoop(U32 loopBlockStart, U32 breakPoint, U32 continuePoint);
445
446   inline void addBreakLine(U32 lineNumber, U32 ip)
447   {
448      mBreakLines.push_back(lineNumber);
449      mBreakLines.push_back(ip);
450   }
451
452   inline U32 getNumLineBreaks()
453   {
454      return mBreakLines.size() / 2;
455   }
456
457   void emitCodeStream(U32 *size, U32 **stream, U32 **lineBreaks);
458
459   void reset();
460};
461
462#endif
463