Files
PrimeAPI/script/Mangle.py
T

253 lines
5.8 KiB
Python

# CodeWarrior-style C++ name mangling
MANGLED_TYPES = {
'void': 'v',
'bool': 'b',
'char': 'c',
'wchar_t': 'w',
'short': 's',
'int': 'i',
'long': 'l',
'size_t': 'Ul',
'long long': 'x',
'signed char': 'c',
'unsigned char': 'Uc',
'signed short': 's',
'unsigned short': 'Us',
'signed int': 'i',
'unsigned int': 'Ui',
'signed long': 'l',
'unsigned long': 'Ul',
'signed long long': 'x',
'unsigned long long': 'Ux',
'uint': 'Ui',
'int8': 'c',
'uint8': 'Uc',
'int16': 's',
'uint16': 'Us',
'int32': 'l',
'uint32': 'Ul',
'int64': 'x',
'uint64': 'Ux',
'float': 'f',
'double': 'd'
}
def is_basic_type(typeName):
return typeName in MANGLED_TYPES
def mangle_operator(operName):
# Note: There are some missing operators here (particularly bitwise operators).
name = operName.replace(' ', '')
# Arithmetic
if name == "operator=":
return "__as"
elif name == "operator+":
return "__pl"
elif name == "operator+=":
return "__apl"
elif name == "operator-":
return "__mi"
elif name == "operator-=":
return "__ami"
elif name == "operator*":
return "__ml"
elif name == "operator*=":
return "__amu"
elif name == "operator/":
return "__dv"
elif name == "operator/=":
return "__adv"
# Logic
elif name == "operator<":
return "__lt"
elif name == "operator<=":
return "__le"
elif name == "operator>":
return "__gt"
elif name == "operator>=":
return "__ge"
elif name == "operator==":
return "__eq"
elif name == "operator!=":
return "__ne"
# Allocation
elif name == "operatornew":
return "__nw"
elif name == "operatornew[]":
return "__nwa"
elif name == "operatordelete":
return "__dl"
elif name == "operatordelete[]":
return "__dla"
return operName
def split_scopes(scopedName):
isOperatorFunc = False
innerDepth = 0
lastSplit = -2
out = []
for chrIdx in range(0, len(scopedName)):
if scopedName[chrIdx:chrIdx+8] == "operator":
isOperatorFunc = True
elif (scopedName[chrIdx] == '<' or scopedName[chrIdx] == '(') and not isOperatorFunc:
innerDepth += 1
elif (scopedName[chrIdx] == '>' or scopedName[chrIdx] == ')') and not isOperatorFunc:
innerDepth -= 1
elif scopedName[chrIdx:chrIdx+2] == '::' and innerDepth == 0:
out.append(scopedName[lastSplit + 2 : chrIdx])
lastSplit = chrIdx
out.append(scopedName[lastSplit + 2 : len(scopedName)])
return out
def split_params(paramText):
out = []
templateDepth = 0
lastSplit = -1
for chrIdx in range(0, len(paramText)):
chr = paramText[chrIdx]
if chr == '<':
templateDepth += 1
elif chr == '>':
templateDepth -= 1
elif chr == ',' and templateDepth == 0:
out.append(paramText[lastSplit+1 : chrIdx].strip())
lastSplit = chrIdx
out.append(paramText[lastSplit+1 : len(paramText)].strip())
return out
def mangle_template(templateText):
assert(templateText.startswith('<') and templateText.endswith('>'))
templateText = templateText[1:-1]
params = split_params(templateText)
mangledParams = []
for param in params:
mangledParams.append( mangle_type(param) )
return '<' + ','.join(mangledParams) + '>'
def mangle_type(typename):
if is_basic_type(typename):
baseTypeName = MANGLED_TYPES[typename]
else:
baseTypeName = ""
scopes = split_scopes(typename)
if len(scopes) > 1:
baseTypeName = "Q%d" % len(scopes)
for scope in scopes:
# Check for template
templateBegin = scope.find('<')
if templateBegin != -1:
templateEnd = scope.rfind('>')
assert(templateEnd != -1)
baseType = scope[0:templateBegin]
mangledTemplate = mangle_template(scope[templateBegin : templateEnd + 1])
baseTypeName += '%d%s%s' % (len(baseType) + len(mangledTemplate), baseType, mangledTemplate)
else:
baseTypeName += '%d%s' % (len(scope), scope)
return baseTypeName
def mangle_params(params):
if not params:
return 'Fv'
# Get list of arguments. Can't use split() due to potential templates with multiple parameters
args = split_params(params)
out = ['F']
for arg in args:
type = arg
qualifiers = ''
baseTypeName = ''
while len(type) > 0:
if type.endswith('&'):
qualifiers += 'R'
type = type[:-1].strip()
elif type.endswith('*'):
qualifiers += 'P'
type = type[:-1].strip()
elif type.endswith('const'):
qualifiers += 'C'
type = type[:-5].strip()
else:
if type.endswith('>'):
searchLen = type.find('<')
else:
searchLen = len(type)
baseBegin = max(type.rfind(chr, 0, searchLen) for chr in " *&") + 1
if type[baseBegin - 9 : baseBegin - 1] == "unsigned":
baseBegin -= 9
elif type[baseBegin - 7 : baseBegin - 1] == "signed":
baseBegin -= 7
baseType = type[baseBegin:len(type)]
baseTypeName = mangle_type(baseType)
type = type[:-len(baseType)].strip()
out.append(qualifiers + baseTypeName)
return ''.join(out)
def mangle(funcSignature):
mangled = ''
funcName = funcSignature[0:funcSignature.find('(')]
scopes = split_scopes(funcName)
isScoped = len(scopes) > 1
isConst = funcSignature.find('const', funcSignature.rfind(')')) != -1
baseName = scopes[-1]
# Check for operators/templates
if baseName.startswith("operator"):
baseName = mangle_operator(baseName)
elif '<' in baseName:
templateBegin = baseName.find('<')
templateEnd = baseName.rfind('>')
assert(templateBegin != -1 and templateEnd != -1)
baseFuncName = baseName[0:templateBegin]
mangledTemplate = mangle_template(baseName[templateBegin : templateEnd + 1])
baseName = baseFuncName + mangledTemplate
mangled = baseName + '__'
if isScoped:
del scopes[-1]
if len(scopes) > 1:
mangled += "Q%d" % len(scopes)
for name in scopes:
mangled += "%d%s" % (len(name), name)
if isConst:
mangled += 'C'
params = funcSignature[ funcSignature.find('(') + 1 : funcSignature.rfind(')') ]
return mangled + mangle_params(params)