|  | /* | 
|  | Copyright (c) 2009, 2010 mingw-w64 project | 
|  |  | 
|  | Contributing authors: Kai Tietz, Jonathan Yong | 
|  |  | 
|  | Permission is hereby granted, free of charge, to any person obtaining a | 
|  | copy of this software and associated documentation files (the "Software"), | 
|  | to deal in the Software without restriction, including without limitation | 
|  | the rights to use, copy, modify, merge, publish, distribute, sublicense, | 
|  | and/or sell copies of the Software, and to permit persons to whom the | 
|  | Software is furnished to do so, subject to the following conditions: | 
|  |  | 
|  | The above copyright notice and this permission notice shall be included in | 
|  | all copies or substantial portions of the Software. | 
|  |  | 
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | 
|  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | 
|  | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | 
|  | DEALINGS IN THE SOFTWARE. | 
|  | */ | 
|  |  | 
|  | #include <stdio.h> | 
|  | #include <stdlib.h> | 
|  | #include <malloc.h> | 
|  | #include <string.h> | 
|  | #include <inttypes.h> | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include "m_token.h" | 
|  | #include "m_ms.h" | 
|  |  | 
|  | static uMToken *m_combine (sMSCtx *c, uMToken *l, uMToken *r); | 
|  | static uMToken *m_type (sMSCtx *c, const char *typname); | 
|  | static uMToken *m_cv (sMSCtx *c, const char *cv); | 
|  | static uMToken *m_coloncolon (sMSCtx *c, uMToken *l, uMToken *r); | 
|  | static uMToken *m_element (sMSCtx *c, uMToken *el); | 
|  | static uMToken *m_array (sMSCtx *c, uMToken *dim); | 
|  | static uMToken *m_scope (sMSCtx *c, uMToken *n); | 
|  | static uMToken *m_oper (sMSCtx *c, uMToken *n); | 
|  | static uMToken *m_name (sMSCtx *c, const char *str); | 
|  | static uMToken *m_colon (sMSCtx *c, const char *str); | 
|  | static uMToken *m_opname (sMSCtx *c, const char *str); | 
|  | static uMToken *m_rtti (sMSCtx *c, const char *str); | 
|  | static uMToken *m_frame (sMSCtx *c, uMToken *u); | 
|  | static uMToken *m_rframe (sMSCtx *c, uMToken *u); | 
|  | static uMToken *m_ltgt (sMSCtx *c, uMToken *u); | 
|  | static uMToken *m_throw (sMSCtx *c, uMToken *u); | 
|  | static uMToken *m_lexical_frame (sMSCtx *c, uMToken *u); | 
|  |  | 
|  | static uMToken *get_decorated_name (sMSCtx *c); | 
|  | static uMToken *get_string_literal_type (sMSCtx *c); | 
|  | static uMToken *get_symbol_name (sMSCtx *c); | 
|  | static uMToken *get_zbuf_name (sMSCtx *c, int updateCache); | 
|  | static uMToken *get_dimension_signed (sMSCtx *c); | 
|  | static uMToken *get_dimension (sMSCtx *c,int fSigned, int fNegate); | 
|  | static uMToken *extract_name (sMSCtx *c, char term); | 
|  | static uMToken *get_scope (sMSCtx *c); | 
|  | static uMToken *get_template_name (sMSCtx *c, int fReadTerminator); | 
|  | static uMToken *get_operator_name (sMSCtx *c, int fIsTemplate, int *pfReadTemplateArguments); | 
|  | static uMToken *get_template_argument_list (sMSCtx *c); | 
|  | static uMToken *get_lexical_frame(sMSCtx *c); | 
|  | static uMToken *get_string_encoding (sMSCtx *c, int wantBody); | 
|  | static uMToken *get_template_constant (sMSCtx *c); | 
|  | static uMToken *get_data_type (sMSCtx *c); | 
|  | static uMToken *get_indirect_data_type(sMSCtx *c, uMToken *superType, char prType, uMToken *cvType, int thisFlag); | 
|  | static uMToken *get_primary_data_type (sMSCtx *c, uMToken *superType); | 
|  | static uMToken *get_based_type (sMSCtx *c); | 
|  | static uMToken *get_scoped_name (sMSCtx *c); | 
|  | static uMToken *get_basic_data_type (sMSCtx *c, uMToken *superName); | 
|  | static uMToken *get_pointer_reference_type (sMSCtx *c, uMToken *cvType, uMToken *superType, char ptrChar); | 
|  | static uMToken *get_indirect_function_type (sMSCtx *c, uMToken *superType); | 
|  | static uMToken *get_pointer_reference_data_type (sMSCtx *c, uMToken *superType,int isPtr); | 
|  | static uMToken *get_ECSU_data_type (sMSCtx *c); | 
|  | static uMToken *get_enum_size_type (sMSCtx *c); | 
|  | static uMToken *get_this_type (sMSCtx *c); | 
|  | static uMToken *get_calling_convention (sMSCtx *c); | 
|  | static uMToken *get_throw_types (sMSCtx *c); | 
|  | static uMToken *get_argument_types (sMSCtx *c); | 
|  | static uMToken *get_return_type (sMSCtx *c); | 
|  | static uMToken *get_array_type (sMSCtx *c, uMToken *superType); | 
|  | static uMToken *get_argument_list (sMSCtx *c); | 
|  | static uMToken *compose_decl (sMSCtx *c, uMToken *symbol); | 
|  | static uMToken *get_vftable_type (sMSCtx *c, uMToken *superType); | 
|  | static int get_number_of_dimensions (sMSCtx *c); | 
|  | static int get_encoded_type (sMSCtx *); | 
|  | static uMToken *get_vdisp_map_type (sMSCtx *c, uMToken *superType); | 
|  | static uMToken *get_ext_data_type (sMSCtx *c, uMToken *superType); | 
|  |  | 
|  | uMToken * | 
|  | libmangle_decode_ms_name (libmangle_gc_context_t *gc, const char *name) | 
|  | { | 
|  | sMSCtx ctx; | 
|  | sCached ZNameList, ArgList, TempArgList; | 
|  | uMToken *ret = NULL; | 
|  | if (!name || *name == 0) | 
|  | return NULL; | 
|  |  | 
|  | memset (&ctx, 0, sizeof (ctx)); | 
|  | ctx.gc = gc; | 
|  | memset (&ZNameList, 0, sizeof (ZNameList)); | 
|  | memset (&ArgList, 0, sizeof (ArgList)); | 
|  | memset (&TempArgList, 0, sizeof (TempArgList)); | 
|  | ctx.name = name; | 
|  | ctx.end = name + strlen (name); | 
|  | ctx.pos = ctx.name; | 
|  |  | 
|  | ctx.pZNameList = &ZNameList; | 
|  | ctx.pArgList = &ArgList; | 
|  | ctx.pTemplateArgList = &TempArgList; | 
|  |  | 
|  | #if 0 | 
|  | fprintf(stderr,"decode_ms_name: %s\n", name); | 
|  | #endif | 
|  |  | 
|  | if (name[0] == '?') | 
|  | { | 
|  | if (name[1] == '@') | 
|  | { | 
|  | SKIP_CHAR(&ctx,2); | 
|  | ret = get_decorated_name (&ctx); | 
|  | /* CV: ??? */ | 
|  | } | 
|  | else if (name[1] == '$') | 
|  | { | 
|  | if (!(ret = get_template_name (&ctx, 0))) | 
|  | ret = get_decorated_name (&ctx); | 
|  | } | 
|  | else | 
|  | ret = get_decorated_name (&ctx); | 
|  | } | 
|  | else | 
|  | ret = get_decorated_name (&ctx); | 
|  |  | 
|  | if (!ret) | 
|  | { | 
|  | ret = gen_name (ctx.gc, eMST_unmangled, name); | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | char * | 
|  | libmangle_encode_ms_name (libmangle_gc_context_t *gc, uMToken *tok) | 
|  | { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_decorated_name (sMSCtx *c) | 
|  | { | 
|  | uMToken *n = NULL; | 
|  | uMToken *d = NULL; | 
|  | int isudc; | 
|  | if (GET_CHAR (c) != '?') | 
|  | { | 
|  | if (GET_CHAR (c) == 0) | 
|  | c->err = 1; | 
|  | fprintf (stderr,"*** get_decorated_name %s empty\n", c->name); | 
|  | return NULL; | 
|  | } | 
|  | INC_CHAR (c); | 
|  |  | 
|  | n = get_symbol_name (c); | 
|  | isudc = (n && (MTOKEN_FLAGS (n) & MTOKEN_FLAGS_UDC)) ? 1 : 0; | 
|  | if (c->err) | 
|  | return n; | 
|  | if (GET_CHAR (c) != 0 && GET_CHAR (c) != '@') | 
|  | { | 
|  | d = get_scope (c); | 
|  | if (d) | 
|  | { | 
|  | if (c->fExplicitTemplateParams == 0) | 
|  | n = m_coloncolon (c, d, n); | 
|  | else | 
|  | { | 
|  | c->fExplicitTemplateParams = 0; | 
|  | n = m_combine (c, n, d); | 
|  | if (GET_CHAR (c) != '@') | 
|  | { | 
|  | d = get_scope (c); | 
|  | n = m_coloncolon (c, d, n); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | if (!n) | 
|  | return n; | 
|  | if (isudc) | 
|  | MTOKEN_FLAGS (n) |= MTOKEN_FLAGS_UDC; | 
|  | if (MTOKEN_FLAGS (n) & MTOKEN_FLAGS_NOTE) | 
|  | return n; | 
|  | if (GET_CHAR (c) != 0) | 
|  | { | 
|  | if (GET_CHAR (c) != '@') | 
|  | return NULL; | 
|  | INC_CHAR (c); | 
|  | } | 
|  | return compose_decl (c, n); | 
|  | } | 
|  |  | 
|  |  | 
|  | static uMToken * | 
|  | get_symbol_name (sMSCtx *c) | 
|  | { | 
|  | if (GET_CHAR (c) != '?') | 
|  | return get_zbuf_name (c, 1); | 
|  | if (c->pos[1] == '$') | 
|  | return get_template_name (c, 1); | 
|  | INC_CHAR (c); | 
|  | return get_operator_name (c, 0, NULL); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_zbuf_name (sMSCtx *c, int updateCache) | 
|  | { | 
|  | const char *ntmp; | 
|  | uMToken *dim, *ret = NULL, *n = NULL; | 
|  |  | 
|  | if (GET_CHAR(c) >= '0' && GET_CHAR (c) <= '9') | 
|  | { | 
|  | ret = c->pZNameList->arr[GET_CHAR (c) - '0']; | 
|  | INC_CHAR (c); | 
|  | return ret; | 
|  | } | 
|  | if (GET_CHAR (c) == '?') | 
|  | { | 
|  | n = get_template_name (c, 0); | 
|  | if (GET_CHAR (c) == '@') | 
|  | INC_CHAR (c); | 
|  | if (updateCache && c->pZNameList->count < 10) | 
|  | { | 
|  | c->pZNameList->arr[c->pZNameList->count] = n; | 
|  | c->pZNameList->count += 1; | 
|  | } | 
|  | return n; | 
|  | } | 
|  | ntmp="template-parameter-"; | 
|  | if (!strncmp(c->pos,"template-parameter-",19)) | 
|  | SKIP_CHAR (c,19); | 
|  | else | 
|  | { | 
|  | ntmp="generic-type-"; | 
|  | if (!strncmp(c->pos, "generic-type-", 13)) | 
|  | SKIP_CHAR (c,13); | 
|  | else | 
|  | { | 
|  | n = extract_name (c, '@'); | 
|  | if (updateCache && c->pZNameList->count < 10) | 
|  | { | 
|  | c->pZNameList->arr[c->pZNameList->count] = n; | 
|  | c->pZNameList->count += 1; | 
|  | } | 
|  | return n; | 
|  | } | 
|  | } | 
|  | dim=get_dimension_signed (c); | 
|  | n=chain_tok (gen_name (c->gc, eMST_templargname, ntmp), dim); | 
|  | if (updateCache && c->pZNameList->count < 10) | 
|  | { | 
|  | c->pZNameList->arr[c->pZNameList->count] = n; | 
|  | c->pZNameList->count += 1; | 
|  | } | 
|  | return n; | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_dimension_signed (sMSCtx *c) | 
|  | { | 
|  | if (GET_CHAR (c) == 0) | 
|  | { | 
|  | c->err=1; | 
|  | return NULL; | 
|  | } | 
|  | if (GET_CHAR (c) != '?') | 
|  | return get_dimension (c, 0, 0); | 
|  | INC_CHAR (c); | 
|  | return get_dimension (c, 0, 1/* be negative*/); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_dimension (sMSCtx *c, int fSigned, int fNegate) | 
|  | { | 
|  | const char *non_tt_param=NULL; | 
|  | uint64_t v_r = 0ULL, v1; | 
|  |  | 
|  | if (GET_CHAR (c) == 'Q') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | non_tt_param="'non-type-template-parameter"; | 
|  | } | 
|  | if (GET_CHAR (c) == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | return NULL; | 
|  | } | 
|  | if (GET_CHAR (c) >= '0' && GET_CHAR (c) <= '9') | 
|  | { | 
|  | uint64_t v = (uint64_t) ((GET_CHAR (c)-'0') + 1); | 
|  | INC_CHAR (c); | 
|  | return gen_dim (c->gc, eMST_dim,v, non_tt_param, fSigned, fNegate); | 
|  | } | 
|  |  | 
|  | while (GET_CHAR (c) != '@') | 
|  | { | 
|  | if (GET_CHAR (c) == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | return NULL; | 
|  | } | 
|  | if (GET_CHAR (c) < 'A' || GET_CHAR (c) > 'P') | 
|  | { | 
|  | c->err = 1; | 
|  | return NULL; | 
|  | } | 
|  | v1=(uint64_t) (GET_CHAR (c) - 'A'); | 
|  | v_r = v_r*10ULL + v1; | 
|  | INC_CHAR (c); | 
|  | } | 
|  | if (GET_CHAR (c) !='@') | 
|  | { | 
|  | c->err = 1; | 
|  | return NULL; | 
|  | } | 
|  | INC_CHAR (c); | 
|  | return gen_dim (c->gc, eMST_dim,v_r, non_tt_param, fSigned, fNegate); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | extract_name (sMSCtx *c, char term) | 
|  | { | 
|  | uMToken *ret; | 
|  | char *txt; | 
|  | size_t len; | 
|  | const char *sv = c->pos; | 
|  | while (GET_CHAR (c) != 0 && GET_CHAR (c) != term) | 
|  | { | 
|  | INC_CHAR (c); | 
|  | } | 
|  | if (GET_CHAR (c) != '@') | 
|  | { | 
|  | c->err = 1; | 
|  | return NULL; | 
|  | } | 
|  | len = (size_t) (c->pos - sv); | 
|  | txt = (char *) malloc (len + 1); | 
|  | memcpy (txt, sv, len); | 
|  | txt[len] = 0; | 
|  | INC_CHAR (c); | 
|  | ret = m_name (c, txt); | 
|  | free (txt); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_scope (sMSCtx *c) | 
|  | { | 
|  | uMToken *n = NULL; | 
|  |  | 
|  | while (1) | 
|  | { | 
|  | if (GET_CHAR (c) == 0 || GET_CHAR (c) == '@') | 
|  | break; | 
|  | if (c->fExplicitTemplateParams != 0 && !c->fGetTemplateArgumentList) | 
|  | return n; | 
|  | if (GET_CHAR (c) == '?') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | if (GET_CHAR (c) == '$') | 
|  | { | 
|  | DEC_CHAR (c); | 
|  | n = m_coloncolon (c, get_zbuf_name (c, 1), n); | 
|  | } | 
|  | else if (GET_CHAR (c) == '%' || GET_CHAR (c) == 'A') | 
|  | { | 
|  | while (GET_CHAR (c) != '@') | 
|  | INC_CHAR (c); | 
|  | INC_CHAR (c); | 
|  | n = m_coloncolon (c, m_name (c, "anonymous_namespace"), n); | 
|  | } | 
|  | else if (GET_CHAR (c) == '?') | 
|  | { | 
|  | if (c->pos[1] == '_' && c->pos[2] == '?') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | n = m_coloncolon (c, get_operator_name (c, 0,NULL), n); | 
|  | if (GET_CHAR (c) == '@') | 
|  | INC_CHAR (c); | 
|  | } | 
|  | else | 
|  | { | 
|  | n = m_coloncolon (c, gen_unary (c->gc, eMST_slashed, get_decorated_name (c)), n); | 
|  | } | 
|  | } | 
|  | else if (GET_CHAR (c) == 'I') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | n = m_coloncolon (c, m_array (c, get_zbuf_name (c, 1)), n); | 
|  | } | 
|  | else | 
|  | n = m_coloncolon (c, get_lexical_frame (c), n); | 
|  | } | 
|  | else | 
|  | n = m_coloncolon (c, get_zbuf_name (c, 1), n); | 
|  | } | 
|  | if (n) | 
|  | n = m_scope (c, n); | 
|  | if (GET_CHAR (c)) | 
|  | { | 
|  | if (GET_CHAR (c) == '@') | 
|  | return n; | 
|  | } | 
|  | else | 
|  | { | 
|  | c->err = 2; | 
|  | return n; | 
|  | } | 
|  | return n; | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_template_name (sMSCtx *c, int fReadTerminator) | 
|  | { | 
|  | sCached rep1; | 
|  | sCached rep2; | 
|  | sCached rep3; | 
|  | sCached *svZName,*svArgList,*svTempArgList; | 
|  | uMToken *n = NULL; | 
|  | int fFlag = 0; | 
|  |  | 
|  | if (GET_CHAR (c) !='?' || c->pos[1] != '$') | 
|  | return NULL; | 
|  | memset (&rep1, 0, sizeof (rep1)); | 
|  | memset (&rep2, 0, sizeof (rep2)); | 
|  | memset (&rep3, 0, sizeof (rep3)); | 
|  |  | 
|  | svTempArgList = c->pTemplateArgList; | 
|  | svArgList = c->pArgList; | 
|  | svZName = c->pZNameList; | 
|  |  | 
|  | SKIP_CHAR(c,2); | 
|  |  | 
|  | c->pArgList=&rep1; | 
|  | c->pZNameList=&rep2; | 
|  | c->pTemplateArgList=&rep3; | 
|  |  | 
|  | if (GET_CHAR (c) == '?') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | n = get_operator_name (c, 1, &fFlag); | 
|  | } | 
|  | else | 
|  | n = get_zbuf_name (c, 1); | 
|  | if (!n) | 
|  | c->fExplicitTemplateParams = 1; | 
|  | if (!fFlag) | 
|  | { | 
|  | n = get_template_argument_list (c); | 
|  | n = m_ltgt (c, n); | 
|  | if (fReadTerminator) | 
|  | INC_CHAR (c); | 
|  | } | 
|  | c->pArgList = svArgList; | 
|  | c->pZNameList = svZName; | 
|  | c->pTemplateArgList = svTempArgList; | 
|  | return n; | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_operator_name (sMSCtx *c, int fIsTemplate, int *pfReadTemplateArguments) | 
|  | { | 
|  | const char *svName; | 
|  | char ch = GET_CHAR (c); | 
|  | uMToken *n = NULL,*h = NULL; | 
|  |  | 
|  | if (!ch) | 
|  | { | 
|  | c->err = 2; | 
|  | return NULL; | 
|  | } | 
|  | INC_CHAR (c); | 
|  | switch(ch) | 
|  | { | 
|  | case '0': case '1': | 
|  | if (fIsTemplate) | 
|  | { | 
|  | h = m_ltgt (c, get_template_argument_list (c)); | 
|  | if (pfReadTemplateArguments) | 
|  | *pfReadTemplateArguments = 1; | 
|  | ch = GET_CHAR (c); | 
|  | if (ch == 0) | 
|  | return m_oper (c, h); | 
|  | INC_CHAR (c); | 
|  | } | 
|  | svName = c->pos; | 
|  | n = get_zbuf_name (c, 0); | 
|  | c->pos = svName; | 
|  | if (n && ch == '1') | 
|  | n=gen_unary (c->gc, eMST_destructor, n); | 
|  | n = chain_tok (n, h); | 
|  | return m_oper (c, n); | 
|  | case '2': | 
|  | return m_oper (c, m_opname (c, "operator new")); | 
|  | case '3': | 
|  | return m_oper (c, m_opname (c, "operator delete")); | 
|  | case '4': | 
|  | return m_oper (c, m_opname (c, "operator =")); | 
|  | case '5': | 
|  | return m_oper (c, m_opname (c, "operator >>")); | 
|  | case '6': | 
|  | return m_oper (c, m_opname (c, "operator <<")); | 
|  | case '7': | 
|  | return m_oper (c, m_opname (c, "operator !")); | 
|  | case '8': | 
|  | return m_oper (c, m_opname (c, "operator ==")); | 
|  | case '9': | 
|  | return m_oper (c, m_opname (c, "operator !=")); | 
|  | case 'A': | 
|  | return m_oper (c, m_opname (c, "operator []")); | 
|  | case 'B': | 
|  | n = m_opname (c,  "operator"); | 
|  | MTOKEN_FLAGS(n) |= MTOKEN_FLAGS_UDC; | 
|  | n = m_oper (c, n); | 
|  | MTOKEN_FLAGS(n) |= MTOKEN_FLAGS_UDC; | 
|  | return n; | 
|  | case 'C': | 
|  | return m_oper (c, m_opname (c, "operator ->")); | 
|  | case 'D': | 
|  | return m_oper (c, m_opname (c, "operator *")); | 
|  | case 'E': | 
|  | return m_oper (c, m_opname (c, "operator ++")); | 
|  | case 'F': | 
|  | return m_oper (c, m_opname (c, "operator --")); | 
|  | case 'G': | 
|  | return m_oper (c, m_opname (c, "operator -")); | 
|  | case 'H': | 
|  | return m_oper (c, m_opname (c, "operator +")); | 
|  | case 'I': | 
|  | return m_oper (c, m_opname (c, "operator &")); | 
|  | case 'J': | 
|  | return m_oper (c, m_opname (c, "operator ->*")); | 
|  | case 'K': | 
|  | return m_oper (c, m_opname (c, "operator /")); | 
|  | case 'L': | 
|  | return m_oper (c, m_opname (c, "operator %")); | 
|  | case 'M': | 
|  | return m_oper (c, m_opname (c, "operator <")); | 
|  | case 'N': | 
|  | return m_oper (c, m_opname (c, "operator <=")); | 
|  | case 'O': | 
|  | return m_oper (c, m_opname (c, "operator >")); | 
|  | case 'P': | 
|  | return m_oper (c, m_opname (c, "operator >=")); | 
|  | case 'Q': | 
|  | return m_oper (c, m_opname (c, "operator ,")); | 
|  | case 'R': | 
|  | return m_oper (c, m_opname (c, "operator ()")); | 
|  | case 'S': | 
|  | return m_oper (c, m_opname (c, "operator ~")); | 
|  | case 'T': | 
|  | return m_oper (c, m_opname (c, "operator ^")); | 
|  | case 'U': | 
|  | return m_oper (c, m_opname (c, "operator |")); | 
|  | case 'V': | 
|  | return m_oper (c, m_opname (c, "operator &&")); | 
|  | case 'W': | 
|  | return m_oper (c, m_opname (c, "operator ||")); | 
|  | case 'X': | 
|  | return m_oper (c, m_opname (c, "operator *=")); | 
|  | case 'Y': | 
|  | return m_oper (c, m_opname (c, "operator +=")); | 
|  | case 'Z': | 
|  | return m_oper (c, m_opname (c, "operator -=")); | 
|  | case '_': | 
|  | break; | 
|  | default: | 
|  | fprintf (stderr, " *** get_operator_name unknown '%c'\n", ch); | 
|  | return NULL; | 
|  | } | 
|  | ch = GET_CHAR (c); | 
|  | if (! ch) | 
|  | { | 
|  | c->err = 2; | 
|  | return NULL; | 
|  | } | 
|  | INC_CHAR (c); | 
|  | switch(ch) | 
|  | { | 
|  | case '_': | 
|  | ch = GET_CHAR (c); | 
|  | INC_CHAR (c); | 
|  | switch (ch) | 
|  | { | 
|  | case 'A': | 
|  | return m_oper (c, m_opname (c, "__man_vec_ctor")); | 
|  | case 'B': | 
|  | return m_oper (c, m_opname (c, "__man_vec_dtor")); | 
|  | case 'C': | 
|  | return m_oper (c, m_opname (c, "__ehvec_copy_ctor")); | 
|  | case 'D': | 
|  | return m_oper (c, m_opname (c, "__ehvec_copy_ctor_vb")); | 
|  | } | 
|  | fprintf (stderr, " *** get_operator_name unknown '__%c'\n", ch); | 
|  | return NULL; | 
|  |  | 
|  | case '0': | 
|  | return m_oper (c, m_opname (c, "operator /=")); | 
|  | case '1': | 
|  | return m_oper (c, m_opname (c, "operator %=")); | 
|  | case '2': | 
|  | return m_oper (c, m_opname (c, "operator >>=")); | 
|  | case '3': | 
|  | return m_oper (c, m_opname (c, "operator <<=")); | 
|  | case '4': | 
|  | return m_oper (c, m_opname (c, "operator &=")); | 
|  | case '5': | 
|  | return m_oper (c, m_opname (c, "operator |=")); | 
|  | case '6': | 
|  | return m_oper (c, m_opname (c, "operator ^=")); | 
|  | case '7': | 
|  | return m_oper (c, gen_name (c->gc, eMST_vftable, "$vftable")); | 
|  | case '8': | 
|  | return m_oper (c, gen_name (c->gc, eMST_vbtable, "$vbtable")); | 
|  | case '9': | 
|  | return m_oper (c, gen_name (c->gc, eMST_vcall, "vcall")); | 
|  | case 'A': | 
|  | return m_oper (c, m_opname (c,"typeof")); | 
|  | case 'B': | 
|  | return m_oper (c, m_opname (c,"local_static_guard")); | 
|  | case 'C': | 
|  | n = get_string_encoding (c, 1); | 
|  | MTOKEN_FLAGS(n) |= MTOKEN_FLAGS_NOTE; | 
|  | return n; | 
|  | case 'D': | 
|  | return m_oper (c, m_opname (c,"vbase_destructor")); | 
|  | case 'E': | 
|  | return m_oper (c, m_opname (c,"__vecDelDtor")); | 
|  | case 'F': | 
|  | return m_oper (c, m_opname (c,"__dflt_ctor_closure")); | 
|  | case 'G': | 
|  | return m_oper (c, m_opname (c, "__delDtor")); | 
|  | case 'H': | 
|  | return m_oper (c, m_opname (c, "__vec_ctor")); | 
|  | case 'I': | 
|  | return m_oper (c, m_opname (c, "__vec_dtor")); | 
|  | case 'J': | 
|  | return m_oper (c, m_opname (c, "__vec_ctor_vb")); | 
|  | case 'K': | 
|  | return m_oper (c, m_opname (c, "$vdispmap")); | 
|  | case 'L': | 
|  | return m_oper (c, m_opname (c, "__ehvec_ctor")); | 
|  | case 'M': | 
|  | return m_oper (c, m_opname (c, "__ehvec_dtor")); | 
|  | case 'N': | 
|  | return m_oper (c, m_name (c, "__ehvec_ctor_vb")); | 
|  | case 'O': | 
|  | return m_oper (c, m_opname (c, "__copy_ctor_closure")); | 
|  | case 'P': | 
|  | return gen_unary (c->gc, eMST_udt_returning, get_operator_name (c, 0, NULL)); | 
|  | case 'Q': | 
|  | return m_oper (c, m_opname (c,  "operator 'EH'")); | 
|  | case 'R': | 
|  | ch = GET_CHAR (c); | 
|  | INC_CHAR (c); | 
|  | switch (ch) | 
|  | { | 
|  | case '0': | 
|  | h = m_rtti (c, "$type_descriptor"); | 
|  | return m_oper (c, m_combine (c, get_data_type (c) , h)); | 
|  | case '1': | 
|  | h = m_rtti (c, "base_class_descriptor"); | 
|  | n = m_element (c, get_dimension_signed (c)); | 
|  | n = chain_tok (n, m_element (c, get_dimension_signed (c))); | 
|  | n = chain_tok (n, m_element (c, get_dimension_signed (c))); | 
|  | n = chain_tok (n, m_element (c, get_dimension (c, 0, 0))); | 
|  | n = m_frame (c, n); | 
|  | return m_oper (c, gen_binary (c->gc, eMST_assign, h, n)); | 
|  | case '2': | 
|  | return m_oper (c, m_rtti (c, "base_class_array")); | 
|  | case '3': | 
|  | return m_oper (c, m_rtti (c, "class_hierarchy_descriptor")); | 
|  | case '4': | 
|  | return m_oper (c, m_rtti (c, "complete_object_locator")); | 
|  | } | 
|  | DEC_CHAR (c); | 
|  | fprintf (stderr, " *** Unkown RTTI %c\n", ch); | 
|  | c->err = 2; | 
|  | return NULL; | 
|  | case 'S': | 
|  | return m_oper (c, m_opname (c, "$locvftable")); | 
|  | case 'T': | 
|  | return m_oper (c, m_opname (c, "__local_vftable_ctor_closure")); | 
|  | case 'U': | 
|  | n = m_opname (c, "operator new[]"); | 
|  | return m_oper (c, n); | 
|  | case 'V': | 
|  | n = m_opname (c,  "operator delete[]"); | 
|  | return m_oper (c, n); | 
|  | case 'W': /* omni callsig ??? */ | 
|  | default: | 
|  | fprintf (stderr, " *** get_operator_name unknown '_%c'\n", ch); | 
|  | return NULL; | 
|  | case 'X': | 
|  | return m_oper (c, m_opname (c,  "__placement_delete_closure")); | 
|  | case 'Y': | 
|  | return m_oper (c, m_opname (c,  "__placement_arrayDelete_closure")); | 
|  | case '?': | 
|  | break; | 
|  | } | 
|  | ch = GET_CHAR (c); | 
|  | if (!ch) | 
|  | { | 
|  | c->err = 2; | 
|  | return NULL; | 
|  | } | 
|  | INC_CHAR (c); | 
|  | switch(ch) | 
|  | { | 
|  | case '0': | 
|  | m_combine (c, m_name (c, "using namespace"), get_string_encoding (c, 0)); | 
|  | MTOKEN_FLAGS (n) |= MTOKEN_FLAGS_NOTE; | 
|  | return n; | 
|  | } | 
|  | fprintf (stderr, " *** get_operator_name unknown '__?%c'\n", ch); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_template_argument_list (sMSCtx *c) | 
|  | { | 
|  | uMToken *n = NULL; | 
|  | uMToken *h = NULL; | 
|  | int idx; | 
|  | int beFirst=1; | 
|  | c->fGetTemplateArgumentList = 1; | 
|  | do | 
|  | { | 
|  | if (GET_CHAR (c) == 0 || GET_CHAR (c) == '@') | 
|  | break; | 
|  | idx = (int) (GET_CHAR (c) - '0'); | 
|  | if (GET_CHAR (c) >= '0' && GET_CHAR (c) <= '9') | 
|  | { | 
|  | h = c->pTemplateArgList->arr[idx]; | 
|  | INC_CHAR (c); | 
|  | } | 
|  | else | 
|  | { | 
|  | const char *svPos = c->pos; | 
|  | if (GET_CHAR (c) =='X') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | h = m_type (c, "void"); | 
|  | } | 
|  | else if (GET_CHAR (c) == '$' && c->pos[1] != '$') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | h = get_template_constant (c); | 
|  | } | 
|  | else if (GET_CHAR (c) == '?') | 
|  | { | 
|  | uMToken *sdim = get_dimension_signed (c); | 
|  | h = gen_binary (c->gc, eMST_templateparam, m_name (c, "template-parameter"), sdim); | 
|  | } | 
|  | else | 
|  | h = get_primary_data_type (c, NULL); | 
|  | if ((int)(c->pos-svPos)>1 && | 
|  | c->pTemplateArgList->count < 10) | 
|  | { | 
|  | c->pTemplateArgList->arr[c->pTemplateArgList->count] = h; | 
|  | c->pTemplateArgList->count += 1; | 
|  | } | 
|  | } | 
|  | h = m_element (c, h); | 
|  | if (beFirst) | 
|  | { | 
|  | n = h; | 
|  | beFirst = 0; | 
|  | } | 
|  | else | 
|  | { | 
|  | n = chain_tok (n, h); | 
|  | } | 
|  | } | 
|  | while (c->err == 0); | 
|  | c->fGetTemplateArgumentList = 0; | 
|  | if (n) | 
|  | n = gen_unary (c->gc, eMST_template_argument_list, n); | 
|  | return n; | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_lexical_frame (sMSCtx *c) | 
|  | { | 
|  | return m_lexical_frame (c, get_dimension (c, 0, 0)); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_string_encoding (sMSCtx *c, int wantBody) | 
|  | { | 
|  | uMToken *length = NULL; | 
|  | uMToken *crc = NULL, *h = NULL; | 
|  | uMToken *typ = NULL; | 
|  | const char *svName; | 
|  | size_t len; | 
|  | char *hp; | 
|  |  | 
|  | if (GET_CHAR (c) != '@') return NULL; | 
|  | INC_CHAR (c); | 
|  | typ = get_string_literal_type (c); | 
|  | length = get_dimension (c, 0, 0); | 
|  | crc = get_dimension (c, 0, 0); | 
|  | if (GET_CHAR (c) == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | return NULL; | 
|  | } | 
|  | svName = c->pos; | 
|  | while (GET_CHAR (c) != 0) | 
|  | { | 
|  | if (GET_CHAR (c) == '@') | 
|  | break; | 
|  | INC_CHAR (c); | 
|  | } | 
|  | if (GET_CHAR (c) == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | return NULL; | 
|  | } | 
|  | len = (size_t) (c->pos - svName); | 
|  | hp = (char *) malloc (len + 1); | 
|  | memcpy (hp, svName, len); | 
|  | hp[len] = 0; | 
|  | INC_CHAR (c); | 
|  | h = m_name (c, hp); | 
|  | free (hp); | 
|  | if (wantBody) | 
|  | h = m_combine (c, typ, m_combine (c, h, m_array (c, length))); | 
|  | return h; | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_template_constant (sMSCtx *c) | 
|  | { | 
|  | char ch; | 
|  | uMToken *n = NULL; | 
|  | uMToken *exp; | 
|  |  | 
|  | ch = GET_CHAR(c); | 
|  | if (!ch) | 
|  | { | 
|  | c->err = 2; | 
|  | return NULL; | 
|  | } | 
|  | INC_CHAR (c); | 
|  | if (ch =='E') | 
|  | return get_decorated_name (c); | 
|  | if (ch > 'E' && ch <= 'J') | 
|  | { | 
|  | if (ch >= 'H' && ch <= 'J') | 
|  | { | 
|  | exp = m_element (c, get_decorated_name (c)); | 
|  | if (!n) n = exp; | 
|  | else chain_tok (n, exp); | 
|  | } | 
|  | switch(ch) | 
|  | { | 
|  | case 'G': case 'J': | 
|  | exp = m_element (c, get_dimension_signed (c)); | 
|  | if (!n) n = exp; | 
|  | else chain_tok (n, exp); | 
|  | case 'F': case 'I': | 
|  | exp = m_element (c, get_dimension_signed (c)); | 
|  | if (!n) n = exp; | 
|  | else chain_tok (n, exp); | 
|  | case 'H': | 
|  | exp = m_element (c, get_dimension_signed (c)); | 
|  | if (!n) n = exp; | 
|  | else chain_tok (n, exp); | 
|  | break; | 
|  | } | 
|  | return m_frame (c, n); | 
|  | } | 
|  | if (ch == 'Q' || ch == 'D') | 
|  | { | 
|  | n = get_dimension_signed (c); | 
|  | if (ch == 'D') | 
|  | return gen_binary (c->gc, eMST_templateparam, m_name (c, "template-parameter"), n); | 
|  | return gen_binary (c->gc, eMST_nonetypetemplateparam, m_name (c, "none-type-template-parameter"), n); | 
|  | } | 
|  | if (ch == '0') | 
|  | return get_dimension_signed (c); | 
|  | if (ch == '1') | 
|  | { | 
|  | if (GET_CHAR (c) != '@') | 
|  | return m_combine (c, m_cv (c, "&"), get_decorated_name (c)); | 
|  | INC_CHAR (c); | 
|  | return m_name (c, "NULL"); | 
|  | } | 
|  | if (ch != '2') | 
|  | { | 
|  | fprintf (stderr, " *** get_template_constant unknown '%c'\n", ch); | 
|  | return NULL; | 
|  | } | 
|  | n = get_dimension_signed (c); | 
|  | exp = get_dimension_signed (c); | 
|  | return gen_binary (c->gc, eMST_exp, n, exp); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_data_type (sMSCtx *c) | 
|  | { | 
|  | uMToken *n = NULL; | 
|  | if (GET_CHAR (c) == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | return n; | 
|  | } | 
|  | if (GET_CHAR (c) == '?') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | n = get_indirect_data_type (c, n, (char)0, NULL, 0); | 
|  | return get_primary_data_type (c, n); | 
|  | } | 
|  | if (GET_CHAR (c) != 'X') | 
|  | return get_primary_data_type (c, n); | 
|  | INC_CHAR (c); | 
|  | return m_combine (c, m_type (c, "void"), n); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_indirect_data_type (sMSCtx *c, uMToken *superType, char prType, uMToken *cvType, int thisFlag) | 
|  | { | 
|  | uMToken *n = NULL, *n1 = NULL, *n2 = NULL; | 
|  | int state; | 
|  |  | 
|  | if (GET_CHAR (c) == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | if (thisFlag != 0) | 
|  | return NULL; | 
|  | if (!superType) | 
|  | { | 
|  | if (!cvType) | 
|  | return NULL; | 
|  | return cvType; | 
|  | } | 
|  | if (MTOKEN_FLAGS (superType) & MTOKEN_FLAGS_PTRREF) | 
|  | return superType; | 
|  | if (!cvType) | 
|  | return superType; | 
|  | return m_combine (c, cvType, superType); | 
|  | } | 
|  | if (GET_CHAR (c) == '$') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | if (GET_CHAR (c) == 'A') | 
|  | { | 
|  | n = m_cv (c, "__gc"); | 
|  | INC_CHAR (c); | 
|  | } | 
|  | else if (GET_CHAR (c) == 'B') | 
|  | { | 
|  | n = m_cv (c, "__pin"); | 
|  | INC_CHAR (c); | 
|  | } | 
|  | else | 
|  | { | 
|  | state = (int)(GET_CHAR (c) - '3')*16; | 
|  | INC_CHAR (c); | 
|  | state += (int)GET_CHAR (c); | 
|  | INC_CHAR (c); | 
|  | n = gen_value (c->gc, eMST_gcarray, (uint64_t) state, 0, 4); | 
|  | if (superType) | 
|  | { | 
|  | if (!(MTOKEN_FLAGS (superType) & MTOKEN_FLAGS_ARRAY)) | 
|  | superType = m_rframe (c, superType); | 
|  | n=m_combine (c, superType, n); | 
|  | } | 
|  | INC_CHAR (c); | 
|  | return n; | 
|  | } | 
|  | } | 
|  | state = (GET_CHAR (c) - (GET_CHAR (c) < 'A' ? 0x16 : 0x41)); | 
|  | while (1) | 
|  | { | 
|  | if (state == 4) | 
|  | n1 = m_combine (c, n1, m_cv (c, "__ptr64")); | 
|  | else if (state == 5) | 
|  | n2 = m_combine (c, n2, m_cv (c, "__unaligned")); | 
|  | else if (state != 8) | 
|  | { | 
|  | uMToken *ret = NULL; | 
|  | INC_CHAR (c); | 
|  | if (state > 31) | 
|  | return NULL; | 
|  | if (prType == '*') | 
|  | ret = m_cv (c, "*"); | 
|  | else if (prType == '&') | 
|  | ret = m_cv (c, "&"); | 
|  |  | 
|  | ret = m_combine (c, n ,ret); | 
|  | ret = m_combine (c, ret, n1); | 
|  | ret = m_combine (c, n2, ret); | 
|  | if ((state & 0x10) != 0) | 
|  | { | 
|  | if (thisFlag != 0) | 
|  | return NULL; | 
|  | if (prType) | 
|  | { | 
|  | if (GET_CHAR (c) == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | return ret; | 
|  | } | 
|  | else | 
|  | { | 
|  | if (ret) | 
|  | ret = gen_binary (c->gc, eMST_coloncolon , get_scope (c), ret); | 
|  | else | 
|  | ret = get_scope (c); | 
|  | } | 
|  | if (GET_CHAR (c) == 0) c->err = 2; | 
|  | else | 
|  | { | 
|  | char ch = GET_CHAR (c); | 
|  | INC_CHAR (c); | 
|  | if (ch != '@') | 
|  | return NULL; | 
|  | } | 
|  | } | 
|  | else if (GET_CHAR (c) == 0) | 
|  | c->err = 2; | 
|  | else | 
|  | { | 
|  | ret = get_scope (c); | 
|  | if (GET_CHAR (c) != 0) | 
|  | { | 
|  | char ch = GET_CHAR (c); | 
|  | INC_CHAR (c); | 
|  | if (ch != '@') | 
|  | return NULL; | 
|  | } | 
|  | else | 
|  | c->err = 2; | 
|  | } | 
|  | } | 
|  | if ((state&0xc)==0xc) | 
|  | { | 
|  | if (thisFlag != 0) | 
|  | return NULL; | 
|  | ret = m_combine (c, get_based_type (c), ret); | 
|  | } | 
|  | if ((state & 2) != 0) | 
|  | ret = m_combine (c, m_cv (c, "volatile"), ret); | 
|  | if ((state & 1) != 0) | 
|  | ret = m_combine (c, m_cv (c, "const"), ret); | 
|  | if (thisFlag != 0) | 
|  | { | 
|  | if (!ret) | 
|  | ret = m_name (c, ""); | 
|  | MTOKEN_FLAGS(ret) |= MTOKEN_FLAGS_PTRREF; | 
|  | return ret; | 
|  | } | 
|  | if (!superType) | 
|  | { | 
|  | if (cvType) | 
|  | ret = m_combine (c, ret, cvType); | 
|  | if (!ret) | 
|  | ret = m_name (c, ""); | 
|  | MTOKEN_FLAGS(ret) |= MTOKEN_FLAGS_PTRREF; | 
|  | return ret; | 
|  | } | 
|  | if (MTOKEN_FLAGS(superType) & MTOKEN_FLAGS_PTRREF) | 
|  | { | 
|  | if (cvType) | 
|  | { | 
|  | ret = m_combine (c, ret, cvType); | 
|  | ret = m_combine (c, ret, superType); | 
|  | MTOKEN_FLAGS(ret) |= MTOKEN_FLAGS_PTRREF; | 
|  | return ret; | 
|  | } | 
|  | } | 
|  | if (!(MTOKEN_FLAGS(superType)&MTOKEN_FLAGS_ARRAY)) | 
|  | ret = m_combine (c, ret, superType); | 
|  | else | 
|  | ret = superType; | 
|  | MTOKEN_FLAGS(ret) |= MTOKEN_FLAGS_PTRREF; | 
|  | return ret; | 
|  | } | 
|  | else | 
|  | { | 
|  | if (!n1) | 
|  | n1 = m_cv (c, "__restrict"); | 
|  | else | 
|  | n1 = m_combine (c, n1, m_cv (c, "__restrict")); | 
|  | } | 
|  | INC_CHAR (c); | 
|  | state=GET_CHAR (c)-(GET_CHAR (c) < 'A' ? 0x16 : 0x41); | 
|  | } | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_primary_data_type (sMSCtx *c, uMToken *superType) | 
|  | { | 
|  | uMToken *superName = NULL; | 
|  | uMToken *cvType = NULL; | 
|  | switch(GET_CHAR (c)) | 
|  | { | 
|  | case 0: | 
|  | c->err = 2; | 
|  | return superType; | 
|  | case 'B': | 
|  | cvType = m_cv (c, "volatile"); | 
|  | /* fall through */ | 
|  | case 'A': | 
|  | superName = superType; | 
|  | if (!superName) | 
|  | superName = m_name (c, ""); | 
|  | MTOKEN_FLAGS (superName) |= MTOKEN_FLAGS_PTRREF; | 
|  | INC_CHAR (c); | 
|  | return get_pointer_reference_type (c, cvType, superName, '&'); | 
|  | case '$': | 
|  | if (c->pos[1] == '$') | 
|  | { | 
|  | SKIP_CHAR (c, 2); | 
|  | break; | 
|  | } | 
|  | if (c->pos[1] == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | return NULL; | 
|  | } | 
|  | fprintf (stderr, " *** get_primary_data_type '$%c' unknown\n", c->pos[1]); | 
|  | return NULL; | 
|  | default: | 
|  | return get_basic_data_type (c, superType); | 
|  | } | 
|  | switch(GET_CHAR (c)) | 
|  | { | 
|  | case 0: | 
|  | c->err = 2; | 
|  | return superType; | 
|  | case 'A': | 
|  | INC_CHAR (c); | 
|  | return get_indirect_function_type (c, superType); | 
|  | case 'B': | 
|  | INC_CHAR (c); | 
|  | return get_pointer_reference_data_type (c, superType, 1); | 
|  | case 'C': | 
|  | INC_CHAR (c); | 
|  | return get_basic_data_type (c, get_indirect_data_type (c, superType, (char)0, superName, 0)); | 
|  | } | 
|  | fprintf (stderr, " *** get_primary_data_type '$$%c' unknown\n", GET_CHAR (c)); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_based_type (sMSCtx *c) | 
|  | { | 
|  | uMToken *n = m_cv (c, "__based"); | 
|  | uMToken *p = NULL; | 
|  | char ch; | 
|  |  | 
|  | if (GET_CHAR (c) == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | return gen_binary (c->gc, eMST_based, n, NULL); | 
|  | } | 
|  | ch = GET_CHAR (c); | 
|  | INC_CHAR (c); | 
|  | switch(ch) | 
|  | { | 
|  | case '0': | 
|  | p = m_type (c, "void"); | 
|  | break; | 
|  | case '2': | 
|  | p = get_scoped_name (c); | 
|  | break; | 
|  | case '5': | 
|  | fprintf (stderr, " *** get_based_type unknown '%c'\n", ch); | 
|  | return NULL; | 
|  | default: | 
|  | fprintf (stderr, " *** get_based_type unknown '%c' (ignored)\n", ch); | 
|  | break; | 
|  | } | 
|  | return gen_binary (c->gc, eMST_based, n, p); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_scoped_name (sMSCtx *c) | 
|  | { | 
|  | uMToken *n = NULL; | 
|  | n = get_zbuf_name (c, 1); | 
|  | if (n && GET_CHAR (c) != 0) | 
|  | { | 
|  | if (GET_CHAR (c) =='@') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | return n; | 
|  | } | 
|  | n = m_coloncolon (c, get_scope (c), n); | 
|  | } | 
|  | if (GET_CHAR (c) == '@') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | return n; | 
|  | } | 
|  | if (GET_CHAR (c) != 0) | 
|  | return n; | 
|  | c->err = 2; | 
|  | return n; | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_basic_data_type (sMSCtx *c, uMToken *superName) | 
|  | { | 
|  | uMToken *bTyp = NULL; | 
|  | uMToken *cvName = NULL; | 
|  | uMToken *arType = NULL; | 
|  | uMToken *tmp = NULL; | 
|  | char svChar,svChar1; | 
|  | int flags; | 
|  |  | 
|  | if (GET_CHAR (c) == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | return superName; | 
|  | } | 
|  | svChar1 = GET_CHAR (c); | 
|  | INC_CHAR (c); | 
|  | flags=~0; | 
|  | switch (svChar1) | 
|  | { | 
|  | case 'M': | 
|  | bTyp = m_type (c, "float"); | 
|  | break; | 
|  | case 'C': | 
|  | bTyp = m_type (c, "signed char"); | 
|  | break; | 
|  | case 'D': | 
|  | bTyp = m_type (c, "char"); | 
|  | break; | 
|  | case 'E': | 
|  | bTyp = m_type (c, "unsigned char"); | 
|  | break; | 
|  | case 'F': | 
|  | bTyp = m_type (c, "short"); | 
|  | break; | 
|  | case 'G': | 
|  | bTyp = m_type (c, "unsigned short"); | 
|  | break; | 
|  | case 'H': | 
|  | bTyp = m_type (c, "int"); | 
|  | break; | 
|  | case 'I': | 
|  | bTyp = m_type (c, "unsigned int"); | 
|  | break; | 
|  | case 'J': | 
|  | bTyp = m_type (c, "long"); | 
|  | break; | 
|  | case 'K': | 
|  | bTyp = m_type (c, "unsigned long"); | 
|  | break; | 
|  | case 'N': | 
|  | bTyp = m_type (c, "double"); | 
|  | break; | 
|  | case 'O': | 
|  | bTyp = m_type (c, "long double"); | 
|  | break; | 
|  | case 'P': | 
|  | return get_pointer_reference_type (c, bTyp, superName, '*'); | 
|  | case 'Q': | 
|  | if (!superName) | 
|  | bTyp = m_cv (c, "const"); | 
|  | return get_pointer_reference_type (c, bTyp, superName, '*'); | 
|  | case 'R': | 
|  | if (!superName) | 
|  | bTyp = m_cv (c, "volatile"); | 
|  | return get_pointer_reference_type (c, bTyp, superName, '*'); | 
|  | case 'S': | 
|  | if (!superName) | 
|  | { | 
|  | bTyp = m_cv (c, "const"); | 
|  | bTyp = m_combine (c, bTyp, m_cv (c, "volatile")); | 
|  | } | 
|  | return get_pointer_reference_type (c, bTyp, superName, '*'); | 
|  | case '_': | 
|  | svChar = GET_CHAR (c); | 
|  | INC_CHAR (c); | 
|  | switch(svChar) | 
|  | { | 
|  | case 'N': | 
|  | bTyp = m_type (c, "bool"); | 
|  | break; | 
|  | case 'O': | 
|  | if (!superName) | 
|  | superName = m_name (c, ""); | 
|  | cvName=superName; | 
|  | MTOKEN_FLAGS (cvName) |= MTOKEN_FLAGS_ARRAY; | 
|  | arType = get_pointer_reference_type (c, bTyp, cvName, 0); | 
|  | if (!(MTOKEN_FLAGS (arType)&MTOKEN_FLAGS_ARRAY)) | 
|  | arType = m_combine (c, arType, m_array (c, NULL)); | 
|  | return arType; | 
|  | case 'W': | 
|  | bTyp = m_type (c, "wchar_t"); | 
|  | break; | 
|  | case 'X': | 
|  | case 'Y': | 
|  | DEC_CHAR (c); | 
|  | if (!(bTyp = get_ECSU_data_type (c))) | 
|  | return NULL; | 
|  | break; | 
|  | case 'D': | 
|  | bTyp = m_type (c, "__int8"); | 
|  | break; | 
|  | case 'E': | 
|  | bTyp = m_type (c, "unsigned __int8"); | 
|  | break; | 
|  | case 'F': | 
|  | bTyp = m_type (c, "__int16"); | 
|  | break; | 
|  | case 'G': | 
|  | bTyp = m_type (c, "unsigned __int16"); | 
|  | break; | 
|  | case 'H': | 
|  | bTyp = m_type (c, "__int32"); | 
|  | break; | 
|  | case 'I': | 
|  | bTyp = m_type (c, "unsigned __int32"); | 
|  | break; | 
|  | case 'J': | 
|  | bTyp = m_type (c, "__int64"); | 
|  | break; | 
|  | case 'K': | 
|  | bTyp = m_type (c, "unsigned __int64"); | 
|  | break; | 
|  | case 'L': | 
|  | bTyp = m_type (c, "__int128"); | 
|  | break; | 
|  | case 'M': | 
|  | bTyp = m_type (c, "unsigned"); | 
|  | break; | 
|  | case '$': | 
|  | bTyp = get_basic_data_type (c, superName); | 
|  | return m_combine (c, m_cv (c, "__w64"), bTyp); | 
|  | default: | 
|  | fprintf (stderr, " *** get_basic_data_type unknown '_%c' (ignored).\n", svChar); | 
|  | bTyp = m_type (c, "UNKNOWN"); | 
|  | break; | 
|  | } | 
|  | break; | 
|  | default: | 
|  | DEC_CHAR (c); | 
|  | bTyp = get_ECSU_data_type (c); | 
|  | if (!bTyp) | 
|  | return bTyp; | 
|  | break; | 
|  | } | 
|  | if (superName) | 
|  | bTyp = m_combine (c, bTyp, superName); | 
|  | return bTyp; | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_pointer_reference_type (sMSCtx *c, uMToken *cvType, uMToken *superType, char ptrChar) | 
|  | { | 
|  | uMToken *n = NULL; | 
|  | if (ptrChar == '&') | 
|  | n = m_cv (c, "&"); | 
|  | else if (ptrChar == '*') | 
|  | n = m_cv (c, "*"); | 
|  | if (GET_CHAR (c) == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | if (cvType) | 
|  | { | 
|  | if (!n) | 
|  | n = cvType; | 
|  | else | 
|  | n = m_combine (c, n, cvType); | 
|  | } | 
|  | if (superType) | 
|  | n = m_combine (c, n, superType); | 
|  | return n; | 
|  | } | 
|  | if (GET_CHAR (c) < '6' || GET_CHAR (c) > '9') | 
|  | { | 
|  | if (GET_CHAR (c) != '_') | 
|  | return get_pointer_reference_data_type (c, | 
|  | get_indirect_data_type (c, superType, ptrChar, cvType, 0),(ptrChar=='*' ? 1 : 0)); | 
|  | } | 
|  | if (cvType) | 
|  | { | 
|  | if (!superType || !(MTOKEN_FLAGS (superType)&MTOKEN_FLAGS_PTRREF)) | 
|  | { | 
|  | if (!n) | 
|  | n = cvType; | 
|  | else | 
|  | n = m_combine (c, n, cvType); | 
|  | } | 
|  | } | 
|  | if (superType) | 
|  | { | 
|  | if (!n) | 
|  | n = superType; | 
|  | else | 
|  | n = m_combine (c, n, superType); | 
|  | } | 
|  | return get_indirect_function_type (c, n); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_indirect_function_type (sMSCtx *c, uMToken *superType) | 
|  | { | 
|  | uMToken *retType = NULL; | 
|  | uMToken *n1 = NULL, *n2 = NULL; | 
|  | int flag; | 
|  | int cidx; | 
|  | char ch = GET_CHAR (c); | 
|  | if (ch == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | return superType; | 
|  | } | 
|  | if (ch != '_' && (ch < '6' || ch > '9')) | 
|  | return NULL; | 
|  | cidx = (int) (ch - '6'); | 
|  | INC_CHAR (c); | 
|  | if (ch == '_') | 
|  | { | 
|  | ch = GET_CHAR (c); | 
|  | if (ch == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | return superType; | 
|  | } | 
|  | if (ch < 'A' || ch > 'D') | 
|  | return NULL; | 
|  | cidx=(int)(ch - 'A') + 4; | 
|  | INC_CHAR (c); | 
|  | } | 
|  | n2 = superType; | 
|  | flag = cidx & 2; | 
|  | if (flag) | 
|  | { | 
|  | ch = GET_CHAR (c); | 
|  | if (ch == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | return n2; | 
|  | } | 
|  | n2 = m_coloncolon (c, get_scope (c), n2); | 
|  | if (GET_CHAR (c) == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | return n2; | 
|  | } | 
|  | if (GET_CHAR (c) != '@') | 
|  | return NULL; | 
|  | INC_CHAR (c); | 
|  | n1 = get_this_type (c); | 
|  | } | 
|  | if (cidx & 4) | 
|  | n2 = m_combine (c, get_based_type (c), n2); | 
|  | n2 = m_combine (c, get_calling_convention (c), n2); | 
|  | if (superType) | 
|  | n2 = m_rframe (c, n2); | 
|  | retType = get_return_type (c); | 
|  | n2 = m_combine (c, n2, m_rframe (c, get_argument_types (c))); | 
|  | if (flag) | 
|  | n2 = m_combine (c, n2, n1); | 
|  | n2 = m_combine (c, n2, get_throw_types (c)); | 
|  | return m_combine (c, retType, n2); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_pointer_reference_data_type (sMSCtx *c, uMToken *superType,int isPtr) | 
|  | { | 
|  | uMToken *n = NULL; | 
|  | if (GET_CHAR (c) == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | return superType; | 
|  | } | 
|  |  | 
|  | if (isPtr && GET_CHAR (c) == 'X') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | n = m_type (c, "void"); | 
|  | if (superType) | 
|  | n = m_combine (c, n, superType); | 
|  | return n; | 
|  | } | 
|  | if (GET_CHAR (c) == 'Y') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | return get_array_type (c, superType); | 
|  | } | 
|  | if (GET_CHAR (c) != '_') | 
|  | return get_basic_data_type (c, superType); | 
|  | if (c->pos[1] != 'Z') | 
|  | return get_basic_data_type (c, superType); | 
|  | SKIP_CHAR (c, 2); | 
|  | n = m_cv (c, "__box"); | 
|  | return m_combine (c, n, get_basic_data_type (c, superType)); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_ECSU_data_type (sMSCtx *c) | 
|  | { | 
|  | char ch = GET_CHAR (c); | 
|  | uMToken *n = NULL; | 
|  |  | 
|  | if (!ch) | 
|  | { | 
|  | c->err = 2; | 
|  | return m_type (c, "no-ecsu"); | 
|  | } | 
|  | INC_CHAR (c); | 
|  | switch (ch) | 
|  | { | 
|  | default: | 
|  | fprintf (stderr, " *** get_ECSU_data_type unknown %c\n", ch); | 
|  | n = m_type (c, "unknown ecsu"); | 
|  | break; | 
|  | case 'T': | 
|  | n = m_type (c, "union"); | 
|  | break; | 
|  | case 'U': | 
|  | n = m_type (c, "struct"); | 
|  | break; | 
|  | case 'V': | 
|  | n = m_type (c, "class"); | 
|  | break; | 
|  | case 'W': | 
|  | n = m_type (c, "enum"); | 
|  | get_enum_size_type (c); | 
|  | break; | 
|  | case 'X': | 
|  | n = m_type (c, "coclass"); | 
|  | break; | 
|  | case 'Y': | 
|  | n = m_type (c, "cointerface"); | 
|  | break; | 
|  | } | 
|  | return gen_binary (c->gc, eMST_ecsu, n, get_scoped_name (c)); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_string_literal_type (sMSCtx *c) | 
|  | { | 
|  | uMToken *n = NULL; | 
|  | char ch = GET_CHAR (c); | 
|  | if (ch == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | return NULL; | 
|  | } | 
|  | if (ch == '_') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | n = m_cv (c, "const"); | 
|  | } | 
|  | ch = GET_CHAR (c); | 
|  | if (GET_CHAR (c) == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | return NULL; | 
|  | } | 
|  | INC_CHAR (c); | 
|  | switch (ch) | 
|  | { | 
|  | case '0': | 
|  | return m_combine (c, n, m_type (c, "char")); | 
|  | case '1': | 
|  | return m_combine (c, n, m_type (c, "wchar_t")); | 
|  | } | 
|  | fprintf (stderr, " *** get_string_literal_type unknown '_%c'\n", ch); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_enum_size_type (sMSCtx *c) | 
|  | { | 
|  | uMToken *n = NULL; | 
|  | switch (GET_CHAR (c)) | 
|  | { | 
|  | case 0: | 
|  | c->err = 2; | 
|  | return NULL; | 
|  | case '0': | 
|  | n = m_type (c, "char"); | 
|  | break; | 
|  | case '1': | 
|  | n = m_type (c, "unsigned char"); | 
|  | break; | 
|  | case '2': | 
|  | n = m_type (c, "short"); | 
|  | break; | 
|  | case '3': | 
|  | n = m_type (c, "unsigned short"); | 
|  | break; | 
|  | case '4': | 
|  | n = m_type (c, "int"); | 
|  | break; | 
|  | case '5': | 
|  | n = m_type (c, "unsigned int"); | 
|  | break; | 
|  | case '6': | 
|  | n = m_type (c, "long"); | 
|  | break; | 
|  | case '7': | 
|  | n = m_type (c, "unsigned long"); | 
|  | break; | 
|  | default: | 
|  | fprintf (stderr, " *** get_enum_size_type unknown ,%c'\n", GET_CHAR (c)); | 
|  | return NULL; | 
|  | } | 
|  | INC_CHAR (c); | 
|  | return n; | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_this_type (sMSCtx *c) | 
|  | { | 
|  | return get_indirect_data_type (c, NULL, (char)0, NULL, 1); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_calling_convention (sMSCtx *c) | 
|  | { | 
|  | char ch = GET_CHAR (c); | 
|  |  | 
|  | if (ch == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | return NULL; | 
|  | } | 
|  | INC_CHAR (c); | 
|  | switch(ch) | 
|  | { | 
|  | case 'A': case 'B': | 
|  | return m_cv (c, "__cdecl"); | 
|  | case 'C': case 'D': | 
|  | return m_cv (c, "__pascal"); | 
|  | case 'E': case 'F': | 
|  | return m_cv (c, "__thiscall"); | 
|  | case 'G': case 'H': | 
|  | return m_cv (c, "__stdcall"); | 
|  | case 'I': case 'J': | 
|  | return m_cv (c, "__fastcall"); | 
|  | case 'K': case 'L': | 
|  | return m_cv (c, ""); | 
|  | case 'M': | 
|  | return m_cv (c, "__clrcall"); | 
|  | } | 
|  | fprintf (stderr, " *** get_calling_convention ,%c' unknown.\n", ch); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_throw_types (sMSCtx *c) | 
|  | { | 
|  | if (GET_CHAR (c) == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | return m_throw (c, m_rframe (c, NULL)); | 
|  | } | 
|  | if (GET_CHAR (c) == 'Z') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | return m_name (c, ""); | 
|  | } | 
|  | return m_throw (c, m_rframe (c, get_argument_types (c))); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_argument_types (sMSCtx *c) | 
|  | { | 
|  | char ch = GET_CHAR (c); | 
|  | uMToken *n = NULL; | 
|  |  | 
|  | if (ch == 'X') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | return m_element (c, m_type (c, "void")); | 
|  | } | 
|  | if (ch == 'Z') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | return m_element (c, m_type (c, "...")); | 
|  | } | 
|  | n = get_argument_list (c); | 
|  | if (!n || c->err) | 
|  | return n; | 
|  | if (GET_CHAR (c) == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | return n; | 
|  | } | 
|  | if (GET_CHAR (c) == '@') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | return n; | 
|  | } | 
|  | if (GET_CHAR (c) == 'Z') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | return chain_tok (n, m_element (c, m_type (c, "..."))); | 
|  | } | 
|  | fprintf (stderr, " *** get_argument_types unknown ,%c'\n", GET_CHAR (c)); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_return_type (sMSCtx *c) | 
|  | { | 
|  | if (GET_CHAR (c) == '@') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | return m_name (c, ""); | 
|  | } | 
|  | return get_data_type (c); | 
|  | } | 
|  |  | 
|  | static int | 
|  | get_number_of_dimensions (sMSCtx *c) | 
|  | { | 
|  | int ret = 0; | 
|  | if (GET_CHAR (c)) | 
|  | return 0; | 
|  | if (GET_CHAR (c) >= '0' && GET_CHAR (c) <= '9') | 
|  | { | 
|  | ret = (int) (GET_CHAR (c) - '0') + 1; | 
|  | INC_CHAR (c); | 
|  | return ret; | 
|  | } | 
|  | while (GET_CHAR (c) != '@') | 
|  | { | 
|  | if (GET_CHAR (c) == 0) | 
|  | return 0; | 
|  | if (GET_CHAR (c) < 'A' || GET_CHAR (c) > 'P') | 
|  | return -1; | 
|  | ret <<= 4; | 
|  | ret += (int) (GET_CHAR (c) - 'A'); | 
|  | INC_CHAR (c); | 
|  | } | 
|  | if (GET_CHAR (c) == '@') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | return ret; | 
|  | } | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_array_type (sMSCtx *c, uMToken *superType) | 
|  | { | 
|  | uMToken *n = NULL, *h = NULL; | 
|  | int dims; | 
|  |  | 
|  | if (GET_CHAR (c) == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | if (superType) | 
|  | return m_combine (c, m_rframe (c, superType), m_array (c, NULL)); | 
|  | return m_array (c, NULL); | 
|  | } | 
|  | dims = get_number_of_dimensions (c); | 
|  | if ( dims < 0) | 
|  | dims=0; | 
|  | if (!dims) | 
|  | { | 
|  | c->err = 2; | 
|  | return get_basic_data_type (c, m_array (c, NULL)); | 
|  | } | 
|  | if (superType && (MTOKEN_FLAGS(superType)&MTOKEN_FLAGS_ARRAY)) | 
|  | h = m_array (c, NULL); | 
|  | do { | 
|  | n = m_array (c, get_dimension (c, 0, 0)); | 
|  | if (!h) | 
|  | h = n; | 
|  | else | 
|  | h = m_combine (c, h, n); | 
|  | } while (--dims != 0); | 
|  | if (superType) | 
|  | { | 
|  | if (!(MTOKEN_FLAGS(superType)&MTOKEN_FLAGS_ARRAY)) | 
|  | superType = m_rframe (c, superType); | 
|  | h = m_combine (c, superType, h); | 
|  | } | 
|  | n = get_primary_data_type (c, h); | 
|  | MTOKEN_FLAGS (n) |= MTOKEN_FLAGS_ARRAY; | 
|  | return n; | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_argument_list (sMSCtx *c) | 
|  | { | 
|  | uMToken *n = NULL, *h = NULL; | 
|  | int idx; | 
|  |  | 
|  | if (c->err) | 
|  | return NULL; | 
|  | do { | 
|  | h = NULL; | 
|  | if (GET_CHAR (c) == '@' || GET_CHAR (c) == 'Z') | 
|  | return n; | 
|  | if (GET_CHAR (c) == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | return n; | 
|  | } | 
|  | idx= (int) (GET_CHAR (c) - '0'); | 
|  | if (idx < 0 || idx > 9) | 
|  | { | 
|  | const char *svName = c->pos; | 
|  | h = get_primary_data_type (c, NULL); | 
|  | if ((size_t) (c->pos - svName)>1 && c->pArgList->count < 10) | 
|  | { | 
|  | c->pArgList->arr[c->pArgList->count]=h; | 
|  | c->pArgList->count += 1; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | INC_CHAR (c); | 
|  | h = c->pArgList->arr[idx]; | 
|  | } | 
|  | h = m_element (c, h); | 
|  | n = chain_tok (n, h); | 
|  | } while (c->err != 2); | 
|  | return n; | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_vdisp_map_type (sMSCtx *c, uMToken *superType) | 
|  | { | 
|  | uMToken *n = superType; | 
|  | uMToken *h = get_scope (c); | 
|  | h = m_combine (c, m_name (c, "for"), h); | 
|  | h = m_frame (c, h); | 
|  | n = m_combine (c, n, h); | 
|  | if (GET_CHAR (c) =='@') | 
|  | INC_CHAR (c); | 
|  | return n; | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_ext_data_type (sMSCtx *c, uMToken *superType) | 
|  | { | 
|  | uMToken *dt = NULL,*n = NULL; | 
|  | dt = get_data_type (c); | 
|  | n = get_indirect_data_type (c, NULL, (char)0, NULL, 0); | 
|  | if (superType) | 
|  | n = m_combine (c, n, superType); | 
|  |  | 
|  | return m_combine (c, dt, n); | 
|  | } | 
|  |  | 
|  | static uMToken *getVCallThunkType(sMSCtx *c) | 
|  | { | 
|  | if (GET_CHAR (c) == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | return NULL; | 
|  | } | 
|  | if (GET_CHAR (c) != 'A') | 
|  | { | 
|  | fprintf (stderr, " *** getVCallThunkType unknown '%c'\n", GET_CHAR (c)); | 
|  | return NULL; | 
|  | } | 
|  | INC_CHAR (c); | 
|  | return m_cv (c, "{flat}"); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | get_vftable_type (sMSCtx *c, uMToken *superType) | 
|  | { | 
|  | uMToken *n = superType; | 
|  | if (c->err || GET_CHAR (c) == 0) | 
|  | { | 
|  | c->err = 2; | 
|  | return n; | 
|  | } | 
|  | n = m_combine (c, get_indirect_data_type (c, NULL, (char)0, NULL, 0), n); | 
|  | if (c->err == 2 || !n) | 
|  | return n; | 
|  | if (GET_CHAR (c) != '@') | 
|  | { | 
|  | n = m_combine (c, n, m_name (c, "{for ")); | 
|  | while (c->err == 0) | 
|  | { | 
|  | if (GET_CHAR (c) ==0 || GET_CHAR (c) =='@') | 
|  | break; | 
|  | n = m_combine (c, n, m_lexical_frame (c, get_scope (c))); | 
|  | if (GET_CHAR (c) == '@') | 
|  | INC_CHAR (c); | 
|  | if (c->err == 0 && GET_CHAR (c) != '@') | 
|  | n = m_combine (c, n, m_name (c, "s ")); | 
|  | } | 
|  | if (c->err == 0) | 
|  | { | 
|  | if (GET_CHAR (c) == 0) | 
|  | c->err = 2; | 
|  | n = m_combine (c, n, m_name (c, "}")); | 
|  | } | 
|  | if (GET_CHAR (c) != '@') | 
|  | return n; | 
|  | } | 
|  | INC_CHAR (c); | 
|  | return n; | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | compose_decl (sMSCtx *c, uMToken *symbol) | 
|  | { | 
|  | uMToken *n = NULL; | 
|  | int et = get_encoded_type (c); | 
|  | int nIsUDC = (symbol && (MTOKEN_FLAGS (symbol) & MTOKEN_FLAGS_UDC)) ? 1 : 0; | 
|  | if (et==0xffff) | 
|  | return NULL; | 
|  | if (et==0xfffe) | 
|  | { | 
|  | c->err = 2; | 
|  | return symbol; | 
|  | } | 
|  | if (et==0xfffd) | 
|  | return symbol; | 
|  | if ((et&0x8000)==0) | 
|  | { | 
|  | n = symbol; | 
|  | if ((et&0x7c00)==0x6800) | 
|  | return get_vftable_type (c, n); | 
|  | if ((et&0x7c00)==0x7000) | 
|  | return get_vftable_type (c, n); | 
|  | if ((et&0x7c00)==0x6000) | 
|  | { | 
|  | uMToken *ll = m_element (c, get_dimension (c, 0, 0)); | 
|  | ll = m_frame (c, ll); | 
|  | return m_combine (c, n, ll); | 
|  | } | 
|  | if ((et&0x7c00)==0x7c00) | 
|  | return get_vdisp_map_type (c, n); | 
|  | if ((et&0x7c00)==0x7800) | 
|  | return n; | 
|  | n = get_ext_data_type (c, n); | 
|  | if ((et&0x6000)!=0) | 
|  | { | 
|  | if ((et&0x1000)) | 
|  | n = m_combine (c, m_colon (c, "[thunk]"), n); | 
|  | return n; | 
|  | } | 
|  | n = m_combine (c, m_cv (c, "static"), n); | 
|  | if ((et&0x700) == 0x400 || (et&0x700) == 0x500) | 
|  | n = m_combine (c, m_cv (c, "virtual"), n); | 
|  | switch ((et&0x1800)) | 
|  | { | 
|  | case 0x800: | 
|  | n = m_combine (c, m_colon (c, "private"), n); | 
|  | break; | 
|  | case 0x1000: | 
|  | n = m_combine (c, m_colon (c, "protected"), n); | 
|  | break; | 
|  | case 0x0: | 
|  | n = m_combine (c, m_colon (c, "public"), n); | 
|  | break; | 
|  | } | 
|  | if ((et&0x400)) | 
|  | n = m_combine (c, m_colon (c, "[thunk]"), n); | 
|  | return n; | 
|  | } | 
|  | if ((et&0x1f00)==0x1000 || (et&0x1f00)==0x1400) | 
|  | { | 
|  | n = symbol; | 
|  | if ((et&0x6000)!=0 || (et&0x7f00)==0x1400) | 
|  | n = m_combine (c, n, m_name (c, "local_static_destructor_helper")); | 
|  | n = get_ext_data_type (c, n); | 
|  | symbol = NULL; | 
|  | } | 
|  | else if ((et&0x1f00)==0x1500 || (et&0x1f00)==0x1600) | 
|  | { | 
|  | n = symbol; | 
|  | symbol = NULL; | 
|  | if ((et&0x1f00)==0x1500) | 
|  | n = m_combine (c, n, m_name (c, "template_static_data_member_constructor_helper")); | 
|  | else if ((et&0x1f00)==0x1600) | 
|  | n = m_combine (c, n, m_name (c, "template_static_data_member_destructor_helper")); | 
|  | } | 
|  | else | 
|  | { | 
|  | if ((et&0x4000)!=0) | 
|  | n = get_based_type (c); | 
|  | if ((et&0x1800)==0x1800) | 
|  | { | 
|  | uMToken *hh = NULL; | 
|  | hh = m_element (c, get_dimension (c, 0, 0)); | 
|  | hh = chain_tok (hh, m_element (c, getVCallThunkType (c))); | 
|  | n = m_combine (c, symbol, | 
|  | m_frame (c, hh)); | 
|  | n = m_combine (c, get_calling_convention (c), n); | 
|  | } | 
|  | else | 
|  | { | 
|  | uMToken *h = NULL; | 
|  | uMToken *n1 = NULL; | 
|  | uMToken *n2 = NULL; | 
|  | uMToken *n3 = NULL; | 
|  | if ((et&0x1000)!=0 || (et&0x1c00)==0xc00) | 
|  | { | 
|  | if ((et&0x1f00)==0xd00) | 
|  | n1 = get_dimension (c, 1, 0); | 
|  | n2 = get_dimension (c, 1, 0); | 
|  | } | 
|  | if (((et&0x1800)==0x800) && (et&0x700)!=0x200) | 
|  | n3 = get_this_type (c); | 
|  | n = m_combine (c, get_calling_convention (c), n); | 
|  | if (symbol) | 
|  | n = m_combine (c, n, symbol); | 
|  |  | 
|  | if (nIsUDC) | 
|  | n = m_combine (c, n, get_return_type (c)); | 
|  | h = get_return_type (c); | 
|  | if (((et&0x1800)!=0x800 ? (et&0x1000)!=0 : (et&0x400)!=0)) | 
|  | { | 
|  | if (((et&0x1800)==0x800) && (et&0x700)==0x500) | 
|  | { | 
|  | n2 = chain_tok ( | 
|  | m_element (c, n1), | 
|  | m_element (c, n2)); | 
|  | n2 = m_frame (c, n2); | 
|  | n = m_combine (c, n, m_combine (c, m_name (c, "vtordisp"), n2)); | 
|  | } | 
|  | else | 
|  | { | 
|  | n2 = m_frame (c, m_element (c, n2)); | 
|  | n = m_combine (c, n, m_combine (c, m_name (c, "adjustor"), n2)); | 
|  | } | 
|  | } | 
|  | n = m_combine (c, n, m_rframe (c, get_argument_types (c))); | 
|  | if (((et&0x1800)==0x800) && (et&0x700)!=0x200) | 
|  | n = m_combine (c, n, n3); | 
|  | n = m_combine (c, n, get_throw_types (c)); | 
|  | if (h) | 
|  | n = m_combine (c, h, n); | 
|  | } | 
|  | } | 
|  | if ((et&0x1800)!=0x800) { | 
|  | if ((et&0x1000)) | 
|  | n = m_combine (c, m_colon (c, "[thunk]"), n); | 
|  | return n; | 
|  | } | 
|  | switch ((et&0x700)) | 
|  | { | 
|  | case 0x200: | 
|  | n = m_combine (c, m_cv (c, "static"), n); | 
|  | break; | 
|  | case 0x100: | 
|  | case 0x400: | 
|  | case 0x500: | 
|  | n = m_combine (c, m_cv (c, "virtual"), n); | 
|  | break; | 
|  | } | 
|  | switch ((et&0xc0)) | 
|  | { | 
|  | case 0x40: | 
|  | n = m_combine (c, m_colon (c, "private"), n); | 
|  | break; | 
|  | case 0x80: | 
|  | n = m_combine (c, m_colon (c, "protected"), n); | 
|  | break; | 
|  | case 0x0: | 
|  | n = m_combine (c, m_colon (c, "public"), n); | 
|  | break; | 
|  | } | 
|  | if ((et&0x400)) | 
|  | n = m_combine (c, m_colon (c, "[thunk]"), n); | 
|  | return n; | 
|  | } | 
|  |  | 
|  | static int | 
|  | get_encoded_type (sMSCtx *c) | 
|  | { | 
|  | int ret; | 
|  |  | 
|  | for(;;) | 
|  | { | 
|  | ret = 0; | 
|  | if (GET_CHAR (c) == '_') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | ret = 0x4000; | 
|  | } | 
|  | if (GET_CHAR (c) >= 'A' && GET_CHAR (c) <= 'Z') | 
|  | { | 
|  | int chc = (int) (GET_CHAR (c) - 'A'); | 
|  | INC_CHAR (c); | 
|  | if ((chc & 1) == 0) | 
|  | ret |= 0x8000; | 
|  | else | 
|  | ret |= 0xa000; | 
|  | if (chc >= 0x18) | 
|  | return ret; | 
|  | ret |= 0x800; | 
|  | switch((chc&0x18)) | 
|  | { | 
|  | case 0: | 
|  | ret |= 0x40; | 
|  | break; | 
|  | case 8: | 
|  | ret |= 0x80; | 
|  | break; | 
|  | case 0x10: | 
|  | break; | 
|  | } | 
|  | switch((chc&6)) | 
|  | { | 
|  | case 0: | 
|  | return ret; | 
|  | case 2: | 
|  | return ret|0x200; | 
|  | case 4: | 
|  | return ret|0x100; | 
|  | case 6: | 
|  | return ret|0x400; | 
|  | } | 
|  | return 0xffff; | 
|  | } | 
|  | if (GET_CHAR (c) != '$') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | switch(c->pos[-1]) | 
|  | { | 
|  | case '0': | 
|  | return 0x800; | 
|  | case '1': | 
|  | return 0x1000; | 
|  | case '2': | 
|  | return 0; | 
|  | case '3': | 
|  | return 0x4000; | 
|  | case '4': | 
|  | return 0x2000; | 
|  | case '5': | 
|  | return 0x6000; | 
|  | case '6': | 
|  | return 0x6800; | 
|  | case '7': | 
|  | return 0x7000; | 
|  | case '8': | 
|  | return 0x7800; | 
|  | case '9': | 
|  | return 0xfffd; | 
|  | case 0: | 
|  | DEC_CHAR (c); | 
|  | return 0xfffe; | 
|  | } | 
|  | DEC_CHAR (c); | 
|  | return 0xffff; | 
|  | } | 
|  | INC_CHAR (c); | 
|  | switch(GET_CHAR (c)) | 
|  | { | 
|  | case 'A': | 
|  | INC_CHAR (c); | 
|  | return ret|0x9000; | 
|  | case 'B': | 
|  | INC_CHAR (c); | 
|  | return ret|0x9800; | 
|  | case 'C': | 
|  | INC_CHAR (c); | 
|  | return ret|0x7c00; | 
|  | case 'D': | 
|  | INC_CHAR (c); | 
|  | return ret|0x9100; | 
|  | case 'E': | 
|  | INC_CHAR (c); | 
|  | return ret|0x9200; | 
|  | case 0: | 
|  | INC_CHAR (c); | 
|  | return 0xfffe; | 
|  | case '0': | 
|  | INC_CHAR (c); | 
|  | return ret|0x8d40; | 
|  | case '1': | 
|  | INC_CHAR (c); | 
|  | return ret|0xad40; | 
|  | case '2': | 
|  | INC_CHAR (c); | 
|  | return ret|0x8d80; | 
|  | case '3': | 
|  | INC_CHAR (c); | 
|  | return ret|0xad80; | 
|  | case '4': | 
|  | INC_CHAR (c); | 
|  | return ret|0x8d00; | 
|  | case '5': | 
|  | INC_CHAR (c); | 
|  | return ret|0xad00; | 
|  | case '$': | 
|  | if (c->pos[1] == 'P') | 
|  | INC_CHAR (c); | 
|  | break; | 
|  | default: | 
|  | return 0xffff; | 
|  | } | 
|  | INC_CHAR (c); | 
|  | switch(GET_CHAR (c)) | 
|  | { | 
|  | case 'F': case 'G': case 'H': case 'I': case 'L': case 'M': | 
|  | INC_CHAR (c); | 
|  | break; | 
|  | case 'J': case 'K': case 'N': case 'O': | 
|  | INC_CHAR (c); | 
|  | if (GET_CHAR (c) < '0' || GET_CHAR (c) > '9') | 
|  | { | 
|  | INC_CHAR (c); | 
|  | return 0xffff; | 
|  | } | 
|  | { | 
|  | int skip = (GET_CHAR (c) - '0') + 1; | 
|  | SKIP_CHAR (c, skip); | 
|  | } | 
|  | break; | 
|  | default: | 
|  | INC_CHAR (c); | 
|  | return ret; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | m_combine (sMSCtx *c, uMToken *l, uMToken *r) | 
|  | { | 
|  | if (!l && !r) | 
|  | return NULL; | 
|  | if (!l) | 
|  | return r; | 
|  | if (!r) | 
|  | return l; | 
|  | return gen_binary (c->gc, eMST_combine, l, r); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | m_type (sMSCtx *c, const char *typname) | 
|  | { | 
|  | return gen_name (c->gc, eMST_type, typname); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | m_cv (sMSCtx *c, const char *cv) | 
|  | { | 
|  | return gen_name (c->gc, eMST_cv, cv); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | m_coloncolon (sMSCtx *c, uMToken *l, uMToken *r) | 
|  | { | 
|  | if (!l) | 
|  | return r; | 
|  | if (!r) | 
|  | return l; | 
|  | return gen_binary (c->gc, eMST_coloncolon, l, r); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | m_element (sMSCtx *c, uMToken *el) | 
|  | { | 
|  | return gen_unary (c->gc, eMST_element, el); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | m_array (sMSCtx *c, uMToken *dim) | 
|  | { | 
|  | return gen_unary (c->gc, eMST_array, dim); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | m_scope (sMSCtx *c, uMToken *n) | 
|  | { | 
|  | return gen_unary (c->gc, eMST_scope, n); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | m_oper (sMSCtx *c, uMToken *n) | 
|  | { | 
|  | return gen_unary (c->gc, eMST_oper, n); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | m_name (sMSCtx *c, const char *str) | 
|  | { | 
|  | return gen_name (c->gc, eMST_name, str); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | m_colon (sMSCtx *c, const char *str) | 
|  | { | 
|  | return gen_name (c->gc, eMST_colon, str); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | m_opname (sMSCtx *c, const char *str) | 
|  | { | 
|  | return gen_name (c->gc, eMST_opname, str); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | m_rtti (sMSCtx *c, const char *str) | 
|  | { | 
|  | return gen_name (c->gc, eMST_rtti, str); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | m_frame (sMSCtx *c, uMToken *u) | 
|  | { | 
|  | return gen_unary (c->gc, eMST_frame, u); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | m_rframe (sMSCtx *c, uMToken *u) | 
|  | { | 
|  | return gen_unary (c->gc, eMST_rframe, u); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | m_ltgt (sMSCtx *c, uMToken *u) | 
|  | { | 
|  | return gen_unary (c->gc, eMST_ltgt, u); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | m_throw (sMSCtx *c, uMToken *u) | 
|  | { | 
|  | return gen_unary (c->gc, eMST_throw, u); | 
|  | } | 
|  |  | 
|  | static uMToken * | 
|  | m_lexical_frame (sMSCtx *c, uMToken *u) | 
|  | { | 
|  | return gen_unary (c->gc, eMST_lexical_frame, u); | 
|  | } |