compiler.h
Engine/source/console/compiler.h
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