fixed a bunch of issues

This commit is contained in:
Irmen de Jong 2018-01-15 00:20:36 +01:00
parent 10d0dbe80b
commit afc4ba8ff0
18 changed files with 251 additions and 120 deletions

View File

@ -13,7 +13,7 @@ from typing import Optional, Tuple, Set, Dict, List, Any, no_type_check
import attr
from .plyparse import parse_file, ParseError, Module, Directive, Block, Subroutine, Scope, VarDef, LiteralValue, \
SubCall, Goto, Return, Assignment, InlineAssembly, Register, Expression, ProgramFormat, ZpOptions,\
SymbolName, Dereference, AddressOf, IncrDecr, TargetRegisters
SymbolName, Dereference, AddressOf, IncrDecr, Label, AstNode, datatype_of, coerce_constant_value
from .plylex import SourceRef, print_bold
from .optimize import optimize
from .datatypes import DataType, VarType
@ -57,15 +57,43 @@ class PlyParser:
def semantic_check(self, module: Module) -> None:
# perform semantic analysis / checks on the syntactic parse tree we have so far
def check_last_statement_is_return(last_stmt: AstNode) -> None:
if isinstance(last_stmt, Subroutine):
return
if isinstance(last_stmt, Directive) and last_stmt.name == "noreturn":
return
if isinstance(last_stmt, InlineAssembly):
for line in reversed(last_stmt.assembly.splitlines()):
line = line.strip()
if line.startswith(";"):
continue
if "jmp " in line or "jmp\t" in line or "rts" in line or "rti" in line:
return
raise ParseError("last statement in a block/subroutine must be a return or goto, "
"(or %noreturn directive to silence this error)", last_stmt.sourceref)
for block, parent in module.all_scopes():
assert isinstance(block, (Module, Block, Subroutine))
assert parent is None or isinstance(parent, (Module, Block, Subroutine))
previous_stmt = None
for stmt in block.nodes:
if isinstance(stmt, Subroutine):
# the previous statement (if any) must be a Goto or Return
if previous_stmt and not isinstance(previous_stmt, (Goto, Return, VarDef, Subroutine)):
raise ParseError("statement preceding subroutine must be a goto or return or another subroutine", stmt.sourceref)
if isinstance(previous_stmt, Subroutine):
# the statement after a subroutine can not be some random executable instruction because it could not be reached
if not isinstance(stmt, (Subroutine, Label, Directive, InlineAssembly, VarDef)):
raise ParseError("statement following a subroutine can't be runnable code, "
"at least use a label first", stmt.sourceref)
previous_stmt = stmt
if isinstance(stmt, IncrDecr):
if isinstance(stmt.target, SymbolName):
symdef = block.scope[stmt.target.name]
if isinstance(symdef, VarDef) and symdef.vartype == VarType.CONST:
raise ParseError("cannot modify a constant", stmt.sourceref)
if parent and block.name != "ZP" and not isinstance(stmt, (Return, Goto)):
check_last_statement_is_return(stmt)
def check_and_merge_zeropages(self, module: Module) -> None:
# merge all ZP blocks into one
@ -122,6 +150,15 @@ class PlyParser:
raise
except Exception as x:
self.handle_internal_error(x, "process_expressions of node {} in block {}".format(node, block.name))
if isinstance(node, IncrDecr) and node.howmuch not in (0, 1):
_, node.howmuch = coerce_constant_value(datatype_of(node.target, block.scope), node.howmuch, node.sourceref)
elif isinstance(node, Assignment):
lvalue_types = set(datatype_of(lv, block.scope) for lv in node.left)
if len(lvalue_types) == 1:
_, node.right = coerce_constant_value(lvalue_types.pop(), node.right, node.sourceref)
else:
for lv_dt in lvalue_types:
coerce_constant_value(lv_dt, node.right, node.sourceref)
def create_multiassigns(self, module: Module) -> None:
# create multi-assign statements from nested assignments (A=B=C=5),
@ -201,7 +238,7 @@ class PlyParser:
for directive in block.scope.filter_nodes(Directive):
if directive.name == "saveregisters":
set_save_registers(block.scope, directive)
elif directive.name in ("breakpoint", "asmbinary", "asminclude"):
elif directive.name in ("breakpoint", "asmbinary", "asminclude", "noreturn"):
continue
else:
raise NotImplementedError(directive.name)
@ -211,7 +248,7 @@ class PlyParser:
for directive in block.scope.filter_nodes(Directive):
if directive.name == "saveregisters":
set_save_registers(block.scope, directive)
elif directive.name in ("breakpoint", "asmbinary", "asminclude"):
elif directive.name in ("breakpoint", "asmbinary", "asminclude", "noreturn"):
continue
else:
raise NotImplementedError(directive.name)
@ -326,7 +363,7 @@ class PlyParser:
# check module-level directives
imports = set() # type: Set[str]
for directive in node.scope.filter_nodes(Directive):
if directive.name not in {"output", "zp", "address", "import", "saveregisters"}:
if directive.name not in {"output", "zp", "address", "import", "saveregisters", "noreturn"}:
raise ParseError("invalid directive in module", directive.sourceref)
if directive.name == "import":
if imports & set(directive.args):
@ -339,7 +376,7 @@ class PlyParser:
continue
for sub_node in node.scope.nodes:
if isinstance(sub_node, Directive):
if sub_node.name not in {"asmbinary", "asminclude", "breakpoint", "saveregisters"}:
if sub_node.name not in {"asmbinary", "asminclude", "breakpoint", "saveregisters", "noreturn"}:
raise ParseError("invalid directive in " + node.__class__.__name__.lower(), sub_node.sourceref)
if sub_node.name == "saveregisters" and not first_node:
raise ParseError("saveregisters directive must be the first", sub_node.sourceref)
@ -396,28 +433,30 @@ class PlyParser:
def handle_parse_error(self, exc: ParseError) -> None:
self.parse_errors += 1
if sys.stderr.isatty():
print("\x1b[1m", file=sys.stderr)
out = sys.stdout
if out.isatty():
print("\x1b[1m", file=out)
if self.parsing_import:
print("Error (in imported file):", str(exc), file=sys.stderr)
print("Error (in imported file):", str(exc), file=out)
else:
print("Error:", str(exc), file=sys.stderr)
print("Error:", str(exc), file=out)
sourcetext = linecache.getline(exc.sourceref.file, exc.sourceref.line).rstrip()
if sourcetext:
print(" " + sourcetext.expandtabs(8), file=sys.stderr)
print(" " + sourcetext.expandtabs(8), file=out)
if exc.sourceref.column:
print(' ' * (1+exc.sourceref.column) + '^', file=sys.stderr)
if sys.stderr.isatty():
print("\x1b[0m", file=sys.stderr, end="", flush=True)
print(' ' * (1+exc.sourceref.column) + '^', file=out)
if out.isatty():
print("\x1b[0m", file=out, end="", flush=True)
def handle_internal_error(self, exc: Exception, msg: str="") -> None:
if sys.stderr.isatty():
print("\x1b[1m", file=sys.stderr)
print("\nERROR: internal parser error: ", exc, file=sys.stderr)
out = sys.stdout
if out.isatty():
print("\x1b[1m", file=out)
print("\nERROR: internal parser error: ", exc, file=out)
if msg:
print(" Message:", msg, end="\n\n")
if sys.stderr.isatty():
print("\x1b[0m", file=sys.stderr, end="", flush=True)
if out.isatty():
print("\x1b[0m", file=out, end="", flush=True)
raise exc

View File

@ -67,35 +67,6 @@ FLOAT_MAX_POSITIVE = 1.7014118345e+38
FLOAT_MAX_NEGATIVE = -1.7014118345e+38
def coerce_value(datatype: DataType, value: Union[int, float, str], sourceref: SourceRef=None) -> Tuple[bool, Union[int, float, str]]:
# if we're a BYTE type, and the value is a single character, convert it to the numeric value
def verify_bounds(value: Union[int, float, str]) -> None:
# if the value is out of bounds, raise an overflow exception
if isinstance(value, (int, float)):
if datatype == DataType.BYTE and not (0 <= value <= 0xff): # type: ignore
raise OverflowError("value out of range for byte: " + str(value))
if datatype == DataType.WORD and not (0 <= value <= 0xffff): # type: ignore
raise OverflowError("value out of range for word: " + str(value))
if datatype == DataType.FLOAT and not (FLOAT_MAX_NEGATIVE <= value <= FLOAT_MAX_POSITIVE): # type: ignore
raise OverflowError("value out of range for float: " + str(value))
if datatype in (DataType.BYTE, DataType.WORD, DataType.FLOAT):
if not isinstance(value, (int, float)):
raise TypeError("cannot assign '{:s}' to {:s}".format(type(value).__name__, datatype.name.lower()))
if datatype in (DataType.BYTE, DataType.BYTEARRAY, DataType.MATRIX) and isinstance(value, str):
if len(value) == 1:
return True, char_to_bytevalue(value)
# if we're an integer value and the passed value is float, truncate it (and give a warning)
if datatype in (DataType.BYTE, DataType.WORD, DataType.MATRIX) and isinstance(value, float):
frac = math.modf(value)
if frac != 0:
print_warning("float value truncated ({} to datatype {})".format(value, datatype.name), sourceref=sourceref)
value = int(value)
verify_bounds(value)
return True, value
verify_bounds(value)
return False, value
def char_to_bytevalue(character: str, petscii: bool=True) -> int:
assert len(character) == 1
if petscii:

View File

@ -8,21 +8,6 @@ Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
from typing import Callable
from ..plyparse import AstNode, Scope, VarDef, Dereference, Register, TargetRegisters,\
LiteralValue, Assignment, AugAssignment
from ..datatypes import DataType
from ..plyparse import SymbolName
def datatype_of(assignmenttarget: AstNode, scope: Scope) -> DataType:
if isinstance(assignmenttarget, (VarDef, Dereference, Register)):
return assignmenttarget.datatype
elif isinstance(assignmenttarget, SymbolName):
symdef = scope[assignmenttarget.name]
if isinstance(symdef, VarDef):
return symdef.datatype
elif isinstance(assignmenttarget, TargetRegisters):
if len(assignmenttarget.registers) == 1:
return datatype_of(assignmenttarget.registers[0], scope)
raise TypeError("cannot determine datatype", assignmenttarget)
def generate_assignment(out: Callable, stmt: Assignment) -> None:

View File

@ -117,7 +117,7 @@ class AssemblyGenerator:
out("\vcld")
out("\vjmp _il65_restore_zeropage\n")
# include the assembly code for the save/restore zeropage routines
zprestorefile = os.path.join(os.path.split(__file__)[0], "lib", "restorezp.asm")
zprestorefile = os.path.join(os.path.split(__file__)[0], "../lib", "restorezp.asm")
with open(zprestorefile, "rU") as f:
for line in f.readlines():
out(line.rstrip("\n"))

View File

@ -1,15 +1,16 @@
"""
Programming Language for 6502/6510 microprocessors, codename 'Sick'
This is the code generator for the in-place incr and decr instructions.
Incrementing or decrementing variables by 1 (or another constant amount)
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 typing import Callable
from ..plyparse import Scope, VarType, VarDef, Register, TargetRegisters, IncrDecr, SymbolName, Dereference
from ..plyparse import Scope, VarType, VarDef, Register, IncrDecr, SymbolName, Dereference, datatype_of
from ..datatypes import DataType, REGISTER_BYTES
from . import CodeError, to_hex, preserving_registers
from .assignment import datatype_of
from . import CodeError, preserving_registers
def generate_incrdecr(out: Callable, stmt: IncrDecr, scope: Scope) -> None:
@ -190,7 +191,7 @@ def generate_incrdecr(out: Callable, stmt: IncrDecr, scope: Scope) -> None:
out("\vjsr c64flt.float_add_one")
else:
out("\vjsr c64flt.float_sub_one")
elif stmt.value.name: # XXX
elif NOTYETIMPLEMENTED: # XXX for the float += otherfloat cases
with preserving_registers({'A', 'X', 'Y'}, scope, out, loads_a_within=True):
out("\vlda #<" + stmt.value.name)
out("\vsta c64.SCRATCH_ZPWORD1")

View File

@ -259,7 +259,7 @@ sub init_system () -> (?) {
}
}
%noreturn
} ; ------ end of block c64
@ -442,6 +442,8 @@ sub float_sub_SW1_from_XY (mflt: XY) -> (?) {
}
}
%noreturn
} ; ------ end of block c64flt
@ -1029,6 +1031,7 @@ sub input_chars (buffer: AX) -> (A?, Y) {
}
}
%noreturn
} ; ---- end block c64scr

View File

@ -168,4 +168,6 @@ _done rts
}
%noreturn
}

View File

@ -5,7 +5,8 @@ This is the optimizer that applies various optimizations to the parse tree.
Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
"""
from .plyparse import Module, Subroutine, Block, Directive, Assignment, AugAssignment, Goto, Expression, IncrDecr
from .plyparse import Module, Subroutine, Block, Directive, Assignment, AugAssignment, Goto, Expression, IncrDecr,\
datatype_of, coerce_constant_value
from .plylex import print_warning, print_bold
@ -21,6 +22,7 @@ class Optimizer:
self.optimize_multiassigns()
self.remove_unused_subroutines()
self.optimize_compare_with_zero()
# @todo join multiple incr/decr of same var into one (if value stays < 256)
self.remove_empty_blocks()
def optimize_assignments(self):
@ -47,8 +49,11 @@ class Optimizer:
new_stmt = Assignment(left=[assignment.left], right=0, sourceref=assignment.sourceref)
block.scope.replace_node(assignment, new_stmt)
if assignment.operator in ("+=", "-=") and 0 < assignment.right < 256:
howmuch = assignment.right
if howmuch not in (0, 1):
_, howmuch = coerce_constant_value(datatype_of(assignment.left, block.scope), howmuch, assignment.sourceref)
new_stmt = IncrDecr(target=assignment.left, operator="++" if assignment.operator == "+=" else "--",
howmuch=assignment.right, sourceref=assignment.sourceref)
howmuch=howmuch, sourceref=assignment.sourceref)
block.scope.replace_node(assignment, new_stmt)
def combine_assignments_into_multi(self):

View File

@ -321,7 +321,7 @@ def t_error(t):
if hasattr(t.lexer, "error_function"):
t.lexer.error_function(sref, "illegal character '{:s}'", t.value[0])
else:
print("{}: illegal character '{:s}'".format(sref, t.value[0]), file=sys.stderr)
print("{}: illegal character '{:s}'".format(sref, t.value[0]))
t.lexer.skip(1)
@ -332,7 +332,7 @@ def custom_error(t, message):
if hasattr(t.lexer, "error_function"):
t.lexer.error_function(sref, message)
else:
print(sref, message, file=sys.stderr)
print(sref, message)
t.lexer.skip(1)

View File

@ -13,8 +13,9 @@ from collections import defaultdict
from typing import Union, Generator, Tuple, List, Optional, Dict, Any, Iterable
import attr
from ply.yacc import yacc
from .plylex import SourceRef, tokens, lexer, find_tok_column
from .datatypes import DataType, VarType, coerce_value, REGISTER_SYMBOLS, REGISTER_BYTES, REGISTER_WORDS
from .plylex import SourceRef, tokens, lexer, find_tok_column, print_warning
from .datatypes import DataType, VarType, REGISTER_SYMBOLS, REGISTER_BYTES, REGISTER_WORDS, \
char_to_bytevalue, FLOAT_MAX_NEGATIVE, FLOAT_MAX_POSITIVE
class ProgramFormat(enum.Enum):
@ -293,6 +294,8 @@ class Register(AstNode):
self.datatype = DataType.BYTE
elif self.name in REGISTER_WORDS:
self.datatype = DataType.WORD
else:
self.datatype = None # register 'SC' etc.
def __hash__(self) -> int:
return hash(self.name)
@ -359,21 +362,21 @@ class Return(AstNode):
self.value_A = process_expression(self.value_A, scope, self.sourceref)
if isinstance(self.value_A, (int, float, str, bool)):
try:
_, self.value_A = coerce_value(DataType.BYTE, self.value_A, self.sourceref)
_, self.value_A = coerce_constant_value(DataType.BYTE, self.value_A, self.sourceref)
except (OverflowError, TypeError) as x:
raise ParseError("first value (A): " + str(x), self.sourceref) from None
if self.value_X is not None:
self.value_X = process_expression(self.value_X, scope, self.sourceref)
if isinstance(self.value_X, (int, float, str, bool)):
try:
_, self.value_X = coerce_value(DataType.BYTE, self.value_X, self.sourceref)
_, self.value_X = coerce_constant_value(DataType.BYTE, self.value_X, self.sourceref)
except (OverflowError, TypeError) as x:
raise ParseError("second value (X): " + str(x), self.sourceref) from None
if self.value_Y is not None:
self.value_Y = process_expression(self.value_Y, scope, self.sourceref)
if isinstance(self.value_Y, (int, float, str, bool)):
try:
_, self.value_Y = coerce_value(DataType.BYTE, self.value_Y, self.sourceref)
_, self.value_Y = coerce_constant_value(DataType.BYTE, self.value_Y, self.sourceref)
except (OverflowError, TypeError) as x:
raise ParseError("third value (Y): " + str(x), self.sourceref) from None
@ -444,7 +447,7 @@ class VarDef(AstNode):
assert not isinstance(self.value, Expression), "processed expression for vardef should reduce to a constant value"
if self.vartype in (VarType.CONST, VarType.VAR):
try:
_, self.value = coerce_value(self.datatype, self.value, self.sourceref)
_, self.value = coerce_constant_value(self.datatype, self.value, self.sourceref)
except OverflowError as x:
raise ParseError(str(x), self.sourceref) from None
except TypeError as x:
@ -538,7 +541,7 @@ class AddressOf(AstNode):
@attr.s(cmp=False, repr=False)
class IncrDecr(AstNode):
# increment or decrement something by a constant value (1 or more)
# increment or decrement something by a CONSTANT value (1 or more)
target = attr.ib()
operator = attr.ib(type=str, validator=attr.validators.in_(["++", "--"]))
howmuch = attr.ib(default=1)
@ -616,6 +619,51 @@ class Expression(AstNode):
print(tree(self, 0))
def datatype_of(assignmenttarget: AstNode, scope: Scope) -> DataType:
# tries to determine the DataType of an assignment target node
if isinstance(assignmenttarget, (VarDef, Dereference, Register)):
return assignmenttarget.datatype
elif isinstance(assignmenttarget, SymbolName):
symdef = scope[assignmenttarget.name]
if isinstance(symdef, VarDef):
return symdef.datatype
elif isinstance(assignmenttarget, TargetRegisters):
if len(assignmenttarget.registers) == 1:
return datatype_of(assignmenttarget.registers[0], scope)
raise TypeError("cannot determine datatype", assignmenttarget)
def coerce_constant_value(datatype: DataType, value: Union[int, float, str],
sourceref: SourceRef=None) -> Tuple[bool, Union[int, float, str]]:
# if we're a BYTE type, and the value is a single character, convert it to the numeric value
def verify_bounds(value: Union[int, float, str]) -> None:
# if the value is out of bounds, raise an overflow exception
if isinstance(value, (int, float)):
if datatype == DataType.BYTE and not (0 <= value <= 0xff): # type: ignore
raise OverflowError("value out of range for byte: " + str(value))
if datatype == DataType.WORD and not (0 <= value <= 0xffff): # type: ignore
raise OverflowError("value out of range for word: " + str(value))
if datatype == DataType.FLOAT and not (FLOAT_MAX_NEGATIVE <= value <= FLOAT_MAX_POSITIVE): # type: ignore
raise OverflowError("value out of range for float: " + str(value))
if datatype in (DataType.BYTE, DataType.WORD, DataType.FLOAT):
if not isinstance(value, (int, float)):
raise TypeError("cannot assign '{:s}' to {:s}".format(type(value).__name__, datatype.name.lower()))
if datatype in (DataType.BYTE, DataType.BYTEARRAY, DataType.MATRIX) and isinstance(value, str):
if len(value) == 1:
return True, char_to_bytevalue(value)
# if we're an integer value and the passed value is float, truncate it (and give a warning)
if datatype in (DataType.BYTE, DataType.WORD, DataType.MATRIX) and isinstance(value, float):
frac = math.modf(value)
if frac != 0:
print_warning("float value truncated ({} to datatype {})".format(value, datatype.name), sourceref=sourceref)
value = int(value)
verify_bounds(value)
return True, value
if isinstance(value, (int, float)):
verify_bounds(value)
return False, value
def process_expression(value: Any, scope: Scope, sourceref: SourceRef) -> Any:
# process/simplify all expressions (constant folding etc)
if isinstance(value, AstNode):

View File

@ -627,3 +627,13 @@ and SPRITES (24x21 monochrome or 12x21 multicolor = 63 bytes)
A = X * Y
A /= Y
A = Y / Y
Troubleshooting
---------------
Getting assembler error about undefined symbols such as ``not defined 'c64flt'``?
This happens when your program uses floating point values, and you forgot to import the ``c64lib``.
If you use floating points, the program will need routines from that library.
Fix it by adding an ``%import c64lib``.

View File

@ -1,6 +1,13 @@
from il65.plylex import lexer, tokens, find_tok_column, literals, reserved, SourceRef
from il65.plyparse import parser, TokenFilter, Module, Subroutine, Block, Return, Scope, \
VarDef, Expression, LiteralValue, Label, SubCall, CallTarget, SymbolName
VarDef, Expression, LiteralValue, Label, SubCall, CallTarget, SymbolName, Dereference
from il65.datatypes import DataType
def lexer_error(sourceref: SourceRef, fmtstring: str, *args: str) -> None:
print("ERROR: {}: {}".format(sourceref, fmtstring.format(*args)))
lexer.error_function = lexer_error
def test_lexer_definitions():
@ -184,10 +191,10 @@ def test_parser_2():
test_source_3 = """
~ {
goto.XY = 5
AX.text = 5
[$c000.word] = 5
[AX.word] = 5
[$c000 .byte] = 5
[AX .word] = 5
[AX .float] = 5
}
"""
@ -202,7 +209,27 @@ def test_typespec():
assert assignment2.right.value == 5
assert assignment3.right.value == 5
assert assignment4.right.value == 5
print("A1", assignment1.left)
print("A2", assignment2.left)
print("A3", assignment3.left)
print("A4", assignment4.left)
assert len(assignment1.left) == 1
assert len(assignment2.left) == 1
assert len(assignment3.left) == 1
assert len(assignment4.left) == 1
t1 = assignment1.left[0]
t2 = assignment2.left[0]
t3 = assignment3.left[0]
t4 = assignment4.left[0]
assert isinstance(t1, Dereference)
assert isinstance(t2, Dereference)
assert isinstance(t3, Dereference)
assert isinstance(t4, Dereference)
assert t1.location == 0xc000
assert t2.location == 0xc000
assert t3.location == "AX"
assert t4.location == "AX"
assert t1.datatype == DataType.WORD
assert t2.datatype == DataType.BYTE
assert t3.datatype == DataType.WORD
assert t4.datatype == DataType.FLOAT
assert t1.size is None
assert t2.size is None
assert t3.size is None
assert t4.size is None

View File

@ -141,6 +141,8 @@ bar: goto $c000
constw()
sub1()
main.start()
return
}

View File

@ -36,6 +36,7 @@
var foovar1
memory foomem1 = $f0f0
const fooconst = 1.234
return
}
@ -152,7 +153,8 @@ start:
A = 0
A = '@'
A = 1.2345
A = true
A=X=Y= true
A=XY= true
A = false
A = 255
A = X
@ -308,4 +310,5 @@ start:
[$c000.word] = "another" ; must reuse string
[$c100.word] = "text-immediate" ; must reuse string
[$c200.word] = "" ; must reuse string
return
}

View File

@ -295,7 +295,7 @@ max:
initfloat2 = initword2
initfloat1 = uninitfloat
initfloat1 = initfloat2
%noreturn
}
@ -404,6 +404,7 @@ bar:
constw()
sub1()
main.start()
%noreturn
}
~ blockdtypes2 {
@ -648,7 +649,7 @@ max:
initfloat2 = initword2
initfloat1 = uninitfloat
initfloat1 = initfloat2
%noreturn
}
@ -757,6 +758,7 @@ bar:
constw()
sub1()
main.start()
%noreturn
}
~ blockdtypes3 {
@ -1001,7 +1003,7 @@ max:
initfloat2 = initword2
initfloat1 = uninitfloat
initfloat1 = initfloat2
%noreturn
}
@ -1110,6 +1112,7 @@ bar:
constw()
sub1()
main.start()
%noreturn
}
~ blockdtypes4 {
@ -1354,7 +1357,7 @@ max:
initfloat2 = initword2
initfloat1 = uninitfloat
initfloat1 = initfloat2
%noreturn
}
@ -1463,6 +1466,7 @@ bar:
constw()
sub1()
main.start()
%noreturn
}
~ blockdtypes5 {
@ -1707,7 +1711,7 @@ max:
initfloat2 = initword2
initfloat1 = uninitfloat
initfloat1 = initfloat2
%noreturn
}
@ -1816,6 +1820,7 @@ bar:
constw()
sub1()
main.start()
%noreturn
}
~ blockdtypes6 {
@ -2060,7 +2065,7 @@ max:
initfloat2 = initword2
initfloat1 = uninitfloat
initfloat1 = initfloat2
%noreturn
}
@ -2169,6 +2174,7 @@ bar:
constw()
sub1()
main.start()
%noreturn
}
~ blockdtypes7 {
@ -2413,7 +2419,7 @@ max:
initfloat2 = initword2
initfloat1 = uninitfloat
initfloat1 = initfloat2
%noreturn
}
@ -2522,6 +2528,7 @@ bar:
constw()
sub1()
main.start()
%noreturn
}
~ blockdtypes8 {
@ -2766,7 +2773,7 @@ max:
initfloat2 = initword2
initfloat1 = uninitfloat
initfloat1 = initfloat2
%noreturn
}
@ -2875,6 +2882,7 @@ bar:
constw()
sub1()
main.start()
%noreturn
}
~ blockdtypes9 {
@ -3119,7 +3127,7 @@ max:
initfloat2 = initword2
initfloat1 = uninitfloat
initfloat1 = initfloat2
%noreturn
}
@ -3228,6 +3236,7 @@ bar:
constw()
sub1()
main.start()
%noreturn
}
~ blockdtypes10 {
@ -3472,7 +3481,7 @@ max:
initfloat2 = initword2
initfloat1 = uninitfloat
initfloat1 = initfloat2
%noreturn
}
@ -3581,6 +3590,7 @@ bar:
constw()
sub1()
main.start()
%noreturn
}
~ blockdtypes11 {
@ -3825,7 +3835,7 @@ max:
initfloat2 = initword2
initfloat1 = uninitfloat
initfloat1 = initfloat2
%noreturn
}
@ -3934,6 +3944,7 @@ bar:
constw()
sub1()
main.start()
%noreturn
}
~ blockdtypes12 {
@ -4178,7 +4189,7 @@ max:
initfloat2 = initword2
initfloat1 = uninitfloat
initfloat1 = initfloat2
%noreturn
}
@ -4287,6 +4298,7 @@ bar:
constw()
sub1()
main.start()
%noreturn
}
~ blockdtypes13 {
@ -4531,7 +4543,7 @@ max:
initfloat2 = initword2
initfloat1 = uninitfloat
initfloat1 = initfloat2
%noreturn
}
@ -4640,6 +4652,7 @@ bar:
constw()
sub1()
main.start()
%noreturn
}
~ blockdtypes14 {
@ -4884,7 +4897,7 @@ max:
initfloat2 = initword2
initfloat1 = uninitfloat
initfloat1 = initfloat2
%noreturn
}
@ -4993,6 +5006,7 @@ bar:
constw()
sub1()
main.start()
%noreturn
}
~ blockdtypes15 {
@ -5237,7 +5251,7 @@ max:
initfloat2 = initword2
initfloat1 = uninitfloat
initfloat1 = initfloat2
%noreturn
}
@ -5346,6 +5360,7 @@ bar:
constw()
sub1()
main.start()
%noreturn
}
~ blockdtypes16 {
@ -5590,7 +5605,7 @@ max:
initfloat2 = initword2
initfloat1 = uninitfloat
initfloat1 = initfloat2
%noreturn
}
@ -5699,6 +5714,7 @@ bar:
constw()
sub1()
main.start()
%noreturn
}
~ blockdtypes17 {
@ -5943,7 +5959,7 @@ max:
initfloat2 = initword2
initfloat1 = uninitfloat
initfloat1 = initfloat2
%noreturn
}
@ -6052,6 +6068,7 @@ bar:
constw()
sub1()
main.start()
%noreturn
}
~ blockdtypes18 {
@ -6296,7 +6313,7 @@ max:
initfloat2 = initword2
initfloat1 = uninitfloat
initfloat1 = initfloat2
%noreturn
}
@ -6405,6 +6422,7 @@ bar:
constw()
sub1()
main.start()
%noreturn
}
~ blockdtypes19 {
@ -6649,7 +6667,7 @@ max:
initfloat2 = initword2
initfloat1 = uninitfloat
initfloat1 = initfloat2
%noreturn
}
@ -6758,6 +6776,7 @@ bar:
constw()
sub1()
main.start()
%noreturn
}
~ blockdtypes20 {
@ -7002,7 +7021,7 @@ max:
initfloat2 = initword2
initfloat1 = uninitfloat
initfloat1 = initfloat2
%noreturn
}
@ -7111,5 +7130,6 @@ bar:
constw()
sub1()
main.start()
%noreturn
}

View File

@ -117,6 +117,7 @@ somelabel1222:
const red = 2
const .word border2 = $d020
const .word screen2 = $d021
return
}
~ block3 {

View File

@ -22,4 +22,6 @@ start:
;%asmbinary " included.binary 234 "
;%asmbinary " included.binary", $40
%asmbinary "included.binary", $40, $200
return
}

View File

@ -1,4 +1,5 @@
%output basic
%import c64lib
~ main {
@ -15,7 +16,7 @@
var .array(20) arr1 = $ea
var .wordarray(20) arr2 = $ea
memory border = $d020
const .word cword = 2
const .word cword = 5/3
start:
%breakpoint abc,def
@ -27,16 +28,23 @@ start:
border++
zp1_1++
zpf1++
[AX]++
[AX .byte]++
[AX .word]++
[AX .float]++
[$ccc0]++
[$ccc0 .byte]++
[$ccc0 .word]++
[$ccc0 .float]++
;[AX]++
;[AX .byte]++
;[AX .word]++
;[AX .float]++
;[$ccc0]++
;[$ccc0 .byte]++
;[$ccc0 .word]++
;[$ccc0 .float]++
A+=2
A+=3
XY+=6
XY+=222
A=222/13 ; @todo warn truncate (in assignment stmt)
XY+=666
zpf1+=1
zpf1+=2
zpf1+=2.123425425 ; @todo store as constant float with generated name, replace value node
foobar()
@ -47,8 +55,12 @@ sub foobar () -> () {
return
%breakpoint yep
; @todo check that subs/asm blocks end with return/rts
}
return
}
label2:
A++
%noreturn
}