/** * @file lscript_scope.h * @brief builds nametable and checks scope * * $LicenseInfo:firstyear=2002&license=viewergpl$ * * Copyright (c) 2002-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ #ifndef LL_LSCRIPT_SCOPE_H #define LL_LSCRIPT_SCOPE_H #include "string_table.h" #include "llmap.h" #include "lscript_byteformat.h" typedef enum e_lscript_identifier_type { LIT_INVALID, LIT_GLOBAL, LIT_VARIABLE, LIT_FUNCTION, LIT_LABEL, LIT_STATE, LIT_HANDLER, LIT_LIBRARY_FUNCTION, LIT_EOF } LSCRIPTIdentifierType; const char LSCRIPTFunctionTypeStrings[LST_EOF] = /*Flawfinder: ignore*/ { '0', 'i', 'f', 's', 'k', 'v', 'q', 'l', '0' }; const char * const LSCRIPTListDescription[LST_EOF] = /*Flawfinder: ignore*/ { "PUSHARGB 0", "PUSHARGB 1", "PUSHARGB 2", "PUSHARGB 3", "PUSHARGB 4", "PUSHARGB 5", "PUSHARGB 6", "PUSHARGB 7", "PUSHARGB 0" }; const char * const LSCRIPTTypePush[LST_EOF] = /*Flawfinder: ignore*/ { "INVALID", "PUSHE", "PUSHE", "PUSHE", "PUSHE", "PUSHEV", "PUSHEQ", "PUSHE", "undefined" }; const char * const LSCRIPTTypeReturn[LST_EOF] = /*Flawfinder: ignore*/ { "INVALID", "LOADP -12", "LOADP -12", "STORES -12\nPOP", "STORES -12\nPOP", "LOADVP -20", "LOADQP -24", "LOADLP -12", "undefined" }; const char * const LSCRIPTTypePop[LST_EOF] = /*Flawfinder: ignore*/ { "INVALID", "POP", "POP", "POPS", "POPS", "POPV", "POPQ", "POPL", "undefined" }; const char * const LSCRIPTTypeDuplicate[LST_EOF] = /*Flawfinder: ignore*/ { "INVALID", "DUP", "DUP", "DUPS", "DUPS", "DUPV", "DUPQ", "DUPL", "undefined" }; const char * const LSCRIPTTypeLocalStore[LST_EOF] = /*Flawfinder: ignore*/ { "INVALID", "STORE ", "STORE ", "STORES ", "STORES ", "STOREV ", "STOREQ ", "STOREL ", "undefined" }; const char * const LSCRIPTTypeLocalDeclaration[LST_EOF] = /*Flawfinder: ignore*/ { "INVALID", "STOREP ", "STOREP ", "STORESP ", "STORESP ", "STOREVP ", "STOREQP ", "STORELP ", "undefined" }; const char * const LSCRIPTTypeGlobalStore[LST_EOF] = /*Flawfinder: ignore*/ { "INVALID", "STOREG ", "STOREG ", "STORESG ", "STORESG ", "STOREGV ", "STOREGQ ", "STORELG ", "undefined" }; const char * const LSCRIPTTypeLocalPush[LST_EOF] = /*Flawfinder: ignore*/ { "INVALID", "PUSH ", "PUSH ", "PUSHS ", "PUSHS ", "PUSHV ", "PUSHQ ", "PUSHL ", "undefined" }; const char * const LSCRIPTTypeLocalPush1[LST_EOF] = /*Flawfinder: ignore*/ { "INVALID", "PUSHARGI 1", "PUSHARGF 1", "undefined", "undefined", "undefined", "undefined", "undefined", "undefined" }; const char * const LSCRIPTTypeGlobalPush[LST_EOF] = /*Flawfinder: ignore*/ { "INVALID", "PUSHG ", "PUSHG ", "PUSHGS ", "PUSHGS ", "PUSHGV ", "PUSHGQ ", "PUSHGL ", "undefined" }; class LLScriptSimpleAssignable; class LLScriptArgString { public: LLScriptArgString() : mString(NULL) {} ~LLScriptArgString() { delete [] mString; } LSCRIPTType getType(S32 count) { if (!mString) return LST_NULL; S32 length = (S32)strlen(mString); /*Flawfinder: ignore*/ if (count >= length) { return LST_NULL; } switch(mString[count]) { case 'i': return LST_INTEGER; case 'f': return LST_FLOATINGPOINT; case 's': return LST_STRING; case 'k': return LST_KEY; case 'v': return LST_VECTOR; case 'q': return LST_QUATERNION; case 'l': return LST_LIST; default: return LST_NULL; } } void addType(LSCRIPTType type) { S32 count = 0; if (mString) { count = (S32)strlen(mString); /*Flawfinder: ignore*/ char *temp = new char[count + 2]; memcpy(temp, mString, count); /*Flawfinder: ignore*/ delete [] mString; mString = temp; mString[count + 1] = 0; } else { mString = new char[count + 2]; mString[count + 1] = 0; } mString[count++] = LSCRIPTFunctionTypeStrings[type]; } S32 getNumber() { if (mString) return (S32)strlen(mString); /*Flawfinder: ignore*/ else return 0; } char *mString; }; class LLScriptScopeEntry { public: LLScriptScopeEntry(const char *identifier, LSCRIPTIdentifierType idtype, LSCRIPTType type, S32 count = 0) : mIdentifier(identifier), mIDType(idtype), mType(type), mOffset(0), mSize(0), mAssignable(NULL), mCount(count), mLibraryNumber(0) { } ~LLScriptScopeEntry() {} const char *mIdentifier; LSCRIPTIdentifierType mIDType; LSCRIPTType mType; S32 mOffset; S32 mSize; LLScriptSimpleAssignable *mAssignable; S32 mCount; // NOTE: Index for locals in CIL. U16 mLibraryNumber; LLScriptArgString mFunctionArgs; LLScriptArgString mLocals; }; class LLScriptScope { public: LLScriptScope(LLStringTable *stable) : mParentScope(NULL), mSTable(stable), mFunctionCount(0), mStateCount(0) { } ~LLScriptScope() { mEntryMap.deleteAllData(); } LLScriptScopeEntry *addEntry(const char *identifier, LSCRIPTIdentifierType idtype, LSCRIPTType type) { const char *name = mSTable->addString(identifier); if (!mEntryMap.checkData(name)) { if (idtype == LIT_FUNCTION) mEntryMap[name] = new LLScriptScopeEntry(name, idtype, type, mFunctionCount++); else if (idtype == LIT_STATE) mEntryMap[name] = new LLScriptScopeEntry(name, idtype, type, mStateCount++); else mEntryMap[name] = new LLScriptScopeEntry(name, idtype, type); return mEntryMap[name]; } else { // identifier already exists at this scope return NULL; } } BOOL checkEntry(const char *identifier) { const char *name = mSTable->addString(identifier); if (mEntryMap.checkData(name)) { return TRUE; } else { // identifier already exists at this scope return FALSE; } } LLScriptScopeEntry *findEntry(const char *identifier) { const char *name = mSTable->addString(identifier); LLScriptScope *scope = this; while (scope) { if (scope->mEntryMap.checkData(name)) { // cool, we found it at this scope return scope->mEntryMap[name]; } scope = scope->mParentScope; } return NULL; } LLScriptScopeEntry *findEntryTyped(const char *identifier, LSCRIPTIdentifierType idtype) { const char *name = mSTable->addString(identifier); LLScriptScope *scope = this; while (scope) { if (scope->mEntryMap.checkData(name)) { // need to check type, and if type is function we need to check both types if (idtype == LIT_FUNCTION) { if (scope->mEntryMap[name]->mIDType == LIT_FUNCTION) { return scope->mEntryMap[name]; } else if (scope->mEntryMap[name]->mIDType == LIT_LIBRARY_FUNCTION) { return scope->mEntryMap[name]; } } else if (scope->mEntryMap[name]->mIDType == idtype) { // cool, we found it at this scope return scope->mEntryMap[name]; } } scope = scope->mParentScope; } return NULL; } void addParentScope(LLScriptScope *scope) { mParentScope = scope; } LLMap<const char *, LLScriptScopeEntry *> mEntryMap; LLScriptScope *mParentScope; LLStringTable *mSTable; S32 mFunctionCount; S32 mStateCount; }; extern LLStringTable *gScopeStringTable; #endif