mirror of
https://github.com/irmen/prog8.git
synced 2024-09-11 00:54:31 +00:00
expression float consts
This commit is contained in:
parent
dba4dd780a
commit
43a59817bf
@ -42,8 +42,8 @@ class PlyParser:
|
|||||||
self.determine_subroutine_usage(module)
|
self.determine_subroutine_usage(module)
|
||||||
self.all_parents_connected(module)
|
self.all_parents_connected(module)
|
||||||
self.semantic_check(module)
|
self.semantic_check(module)
|
||||||
self.allocate_zeropage_vars(module)
|
|
||||||
self.coerce_values(module)
|
self.coerce_values(module)
|
||||||
|
self.allocate_zeropage_vars(module)
|
||||||
except ParseError as x:
|
except ParseError as x:
|
||||||
self.handle_parse_error(x)
|
self.handle_parse_error(x)
|
||||||
if self.parse_errors:
|
if self.parse_errors:
|
||||||
@ -73,9 +73,9 @@ class PlyParser:
|
|||||||
def coerce_values(self, module: Module) -> None:
|
def coerce_values(self, module: Module) -> None:
|
||||||
for node in module.all_nodes():
|
for node in module.all_nodes():
|
||||||
try:
|
try:
|
||||||
if isinstance(node, Assignment):
|
# note: not processing regular assignments, because they can contain multiple targets of different datatype.
|
||||||
pass # @todo coerce assignment
|
# this has to be dealt with anyway later, so we don't bother dealing with it here for just a special case.
|
||||||
elif isinstance(node, AugAssignment):
|
if isinstance(node, AugAssignment):
|
||||||
if node.right.is_compile_constant():
|
if node.right.is_compile_constant():
|
||||||
_, node.right = coerce_constant_value(datatype_of(node.left, node.my_scope()), node.right, node.right.sourceref)
|
_, node.right = coerce_constant_value(datatype_of(node.left, node.my_scope()), node.right, node.right.sourceref)
|
||||||
elif isinstance(node, Goto):
|
elif isinstance(node, Goto):
|
||||||
@ -165,6 +165,9 @@ class PlyParser:
|
|||||||
if node.operator in ("/=", "//="):
|
if node.operator in ("/=", "//="):
|
||||||
if isinstance(node.right, LiteralValue) and node.right.value == 0:
|
if isinstance(node.right, LiteralValue) and node.right.value == 0:
|
||||||
raise ParseError("division by zero", node.right.sourceref)
|
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
|
previous_stmt = node
|
||||||
|
|
||||||
def check_subroutine_arguments(self, call: SubCall, subdef: Subroutine) -> None:
|
def check_subroutine_arguments(self, call: SubCall, subdef: Subroutine) -> None:
|
||||||
@ -223,7 +226,6 @@ class PlyParser:
|
|||||||
@no_type_check
|
@no_type_check
|
||||||
def create_multiassigns(self, module: Module) -> None:
|
def create_multiassigns(self, module: Module) -> None:
|
||||||
# create multi-assign statements from nested assignments (A=B=C=5),
|
# 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:
|
def reduce_right(assign: Assignment) -> Assignment:
|
||||||
if isinstance(assign.right, Assignment):
|
if isinstance(assign.right, Assignment):
|
||||||
right = reduce_right(assign.right)
|
right = reduce_right(assign.right)
|
||||||
|
@ -11,7 +11,7 @@ from typing import TextIO, Callable, no_type_check
|
|||||||
from ..plylex import print_bold
|
from ..plylex import print_bold
|
||||||
from ..plyparse import Module, Scope, ProgramFormat, Block, Directive, VarDef, Label, Subroutine, AstNode, ZpOptions, \
|
from ..plyparse import Module, Scope, ProgramFormat, Block, Directive, VarDef, Label, Subroutine, AstNode, ZpOptions, \
|
||||||
InlineAssembly, Return, Register, Goto, SubCall, Assignment, AugAssignment, IncrDecr, AssignmentTargets
|
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 .variables import generate_block_init, generate_block_vars
|
||||||
from .assignment import generate_assignment, generate_aug_assignment
|
from .assignment import generate_assignment, generate_aug_assignment
|
||||||
from .calls import generate_goto, generate_subcall
|
from .calls import generate_goto, generate_subcall
|
||||||
@ -174,6 +174,11 @@ class AssemblyGenerator:
|
|||||||
self.cur_block = cur_block
|
self.cur_block = cur_block
|
||||||
out("")
|
out("")
|
||||||
out("; -- end block subroutines")
|
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")
|
out("\n\v.pend\n")
|
||||||
|
|
||||||
@no_type_check
|
@no_type_check
|
||||||
|
@ -193,13 +193,12 @@ def generate_incrdecr(out: Callable, stmt: IncrDecr, scope: Scope) -> None:
|
|||||||
out("\vjsr c64flt.float_add_one")
|
out("\vjsr c64flt.float_add_one")
|
||||||
else:
|
else:
|
||||||
out("\vjsr c64flt.float_sub_one")
|
out("\vjsr c64flt.float_sub_one")
|
||||||
else:
|
elif stmt.howmuch != 0:
|
||||||
# XXX for the float += otherfloat cases
|
float_name = scope.define_float_constant(stmt.howmuch)
|
||||||
print("FLOAT INCR/DECR BY", stmt.howmuch) # XXX
|
|
||||||
with preserving_registers({'A', 'X', 'Y'}, scope, out, loads_a_within=True):
|
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")
|
out("\vsta c64.SCRATCH_ZPWORD1")
|
||||||
# XXX out("\vlda #>" + stmt.value.name)
|
out("\vlda #>" + float_name)
|
||||||
out("\vsta c64.SCRATCH_ZPWORD1+1")
|
out("\vsta c64.SCRATCH_ZPWORD1+1")
|
||||||
out("\vldx #<" + what_str)
|
out("\vldx #<" + what_str)
|
||||||
out("\vldy #>" + what_str)
|
out("\vldy #>" + what_str)
|
||||||
|
@ -67,7 +67,7 @@ def generate_block_init(out: Callable, block: Block) -> None:
|
|||||||
out("\vsta {:s}".format(bytevar.name))
|
out("\vsta {:s}".format(bytevar.name))
|
||||||
for wordvar in sorted(vars_by_datatype[DataType.WORD], key=lambda vd: vd.value):
|
for wordvar in sorted(vars_by_datatype[DataType.WORD], key=lambda vd: vd.value):
|
||||||
if isinstance(wordvar.value, AddressOf):
|
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
|
assert isinstance(wordvar.value, LiteralValue) and type(wordvar.value.value) is int
|
||||||
v_hi, v_lo = divmod(wordvar.value.value, 256)
|
v_hi, v_lo = divmod(wordvar.value.value, 256)
|
||||||
if v_hi != prev_value_a:
|
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)
|
_generate_string_var(out, vardef)
|
||||||
else:
|
else:
|
||||||
raise CodeError("invalid const type", vardef)
|
raise CodeError("invalid const type", vardef)
|
||||||
# @todo float constants that are used in expressions
|
|
||||||
out("; memory mapped variables")
|
out("; memory mapped variables")
|
||||||
for vardef in vars_by_vartype.get(VarType.MEMORY, []):
|
for vardef in vars_by_vartype.get(VarType.MEMORY, []):
|
||||||
# create a definition for variables at a specific place in memory (memory-mapped)
|
# create a definition for variables at a specific place in memory (memory-mapped)
|
||||||
|
@ -207,7 +207,7 @@ class Optimizer:
|
|||||||
self.optimizations_performed = True
|
self.optimizations_performed = True
|
||||||
self.num_warnings += 1
|
self.num_warnings += 1
|
||||||
print_warning("{}: removed statement that has no effect".format(assignment.sourceref))
|
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 isinstance(assignment.right, LiteralValue) and isinstance(assignment.right.value, (int, float)):
|
||||||
if assignment.right.value == 0:
|
if assignment.right.value == 0:
|
||||||
if assignment.operator in ("+=", "-=", "|=", "<<=", ">>=", "^="):
|
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
|
left_sourceref = expr.left.sourceref if isinstance(expr.left, AstNode) else sourceref
|
||||||
expr.left = _process_dynamic_expression(expr.left, left_sourceref)
|
expr.left = _process_dynamic_expression(expr.left, left_sourceref)
|
||||||
expr.left.parent = expr
|
expr.left.parent = expr
|
||||||
try:
|
if expr.is_compile_constant():
|
||||||
return _process_constant_expression(expr, sourceref)
|
try:
|
||||||
except ExpressionEvaluationError:
|
return _process_constant_expression(expr, sourceref)
|
||||||
return expr
|
except ExpressionEvaluationError:
|
||||||
|
pass
|
||||||
|
return expr
|
||||||
else:
|
else:
|
||||||
left_sourceref = expr.left.sourceref if isinstance(expr.left, AstNode) else sourceref
|
left_sourceref = expr.left.sourceref if isinstance(expr.left, AstNode) else sourceref
|
||||||
expr.left = _process_dynamic_expression(expr.left, left_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
|
right_sourceref = expr.right.sourceref if isinstance(expr.right, AstNode) else sourceref
|
||||||
expr.right = _process_dynamic_expression(expr.right, right_sourceref)
|
expr.right = _process_dynamic_expression(expr.right, right_sourceref)
|
||||||
expr.right.parent = expr
|
expr.right.parent = expr
|
||||||
try:
|
if expr.is_compile_constant():
|
||||||
return _process_constant_expression(expr, sourceref)
|
try:
|
||||||
except ExpressionEvaluationError:
|
return _process_constant_expression(expr, sourceref)
|
||||||
return expr
|
except ExpressionEvaluationError:
|
||||||
|
pass
|
||||||
|
return expr
|
||||||
else:
|
else:
|
||||||
raise ParseError("expression required, not {}".format(expr.__class__.__name__), expr.sourceref)
|
raise ParseError("expression required, not {}".format(expr.__class__.__name__), expr.sourceref)
|
||||||
|
|
||||||
|
@ -123,6 +123,7 @@ class Scope(AstNode):
|
|||||||
nodes = attr.ib(type=list, init=True) # requires nodes in __init__
|
nodes = attr.ib(type=list, init=True) # requires nodes in __init__
|
||||||
symbols = attr.ib(init=False)
|
symbols = attr.ib(init=False)
|
||||||
name = attr.ib(init=False) # will be set by enclosing block, or subroutine etc.
|
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)
|
_save_registers = attr.ib(type=bool, default=None, init=False)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -177,6 +178,13 @@ class Scope(AstNode):
|
|||||||
f = BuiltinFunction(name=name, func=func, sourceref=self.sourceref)
|
f = BuiltinFunction(name=name, func=func, sourceref=self.sourceref)
|
||||||
self.add_node(f)
|
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:
|
def lookup(self, name: str) -> AstNode:
|
||||||
assert isinstance(name, str)
|
assert isinstance(name, str)
|
||||||
if '.' in name:
|
if '.' in name:
|
||||||
|
66
todo.ill
66
todo.ill
@ -1,59 +1,25 @@
|
|||||||
|
%import c64lib
|
||||||
|
|
||||||
~ main {
|
~ main {
|
||||||
|
|
||||||
var .float flt
|
; var .float flt
|
||||||
var .word vmemaddr1 = &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:
|
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
|
[border] ++; @todo suport incr/decr on deref constant
|
||||||
Y-=8
|
[$d020] ++ ; @todo suport incr/decr on deref memory
|
||||||
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
|
|
||||||
|
|
||||||
return 44
|
return 44
|
||||||
}
|
}
|
||||||
|
12
todo2.ill
12
todo2.ill
@ -38,11 +38,11 @@ start:
|
|||||||
%breakpoint abc,def
|
%breakpoint abc,def
|
||||||
|
|
||||||
XY+=255
|
XY+=255
|
||||||
XY+=256
|
XY+=254
|
||||||
XY+=257
|
XY+=253
|
||||||
XY-=255
|
XY-=255
|
||||||
XY-=256
|
XY-=254
|
||||||
XY-=257
|
XY-=253
|
||||||
|
|
||||||
v3t++
|
v3t++
|
||||||
v3t+=1
|
v3t+=1
|
||||||
@ -57,7 +57,7 @@ start:
|
|||||||
; v3t+=2.23424 ; @todo store as constant float with generated name, replace value node
|
; 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.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*=2
|
||||||
XY*=3
|
XY*=3
|
||||||
X=3 ; @todo optimize consecutive assignments
|
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=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 ; @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
|
;v3t*=2.23424 * v3t ; @todo store as constant float with generated name, replace value node
|
||||||
; A++
|
; A++
|
||||||
; X--
|
; X--
|
||||||
|
Loading…
Reference in New Issue
Block a user