// Make sure all dependent defines exist and have a valid value #ifndef NO_COMPILER_NAMES #define NO_COMPILER_NAMES 0 #endif #ifndef VERS_32BIT #define VERS_32BIT 1 #endif #ifndef PACK_SIZE #ifdef _CRTBLD #define PACK_SIZE 8 #elif !VERS_32BIT #define PACK_SIZE 2 #elif defined(_X86_) #define PACK_SIZE 4 #else #define PACK_SIZE 8 #endif #endif // Check for version inconsistancies, and setup version flags #ifdef VERS_BSC #undef NO_COMPILER_NAMES #define NO_COMPILER_NAMES 1 #pragma inline_depth ( 3 ) #pragma check_stack ( off ) #else #pragma inline_depth ( 3 ) #pragma check_stack ( off ) #endif #define PURE = 0 #ifndef CC_COR #define CC_COR 1 #endif #include "undname.hxx" #if !defined(_CRTBLD) && (!VERSP_RELEASE || defined(_DEBUG)) #include #define DASSERT(x) assert(x) #else #define DASSERT(x) #endif #if (defined(_CRTBLD) && defined(_MT)) #include #endif #include #include #include "utf8.h" #pragma warning(disable:4291) // No matching operator delete static unsigned int und_strlen ( pcchar_t ); static pchar_t und_strncpy ( pchar_t, pcchar_t, unsigned int ); static unsigned int und_strncmp ( pcchar_t, pcchar_t, unsigned int ); class DName; class DNameNode; class Replicator; class HeapManager; class UnDecorator; // A '512' byte block including the header const unsigned int memBlockSize = 512 - sizeof(void*); class HeapManager { private: Alloc_t pOpNew; Free_t pOpDelete; struct Block { Block * next; char memBlock[ memBlockSize ]; __near Block () { next = 0; } }; Block * head; Block * tail; size_t blockLeft; public: void __near Constructor ( Alloc_t pAlloc, Free_t pFree ) { pOpNew = pAlloc; pOpDelete = pFree; blockLeft = 0; head = 0; tail = 0; } void __far * __near getMemory ( size_t, int ); void __near Destructor ( void ) { if ( pOpDelete != 0 ) while ( tail = head ) { head = tail->next; ( *pOpDelete )( tail ); } } #define gnew new(heap,0) #define rnew new(heap,1) }; void * operator new ( size_t, HeapManager &, int = 0 ); static HeapManager heap; // The MS Token table enum Tokens { #if !VERS_32BIT TOK_near, TOK_nearSp, TOK_nearP, TOK_far, TOK_farSp, TOK_farP, TOK_huge, TOK_hugeSp, TOK_hugeP, #endif TOK_basedLp, TOK_cdecl, TOK_pascal, TOK_stdcall, TOK_thiscall, TOK_fastcall, TOK_cocall, TOK_ptr64, TOK_restrict, TOK_unaligned, #if !VERS_32BIT TOK_interrupt, TOK_saveregs, TOK_self, TOK_segment, TOK_segnameLpQ, #endif TOK__last }; static const pcchar_t __near tokenTable[] = { #if !VERS_32BIT "__near", // TOK_near "__near ", // TOK_nearSp "__near*", // TOK_nearP "__far", // TOK_far "__far ", // TOK_farSp "__far*", // TOK_farP "__huge", // TOK_huge "__huge ", // TOK_hugeSp "__huge*", // TOK_hugeP #endif "__based(", // TOK_basedLp "__cdecl", // TOK_cdecl "__pascal", // TOK_pascal "__stdcall", // TOK_stdcall "__thiscall", // TOK_thiscall "__fastcall", // TOK_fastcall "__clrcall", // TOK_cocall "__ptr64", // TOK_ptr64 "__restrict", // TOK_restrict "__unaligned", // TOK_unaligned #if !VERS_32BIT "__interrupt", // TOK_interrupt "__saveregs", // TOK_saveregs "__self", // TOK_self "__segment", // TOK_segment "__segname(\"", // TOK_segnameLpQ #endif "" }; // The operator mapping table static const pcchar_t __near nameTable[] = { " new", " delete", "=", ">>", "<<", "!", "==", "!=", "[]", "operator", "->", "*", "++", "--", "-", "+", "&", "->*", "/", "%", "<", "<=", ">", ">=", ",", "()", "~", "^", "|", "&&", "||", "*=", "+=", "-=", "/=", "%=", ">>=", "<<=", "&=", "|=", "^=", #if ( !NO_COMPILER_NAMES ) "`vftable'", "`vbtable'", "`vcall'", "`typeof'", "`local static guard'", "`string'", "`vbase destructor'", "`vector deleting destructor'", "`default constructor closure'", "`scalar deleting destructor'", "`vector constructor iterator'", "`vector destructor iterator'", "`vector vbase constructor iterator'", "`virtual displacement map'", "`eh vector constructor iterator'", "`eh vector destructor iterator'", "`eh vector vbase constructor iterator'", "`copy constructor closure'", "`udt returning'", "`EH", //eh initialized struct "`RTTI", //rtti initialized struct "`local vftable'", "`local vftable constructor closure'", #endif // !NO_COMPILER_NAMES " new[]", " delete[]", #if ( !NO_COMPILER_NAMES ) "`omni callsig'", "`placement delete closure'", "`placement delete[] closure'", "`managed vector constructor iterator'", "`managed vector destructor iterator'", "`eh vector copy constructor iterator'", "`eh vector vbase copy constructor iterator'", #endif "" }; static const pcchar_t ehTable[] = { " Ptr to Member Data'", " Catchable Type'", " Catchable Type Array'", " ThrowInfo'", }; static const pcchar_t rttiTable[] = { " Type Descriptor'", " Base Class Descriptor at (", " Base Class Array'", " Class Hierarchy Descriptor'", " Complete Object Locator'", }; // The following 'enum' should really be nested inside 'class DName', but to // make the code compile better with Glockenspiel, I have extracted it enum DNameStatus { DN_valid, DN_invalid, DN_truncated, DN_error }; class DName { public: DName (); DName ( char ); DName ( const DName & ); // Shallow copy DName ( DNameNode * ); DName ( pcchar_t ); DName ( pcchar_t&, char ); DName ( DNameStatus ); DName ( DName * ); DName ( unsigned __int64 ); DName ( __int64 ); int isValid () const; int isEmpty () const; DNameStatus status () const; void clearStatus (); DName & setPtrRef (); int isPtrRef () const; int isUDC () const; void setIsUDC (); int isUDTThunk () const; void setIsUDTThunk (); int isArray() const; void setIsArray(); int isNoTE () const; void setIsNoTE (); int length () const; char getLastChar () const; pchar_t getString ( pchar_t, int ) const; DName operator + ( pcchar_t ) const; DName operator + ( const DName & ) const; DName operator + ( char ) const; DName operator + ( DName * ) const; DName operator + ( DNameStatus ) const; DName & operator += ( char ); DName & operator += ( pcchar_t ); DName & operator += ( DName * ); DName & operator += ( DNameStatus ); DName & operator += ( const DName & ); DName & operator |= ( const DName & ); DName & operator = ( pcchar_t ); DName & operator = ( const DName & ); DName & operator = ( char ); DName & operator = ( DName * ); DName & operator = ( DNameStatus ); // Friends : friend DName operator + ( char, const DName & ); friend DName operator + ( pcchar_t, const DName & ); friend DName operator + ( DNameStatus, const DName & ); private: DNameNode * node; DNameStatus stat : 4; unsigned int isIndir : 1; unsigned int isAUDC : 1; unsigned int isAUDTThunk : 1; unsigned int isArrayType : 1; unsigned int NoTE : 1; void doPchar ( pcchar_t, int ); }; class Replicator { private: // Declare, in order to suppress automatic generation void operator = ( const Replicator& ); int index; DName * dNameBuffer[ 10 ]; const DName ErrorDName; const DName InvalidDName; public: Replicator (); int isFull () const; Replicator & operator += ( const DName & ); const DName & operator [] ( int ) const; }; class UnDecorator { private: // Declare, in order to suppress automatic generation void operator = ( const UnDecorator& ); Replicator ArgList; static Replicator * pArgList; Replicator ZNameList; static Replicator * pZNameList; static Replicator * pTemplateArgList; static pcchar_t gName; static pcchar_t name; static pchar_t outputString; static int maxStringLength; static unsigned long disableFlags; static bool fExplicitTemplateParams; static bool fGetTemplateArgumentList; static DName getDecoratedName ( void ); static DName getSymbolName ( void ); static DName getZName ( bool fUpdateCachedNames ); static DName getOperatorName ( bool fIsTemplate, bool *pfReadTemplateArguments ); static DName getScope ( void ); static DName getScopedName ( void ); static DName getSignedDimension ( void ); static DName getDimension ( bool fSigned = false ); static int getNumberOfDimensions ( void ); static DName getTemplateName ( bool ); static DName getTemplateArgumentList( void ); static DName getTemplateConstant( void ); static DName composeDeclaration ( const DName & ); static int getTypeEncoding ( void ); static DName getBasedType ( void ); static DName getECSUName ( void ); static DName getEnumType ( void ); static DName getCallingConvention ( void ); static DName getReturnType ( DName * = 0 ); static DName getDataType ( DName * ); static DName getPrimaryDataType ( const DName & ); static DName getDataIndirectType ( const DName &, char, const DName &, int = FALSE ); static DName getDataIndirectType (); static DName getBasicDataType ( const DName & ); static DName getECSUDataType ( void ); static DName getPtrRefType ( const DName &, const DName &, char ); static DName getPtrRefDataType ( const DName &, int ); static DName getArrayType ( const DName& ); static DName getFunctionIndirectType( const DName & superType ); static DName getArgumentTypes ( void ); static DName getArgumentList ( void ); static DName getThrowTypes ( void ); static DName getLexicalFrame ( void ); static DName getStorageConvention ( void ); static DName getThisType ( void ); static DName getPointerType ( const DName &, const DName & ); static DName getPointerTypeArray ( const DName &, const DName & ); static DName getReferenceType ( const DName &, const DName & ); static DName getExternalDataType ( const DName & ); static DName getSegmentName ( void ); #if ( !NO_COMPILER_NAMES ) static DName getDisplacement ( void ); static DName getCallIndex ( void ); static DName getGuardNumber ( void ); static DName getVfTableType ( const DName & ); static DName getVbTableType ( const DName & ); static DName getVdispMapType ( const DName & ); static DName getVCallThunkType ( void ); #endif // !NO_COMPILER_NAMES static DName getStringEncoding ( char *prefix, int wantBody ); static GetParameter_t m_pGetParameter; public: UnDecorator ( pchar_t, pcchar_t, int, GetParameter_t, unsigned long ); static int doUnderScore (); static int doMSKeywords (); static int doPtr64 (); static int doFunctionReturns (); static int doAllocationModel (); static int doAllocationLanguage (); #if 0 static int doMSThisType (); static int doCVThisType (); #endif static int doThisTypes (); static int doAccessSpecifiers (); static int doThrowTypes (); static int doMemberTypes (); static int doReturnUDTModel (); static int do32BitNear (); static int doNameOnly (); static int doTypeOnly (); static int haveTemplateParameters (); static int doEcsu (); static int doNoIdentCharCheck (); static pcchar_t UScore ( Tokens ); operator pchar_t (); }; Replicator * UnDecorator::pArgList; Replicator * UnDecorator::pZNameList = 0; Replicator * UnDecorator::pTemplateArgList = 0; pcchar_t UnDecorator::gName = 0; pcchar_t UnDecorator::name = 0; pchar_t UnDecorator::outputString = 0; int UnDecorator::maxStringLength = 0; unsigned long UnDecorator::disableFlags = 0; GetParameter_t UnDecorator::m_pGetParameter = 0; bool UnDecorator::fExplicitTemplateParams = false; bool UnDecorator::fGetTemplateArgumentList = false; #ifdef _CRTBLD pchar_t __far _CRTIMP __loadds __unDName ( pchar_t outputString, #else pchar_t __far __cdecl __loadds unDName ( pchar_t outputString, #endif pcchar_t name, int maxStringLength, // Note, COMMA is leading following optional arguments Alloc_t pAlloc, Free_t pFree, unsigned short disableFlags ) /* * This function will undecorate a name, returning the string corresponding to * the C++ declaration needed to produce the name. Its has a similar interface * to 'strncpy'. * * If the target string 'outputString' is specified to be NULL, a string of * suitable length will be allocated and its address returned. If the returned * string is allocated by 'unDName', then it is the programmers responsibility * to deallocate it. It will have been allocated on the far heap. * * If the target string is not NULL, then the parameter 'maxStringLength' will * specify the maximum number of characters which may be placed in the string. * In this case, the returned value is the same as 'outputString'. * * Both the input parameter 'name' and the returned string are NULL terminated * strings of characters. * * If the returned value is NULL, it indicates that the undecorator ran out of * memory, or an internal error occurred, and was unable to complete its task. */ { // Must have an allocator and a deallocator (and we MUST trust them) if ( !( pAlloc )) return 0; pchar_t unDecoratedName; #if (defined(_CRTBLD) && defined(_MT)) if (!_mtinitlocknum(_UNDNAME_LOCK)) return 0; _mlock(_UNDNAME_LOCK); __try { #endif heap.Constructor ( pAlloc, pFree ); // Create the undecorator object, and get the result UnDecorator unDecorate ( outputString, name, maxStringLength, 0, disableFlags ); unDecoratedName = unDecorate; // Destruct the heap (would use a destructor, but that causes DLL problems) heap.Destructor (); #if (defined(_CRTBLD) && defined(_MT)) } __finally { _munlock(_UNDNAME_LOCK); } #endif // And return the composed name return unDecoratedName; } // End of FUNCTION "unDName" #ifdef _CRTBLD pchar_t __far _CRTIMP __loadds __unDNameEx ( pchar_t outputString, #else pchar_t __far __cdecl __loadds unDNameEx ( pchar_t outputString, #endif pcchar_t name, int maxStringLength, // Note, COMMA is leading following optional arguments Alloc_t pAlloc, Free_t pFree, GetParameter_t pGetParameter, unsigned long disableFlags ) /* * This function will undecorate a name, returning the string corresponding to * the C++ declaration needed to produce the name. Its has a similar interface * to 'strncpy'. * * If the target string 'outputString' is specified to be NULL, a string of * suitable length will be allocated and its address returned. If the returned * string is allocated by 'unDName', then it is the programmers responsibility * to deallocate it. It will have been allocated on the far heap. * * If the target string is not NULL, then the parameter 'maxStringLength' will * specify the maximum number of characters which may be placed in the string. * In this case, the returned value is the same as 'outputString'. * * Both the input parameter 'name' and the returned string are NULL terminated * strings of characters. * * If the returned value is NULL, it indicates that the undecorator ran out of * memory, or an internal error occurred, and was unable to complete its task. */ { // Must have an allocator and a deallocator (and we MUST trust them) if ( !( pAlloc )) return 0; pchar_t unDecoratedName; #if (defined(_CRTBLD) && defined(_MT)) if (!_mtinitlocknum(_UNDNAME_LOCK)) return 0; _mlock(_UNDNAME_LOCK); __try { #endif heap.Constructor ( pAlloc, pFree ); // Create the undecorator object, and get the result UnDecorator unDecorate ( outputString, name, maxStringLength, pGetParameter, disableFlags ); unDecoratedName = unDecorate; // Destruct the heap (would use a destructor, but that causes DLL problems) heap.Destructor (); #if (defined(_CRTBLD) && defined(_MT)) } __finally { _munlock(_UNDNAME_LOCK); } #endif // And return the composed name return unDecoratedName; } // End of FUNCTION "unDName" // The 'UnDecorator' member functions inline UnDecorator::UnDecorator ( pchar_t output, pcchar_t dName, int maxLen, GetParameter_t pGetParameter, unsigned long disable ) { name = dName; gName = name; if ( output ) { maxStringLength = maxLen - 1; // The algorithm in getString doesn't leave room // for terminating NULL; be paranoid and leave one // extra char. // It's a lot easier to fix this here.... outputString = output; } else { outputString = 0; maxStringLength = 0; } pZNameList = &ZNameList; pArgList = &ArgList; disableFlags = disable; m_pGetParameter = pGetParameter; fExplicitTemplateParams = false; } // End of "UnDecorator" CONSTRUCTOR '()' inline UnDecorator::operator pchar_t () { DName result; DName unDName; // Find out if the name is a decorated name or not. Could be a reserved // CodeView variant of a decorated name if ( name ) { if (( *name == '?' ) && ( name[ 1 ] == '@' )) { #if ( !NO_COMPILER_NAMES ) gName += 2; result = "CV: " + getDecoratedName (); #else // } elif NO_COMPILER_NAMES result = DN_invalid; #endif // NO_COMPILER_NAMES } // End of IF then else if (( *name == '?' ) && ( name[1] == '$' )) { result = getTemplateName( false ); if ( result.status () == DN_invalid ) { // // What harm could there be to try again ? // Repro: // ?$S1@?1??VTFromRegType@CRegParser@ATL@@KAHPBGAAG@Z@4IA // ---> unsigned int `protected: static int __cdecl ATL::CRegParser::VTFromRegType(unsigned short const *,unsigned short &)'::`2'::$S1 // // This is a compiler generated symbol for a local static array init. // gName = name; result.clearStatus(); result = getDecoratedName (); } } else { result = getDecoratedName (); } } // End of IF then // If the name was not a valid name, then make the name the same as the original // It is also invalid if there are any remaining characters in the name (except when // we're giving the name only) if ( result.status () == DN_error ) return 0; elif ( (*gName && !doNameOnly ()) || ( result.status () == DN_invalid )) unDName = name; // Return the original name else unDName = result; // Construct the return string if ( !outputString ) { maxStringLength = unDName.length () + 1; outputString = rnew char[ maxStringLength ]; } // End of IF if ( outputString ) { unDName.getString ( outputString, maxStringLength ); // strip extra whitespace out of name pchar_t pRead = outputString; pchar_t pWrite = pRead; while (*pRead) { if (*pRead == ' ') { pRead++; *pWrite++ = ' '; while ( *pRead == ' ' ) { pRead++; } } else *pWrite++ = *pRead++; } *pWrite = *pRead; } // Return the result return outputString; } // End of "UnDecorator" OPERATOR 'pchar_t' DName UnDecorator::getDecoratedName ( void ) { // Ensure that it is intended to be a decorated name if ( doTypeOnly() ) { // Disable the type-only flag, so that if we get here recursively, eg. // in a template tag, we do full name undecoration. disableFlags &= ~UNDNAME_TYPE_ONLY; // If we're decoding just a type, process it as the type for an abstract // declarator, by giving an empty symbol name. DName result = getDataType ( NULL ); disableFlags |= UNDNAME_TYPE_ONLY; return result; } elif ( *gName == '?' ) { // Extract the basic symbol name gName++; // Advance the original name pointer DName symbolName = getSymbolName (); int udcSeen = symbolName.isUDC (); // Abort if the symbol name is invalid if ( !symbolName.isValid ()) return symbolName; // Extract, and prefix the scope qualifiers if ( *gName && ( *gName != '@' )) { DName scope = getScope (); if ( !scope.isEmpty() ) if (fExplicitTemplateParams) { fExplicitTemplateParams = false; symbolName = symbolName + scope; if (*gName != '@') { scope = getScope(); symbolName = scope + "::" + symbolName; } } else { symbolName = scope + "::" + symbolName; } } if ( udcSeen ) symbolName.setIsUDC (); // Now compose declaration if ( symbolName.isEmpty () || symbolName.isNoTE() ) { return symbolName; } elif ( !*gName || ( *gName == '@' ) ) { if ( *gName ) gName++; if (doNameOnly () && !udcSeen) { // Eat the rest of the dname, in case this is a recursive invocation, // such as for a template argument. (void)composeDeclaration( DName() ); return symbolName; } else { return composeDeclaration ( symbolName ); } } // End of ELIF then else return DN_invalid; } // End of IF then elif ( *gName ) return DN_invalid; else return DN_truncated; } // End of "UnDecorator" FUNCTION "getDecoratedName" inline DName UnDecorator::getSymbolName() { if (gName[0] == '?') { if (gName[1] == '$') { return getTemplateName(true); } else { gName += 1; return getOperatorName(false, NULL); } } else { return getZName(true); } } DName UnDecorator::getZName ( bool fUpdateCachedNames ) { int zNameIndex = *gName - '0'; // Handle 'zname-replicators', otherwise an actual name if (( zNameIndex >= 0 ) && ( zNameIndex <= 9 )) { gName++; // Skip past the replicator // And return the indexed name return ( *pZNameList )[ zNameIndex ]; } // End of IF then else { DName zName; if ( *gName == '?' ) { zName = getTemplateName( false ); if ( *gName++ != '@' ) zName = *--gName ? DN_invalid : DN_truncated; } else { #define TEMPLATE_PARAMETER "template-parameter-" #define TEMPLATE_PARAMETER_LEN 19 #define GENERIC_TYPE "generic-type-" #define GENERIC_TYPE_LEN 13 pchar_t genericType; if (und_strncmp(gName, TEMPLATE_PARAMETER, TEMPLATE_PARAMETER_LEN) == 0) { genericType = TEMPLATE_PARAMETER; gName += TEMPLATE_PARAMETER_LEN; } else if (und_strncmp(gName, GENERIC_TYPE, GENERIC_TYPE_LEN) == 0) { genericType = GENERIC_TYPE; gName += GENERIC_TYPE_LEN; } else { genericType = NULL; } if (genericType) { DName dimension = getSignedDimension(); if ( haveTemplateParameters()) { char buffer[16]; dimension.getString( buffer, 16 ); char *str = (*m_pGetParameter)(atol(buffer)); if ( str != NULL ) { zName = str; } else { zName = "`"; zName += genericType + dimension + "'"; } } else { zName = "`"; zName += genericType + dimension + "'"; } } else { // Extract the 'zname' to the terminator zName = DName( gName, '@' ); // This constructor updates 'name' } } // Add it to the current list of 'zname's if ( fUpdateCachedNames && !pZNameList->isFull ()) *pZNameList += zName; // And return the symbol name return zName; } // End of IF else } // End of "UnDecorator" FUNCTION "getZName" inline DName UnDecorator::getOperatorName ( bool fIsTemplate, bool *pfReadTemplateArguments ) { DName operatorName; DName tmpName; int udcSeen = FALSE; // So what type of operator is it ? switch ( *gName++ ) { case 0: gName--; // End of string, better back-track return DN_truncated; case OC_ctor: case OC_dtor: // // The constructor and destructor are special: // Their operator name is the name of their first enclosing scope, which // will always be a tag, which may be a template specialization! // { // // Is this a specialization of a member function template? If it is // then we will actually have the template arguments between the "name" // of the operator and the scope: so we need to read the template // arguments before we try to read the name of the class // DName templateArguments; if ( fIsTemplate ) { templateArguments += '<' + getTemplateArgumentList(); if ( templateArguments.getLastChar () == '>' ) { templateArguments += ' '; } templateArguments += '>'; gName += 1; if ( pfReadTemplateArguments != NULL ) { *pfReadTemplateArguments = true; } } // // Use a temporary. Don't want to advance the name pointer // pcchar_t pName = gName; operatorName = getZName ( false ); gName = pName; // Undo our lookahead if ( !operatorName.isEmpty () && ( gName[ -1 ] == OC_dtor )) operatorName = '~' + operatorName; // // Append the template argumentsa (if there are any) // if ( !templateArguments.isEmpty()) { operatorName += templateArguments; } return operatorName; } // End of CASE 'OC_ctor,OC_dtor' break; case OC_new: case OC_delete: case OC_assign: case OC_rshift: case OC_lshift: case OC_not: case OC_equal: case OC_unequal: operatorName = nameTable[ gName[ -1 ] - OC_new ]; break; case OC_udc: udcSeen = TRUE; // No break case OC_index: case OC_pointer: case OC_star: case OC_incr: case OC_decr: case OC_minus: case OC_plus: case OC_amper: case OC_ptrmem: case OC_divide: case OC_modulo: case OC_less: case OC_leq: case OC_greater: case OC_geq: case OC_comma: case OC_call: case OC_compl: case OC_xor: case OC_or: case OC_land: case OC_lor: case OC_asmul: case OC_asadd: case OC_assub: // Regular operators from the first group operatorName = nameTable[ gName[ -1 ] - OC_index + ( OC_unequal - OC_new + 1 )]; break; case '_': switch ( *gName++ ) { case 0: gName--; // End of string, better back-track return DN_truncated; case OC_asdiv: case OC_asmod: case OC_asrshift: case OC_aslshift: case OC_asand: case OC_asor: case OC_asxor: // Regular operators from the extended group operatorName = nameTable[ gName[ -1 ] - OC_asdiv + ( OC_assub - OC_index + 1 ) + ( OC_unequal - OC_new + 1 )]; break; #if ( !NO_COMPILER_NAMES ) case OC_vftable: case OC_vbtable: case OC_vcall: return nameTable[ gName[ -1 ] - OC_asdiv + ( OC_assub - OC_index + 1 ) + ( OC_unequal - OC_new + 1 )]; case OC_string: { DName result = getStringEncoding( "`string'", TRUE ); result.setIsNoTE(); return result; } case OC_metatype: case OC_guard: case OC_vbdtor: case OC_vdeldtor: case OC_defctor: case OC_sdeldtor: case OC_vctor: case OC_vdtor: case OC_vallctor: case OC_vdispmap: case OC_ehvctor: case OC_ehvdtor: case OC_ehvctorvb: case OC_copyctorclosure: case OC_locvfctorclosure: case OC_locvftable: // Special purpose names case OC_placementDeleteClosure: case OC_placementArrayDeleteClosure: return nameTable[ gName[ -1 ] - OC_metatype + ( OC_vcall - OC_asdiv + 1 ) + ( OC_assub - OC_index + 1 ) + ( OC_unequal - OC_new + 1 )]; case OC_udtthunk: operatorName = nameTable[ gName[ -1 ] - OC_metatype + ( OC_vcall - OC_asdiv + 1 ) + ( OC_assub - OC_index + 1 ) + ( OC_unequal - OC_new + 1 )]; tmpName = getOperatorName( false, NULL ); if ( !tmpName.isEmpty() && tmpName.isUDTThunk() ) return DN_invalid; return operatorName + tmpName; break; case OC_eh_init: break; case OC_rtti_init: operatorName = nameTable[ gName[ -1 ] - OC_metatype + ( OC_vcall - OC_asdiv + 1 ) + ( OC_assub - OC_index + 1 ) + ( OC_unequal - OC_new + 1 )]; tmpName = rttiTable[ gName[0] - OC_rtti_TD ]; switch ( *gName++ ) { case OC_rtti_TD: { DName result = getDataType ( NULL ); return result + ' ' + operatorName + tmpName; } break; case OC_rtti_BCD: { DName result = operatorName + tmpName; result += getSignedDimension() + ','; result += getSignedDimension() + ','; result += getSignedDimension() + ','; result += getDimension() + ')'; return result + '\''; } break; case OC_rtti_BCA: case OC_rtti_CHD: case OC_rtti_COL: return operatorName + tmpName; break; default: gName--; return DN_truncated; break; } break; #endif // !NO_COMPILER_NAMES case OC_arrayNew: case OC_arrayDelete: operatorName = nameTable[ gName[ -1 ] - OC_metatype + ( OC_vcall - OC_asdiv + 1 ) + ( OC_assub - OC_index + 1 ) + ( OC_unequal - OC_new + 1 ) #if NO_COMPILER_NAMES - ( OC_locvfctorclosure - OC_vftable + 1 ) // discount names not in table #endif ]; break; // Yet another level of nested encodings.... case '?': switch( *gName++ ) { case 0: gName--; // End of string, better back-track return DN_truncated; case OC_anonymousNamespace: // // Anonymous namespace (new-style) is a string encoding of the // machine name and the translation unit name. Since the remainder // of the name doesn't really fit the dname grammar, skip it. // There are two '@' markers in the name.... // { DName result = getStringEncoding( "`anonymous namespace'", FALSE ); result.setIsNoTE(); return result; } default: return DN_invalid; } break; // // A double extended operator // case '_': switch (*gName++) { case OC_man_vec_ctor: case OC_man_vec_dtor: case OC_ehvcctor: case OC_ehvcctorvb: return nameTable[ gName[ -1 ] - OC_man_vec_ctor + ( OC_placementArrayDeleteClosure - OC_metatype + 1) + ( OC_vcall - OC_asdiv + 1 ) + ( OC_assub - OC_index + 1 ) + ( OC_unequal - OC_new + 1 )]; default: return DN_invalid; } break; default: return DN_invalid; } // End of SWITCH break; default: return DN_invalid; } // End of SWITCH // This really is an operator name, so prefix it with 'operator' if ( udcSeen ) operatorName.setIsUDC (); elif ( !operatorName.isEmpty ()) operatorName = "operator" + operatorName; return operatorName; } // End of "UnDecorator" FUNCTION "getOperatorName" DName UnDecorator::getStringEncoding ( char *prefix, int wantBody ) { DName result = prefix; // First @ comes right after operator code if ( *gName++ != '@' || *gName++ != '_' ) { return DN_invalid; } // Skip the string kind gName++; // Get (& discard) the length getDimension(); // Get (& discart) the checksum getDimension(); while ( *gName && *gName != '@' ) { // For now, we'll just skip it gName++; } if ( !*gName ) { gName--; return DN_truncated; } // Eat the terminating '@' gName++; return result; } DName UnDecorator::getScope ( void ) { DName scope; bool fNeedBracket = false; // Get the list of scopes while (( scope.status () == DN_valid ) && *gName && ( *gName != '@' )) { // Insert the scope operator if not the first scope if (fExplicitTemplateParams && !fGetTemplateArgumentList) { return scope; } if ( !scope.isEmpty() ) { scope = "::" + scope; if (fNeedBracket) { scope = '[' + scope; fNeedBracket = false; } } // Determine what kind of scope it is if ( *gName == '?' ) switch ( *++gName ) { case '?': if ( gName[1] == '_' && gName[2] == '?' ) { // // Anonymous namespace name (new style) // gName++; scope = getOperatorName ( false, NULL ) + scope; // There should be a zname termination @... if ( *gName == '@' ) { gName++; } } else scope = '`' + getDecoratedName () + '\'' + scope; break; case '$': // It's a template name, which is a kind of zname; back up // and handle like a zname. gName--; scope = getZName ( true ) + scope; break; case 'A': // // This is a new-new encoding for anonymous namespaces // // fall-through case '%': // // It an anonymous namespace (old-style); // skip the (unreadable) name and instead insert // an appropriate string // while ( *gName != '@' ) { gName++; } gName++; scope = "`anonymous namespace'" + scope; break; case 'I': // // This is the interface whose method the class is // implementing // gName++; scope = getZName ( true ) + ']' + scope; fNeedBracket = true; break; default: scope = getLexicalFrame () + scope; break; } // End of SWITCH else scope = getZName ( true ) + scope; } // End of WHILE // Catch error conditions switch ( *gName ) { case 0: if ( scope.isEmpty() ) scope = DN_truncated; else scope = DName ( DN_truncated ) + "::" + scope; break; case '@': // '@' expected to end the scope list break; default: scope = DN_invalid; break; } // End of SWITCH // Return the composed scope return scope; } // End of "UnDecorator" FUNCTION "getScope" DName UnDecorator::getSignedDimension ( void ) { if ( !*gName ) return DN_truncated; elif ( *gName == '?' ) { gName++; // skip the '?' return '-' + getDimension(); } else return getDimension(); } // End of "Undecorator" FUNCTION "getSignedDimension" DName UnDecorator::getDimension ( bool fSigned ) { char* prefix = 0; if (*gName == TC_nontype_dummy) { prefix = "`non-type-template-parameter"; ++gName; } if ( !*gName ) return DN_truncated; elif (( *gName >= '0' ) && ( *gName <= '9' )) return prefix ? (prefix + DName ((unsigned __int64)( *gName++ - '0' + 1 ))) : DName ((unsigned __int64)( *gName++ - '0' + 1 )); else { unsigned __int64 dim = 0ui64; // Don't bother detecting overflow, it's not worth it while ( *gName != '@' ) { if ( !*gName ) return DN_truncated; elif (( *gName >= 'A' ) && ( *gName <= 'P' )) dim = ( dim << 4 ) + ( *gName - 'A' ); else return DN_invalid; gName++; } // End of WHILE // Ensure integrity, and return if ( *gName++ != '@' ) return DN_invalid; // Should never get here if (fSigned) { return prefix ? (prefix + DName((__int64)dim)) : DName((__int64)dim); } else { return prefix ? (prefix + DName(dim)) : dim; } } // End of ELIF else } // End of "UnDecorator" FUNCTION "getDimension" int UnDecorator::getNumberOfDimensions ( void ) { if ( !*gName ) return 0; elif (( *gName >= '0' ) && ( *gName <= '9' )) return (( *gName++ - '0' ) + 1 ); else { int dim = 0; // Don't bother detecting overflow, it's not worth it while ( *gName != '@' ) { if ( !*gName ) return 0; elif (( *gName >= 'A' ) && ( *gName <= 'P' )) dim = ( dim << 4 ) + ( *gName - 'A' ); else return -1; gName++; } // End of WHILE // Ensure integrity, and return if ( *gName++ != '@' ) return -1; // Should never get here return dim; } // End of ELIF else } // End of "UnDecorator" FUNCTION "getNumberOfDimensions" DName UnDecorator::getTemplateName( bool fReadTerminator ) { // // First make sure we're really looking at a template name // if ( gName[0] != '?' || gName[1] != '$' ) return DN_invalid; gName += 2; // Skip the marker characters // // Stack the replicators, since template names are their own replicator scope: // Replicator * pSaveArgList = pArgList; Replicator * pSaveZNameList = pZNameList; Replicator * pSaveTemplateArgList = pTemplateArgList; Replicator localArgList, localZNameList, localTemplateArgList; pArgList = &localArgList; pZNameList = &localZNameList; pTemplateArgList = &localTemplateArgList; // // Crack the template name: // DName templateName; DName templateArguments; bool fReadTemplateArguments = false; if ( *gName == '?' ) { gName += 1; templateName = getOperatorName( true, &fReadTemplateArguments ); } else { templateName = getZName( true ); } if (templateName.isEmpty ()) { fExplicitTemplateParams = true; } // // If we haven't already read the template arguments then // now is the time to read them // if ( !fReadTemplateArguments ) { templateName += '<' + getTemplateArgumentList (); if ( templateName.getLastChar () == '>' ) { templateName += ' '; } templateName += '>'; if ( fReadTerminator ) { gName += 1; } } // // Restore the previous replicators: // pArgList = pSaveArgList; pZNameList = pSaveZNameList; pTemplateArgList = pSaveTemplateArgList; // Return the completed 'template-name' return templateName; } // End of "UnDecorator" FUNCTION "getTemplateName" DName UnDecorator::getTemplateArgumentList ( void ) { int first = TRUE; DName aList; fGetTemplateArgumentList = true; while (( aList.status () == DN_valid ) && *gName && ( *gName != AT_endoflist )) { // Insert the argument list separator if not the first argument if ( first ) first = FALSE; else aList += ','; // Get the individual argument type int argIndex = *gName - '0'; // Handle 'template-argument-replicators', otherwise a new argument type if (( argIndex >= 0 ) && ( argIndex <= 9 )) { gName++; // Skip past the replicator // Append to the argument list aList += ( *pTemplateArgList )[ argIndex ]; } // End of IF then else { pcchar_t oldGName = gName; DName arg; // // Extract the 'argument' type // if ( *gName == DT_void ) { gName++; arg = "void"; } elif ( (*gName == '$') && (gName[1] != '$')) { gName++; arg = getTemplateConstant(); } elif ( *gName == '?' ) { // // This is a template-parameter, i.e. we have a "specialization" of // X. so get the template-parameter-index and use a "generic" name // for this parameter // DName dimension = getSignedDimension(); if ( haveTemplateParameters()) { char buffer[16]; dimension.getString( buffer, 16 ); char *str = (*m_pGetParameter)(atol(buffer)); if ( str != NULL ) { arg = str; } else { arg = "`template-parameter" + dimension + "'"; } } else { arg = "`template-parameter" + dimension + "'"; } } else { arg = getPrimaryDataType ( DName() ); } // Add it to the current list of 'template-argument's, if it is bigger than a one byte encoding if ((( gName - oldGName ) > 1 ) && !pTemplateArgList->isFull ()) *pTemplateArgList += arg; // Append to the argument list aList += arg; } // End of IF else } // End of WHILE // Return the completed template argument list fGetTemplateArgumentList = false; return aList; } // End of "UnDecorator" FUNCTION "getTemplateArgumentList" DName UnDecorator::getTemplateConstant(void) { // // template-constant ::= // '0' // '1' // '2' // char type_category = *gName++; switch ( type_category ) { // // template-integral-constant ::= // // case TC_integral: return getSignedDimension (); // // template-address-constant ::= // '@' // Null pointer // // case TC_address: if ( *gName == TC_nullptr ) { gName++; return "NULL"; } else return DName("&") + getDecoratedName (); // // template-name ::= // // case TC_name: return getDecoratedName (); // // template-floating-point-constant ::= // // case TC_fp: { DName mantissa ( getSignedDimension () ); DName exponent ( getSignedDimension () ); if ( mantissa.isValid() && exponent.isValid() ) { // // Get string representation of mantissa // char buf[100]; // Way overkill for a compiler generated fp constant if ( !mantissa.getString( &(buf[1]), 100 ) ) return DN_invalid; // // Insert decimal point // buf[0] = buf[1]; if ( buf[0] == '-' ) { buf[1] = buf[2]; buf[2] = '.'; } else buf[1] = '.'; // // String it all together // return DName( buf ) + 'e' + exponent; } // End of IF then else return DN_truncated; } // End of BLOCK case TC_fp case TC_dummy: case TC_nontype_dummy: { // // This is a template-parameter, i.e. we have a "specialization" of // X. so get the template-parameter-index and use a "generic" name // for this parameter // DName dimension = getSignedDimension(); if ( haveTemplateParameters()) { char buffer[16]; dimension.getString( buffer, 16 ); char *str = (*m_pGetParameter)(atol(buffer)); if ( str != NULL ) { return str; } } if (type_category == TC_dummy) { return "`template-parameter" + dimension + "'"; } else { return "`non-type-template-parameter" + dimension + "'"; } } break; case TC_vptmd: case TC_gptmd: case TC_mptmf: case TC_vptmf: case TC_gptmf: { DName ptm = '{'; switch (type_category) { case TC_mptmf: case TC_vptmf: case TC_gptmf: ptm += getDecoratedName(); ptm += ','; break; } switch (type_category) { case TC_gptmf: case TC_gptmd: ptm += getSignedDimension(); ptm += ','; // fallthrough case TC_vptmd: case TC_vptmf: ptm += getSignedDimension(); ptm += ','; // fallthrough case TC_mptmf: ptm += getSignedDimension(); } return ptm + '}'; } break; case '\0': --gName; return DN_truncated; default: return DN_invalid; } // End of SWITCH } // End of "UnDecorator" FUNCTION "getTemplateConstant" inline DName UnDecorator::composeDeclaration ( const DName & symbol ) { DName declaration; unsigned int typeCode = getTypeEncoding (); int symIsUDC = symbol.isUDC (); // Handle bad typeCode's, or truncation if ( TE_isbadtype ( typeCode )) return DN_invalid; elif ( TE_istruncated ( typeCode )) return ( DN_truncated + symbol ); elif ( TE_isCident ( typeCode )) return symbol; // This is a very complex part. The type of the declaration must be // determined, and the exact composition must be dictated by this type. // Is it any type of a function ? // However, for ease of decoding, treat the 'localdtor' thunk as data, since // its decoration is a function of the variable to which it belongs and not // a usual function type of decoration. #if ( NO_COMPILER_NAMES ) if ( TE_isthunk ( typeCode )) return DN_invalid; if ( TE_isfunction ( typeCode )) #else // } elif !NO_COMPILER_NAMES { if ( TE_isfunction ( typeCode ) && !(( TE_isthunk ( typeCode ) && TE_islocaldtor ( typeCode )) || ( TE_isthunk ( typeCode ) && ( TE_istemplatector ( typeCode ) || TE_istemplatedtor ( typeCode ))))) #endif // !NO_COMPILER_NAMES { // If it is based, then compose the 'based' prefix for the name if ( TE_isbased ( typeCode )) if ( doMSKeywords () && doAllocationModel ()) declaration = ' ' + getBasedType (); else declaration |= getBasedType (); // Just lose the 'based-type' #if ( !NO_COMPILER_NAMES ) // Check for some of the specially composed 'thunk's if ( TE_isthunk ( typeCode ) && TE_isvcall ( typeCode )) { declaration += symbol + '{' + getCallIndex () + ','; declaration += getVCallThunkType () + "}' "; if ( doMSKeywords () && doAllocationLanguage ()) declaration = ' ' + getCallingConvention () + ' ' + declaration; // What calling convention ? else declaration |= getCallingConvention (); // Just lose the 'calling-convention' } // End of IF then else #endif // !NO_COMPILER_NAMES { DName vtorDisp; DName adjustment; DName thisType; #if ( !NO_COMPILER_NAMES ) if ( TE_isthunk ( typeCode )) { if ( TE_isvtoradj ( typeCode )) vtorDisp = getDisplacement (); adjustment = getDisplacement (); } // End of IF else #endif // !NO_COMPILER_NAMES // Get the 'this-type' for non-static function members if ( TE_ismember ( typeCode ) && !TE_isstatic ( typeCode )) if ( doThisTypes ()) thisType = getThisType (); else thisType |= getThisType (); if ( doMSKeywords ()) { // Attach the calling convention if ( doAllocationLanguage ()) declaration = getCallingConvention () + declaration; // What calling convention ? else declaration |= getCallingConvention (); // Just lose the 'calling-convention' // Any model specifiers ? #if !VERS_32BIT if ( doAllocationModel ()) if ( TE_isnear ( typeCode )) declaration = UScore ( TOK_nearSp ) + declaration; elif ( TE_isfar ( typeCode )) declaration = UScore ( TOK_farSp ) + declaration; #endif } // End of IF else declaration |= getCallingConvention (); // Just lose the 'calling-convention' // Now put them all together if ( !symbol.isEmpty ()) if ( !declaration.isEmpty () && !doNameOnly() ) // And the symbol name declaration += ' ' + symbol; else declaration = symbol; // Compose the return type, catching the UDC case DName * pDeclarator = 0; DName returnType; if ( symIsUDC ) // Is the symbol a UDC operator ? { declaration += " " + getReturnType (); if ( doNameOnly() ) return declaration; } else { pDeclarator = gnew DName; returnType = getReturnType ( pDeclarator ); } // End of IF else #if ( !NO_COMPILER_NAMES ) // Add the displacements for virtual function thunks if ( TE_isthunk ( typeCode )) { if ( TE_isvtoradj ( typeCode )) declaration += "`vtordisp{" + vtorDisp + ','; else declaration += "`adjustor{"; declaration += adjustment + "}' "; } // End of IF #endif // !NO_COMPILER_NAMES // Add the function argument prototype declaration += '(' + getArgumentTypes () + ')'; // If this is a non-static member function, append the 'this' modifiers if ( TE_ismember ( typeCode ) && !TE_isstatic ( typeCode )) declaration += thisType; // Add the 'throw' signature if ( doThrowTypes ()) declaration += getThrowTypes (); else declaration |= getThrowTypes (); // Just lose the 'throw-types' // If it has a declarator, then insert it into the declaration, // sensitive to the return type composition if ( doFunctionReturns () && pDeclarator ) { *pDeclarator = declaration; declaration = returnType; } // End of IF } // End of IF else } // End of IF then else { declaration += symbol; // Catch the special handling cases #if ( !NO_COMPILER_NAMES ) if ( TE_isvftable ( typeCode )) return getVfTableType ( declaration ); elif ( TE_isvbtable ( typeCode )) return getVbTableType ( declaration ); elif ( TE_isguard ( typeCode )) return ( declaration + '{' + getGuardNumber () + "}'" ); elif ( TE_isvdispmap ( typeCode )) return getVdispMapType ( declaration ); elif ( TE_isthunk ( typeCode ) && TE_islocaldtor ( typeCode )) declaration += "`local static destructor helper'"; elif ( TE_isthunk ( typeCode ) && TE_istemplatector ( typeCode )) declaration += "`template static data member constructor helper'"; elif ( TE_isthunk ( typeCode ) && TE_istemplatedtor ( typeCode )) declaration += "`template static data member destructor helper'"; elif ( TE_ismetaclass ( typeCode )) // // Meta-class information has its information in its operator id // return declaration; #else // } elif NO_COMPILER_NAMES { if ( TE_isvftable ( typeCode ) || TE_isvbtable ( typeCode ) || TE_isguard ( typeCode ) || TE_ismetaclass ( typeCode )) return DN_invalid; #endif // NO_COMPILER_NAMES if ( TE_isthunk( typeCode ) && ( TE_istemplatector( typeCode ) || TE_istemplatedtor( typeCode ))) { // // Insert a space before the declaration // declaration = " " + declaration; } else { // All others are decorated as data symbols declaration = getExternalDataType ( declaration ); } } // End of IF else // Prepend the 'virtual' and 'static' attributes for members if ( TE_ismember ( typeCode )) { if ( doMemberTypes ()) { if ( TE_isstatic ( typeCode )) declaration = "static " + declaration; if ( TE_isvirtual ( typeCode ) || ( TE_isthunk ( typeCode ) && ( TE_isvtoradj ( typeCode ) || TE_isadjustor ( typeCode )))) declaration = "virtual " + declaration; } // End of IF // Prepend the access specifiers if ( doAccessSpecifiers ()) if ( TE_isprivate ( typeCode )) declaration = "private: " + declaration; elif ( TE_isprotected ( typeCode )) declaration = "protected: " + declaration; elif ( TE_ispublic ( typeCode )) declaration = "public: " + declaration; } // End of IF #if ( !NO_COMPILER_NAMES ) // If it is a thunk, mark it appropriately if ( TE_isthunk ( typeCode )) declaration = "[thunk]:" + declaration; #endif // !NO_COMPILER_NAMES // Return the composed declaration return declaration; } // End of "UnDecorator" FUNCTION "composeDeclaration" inline int UnDecorator::getTypeEncoding ( void ) { unsigned int typeCode = 0u; // Strip any leading '_' which indicates that it is based if ( *gName == '_' ) { TE_setisbased ( typeCode ); gName++; } // End of IF // Now handle the code proper :- if (( *gName >= 'A' ) && ( *gName <= 'Z' )) // Is it some sort of function ? { int code = *gName++ - 'A'; // Now determine the function type TE_setisfunction ( typeCode ); // All of them are functions ? // Determine the calling model if ( code & TE_far ) TE_setisfar ( typeCode ); else TE_setisnear ( typeCode ); // Is it a member function or not ? if ( code < TE_external ) { // Record the fact that it is a member TE_setismember ( typeCode ); // What access permissions does it have switch ( code & TE_access ) { case TE_private: TE_setisprivate ( typeCode ); break; case TE_protect: TE_setisprotected ( typeCode ); break; case TE_public: TE_setispublic ( typeCode ); break; default: TE_setisbadtype ( typeCode ); return typeCode; } // End of SWITCH // What type of a member function is it ? switch ( code & TE_adjustor ) { case TE_adjustor: TE_setisadjustor ( typeCode ); break; case TE_virtual: TE_setisvirtual ( typeCode ); break; case TE_static: TE_setisstatic ( typeCode ); break; case TE_member: break; default: TE_setisbadtype ( typeCode ); return typeCode; } // End of SWITCH } // End of IF } // End of IF then elif ( *gName == '$' ) // Extended set ? Special handling { // What type of symbol is it ? switch ( *( ++gName )) { case SHF_localdtor: // A destructor helper for a local static ? TE_setislocaldtor ( typeCode ); break; case SHF_vcall: // A VCall-thunk ? TE_setisvcall ( typeCode ); break; case SHF_templateStaticDataMemberCtor: // A constructor helper for template static data members TE_setistemplatector ( typeCode ); break; case SHF_templateStaticDataMemberDtor: // A destructor helper for template static data members TE_setistemplatedtor ( typeCode ); break; case SHF_vdispmap: TE_setvdispmap ( typeCode ); break; case '$': { if ( * ( gName + 1 ) == SHF_AnyDLLImportMethod ) { gName += 1; } switch ( *( ++gName )) { case SHF_CPPManagedILFunction: // C++ managed-IL function case SHF_CPPManagedNativeFunction: // C++ managed-native function case SHF_CPPManagedILMain: // C++ managed-IL main case SHF_CPPManagedNativeMain: // C++ managed-native main case SHF_CPPManagedILDLLImportData: // C++ managed-IL DLL-import function case SHF_CPPManagedNativeDLLImportData: // C++ managed-native DLL-import function // // Skip the encoding // gName += 1; return getTypeEncoding(); case SHF_CManagedILFunction: // C (or extern "C") managed-IL function case SHF_CManagedNativeFunction: // C (or extern "C") managed-native function case SHF_CManagedILDLLImportData: // C (or extern "C") managed-IL DLL-import function case SHF_CManagedNativeDLLImportData: // C (or extern "C") managed-native DLL-import function // // Skip the encoding // gName += 1; // // The next character should be the number of characters // in the byte-count // if (( *gName >= '0' ) && ( *gName <= '9' )) { // // Skip the character count and the byte-count // itself // gName += (( *gName - '0' ) + 1 ); return getTypeEncoding(); } else { TE_setisbadtype( typeCode ); } break; default: break; } } break; case 0: TE_setistruncated ( typeCode ); break; case '0': case '1': case '2': case '3': case '4': case '5': // Construction displacement adjustor thunks { int code = *gName - '0'; // Set up the principal type information TE_setisfunction ( typeCode ); TE_setismember ( typeCode ); TE_setisvtoradj ( typeCode ); // Is it 'near' or 'far' ? if ( code & TE_far ) TE_setisfar ( typeCode ); else TE_setisnear ( typeCode ); // What type of access protection ? switch ( code & TE_access_vadj ) { case TE_private_vadj: TE_setisprivate ( typeCode ); break; case TE_protect_vadj: TE_setisprotected ( typeCode ); break; case TE_public_vadj: TE_setispublic ( typeCode ); break; default: TE_setisbadtype ( typeCode ); return typeCode; } // End of SWITCH } // End of CASE '0,1,2,3,4,5' break; default: TE_setisbadtype ( typeCode ); return typeCode; } // End of SWITCH // Advance past the code character gName++; } // End of ELIF then elif (( *gName >= TE_static_d ) && ( *gName <= TE_metatype )) // Non function decorations ? { int code = *gName++; TE_setisdata ( typeCode ); // What type of symbol is it ? switch ( code ) { case ( TE_static_d | TE_private_d ): TE_setisstatic ( typeCode ); TE_setisprivate ( typeCode ); break; case ( TE_static_d | TE_protect_d ): TE_setisstatic ( typeCode ); TE_setisprotected ( typeCode ); break; case ( TE_static_d | TE_public_d ): TE_setisstatic ( typeCode ); TE_setispublic ( typeCode ); break; case TE_global: TE_setisglobal ( typeCode ); break; case TE_guard: TE_setisguard ( typeCode ); break; case TE_local: TE_setislocal ( typeCode ); break; case TE_vftable: TE_setisvftable ( typeCode ); break; case TE_vbtable: TE_setisvbtable ( typeCode ); break; case TE_metatype: TE_setismetaclass ( typeCode ); break; default: TE_setisbadtype ( typeCode ); return typeCode; } // End of SWITCH } // End of ELIF then elif ( *gName == '9' ) { gName++; TE_setisCident ( typeCode ); } elif ( *gName ) TE_setisbadtype ( typeCode ); else TE_setistruncated ( typeCode ); // Return the composed type code return typeCode; } // End of "UnDecorator" FUNCTION "getTypeEncoding" DName UnDecorator::getBasedType ( void ) { DName basedDecl ( UScore ( TOK_basedLp )); // What type of 'based' is it ? if ( *gName ) { switch ( *gName++ ) { #if !VERS_32BIT case BT_segname: basedDecl += UScore ( TOK_segnameLpQ ) + getSegmentName () + "\")"; break; case BT_segment: basedDecl += DName ( "NYI:" ) + UScore ( TOK_segment ); break; #endif case BT_void: basedDecl += "void"; break; #if !VERS_32BIT case BT_self: basedDecl += UScore ( TOK_self ); break; case BT_nearptr: basedDecl += DName ( "NYI:" ) + UScore ( TOK_nearP ); break; case BT_farptr: basedDecl += DName ( "NYI:" ) + UScore ( TOK_farP ); break; case BT_hugeptr: basedDecl += DName ( "NYI:" ) + UScore ( TOK_hugeP ); break; case BT_segaddr: basedDecl += "NYI:"; break; #else case BT_nearptr: basedDecl += getScopedName(); break; #endif case BT_basedptr: // // Note: based pointer on based pointer is reserved // return DN_invalid; } // End of SWITCH } // End of IF else else basedDecl += DN_truncated; // Close the based syntax basedDecl += ") "; // Return completed based declaration return basedDecl; } // End of "UnDecorator" FUNCTION "getBasedType" DName UnDecorator::getScopedName ( void ) { DName name; // Get the beginning of the name name = getZName ( true ); // Now the scope (if any) if (( name.status () == DN_valid ) && *gName && ( *gName != '@' )) name = getScope () + "::" + name; // Skip the trailing '@' if ( *gName == '@' ) gName++; elif ( *gName ) name = DN_invalid; elif ( name.isEmpty ()) name = DN_truncated; else name = DName ( DN_truncated ) + "::" + name; // And return the complete name return name; } // End of "UnDecorator" FUNCTION "getECSUName" inline DName UnDecorator::getECSUName ( void ) { return getScopedName(); } inline DName UnDecorator::getEnumType ( void ) { DName ecsuName; if ( *gName ) { // What type of an 'enum' is it ? switch ( *gName ) { case ET_schar: case ET_uchar: ecsuName = "char "; break; case ET_sshort: case ET_ushort: ecsuName = "short "; break; case ET_sint: break; case ET_uint: ecsuName = "int "; break; case ET_slong: case ET_ulong: ecsuName = "long "; break; default: return DN_invalid; } // End of SWITCH // Add the 'unsigned'ness if appropriate switch ( *gName++ ) { case ET_uchar: case ET_ushort: case ET_uint: case ET_ulong: ecsuName = "unsigned " + ecsuName; break; } // End of SWITCH // Now return the composed name return ecsuName; } // End of IF then else return DN_truncated; } // End of "UnDecorator" FUNCTION "getEnumType" DName UnDecorator::getCallingConvention ( void ) { if ( *gName ) { unsigned int callCode = ((unsigned int)*gName++ ) - 'A'; // What is the primary calling convention DASSERT(CC_cdecl == 0); #if CC_COR if (/*( callCode >= CC_cdecl ) &&*/( callCode <= CC_cocall )) #else // CC_COR if (/*( callCode >= CC_cdecl ) &&*/( callCode <= CC_interrupt )) #endif // CC_COR { DName callType; // Now, what type of 'calling-convention' is it, 'interrupt' is special ? if ( doMSKeywords ()) #if !VERS_32BIT if ( callCode == CC_interrupt ) callType = UScore ( TOK_interrupt ); else #endif { switch ( callCode & ~CC_saveregs ) { case CC_cdecl: callType = UScore ( TOK_cdecl ); break; case CC_pascal: callType = UScore ( TOK_pascal ); break; case CC_thiscall: callType = UScore ( TOK_thiscall ); break; case CC_stdcall: callType = UScore ( TOK_stdcall ); break; case CC_fastcall: callType = UScore ( TOK_fastcall ); break; case CC_cocall: callType = UScore ( TOK_cocall ); break; } // End of SWITCH // Has it also got 'saveregs' marked ? #if !VERS_32BIT if ( callCode & CC_saveregs ) callType += ' ' + UScore ( TOK_saveregs ); #endif } // End of IF else // And return return callType; } // End of IF then else return DN_invalid; } // End of IF then else return DN_truncated; } // End of "UnDecorator" FUNCTION "getCallingConvention" DName UnDecorator::getReturnType ( DName * pDeclarator ) { if ( *gName == '@' ) // Return type for constructors and destructors ? { gName++; return DName ( pDeclarator ); } // End of IF then else return getDataType ( pDeclarator ); } // End of "UnDecorator" FUNCTION "getReturnType" DName UnDecorator::getDataType ( DName * pDeclarator ) { DName superType ( pDeclarator ); // What type is it ? switch ( *gName ) { case 0: return ( DN_truncated + superType ); case DT_void: gName++; if ( superType.isEmpty ()) return "void"; else return "void " + superType; case '?': { gName++; // Skip the '?' superType = getDataIndirectType ( superType, 0, DName (), 0); return getPrimaryDataType ( superType ); return superType; } // End of CASE '?' default: return getPrimaryDataType ( superType ); } // End of SWITCH } // End of "UnDecorator" FUNCTION "getDataType" DName UnDecorator::getPrimaryDataType ( const DName & superType ) { DName cvType; switch ( *gName ) { case 0: return ( DN_truncated + superType ); case PDT_volatileReference: cvType = "volatile"; if ( !superType.isEmpty ()) cvType += ' '; // No break case PDT_reference: { DName superName ( superType ); gName++; return getReferenceType ( cvType, superName.setPtrRef ()); } // End of CASE 'PDT_reference' case PDT_extend: { // // Extended Primary Data Type (items overlooked in original design): // prefixed by '$$'. // if ( gName[1] != PDT_extend ) if ( gName[1] == '\0' ) return DN_truncated + superType; else return DN_invalid; gName += 2; switch ( *gName ) { case PDT_ex_function: gName++; return getFunctionIndirectType( superType ); case PDT_ex_other: gName++; return getPtrRefDataType( superType, /* isPtr = */ TRUE ); case PDT_ex_qualified: gName++; return(getBasicDataType(getDataIndirectType ( superType, 0, DName (), 0))); case 0: return ( DN_truncated + superType ); default: return DN_invalid; } } default: return getBasicDataType ( superType ); } // End of SWITCH } // End of "UnDecorator" FUNCTION "getPrimaryDataType" DName UnDecorator::getArgumentTypes ( void ) { switch ( *gName ) { case AT_ellipsis: return ( gName++, "..." ); case AT_void: return ( gName++, "void" ); default: { DName arguments ( getArgumentList ()); // Now, is it a varargs function or not ? if ( arguments.status () == DN_valid ) switch ( *gName ) { case 0: return arguments; case AT_ellipsis: return ( gName++, arguments + ",..." ); case AT_endoflist: return ( gName++, arguments ); default: return DN_invalid; } // End of SWITCH else return arguments; } // End of DEFAULT } // End of SWITCH } // End of "UnDecorator" FUNCTION "getArgumentTypes" DName UnDecorator::getArgumentList ( void ) { int first = TRUE; DName aList; while (( aList.status () == DN_valid ) && ( *gName != AT_endoflist ) && ( *gName != AT_ellipsis )) { // Insert the argument list separator if not the first argument if ( first ) first = FALSE; else aList += ','; // Get the individual argument type if ( *gName ) { int argIndex = *gName - '0'; // Handle 'argument-replicators', otherwise a new argument type if (( argIndex >= 0 ) && ( argIndex <= 9 )) { gName++; // Skip past the replicator // Append to the argument list aList += ( *pArgList )[ argIndex ]; } // End of IF then else { pcchar_t oldGName = gName; // Extract the 'argument' type DName arg ( getPrimaryDataType ( DName ())); // Add it to the current list of 'argument's, if it is bigger than a one byte encoding if ((( gName - oldGName ) > 1 ) && !pArgList->isFull ()) *pArgList += arg; // Append to the argument list aList += arg; } // End of IF else } // End of IF then else { aList += DN_truncated; break; } // End of IF else } // End of WHILE // Return the completed argument list return aList; } // End of "UnDecorator" FUNCTION "getArgumentList" DName UnDecorator::getThrowTypes ( void ) { if ( *gName ) if ( *gName == AT_ellipsis ) // Handle ellipsis here to suppress the 'throw' signature return ( gName++, DName ()); else return ( " throw(" + getArgumentTypes () + ')' ); else return ( DName ( " throw(" ) + DN_truncated + ')' ); } // End of "UnDecorator" FUNCTION "getThrowTypes" DName UnDecorator::getBasicDataType ( const DName & superType ) { if ( *gName ) { unsigned char bdtCode = *gName++; unsigned char extended_bdtCode; int pCvCode = -1; DName basicDataType; // Extract the principal type information itself, and validate the codes switch ( bdtCode ) { case BDT_schar: case BDT_char: case ( BDT_char | BDT_unsigned ): basicDataType = "char"; break; case BDT_short: case ( BDT_short | BDT_unsigned ): basicDataType = "short"; break; case BDT_int: case ( BDT_int | BDT_unsigned ): basicDataType = "int"; break; case BDT_long: case ( BDT_long | BDT_unsigned ): basicDataType = "long"; break; #if !VERS_32BIT case BDT_segment: basicDataType = UScore ( TOK_segment ); break; #endif case BDT_float: basicDataType = "float"; break; case BDT_longdouble: basicDataType = "long "; // No break case BDT_double: basicDataType += "double"; break; case BDT_pointer: case ( BDT_pointer | BDT_const ): case ( BDT_pointer | BDT_volatile ): case ( BDT_pointer | BDT_const | BDT_volatile ): pCvCode = ( bdtCode & ( BDT_const | BDT_volatile )); break; case BDT_extend: switch(extended_bdtCode = *gName++) { case BDT_array: pCvCode = -2; break; case BDT_bool: basicDataType = "bool"; break; case BDT_int8: case ( BDT_int8 | BDT_unsigned ): basicDataType = "__int8"; break; case BDT_int16: case ( BDT_int16 | BDT_unsigned ): basicDataType = "__int16"; break; case BDT_int32: case ( BDT_int32 | BDT_unsigned ): basicDataType = "__int32"; break; case BDT_int64: case ( BDT_int64 | BDT_unsigned ): basicDataType = "__int64"; break; case BDT_int128: case ( BDT_int128 | BDT_unsigned ): basicDataType = "__int128"; break; case BDT_wchar_t: basicDataType = "wchar_t"; break; #if CC_COR case BDT_coclass: case BDT_cointerface: { gName--; // Backup, since 'ecsu-data-type' does it's own decoding basicDataType = getECSUDataType(); if ( basicDataType.isEmpty()) { return basicDataType; } } break; #endif // CC_COR case '$': return "__w64 " + getBasicDataType (superType); default: basicDataType = "UNKNOWN"; break; } break; default: gName--; // Backup, since 'ecsu-data-type' does it's own decoding basicDataType = getECSUDataType (); if ( basicDataType.isEmpty ()) return basicDataType; break; } // End of SWITCH // What type of basic data type composition is involved ? if ( pCvCode == -1 ) // Simple ? { // Determine the 'signed/unsigned'ness switch ( bdtCode ) { case ( BDT_char | BDT_unsigned ): case ( BDT_short | BDT_unsigned ): case ( BDT_int | BDT_unsigned ): case ( BDT_long | BDT_unsigned ): basicDataType = "unsigned " + basicDataType; break; case BDT_schar: basicDataType = "signed " + basicDataType; break; case BDT_extend: switch ( extended_bdtCode ) { case ( BDT_int8 | BDT_unsigned ): case ( BDT_int16 | BDT_unsigned ): case ( BDT_int32 | BDT_unsigned ): case ( BDT_int64 | BDT_unsigned ): case ( BDT_int128 | BDT_unsigned ): basicDataType = "unsigned " + basicDataType; break; } // End of SWITCH break; } // End of SWITCH // Add the indirection type to the type if ( !superType.isEmpty () ) basicDataType += ' ' + superType; // And return the completed type return basicDataType; } // End of IF then else { DName cvType; DName superName ( superType ); if ( pCvCode == -2 ) { superName.setIsArray(); DName arType = getPointerTypeArray ( cvType, superName ); // if we didn't get back an array, append. // A multidimensional array sticks the braces in before the // other dimensions at sets isArray on it's return type. if (!arType.isArray()) { arType += "[]"; } return arType; } // Is it 'const/volatile' qualified ? if ( superType . isEmpty() ) { // // const/volatile are redundantly encoded, except at the start // of a "type only" context. In such a context, the super-type // is empty. // if ( pCvCode & BDT_const ) { cvType = "const"; if ( pCvCode & BDT_volatile ) cvType += " volatile"; } // End of IF then elif ( pCvCode & BDT_volatile ) cvType = "volatile"; } // End of IF then // Construct the appropriate pointer type declaration return getPointerType ( cvType, superName ); } // End of IF else } // End of IF then else return ( DN_truncated + superType ); } // End of "UnDecorator" FUNCTION "getBasicDataType" DName UnDecorator::getECSUDataType ( void ) { // Extract the principal type information itself, and validate the codes int fPrefix = doEcsu() && !doNameOnly(); DName Prefix; switch ( *gName++ ) { case 0: gName--; // Backup to permit later error recovery to work safely return "`unknown ecsu'" + DN_truncated; case BDT_union: Prefix = "union "; break; case BDT_struct: Prefix = "struct "; break; case BDT_class: Prefix = "class "; break; #if CC_COR case BDT_coclass: Prefix = "coclass "; break; case BDT_cointerface: Prefix = "cointerface "; break; #endif // CC_COR case BDT_enum: fPrefix = doEcsu(); Prefix = "enum " + getEnumType (); break; // default: // return DN_invalid; } // End of SWITCH DName ecsuDataType; if ( fPrefix ) ecsuDataType = Prefix; // Get the 'class/struct/union' name ecsuDataType += getECSUName (); // And return the formed 'ecsu-data-type' return ecsuDataType; } // End of "UnDecorator" FUNCTION "getECSUDataType" // // Undecorator::getFunctionIndirectType // // Note: this function gets both the function-indirect-type and the function-type. // DName UnDecorator::getFunctionIndirectType( const DName & superType ) { if ( ! *gName ) return DN_truncated + superType; if ( ! IT_isfunction( *gName )) return DN_invalid; int fitCode = *gName++ - '6'; if ( fitCode == ( '_' - '6' )) { if ( *gName ) { fitCode = *gName++ - 'A' + FIT_based; if (( fitCode < FIT_based ) || ( fitCode > ( FIT_based | FIT_far | FIT_member ))) fitCode = -1; } // End of IF then else return ( DN_truncated + superType ); } // End of IF then elif (( fitCode < FIT_near ) || ( fitCode > ( FIT_far | FIT_member ))) fitCode = -1; // Return if invalid name if ( fitCode == -1 ) return DN_invalid; // Otherwise, what are the function indirect attributes DName thisType; DName fitType = superType; // Is it a pointer to member function ? if ( fitCode & FIT_member ) { fitType = "::" + fitType; if ( *gName ) fitType = ' ' + getScope () + fitType; else fitType = DN_truncated + fitType; if ( *gName ) if ( *gName == '@' ) gName++; else return DN_invalid; else return ( DN_truncated + fitType ); if ( doThisTypes ()) thisType = getThisType (); else thisType |= getThisType (); } // End of IF // Is it a based allocated function ? if ( fitCode & FIT_based ) if ( doMSKeywords ()) fitType = ' ' + getBasedType () + fitType; else fitType |= getBasedType (); // Just lose the 'based-type' // Get the 'calling-convention' if ( doMSKeywords ()) { fitType = getCallingConvention () + fitType; // Is it a near or far function pointer #if !VERS_32BIT fitType = UScore ((( fitCode & FIT_far ) ? TOK_farSp : TOK_nearSp )) + fitType; #endif } // End of IF then else fitType |= getCallingConvention (); // Just lose the 'calling-convention' // Parenthesise the indirection component, and work on the rest if ( ! superType . isEmpty() ) { fitType = '(' + fitType + ')'; } // Get the rest of the 'function-type' pieces DName * pDeclarator = gnew DName; DName returnType ( getReturnType ( pDeclarator )); fitType += '(' + getArgumentTypes () + ')'; if ( doThisTypes () && ( fitCode & FIT_member )) fitType += thisType; if ( doThrowTypes ()) fitType += getThrowTypes (); else fitType |= getThrowTypes (); // Just lose the 'throw-types' // Now insert the indirected declarator, catch the allocation failure here if ( pDeclarator ) *pDeclarator = fitType; else return DN_error; // And return the composed function type (now in 'returnType' ) return returnType; } DName UnDecorator::getPtrRefType ( const DName & cvType, const DName & superType, char ptrChar ) { // Doubles up as 'pointer-type' and 'reference-type' if ( *gName ) if ( IT_isfunction ( *gName )) // Is it a function or data indirection ? { DName fitType = ptrChar; if ( !cvType.isEmpty () && ( superType.isEmpty () || !superType.isPtrRef ())) fitType += cvType; if ( !superType.isEmpty ()) fitType += superType; return getFunctionIndirectType( fitType ); } // End of IF then else { // Otherwise, it is either a pointer or a reference to some data type DName innerType ( getDataIndirectType ( superType, ptrChar, cvType )); return getPtrRefDataType ( innerType, ptrChar == '*' ); } // End of IF else else { DName trunk ( DN_truncated ); trunk += ptrChar; if ( !cvType.isEmpty ()) trunk += cvType; if ( !superType.isEmpty ()) { if ( !cvType.isEmpty ()) trunk += ' '; trunk += superType; } // End of IF return trunk; } // End of IF else } // End of "UnDecorator" FUNCTION "getPtrRefType" DName UnDecorator::getDataIndirectType ( const DName & superType, char prType, const DName & cvType, int thisFlag ) { DName szComPlusIndirSpecifier; if ( *gName ) { if( gName[0] == '$' ) { gName++; // swallow up the dollar switch( *gName ) { case PDT_GCPointer: szComPlusIndirSpecifier = "__gc "; gName++; break; case PDT_PinnedPointer: szComPlusIndirSpecifier = "__pin "; gName++; break; default: unsigned int nRank = ((gName[0]-'0') << 4) + (gName[1]-'0'); gName += 2; DASSERT( nRank < 256 ); szComPlusIndirSpecifier = "__gc["; for( unsigned int i=1; i= 'A' ) ? (unsigned int)'A': (unsigned int)( '0' - 26 ))); DName msExtension; DName msExtensionPre; int fContinue = TRUE; do { switch ( ditCode ) { case DIT_ptr64: if ( doMSKeywords () && doPtr64() ) { if ( !msExtension.isEmpty()) msExtension = msExtension + ' ' + UScore( TOK_ptr64 ); else msExtension = UScore( TOK_ptr64 ); } gName++; ditCode = ( *gName - (( *gName >= 'A' ) ? (unsigned int)'A': (unsigned int)( '0' - 26 ))); break; case DIT_unaligned: if ( doMSKeywords ()) { if ( !msExtensionPre.isEmpty()) msExtensionPre = msExtensionPre + ' ' + UScore( TOK_unaligned ); else msExtensionPre = UScore( TOK_unaligned ); } gName++; ditCode = ( *gName - (( *gName >= 'A' ) ? (unsigned int)'A': (unsigned int)( '0' - 26 ))); break; case DIT_restrict: if ( doMSKeywords ()) { if ( !msExtension.isEmpty()) msExtension = msExtension + ' ' + UScore( TOK_restrict ); else msExtension = UScore( TOK_restrict ); } gName++; ditCode = ( *gName - (( *gName >= 'A' ) ? (unsigned int)'A': (unsigned int)( '0' - 26 ))); break; default: fContinue = FALSE; break; } } while (fContinue); gName++; // Skip to next character in name // Is it a valid 'data-indirection-type' ? DASSERT(DIT_near == 0); if (( ditCode <= ( DIT_const | DIT_volatile | DIT_modelmask | DIT_member ))) { DName ditType ( prType ); ditType = szComPlusIndirSpecifier + ditType; if ( !msExtension.isEmpty()) ditType = ditType + ' ' + msExtension; if ( !msExtensionPre.isEmpty()) ditType = msExtensionPre + ' ' + ditType; // If it is a member, then these attributes immediately precede the indirection token if ( ditCode & DIT_member ) { // If it is really 'this-type', then it cannot be any form of pointer to member if ( thisFlag ) return DN_invalid; // Otherwise, extract the scope for the PM if ( prType != '\0' ) { ditType = "::" + ditType; if ( *gName ) ditType = getScope () + ditType; else ditType = DN_truncated + ditType; } elif ( *gName ) { // // The scope is ignored for special uses of data-indirect-type, such // as storage-convention. I think it's a bug that we ever mark things // with Member storage convention, as that is already covered in the // scope of the name. However, we don't want to change the dname scheme, // so we're stuck with it. // ditType |= getScope (); } // Now skip the scope terminator if ( !*gName ) ditType += DN_truncated; elif ( *gName++ != '@' ) return DN_invalid; } // End of IF // Add the 'model' attributes (prefixed) as appropriate if ( doMSKeywords ()) { switch ( ditCode & DIT_modelmask ) { #if !VERS_32BIT case DIT_near: if ( do32BitNear ()) ditType = UScore ( TOK_near ) + ditType; break; case DIT_far: ditType = UScore ( TOK_far ) + ditType; break; case DIT_huge: ditType = UScore ( TOK_huge ) + ditType; break; #endif case DIT_based: // The 'this-type' can never be 'based' if ( thisFlag ) return DN_invalid; ditType = getBasedType () + ditType; break; } // End of SWITCH } // End of IF elif (( ditCode & DIT_modelmask ) == DIT_based ) ditType |= getBasedType (); // Just lose the 'based-type' // Handle the 'const' and 'volatile' attributes if ( ditCode & DIT_volatile ) ditType = "volatile " + ditType; if ( ditCode & DIT_const ) ditType = "const " + ditType; // Append the supertype, if not 'this-type' if ( !thisFlag ) if ( !superType.isEmpty ()) { // Is the super context included 'cv' information, ensure that it is added appropriately if ( superType.isPtrRef () || cvType.isEmpty ()) if (superType.isArray()) ditType = superType; // array type, skip space else ditType += ' ' + superType; else ditType += ' ' + cvType + ' ' + superType; } // End of IF then elif ( !cvType.isEmpty ()) ditType += ' ' + cvType; // Make sure qualifiers aren't re-applied ditType.setPtrRef (); // Finally, return the composed 'data-indirection-type' (with embedded sub-type) return ditType; } // End of IF then else return DN_invalid; } // End of IF then elif ( !thisFlag && !superType.isEmpty ()) { // Is the super context included 'cv' information, ensure that it is added appropriately if ( superType.isPtrRef () || cvType.isEmpty ()) return ( DN_truncated + superType ); else return ( DN_truncated + cvType + ' ' + superType ); } // End of ELIF then elif ( !thisFlag && !cvType.isEmpty ()) return ( DN_truncated + cvType ); else return DN_truncated; } // End of "UnDecorator" FUNCTION "getDataIndirectType" inline DName UnDecorator::getPtrRefDataType ( const DName & superType, int isPtr ) { // Doubles up as 'pointer-data-type' and 'reference-data-type' if ( *gName ) { // Is this a 'pointer-data-type' ? if ( isPtr && ( *gName == PoDT_void )) { gName++; // Skip this character if ( superType.isEmpty ()) return "void"; else return "void " + superType; } // End of IF // Otherwise it may be a 'reference-data-type' if ( *gName == RDT_array ) // An array ? { gName++; return getArrayType( superType ); } // End of IF // Otherwise, it is a 'basic-data-type' if ( *gName == '_' && gName[1] == 'Z' ) // A boxed type ? { gName += 2; return "__box " + getBasicDataType ( superType ); } return getBasicDataType ( superType ); } // End of IF then else return ( DN_truncated + superType ); } // End of "UnDecorator" FUNCTION "getPtrRefDataType" inline DName UnDecorator::getArrayType ( const DName & superType ) { if ( *gName ) { int noDimensions = getNumberOfDimensions (); if ( noDimensions < 0 ) noDimensions = 0; if ( !noDimensions ) return getBasicDataType ( DName ( '[' ) + DN_truncated + ']' ); else { DName arrayType; if ( superType.isArray() ) { arrayType += "[]"; } while ( noDimensions-- ) arrayType += '[' + getDimension () + ']'; // If it is indirect, then parenthesise the 'super-type' if ( !superType.isEmpty () ) if ( superType.isArray() ) arrayType = superType + arrayType; else arrayType = '(' + superType + ')' + arrayType; // Return the finished array dimension information DName newType = getPrimaryDataType ( arrayType ); newType.setIsArray(); return newType; } // End of IF else } // End of IF elif ( !superType.isEmpty ()) return getBasicDataType ( '(' + superType + ")[" + DN_truncated + ']' ); else return getBasicDataType ( DName ( '[' ) + DN_truncated + ']' ); } // End of "UnDecorator" FUNCTION "getArrayType" inline DName UnDecorator::getLexicalFrame ( void ) { return '`' + getDimension () + '\''; } inline DName UnDecorator::getStorageConvention ( void ) { return getDataIndirectType (); } inline DName UnDecorator::getDataIndirectType () { return getDataIndirectType ( DName (), 0, DName ()); } inline DName UnDecorator::getThisType ( void ) { return getDataIndirectType ( DName (), 0, DName (), TRUE ); } inline DName UnDecorator::getPointerType ( const DName & cv, const DName & name ) { return getPtrRefType ( cv, name, '*' ); } inline DName UnDecorator::getPointerTypeArray ( const DName & cv, const DName & name ) { return getPtrRefType ( cv, name, '\0' ); } inline DName UnDecorator::getReferenceType ( const DName & cv, const DName & name ) { return getPtrRefType ( cv, name, '&' ); } inline DName UnDecorator::getSegmentName ( void ) { return getZName ( true ); } #if ( !NO_COMPILER_NAMES ) inline DName UnDecorator::getDisplacement ( void ) { return getDimension ( true ); } inline DName UnDecorator::getCallIndex ( void ) { return getDimension (); } inline DName UnDecorator::getGuardNumber ( void ) { return getDimension (); } inline DName UnDecorator::getVbTableType ( const DName & superType ) { return getVfTableType ( superType ); } inline DName UnDecorator::getVCallThunkType ( void ) { #if VERS_32BIT switch (*gName) { case VMT_nTnCnV: ++gName; return DName("{flat}"); case 0: return DN_truncated; default: return DN_invalid; } #else DName vcallType = '{'; // Get the 'this' model, and validate all values switch ( *gName ) { case VMT_nTnCnV: case VMT_nTfCnV: case VMT_nTnCfV: case VMT_nTfCfV: case VMT_nTnCbV: case VMT_nTfCbV: vcallType += UScore ( TOK_nearSp ); break; case VMT_fTnCnV: case VMT_fTfCnV: case VMT_fTnCfV: case VMT_fTfCfV: case VMT_fTnCbV: case VMT_fTfCbV: vcallType += UScore ( TOK_farSp ); break; case 0: return DN_truncated; default: return DN_invalid; } // End of SWITCH // Always append 'this' vcallType += "this, "; // Get the 'call' model switch ( *gName ) { case VMT_nTnCnV: case VMT_fTnCnV: case VMT_nTnCfV: case VMT_fTnCfV: case VMT_nTnCbV: case VMT_fTnCbV: vcallType += UScore ( TOK_nearSp ); break; case VMT_nTfCnV: case VMT_fTfCnV: case VMT_nTfCfV: case VMT_fTfCfV: case VMT_nTfCbV: case VMT_fTfCbV: vcallType += UScore ( TOK_farSp ); break; } // End of SWITCH // Always append 'call' vcallType += "call, "; // Get the 'vfptr' model switch ( *gName++ ) // Last time, so advance the pointer { case VMT_nTnCnV: case VMT_nTfCnV: case VMT_fTnCnV: case VMT_fTfCnV: vcallType += UScore ( TOK_nearSp ); break; case VMT_nTnCfV: case VMT_nTfCfV: case VMT_fTnCfV: case VMT_fTfCfV: vcallType += UScore ( TOK_farSp ); break; case VMT_nTfCbV: case VMT_fTnCbV: case VMT_fTfCbV: case VMT_nTnCbV: vcallType += getBasedType (); break; } // End of SWITCH // Always append 'vfptr' vcallType += "vfptr}"; // And return the resultant 'vcall-model-type' return vcallType; #endif } // End of "UnDecorator" FUNCTION "getVCallThunk" inline DName UnDecorator::getVfTableType ( const DName & superType ) { DName vxTableName = superType; if ( vxTableName.isValid () && *gName ) { vxTableName = getStorageConvention () + ' ' + vxTableName; if ( vxTableName.isValid ()) { if ( *gName != '@' ) { vxTableName += "{for "; while ( vxTableName.isValid () && *gName && ( *gName != '@' )) { vxTableName += '`' + getScope () + '\''; // Skip the scope delimiter if ( *gName == '@' ) gName++; // Close the current scope, and add a conjunction for the next (if any) if ( vxTableName.isValid () && ( *gName != '@' )) vxTableName += "s "; } // End of WHILE if ( vxTableName.isValid ()) { if ( !*gName ) vxTableName += DN_truncated; vxTableName += '}'; } // End of IF } // End of IF // Skip the 'vpath-name' terminator if ( *gName == '@' ) gName++; } // End of IF } // End of IF then elif ( vxTableName.isValid ()) vxTableName = DN_truncated + vxTableName; return vxTableName; } // End of "UnDecorator" FUNCTION "getVfTableType" inline DName UnDecorator::getVdispMapType ( const DName & superType ) { DName vdispMapName = superType; vdispMapName += "{for "; vdispMapName += getScope(); vdispMapName += '}'; if ( *gName == '@' ) gName++; return vdispMapName; } #endif // !NO_COMPILER_NAMES inline DName UnDecorator::getExternalDataType ( const DName & superType ) { // Create an indirect declarator for the the rest DName * pDeclarator = gnew DName (); DName declaration = getDataType ( pDeclarator ); // Now insert the declarator into the declaration along with its 'storage-convention' *pDeclarator = getStorageConvention () + ' ' + superType; return declaration; } // End of "UnDecorator" FUNCTION "getExternalDataType" inline int UnDecorator::doUnderScore () { return !( disableFlags & UNDNAME_NO_LEADING_UNDERSCORES ); } inline int UnDecorator::doMSKeywords () { return !( disableFlags & UNDNAME_NO_MS_KEYWORDS ); } inline int UnDecorator::doPtr64 () { return !( disableFlags & UNDNAME_NO_PTR64 ); } inline int UnDecorator::doFunctionReturns () { return !( disableFlags & UNDNAME_NO_FUNCTION_RETURNS ); } inline int UnDecorator::doAllocationModel () { return !( disableFlags & UNDNAME_NO_ALLOCATION_MODEL ); } inline int UnDecorator::doAllocationLanguage () { return !( disableFlags & UNDNAME_NO_ALLOCATION_LANGUAGE ); } #if 0 inline int UnDecorator::doMSThisType () { return !( disableFlags & UNDNAME_NO_MS_THISTYPE ); } inline int UnDecorator::doCVThisType () { return !( disableFlags & UNDNAME_NO_CV_THISTYPE ); } #endif inline int UnDecorator::doThisTypes () { return (( disableFlags & UNDNAME_NO_THISTYPE ) != UNDNAME_NO_THISTYPE ); } inline int UnDecorator::doAccessSpecifiers () { return !( disableFlags & UNDNAME_NO_ACCESS_SPECIFIERS ); } inline int UnDecorator::doThrowTypes () { return !( disableFlags & UNDNAME_NO_THROW_SIGNATURES ); } inline int UnDecorator::doMemberTypes () { return !( disableFlags & UNDNAME_NO_MEMBER_TYPE ); } inline int UnDecorator::doReturnUDTModel () { return !( disableFlags & UNDNAME_NO_RETURN_UDT_MODEL ); } inline int UnDecorator::do32BitNear () { return !( disableFlags & UNDNAME_32_BIT_DECODE ); } inline int UnDecorator::doNameOnly () { return ( disableFlags & UNDNAME_NAME_ONLY ); } inline int UnDecorator::doTypeOnly () { return ( disableFlags & UNDNAME_TYPE_ONLY ); } inline int UnDecorator::haveTemplateParameters () { return ( disableFlags & UNDNAME_HAVE_PARAMETERS); } inline int UnDecorator::doEcsu () { return !( disableFlags & UNDNAME_NO_ECSU ); } inline int UnDecorator::doNoIdentCharCheck () { return ( disableFlags & UNDNAME_NO_IDENT_CHAR_CHECK ); } pcchar_t UnDecorator::UScore ( Tokens tok ) { #if !VERS_32BIT if ((( tok == TOK_nearSp ) || ( tok == TOK_nearP )) && !do32BitNear ()) return tokenTable[ tok ] + 6; // Skip '__near' #endif if ( doUnderScore ()) return tokenTable[ tok ]; else return tokenTable[ tok ] + 2 ; } // End of "UnDecorator" FUNCTION "UScore" // Include the string composition support classes. Mostly inline stuff, and // not important to the algorithm. #include "undname.inl"