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