expression float consts

This commit is contained in:
Irmen de Jong 2018-02-01 23:14:12 +01:00
parent dba4dd780a
commit 43a59817bf
8 changed files with 61 additions and 78 deletions

View File

@ -42,8 +42,8 @@ class PlyParser:
self.determine_subroutine_usage(module)
self.all_parents_connected(module)
self.semantic_check(module)
self.allocate_zeropage_vars(module)
self.coerce_values(module)
self.allocate_zeropage_vars(module)
except ParseError as x:
self.handle_parse_error(x)
if self.parse_errors:
@ -73,9 +73,9 @@ class PlyParser:
def coerce_values(self, module: Module) -> None:
for node in module.all_nodes():
try:
if isinstance(node, Assignment):
pass # @todo coerce assignment
elif isinstance(node, AugAssignment):
# note: not processing regular assignments, because they can contain multiple targets of different datatype.
# this has to be dealt with anyway later, so we don't bother dealing with it here for just a special case.
if isinstance(node, AugAssignment):
if node.right.is_compile_constant():
_, node.right = coerce_constant_value(datatype_of(node.left, node.my_scope()), node.right, node.right.sourceref)
elif isinstance(node, Goto):
@ -165,6 +165,9 @@ class PlyParser:
if node.operator in ("/=", "//="):
if isinstance(node.right, LiteralValue) and node.right.value == 0:
raise ParseError("division by zero", node.right.sourceref)
elif isinstance(node, VarDef):
if node.value is not None and not node.value.is_compile_constant():
raise ParseError("variable initialization value should be a compile-time constant", node.value.sourceref)
previous_stmt = node
def check_subroutine_arguments(self, call: SubCall, subdef: Subroutine) -> None:
@ -223,7 +226,6 @@ class PlyParser:
@no_type_check
def create_multiassigns(self, module: Module) -> None:
# create multi-assign statements from nested assignments (A=B=C=5),
# @todo optimize TargetRegisters down to single Register if it's just one register.
def reduce_right(assign: Assignment) -> Assignment:
if isinstance(assign.right, Assignment):
right = reduce_right(assign.right)

View File

@ -11,7 +11,7 @@ from typing import TextIO, Callable, no_type_check
from ..plylex import print_bold
from ..plyparse import Module, Scope, ProgramFormat, Block, Directive, VarDef, Label, Subroutine, AstNode, ZpOptions, \
InlineAssembly, Return, Register, Goto, SubCall, Assignment, AugAssignment, IncrDecr, AssignmentTargets
from . import CodeError, to_hex
from . import CodeError, to_hex, to_mflpt5
from .variables import generate_block_init, generate_block_vars
from .assignment import generate_assignment, generate_aug_assignment
from .calls import generate_goto, generate_subcall
@ -174,6 +174,11 @@ class AssemblyGenerator:
self.cur_block = cur_block
out("")
out("; -- end block subroutines")
if block.scope.float_const_values:
# generate additional float constants that are used in floating point expressions
out("\n; -- float constants")
for name, value in block.scope.float_const_values.items():
out("{:s}\t\t.byte ${:02x}, ${:02x}, ${:02x}, ${:02x}, ${:02x}\t; {}".format(name, *to_mflpt5(value), value))
out("\n\v.pend\n")
@no_type_check

View File

@ -193,13 +193,12 @@ def generate_incrdecr(out: Callable, stmt: IncrDecr, scope: Scope) -> None:
out("\vjsr c64flt.float_add_one")
else:
out("\vjsr c64flt.float_sub_one")
else:
# XXX for the float += otherfloat cases
print("FLOAT INCR/DECR BY", stmt.howmuch) # XXX
elif stmt.howmuch != 0:
float_name = scope.define_float_constant(stmt.howmuch)
with preserving_registers({'A', 'X', 'Y'}, scope, out, loads_a_within=True):
# XXX out("\vlda #<" + stmt.value.name)
out("\vlda #<" + float_name)
out("\vsta c64.SCRATCH_ZPWORD1")
# XXX out("\vlda #>" + stmt.value.name)
out("\vlda #>" + float_name)
out("\vsta c64.SCRATCH_ZPWORD1+1")
out("\vldx #<" + what_str)
out("\vldy #>" + what_str)

View File

@ -67,7 +67,7 @@ def generate_block_init(out: Callable, block: Block) -> None:
out("\vsta {:s}".format(bytevar.name))
for wordvar in sorted(vars_by_datatype[DataType.WORD], key=lambda vd: vd.value):
if isinstance(wordvar.value, AddressOf):
raise CodeError("can't yet use addressof here", wordvar.sourceref) # XXX
raise CodeError("addressof is not a compile-time constant value", wordvar.sourceref)
assert isinstance(wordvar.value, LiteralValue) and type(wordvar.value.value) is int
v_hi, v_lo = divmod(wordvar.value.value, 256)
if v_hi != prev_value_a:
@ -131,7 +131,6 @@ def generate_block_vars(out: Callable, block: Block, zeropage: bool=False) -> No
_generate_string_var(out, vardef)
else:
raise CodeError("invalid const type", vardef)
# @todo float constants that are used in expressions
out("; memory mapped variables")
for vardef in vars_by_vartype.get(VarType.MEMORY, []):
# create a definition for variables at a specific place in memory (memory-mapped)

View File

@ -207,7 +207,7 @@ class Optimizer:
self.optimizations_performed = True
self.num_warnings += 1
print_warning("{}: removed statement that has no effect".format(assignment.sourceref))
if isinstance(assignment, AugAssignment):
elif isinstance(assignment, AugAssignment):
if isinstance(assignment.right, LiteralValue) and isinstance(assignment.right.value, (int, float)):
if assignment.right.value == 0:
if assignment.operator in ("+=", "-=", "|=", "<<=", ">>=", "^="):
@ -538,10 +538,12 @@ def _process_dynamic_expression(expr: Expression, sourceref: SourceRef) -> Expre
left_sourceref = expr.left.sourceref if isinstance(expr.left, AstNode) else sourceref
expr.left = _process_dynamic_expression(expr.left, left_sourceref)
expr.left.parent = expr
try:
return _process_constant_expression(expr, sourceref)
except ExpressionEvaluationError:
return expr
if expr.is_compile_constant():
try:
return _process_constant_expression(expr, sourceref)
except ExpressionEvaluationError:
pass
return expr
else:
left_sourceref = expr.left.sourceref if isinstance(expr.left, AstNode) else sourceref
expr.left = _process_dynamic_expression(expr.left, left_sourceref)
@ -549,10 +551,12 @@ def _process_dynamic_expression(expr: Expression, sourceref: SourceRef) -> Expre
right_sourceref = expr.right.sourceref if isinstance(expr.right, AstNode) else sourceref
expr.right = _process_dynamic_expression(expr.right, right_sourceref)
expr.right.parent = expr
try:
return _process_constant_expression(expr, sourceref)
except ExpressionEvaluationError:
return expr
if expr.is_compile_constant():
try:
return _process_constant_expression(expr, sourceref)
except ExpressionEvaluationError:
pass
return expr
else:
raise ParseError("expression required, not {}".format(expr.__class__.__name__), expr.sourceref)

View File

@ -123,6 +123,7 @@ class Scope(AstNode):
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.
float_const_values = attr.ib(type=dict, default=attr.Factory(dict), init=False) # floatingpoint number -> float const name
_save_registers = attr.ib(type=bool, default=None, init=False)
@property
@ -177,6 +178,13 @@ class Scope(AstNode):
f = BuiltinFunction(name=name, func=func, sourceref=self.sourceref)
self.add_node(f)
def define_float_constant(self, value: float) -> str:
if value in self.float_const_values:
return self.float_const_values[value]
name = "il65_float_const_" + str(1 + len(self.float_const_values))
self.float_const_values[name] = value
return name
def lookup(self, name: str) -> AstNode:
assert isinstance(name, str)
if '.' in name:

View File

@ -1,59 +1,25 @@
%import c64lib
~ main {
var .float flt
var .word vmemaddr1 = &flt
; var .float flt
; var bytevar = 22 + 23 ; @todo constant-fold before semantic check
; var .float initfloat1 = -1.234e-14 ; @todo constant-fold before semantic check / fix float parse?
; var .float initfloat2 = -555.666 ; @todo constant-fold before semantic check / fix float parse?
; var .text guess = '?' * 80 ; @todo constant-fold before semantic check
const .word border = $d020
start:
; @todo float incrdecr/augassign
; flt += 0.1
; flt += 1.1
; flt += 10.1
; flt += 100.1
; flt += 1000.1
; flt *= 2.34
Y-=5
Y-=8
Y--
;flt+=2 ; @todo implement on float
;flt+=2
;flt+=2
;flt+=2
;flt+=2
X=0
X+=5
X=X+22
X=33+X
X-=3
X=X-4
X=X-5
X=8*X
X=24|X
X=X^66
X+=250
X=5+2+3+4
X+=5+2+3+4
X-=100
X-=50
X-=5
Y=Y
X=X
A=A
X++
X--
X+=1
X+=1 ; @todo? (optimize) join with previous
X+=0 ; is removed.
A+=0 ; is removed.
Y+=0 ; is removed.
X+=1 ; @todo? (optimize) join with previous
X+=1 ; @todo? (optimize) join with previous
;@todo float incrdecr/augassign
;flt += 0.1
;flt += 1.1
;flt += 10.1
;flt += 100.1
;flt += 1000.1
;flt *= 2.34
[border] ++; @todo suport incr/decr on deref constant
[$d020] ++ ; @todo suport incr/decr on deref memory
return 44
}

View File

@ -38,11 +38,11 @@ start:
%breakpoint abc,def
XY+=255
XY+=256
XY+=257
XY+=254
XY+=253
XY-=255
XY-=256
XY-=257
XY-=254
XY-=253
v3t++
v3t+=1
@ -57,7 +57,7 @@ start:
; v3t+=2.23424 ; @todo store as constant float with generated name, replace value node
; v3t+=2.23411 ; @todo store as constant float with generated name, replace value node
; v3t+=2.23411 ; @todo store as constant float with generated name, replace value node
v3t=2.23424 * v3t ; @todo store as constant float with generated name, replace value node
;v3t=2.23424 * v3t ; @todo store as constant float with generated name, replace value node
XY*=2
XY*=3
X=3 ; @todo optimize consecutive assignments
@ -78,7 +78,7 @@ start:
XY=XY/0 ; @todo zerodiv (during expression to code generation)
XY=XY//0 ; @todo zerodiv (during expression to code generation)
XY*=2.23424 ; @todo store as constant float with generated name, replace value node
XY*=2.23424 * v3t ; @todo store as constant float with generated name, replace value node
;XY*=2.23424 * v3t ; @todo store as constant float with generated name, replace value node
;v3t*=2.23424 * v3t ; @todo store as constant float with generated name, replace value node
; A++
; X--