astnode properties fix

This commit is contained in:
Irmen de Jong 2018-03-06 22:02:50 +01:00
parent 6696887f0e
commit 44c0d243ef
5 changed files with 25 additions and 59 deletions

View File

@ -129,7 +129,3 @@ def preserving_registers(registers: Set[str], scope: Scope, out: Callable, loads
yield
@no_type_check
def scoped_name(node_with_name: AstNode, current_scope: Scope) -> str:
node_scope = node_with_name.my_scope()
return node_with_name.name if node_scope is current_scope else node_scope.name + "." + node_with_name.name

View File

@ -7,9 +7,9 @@ is quite frequent and this generates assembly code tweaked for this case.
Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
"""
from ..plyparse import VarDef, Register, IncrDecr, SymbolName, Dereference, LiteralValue
from ..plyparse import VarDef, Register, IncrDecr, SymbolName, Dereference, LiteralValue, scoped_name
from ..datatypes import VarType, DataType, REGISTER_BYTES
from . import CodeError, preserving_registers, to_hex, Context, scoped_name
from . import CodeError, preserving_registers, to_hex, Context
def generate_incrdecr(ctx: Context) -> None:

View File

@ -36,7 +36,7 @@ class Optimizer:
# @todo expression optimization: reduce expression nesting / flattening of parenthesis
# @todo expression optimization: simplify logical expression when a term makes it always true or false
# @todo expression optimization: optimize some simple multiplications into shifts (A*=8 -> A<<3)
self.create_aug_assignments()
# @todo expression optimization: create augmented assignment from assignment that only refers to its lvalue (A=A+10, A=4*A, ...)
self.optimize_assignments()
self.remove_superfluous_assignments()
# @todo optimize addition with self into shift 1 (A+=A -> A<<=1)
@ -132,39 +132,6 @@ class Optimizer:
raise TypeError("same_target called with invalid type(s)", node1, node2)
return False
@no_type_check
def create_aug_assignments(self) -> None:
# create augmented assignments from regular assignment that only refers to the lvalue
# A=A+10, A=10+A -> A+=10, A=A*4, A=4*A -> A*=4, etc
for assignment in self.module.all_nodes(Assignment):
if len(assignment.left.nodes) > 1:
continue
if not isinstance(assignment.right, ExpressionWithOperator) or assignment.right.unary:
continue
expr = assignment.right
if expr.operator in ('-', '/', '//', '**', '<<', '>>', '&'): # non-associative operators
if isinstance(expr.right, (LiteralValue, SymbolName)) and self._same_target(assignment.left, expr.left):
num_val = expr.right.const_value()
operator = expr.operator + '='
aug_assign = self._make_aug_assign(assignment, assignment.left.nodes[0], num_val, operator)
assignment.my_scope().replace_node(assignment, aug_assign)
self.optimizations_performed = True
continue
if expr.operator not in ('+', '*', '|', '^'): # associative operators
continue
if isinstance(expr.right, (LiteralValue, SymbolName)) and self._same_target(assignment.left, expr.left):
num_val = expr.right.const_value()
operator = expr.operator + '='
aug_assign = self._make_aug_assign(assignment, assignment.left.nodes[0], num_val, operator)
assignment.my_scope().replace_node(assignment, aug_assign)
self.optimizations_performed = True
elif isinstance(expr.left, (LiteralValue, SymbolName)) and self._same_target(assignment.left, expr.right):
num_val = expr.left.const_value()
operator = expr.operator + '='
aug_assign = self._make_aug_assign(assignment, assignment.left.nodes[0], num_val, operator)
assignment.my_scope().replace_node(assignment, aug_assign)
self.optimizations_performed = True
def remove_superfluous_assignments(self) -> None:
# remove consecutive assignment statements to the same target, only keep the last value (only if its a constant!)
# this is NOT done for memory mapped variables because these often represent a volatile register of some sort!

View File

@ -70,14 +70,12 @@ class UndefinedSymbolError(LookupError):
start = "start"
@attr.s(repr=False, cmp=False, slots=True)
class AstNode:
# all ast nodes have: sourceref, parent, and nodes (=list of zero or more sub-nodes)
__slots__ = ["sourceref", "parent", "nodes"]
def __init__(self, sourceref: SourceRef) -> None:
self.sourceref = sourceref
self.parent = None # type: AstNode # will be hooked up later
self.nodes = [] # type: List[AstNode]
sourceref = attr.ib(type=SourceRef, init=True)
parent = attr.ib(type='AstNode', init=False, default=None) # will be hooked up later
nodes = attr.ib(type=List['AstNode'], init=False, default=attr.Factory(list))
@property
def lineref(self) -> str:
@ -139,7 +137,7 @@ class Directive(AstNode):
@attr.s(cmp=False, slots=True, repr=False)
class Scope(AstNode):
# has zero or more subnodes
level = attr.ib(type=str, init=True)
level = attr.ib(type=str, init=True) # type: ignore
nodes = attr.ib(type=list, init=True) # requires nodes in __init__
symbols = attr.ib(init=False)
name = attr.ib(init=False) # will be set by enclosing block, or subroutine etc.
@ -400,20 +398,20 @@ class Register(Expression):
@attr.s(cmp=False)
class PreserveRegs(AstNode):
registers = attr.ib(type=str)
registers = attr.ib(type=str) # type: ignore
# no subnodes.
@attr.s(cmp=False, repr=False)
class InlineAssembly(AstNode):
# no subnodes.
assembly = attr.ib(type=str)
assembly = attr.ib(type=str) # type: ignore
@attr.s(cmp=False, slots=True)
class DatatypeNode(AstNode):
# no subnodes.
name = attr.ib(type=str)
name = attr.ib(type=str) # type: ignore
dimensions = attr.ib(type=list, default=None, validator=dimensions_validator) # if set, 1 or more dimensions (ints)
def to_enum(self):
@ -436,14 +434,14 @@ class BuiltinFunction(AstNode):
# This is a pseudo-node that will be artificially injected in the top-most scope,
# to represent all supported built-in functions or math-functions.
# No child nodes.
name = attr.ib(type=str)
name = attr.ib(type=str) # type: ignore
func = attr.ib(type=Callable)
@attr.s(cmp=False, repr=False)
class Subroutine(AstNode):
# one subnode: the Scope.
name = attr.ib(type=str)
name = attr.ib(type=str) # type: ignore
param_spec = attr.ib(type=list)
result_spec = attr.ib(type=list)
address = attr.ib(type=int, default=None, validator=validate_address)
@ -552,7 +550,7 @@ class IncrDecr(AstNode):
# increment or decrement something by a small CONSTANT value (1..255)
# larger values will be treated/converted as an augmented assignment += or -=.
# one subnode: target (Register, SymbolName, or Dereference).
operator = attr.ib(type=str, validator=attr.validators.in_(["++", "--"]))
operator = attr.ib(type=str, validator=attr.validators.in_(["++", "--"])) # type: ignore
howmuch = attr.ib(default=1)
@property
@ -730,7 +728,7 @@ class CallArgument(AstNode):
@attr.s(cmp=False)
class CallArguments(AstNode):
# subnodes are zero or more subroutine call arguments (CallArgument)
nodes = attr.ib(type=list, init=True) # requires nodes in __init__
nodes = attr.ib(type=list, init=True) # type: ignore # requires nodes in __init__
@attr.s(cmp=False, repr=False)
@ -772,7 +770,7 @@ class SubCall(Expression):
@attr.s(cmp=False, slots=True, repr=False)
class VarDef(AstNode):
# zero or one subnode: value (Expression).
name = attr.ib(type=str)
name = attr.ib(type=str) # type: ignore
vartype = attr.ib()
datatype = attr.ib()
size = attr.ib(type=list, default=None)
@ -872,7 +870,7 @@ class Assignment(AstNode):
@attr.s(cmp=False, slots=True, repr=False)
class AugAssignment(AstNode):
# has two subnodes: left (=Register, SymbolName, or Dereference) and right (=Expression)
operator = attr.ib(type=str)
operator = attr.ib(type=str) # type: ignore
@property
def left(self) -> Union[Register, SymbolName, Dereference]:
@ -973,6 +971,12 @@ def check_symbol_definition(name: str, scope: Scope, sref: SourceRef) -> Any:
raise ParseError(str(x), sref)
@no_type_check
def scoped_name(node_with_name: AstNode, current_scope: Scope) -> str:
node_scope = node_with_name.my_scope()
return node_with_name.name if node_scope is current_scope else node_scope.name + "." + node_with_name.name
# ----------------- PLY parser definition follows ----------------------
def p_start(p):

View File

@ -7,15 +7,14 @@
start:
counter ++
main.counter ++
; @
todo float augassign
; @todo float augassign
flt += 1000.1
flt *= 2.34
flt *= flt
;[border] &= 2 ; @todo augassign on dereference
flt = flt+ 1 ; @todo optimize into augassign
XY*=3 ; @todo operator
XY=XY/0 ; @todo zerodiv (during expression to code generation) @todo operator
XY=XY//0 ; @todo zerodiv (during expression to code generation) @todo operator