Fix the obnoxious issue with globals propagation in full expressions.

Fixed by backtracking in the parser, and keeping a copy of the original expression if it's a simple_expr, which is used for output in place of the folded one.

There's still the potential issue that if a global is optimized away, then it will "come back" during output and cause an error because the definition is missing.
This commit is contained in:
Sei Lisa 2014-07-31 04:47:19 +02:00
parent 5b401ff9a5
commit e5714eba25
3 changed files with 43 additions and 10 deletions

View file

@ -46,6 +46,16 @@ class optimizer(object):
return value return value
return {'nt':'CAST', 't':newtype, 'ch':[value]} return {'nt':'CAST', 't':newtype, 'ch':[value]}
def CopyNode(self, node):
# This is mainly for simple_expr so not a big deal.
ret = node.copy()
if 'ch' in ret:
new = []
for subnode in ret['ch']:
new.append(self.CopyNode(subnode))
ret['ch'] = new
return ret
def FoldTree(self, parent, index): def FoldTree(self, parent, index):
"""Recursively traverse the tree to fold constants, changing it in """Recursively traverse the tree to fold constants, changing it in
place. place.
@ -512,10 +522,14 @@ class optimizer(object):
if nt == 'DECL': if nt == 'DECL':
if child: if child:
# TODO: Decide if child is a simple_expr. # Check if child is a simple_expr. If it is, then we keep the
# If it is, then we should keep the original # original attached to the folded node and use it in the output.
# attached to the folded node and use it in the output. if child[0].pop('Simple', False):
self.FoldTree(child, 0) orig = self.CopyNode(child[0])
self.FoldTree(child, 0)
child[0]['orig'] = orig
else:
self.FoldTree(child, 0)
# Remove assignment if integer zero. # Remove assignment if integer zero.
if node['t'] == 'integer' and child[0]['nt'] == 'CONST' \ if node['t'] == 'integer' and child[0]['nt'] == 'CONST' \
and not child[0]['value']: and not child[0]['value']:
@ -569,7 +583,7 @@ class optimizer(object):
self.FoldTree(tree, idx) self.FoldTree(tree, idx)
self.globalmode = False self.globalmode = False
if not self.IsValidGlobalConstant(tree[idx]): if not self.IsValidGlobalConstant(tree[idx]):
warning('WARNING: Expression does not collapse to a single constant.') warning('WARNING: Expression does not resolve to a single constant.')
else: else:
self.FoldTree(tree, idx) self.FoldTree(tree, idx)

View file

@ -265,7 +265,10 @@ class outscript(object):
if nt == 'DECL': if nt == 'DECL':
ret = self.dent() + node['t'] + ' ' + node['name'] ret = self.dent() + node['t'] + ' ' + node['name']
if child: if child:
ret += ' = ' + self.OutExpr(child[0]) if 'orig' in child[0]:
ret += ' = ' + self.OutExpr(child[0]['orig'])
else:
ret += ' = ' + self.OutExpr(child[0])
return ret + ';\n' return ret + ';\n'
if nt == ';': if nt == ';':
return self.dent() + ';\n' return self.dent() + ';\n'

View file

@ -1465,7 +1465,7 @@ class parser(object):
raise EParseAlreadyDefined(self) raise EParseAlreadyDefined(self)
self.NextToken() self.NextToken()
if self.tok[0] == '=' or self.tok[0] == ';': if self.tok[0] in ('=', ';'):
# This is a variable definition # This is a variable definition
if typ is None: # Typeless variables are not allowed if typ is None: # Typeless variables are not allowed
raise EParseSyntax(self) raise EParseSyntax(self)
@ -1474,11 +1474,27 @@ class parser(object):
self.NextToken() self.NextToken()
if self.extendedglobalexpr: if self.extendedglobalexpr:
self.globalmode = True # Disallow forward globals. self.globalmode = True # Disallow forward globals.
value = self.Parse_expression() # Use advanced expression evaluation. # Mark backtracking position
pos = self.pos
errorpos = self.errorpos
tok = self.tok
try:
value = self.Parse_simple_expr()
self.expect(';')
value['Simple'] = True # Success - mark it as simple
except EParse:
# Backtrack
self.pos = pos
self.errorpos = errorpos
self.tok = tok
# Use advanced expression evaluation.
value = self.Parse_expression()
self.expect(';')
self.globalmode = False # Allow forward globals again. self.globalmode = False # Allow forward globals again.
else: else:
value = self.Parse_simple_expr() # Use LSL's dull global expression. # Use LSL's dull global expression.
self.expect(';') value = self.Parse_simple_expr()
self.expect(';')
self.NextToken() self.NextToken()
else: # must be semicolon else: # must be semicolon
self.NextToken() self.NextToken()