Fully implement duplabels, and prepare output for general renaming.

There's also a new hidden option, shrinknames, which automatically enables duplabels due to its nature. The idea is that once general renaming is implemented, in order for label names to not cause collision trouble, they are renamed out of the way with unique names.

Not entirely sure this is really necessary.
This commit is contained in:
Sei Lisa 2014-08-01 01:41:21 +02:00
parent b5c440e4bc
commit d65f0f1f75
2 changed files with 49 additions and 14 deletions

View file

@ -135,6 +135,12 @@ class outscript(object):
def dent(self): def dent(self):
return self.indent * self.indentlevel return self.indent * self.indentlevel
def FindName(self, node):
try:
return self.symtab[node['scope']][node['name']]['NewName']
except KeyError:
return node['name']
def OutIndented(self, node): def OutIndented(self, node):
if node['nt'] != '{}': if node['nt'] != '{}':
self.indentlevel += 1 self.indentlevel += 1
@ -167,7 +173,7 @@ class outscript(object):
return self.OutExpr(child[0]) + ' ' + nt + ' ' + self.OutExpr(child[1]) return self.OutExpr(child[0]) + ' ' + nt + ' ' + self.OutExpr(child[1])
if nt == 'IDENT': if nt == 'IDENT':
return expr['name'] return self.FindName(expr)
if nt == 'CONST': if nt == 'CONST':
return self.Value2LSL(expr['value']) return self.Value2LSL(expr['value'])
@ -254,17 +260,17 @@ class outscript(object):
ret += self.OutIndented(child[3]) ret += self.OutIndented(child[3])
return ret return ret
if nt == '@': if nt == '@':
return self.dent() + '@' + node['name'] + ';\n' return self.dent() + '@' + self.FindName(node) + ';\n'
if nt == 'JUMP': if nt == 'JUMP':
return self.dent() + 'jump ' + node['name'] + ';\n' return self.dent() + 'jump ' + self.FindName(node) + ';\n'
if nt == 'STSW': if nt == 'STSW':
return self.dent() + 'state ' + node['name'] + ';\n' return self.dent() + 'state ' + self.FindName(node) + ';\n'
if nt == 'RETURN': if nt == 'RETURN':
if child: if child:
return self.dent() + 'return ' + self.OutExpr(child[0]) + ';\n' return self.dent() + 'return ' + self.OutExpr(child[0]) + ';\n'
return self.dent() + 'return;\n' return self.dent() + 'return;\n'
if nt == 'DECL': if nt == 'DECL':
ret = self.dent() + node['t'] + ' ' + node['name'] ret = self.dent() + node['t'] + ' ' + self.FindName(node)
if child: if child:
if 'orig' in child[0]: if 'orig' in child[0]:
ret += ' = ' + self.OutExpr(child[0]['orig']) ret += ' = ' + self.OutExpr(child[0]['orig'])

View file

@ -2,6 +2,8 @@
from lslcommon import Key, Vector, Quaternion from lslcommon import Key, Vector, Quaternion
import lslfuncs import lslfuncs
import sys, re import sys, re
from base64 import b64encode
import random
# Note this module was basically written from bottom to top, which may help # Note this module was basically written from bottom to top, which may help
# reading it. # reading it.
@ -1156,15 +1158,38 @@ class parser(object):
name = self.tok[1] name = self.tok[1]
if name in self.symtab[self.scopeindex]: if name in self.symtab[self.scopeindex]:
raise EParseAlreadyDefined(self) raise EParseAlreadyDefined(self)
if not self.duplabels and name in self.locallabels: # shrinknames *needs* all labels renamed, so they are out of the way
raise EParseDuplicateLabel(self) if self.duplabels or self.shrinknames:
# All labels go to a common pool local to the current function. # Duplicate labels allowed.
self.locallabels.add(name) if name in self.locallabels or self.shrinknames:
self.AddSymbol('l', self.scopeindex, name) # Generate a new unique name and attach it to the symbol.
while True:
x = random.randint(0, 16777215)
unique = 'J_' + b64encode(chr(x>>16) + chr((x>>8)&255)
+ chr(x&255)).replace('+', '_')
x = random.randint(0, 16777215)
unique += b64encode(chr(x>>16) + chr((x>>8)&255)
+ chr(x&255)).replace('+', '_')
if '/' not in unique and unique not in self.locallabels:
break
else:
# Use the existing name. Faster and more readable.
unique = name
self.locallabels.add(unique)
self.AddSymbol('l', self.scopeindex, name, NewName=unique)
else:
# Duplicate labels disallowed.
# All labels go to a common pool local to the current function.
# Check if it's already there, and add it otherwise.
if name in self.locallabels:
raise EParseDuplicateLabel(self)
self.locallabels.add(name)
self.AddSymbol('l', self.scopeindex, name)
self.NextToken() self.NextToken()
self.expect(';') self.expect(';')
self.NextToken() self.NextToken()
return {'nt':'@', 't':None, 'name':name} return {'nt':'@', 't':None, 'name':name, 'scope':self.scopeindex}
if tok0 == 'JUMP': if tok0 == 'JUMP':
self.NextToken() self.NextToken()
self.expect('IDENT') self.expect('IDENT')
@ -1454,7 +1479,7 @@ class parser(object):
self.locallabels = set() self.locallabels = set()
body = self.Parse_code_block(None) body = self.Parse_code_block(None)
del self.locallabels del self.locallabels
ret.append({'nt':'FNDEF', 't':None, 'name':name, ret.append({'nt':'FNDEF', 't':None, 'name':name, # no scope as these are reserved words
'pscope':self.scopeindex, 'ptypes':params[0], 'pnames':params[1], 'pscope':self.scopeindex, 'ptypes':params[0], 'pnames':params[1],
'ch':[body]}) 'ch':[body]})
self.PopScope() self.PopScope()
@ -1537,7 +1562,7 @@ class parser(object):
paramscope = self.scopeindex paramscope = self.scopeindex
self.AddSymbol('f', 0, name, Loc=len(self.tree), Type=typ, self.AddSymbol('f', 0, name, Loc=len(self.tree), Type=typ,
ParamTypes=params[0], ParamNames=params[1]) ParamTypes=params[0], ParamNames=params[1])
self.tree.append({'nt':'FNDEF', 't':typ, 'name':name, self.tree.append({'nt':'FNDEF', 't':typ, 'name':name, 'scope':0,
'pscope':paramscope, 'pscope':paramscope,
'ptypes':params[0], 'pnames':params[1], 'ch':[body]}) 'ptypes':params[0], 'pnames':params[1], 'ch':[body]})
self.PopScope() self.PopScope()
@ -1765,6 +1790,9 @@ class parser(object):
# Enable use of local labels with duplicate names # Enable use of local labels with duplicate names
self.duplabels = 'duplabels' in options self.duplabels = 'duplabels' in options
# Shrink names. Activates duplabels automatically.
self.shrinknames = 'shrinknames' in options
# Symbol table: # Symbol table:
# This is a list of all local and global symbol tables. # This is a list of all local and global symbol tables.
# The first element (0) is the global scope. Each symbol table is a # The first element (0) is the global scope. Each symbol table is a
@ -1822,7 +1850,8 @@ class parser(object):
# Start the parsing proper # Start the parsing proper
self.Parse_script() self.Parse_script()
del self.globals # No longer needed. The data that is not in self.functions is in self.symtab[0]. # No longer needed. The data is already in self.symtab[0].
del self.globals
# Insert library functions into symbol table # Insert library functions into symbol table
self.symtab[0].update(self.functions) self.symtab[0].update(self.functions)