for loops over iterables now allow different numeric loopvar types

This commit is contained in:
Irmen de Jong 2018-12-29 16:25:20 +01:00
parent b01deb2170
commit 9ddda9fcf7
7 changed files with 128 additions and 44 deletions

View File

@ -46,7 +46,7 @@
rotate_vertices(irq.global_time as float / 30.0)
c64scr.print_ub(X)
c64.CHROUT('\n')
draw_edges() ; @todo doesn't return from the loop...
draw_edges()
c64scr.print_ub(X)
c64.CHROUT('\n')
}
@ -93,7 +93,7 @@
}
; draw all edges of the object
for uword edge in edges { ; @todo invalid loop code generated? (loop doesn't end?)
for uword edge in edges {
ubyte e_from = msb(edge)
ubyte e_to = lsb(edge)

View File

@ -0,0 +1,58 @@
%import c64utils
~ main {
ubyte[3] ubarray = [11,55,222]
byte[3] barray = [-11,-22,-33]
uword[3] uwarray = [111,2222,55555]
word[3] warray = [-111,-222,-555]
float[3] farray = [1.11, 2.22, -3.33]
str text = "hello\n"
sub start() {
c64scr.print_ub(X)
c64.CHROUT('\n')
c64scr.print("loop str\n")
for ubyte c in text {
c64scr.print_ub(c)
c64.CHROUT(',')
}
c64scr.print("\nloop ub\n")
for ubyte ub in ubarray{
c64scr.print_ub(ub)
c64.CHROUT(',')
}
c64scr.print("\nloop b\n")
for byte b in barray {
c64scr.print_b(b)
c64.CHROUT(',')
}
c64scr.print("\nloop uw\n")
for uword uw in uwarray {
c64scr.print_uw(uw)
c64.CHROUT(',')
}
c64scr.print("\nloop w\n")
for word w in warray {
c64scr.print_w(w)
c64.CHROUT(',')
}
c64scr.print("\nloop f\n")
for float f in farray {
c64flt.print_f(f)
c64.CHROUT(',')
}
ending:
c64scr.print("\nending\n")
c64scr.print_ub(X)
c64.CHROUT('\n')
}
}

View File

@ -1,4 +1,5 @@
%import c64utils
%option enable_floats
~ main {
@ -6,6 +7,7 @@
byte[3] barray = [-11,-22,-33]
uword[3] uwarray = [111,2222,55555]
word[3] warray = [-111,-222,-555]
float[3] farray = [1.11, 2.22, -3.33]
str text = "hello\n"
sub start() {
@ -14,33 +16,41 @@
c64scr.print("loop str\n")
for ubyte c in text {
c64scr.print(" c ")
c64scr.print_ub(c)
c64.CHROUT('\n')
c64.CHROUT(',')
}
c64scr.print("loop ub\n")
c64scr.print("\nloop ub\n")
for ubyte ub in ubarray{
c64scr.print(" ub ")
c64scr.print_ub(ub)
c64.CHROUT('\n')
c64.CHROUT(',')
}
; c64scr.print("loop b\n") ; @todo allow signed loopvars
; for byte b in barray { ; @todo loop doesn't end because of register clobbering??
; c64scr.print(" b ")
; c64scr.print_b(b)
; c64.CHROUT('\n')
; }
c64scr.print("\nloop b\n")
for byte b in barray {
c64scr.print_b(b)
c64.CHROUT(',')
}
errorloop:
c64scr.print("loop uw\n")
for uword uw in uwarray { ; @todo loop doesn't end because of register clobbering
c64scr.print(" uw ")
c64scr.print("\nloop uw\n")
for uword uw in uwarray {
c64scr.print_uw(uw)
c64.CHROUT('\n')
c64.CHROUT(',')
}
c64scr.print("\nloop w\n")
for word w in warray {
c64scr.print_w(w)
c64.CHROUT(',')
}
c64scr.print("\nloop f\n")
for float f in farray {
c64flt.print_f(f)
c64.CHROUT(',')
}
ending:
c64scr.print("\nending\n")
c64scr.print_ub(X)

View File

@ -89,6 +89,7 @@ class AstChecker(private val namespace: INameScope,
is VarDecl->true
is InlineAssembly->true
is INameScope->true
is VariableInitializationAssignment->true
else->false
}
if(!ok) {
@ -154,15 +155,27 @@ class AstChecker(private val namespace: INameScope,
when (loopvar.datatype) {
DataType.UBYTE -> {
if(iterableDt!=DataType.UBYTE && iterableDt!=DataType.ARRAY_UB && iterableDt !in StringDatatypes)
checkResult.add(ExpressionError("byte loop variable can only loop over bytes", forLoop.position))
checkResult.add(ExpressionError("ubyte loop variable can only loop over unsigned bytes or strings", forLoop.position))
}
DataType.UWORD -> {
if(iterableDt!=DataType.UBYTE && iterableDt!=DataType.UWORD && iterableDt !in StringDatatypes &&
iterableDt !=DataType.ARRAY_UB && iterableDt!=DataType.ARRAY_UW)
checkResult.add(ExpressionError("uword loop variable can only loop over unsigned bytes, words or strings", forLoop.position))
}
DataType.BYTE -> {
if(iterableDt!=DataType.BYTE && iterableDt!=DataType.ARRAY_B)
checkResult.add(ExpressionError("byte loop variable can only loop over bytes", forLoop.position))
}
DataType.WORD -> {
if(iterableDt!=DataType.BYTE && iterableDt!=DataType.WORD &&
iterableDt !=DataType.ARRAY_B && iterableDt!=DataType.ARRAY_W)
checkResult.add(ExpressionError("word loop variable can only loop over bytes or words", forLoop.position))
}
// there's no support for a floating-point loop variable
else -> checkResult.add(ExpressionError("loop variable must be byte or word type", forLoop.position))
DataType.FLOAT -> {
if(iterableDt!=DataType.FLOAT && iterableDt != DataType.ARRAY_F)
checkResult.add(ExpressionError("float loop variable can only loop over floats", forLoop.position))
}
else -> checkResult.add(ExpressionError("loop variable must be numeric type", forLoop.position))
}
}
}
@ -477,6 +490,13 @@ class AstChecker(private val namespace: INameScope,
err("const modifier can only be used on numeric types (byte, word, float)")
}
// FLOATS
// @todo move floating point routines from c64utils into separately included file, then re-enable this check
// if(!compilerOptions.floats && decl.datatype==DataType.FLOAT && decl.type!=VarDeclType.MEMORY) {
// checkResult.add(SyntaxError("floating point used, but that is not enabled via options", decl.position))
// }
when(decl.type) {
VarDeclType.VAR, VarDeclType.CONST -> {
if (decl.value == null) {
@ -619,7 +639,7 @@ class AstChecker(private val namespace: INameScope,
override fun process(literalValue: LiteralValue): LiteralValue {
if(!compilerOptions.floats && literalValue.type==DataType.FLOAT) {
checkResult.add(SyntaxError("floating point value used, but floating point is not enabled via options", literalValue.position))
checkResult.add(SyntaxError("floating point used, but that is not enabled via options", literalValue.position))
}
val arrayspec =
if(literalValue.isArray)

View File

@ -162,23 +162,21 @@ class AstIdentifiersChecker(val heap: HeapValues) : IAstProcessor {
printWarning("writing to the X register is dangerous, because it's used as an internal pointer", forLoop.position)
} else if(forLoop.loopVar!=null) {
val varName = forLoop.loopVar.nameInSource.last()
when (forLoop.decltype) {
DataType.UBYTE, DataType.UWORD -> {
val existing = if(forLoop.body.isEmpty()) null else forLoop.body.lookup(forLoop.loopVar.nameInSource, forLoop.body.statements.first())
if(existing==null) {
// create the local scoped for loop variable itself
val vardecl = VarDecl(VarDeclType.VAR, forLoop.decltype, null, varName, null, forLoop.loopVar.position)
vardecl.linkParents(forLoop.body)
forLoop.body.statements.add(0, vardecl)
forLoop.loopVar.parent = forLoop.body // loopvar 'is defined in the body'
}
}
DataType.BYTE, DataType.WORD -> {
checkResult.add(SyntaxError("loop variables can only be unsigned byte or unsigned word", forLoop.position)) // TODO allow signed loopvars
}
null -> {}
else -> checkResult.add(SyntaxError("loop variables can only be a byte or word", forLoop.position))
if(forLoop.iterable is RangeExpr && forLoop.decltype!=null && forLoop.decltype !in setOf(DataType.UBYTE, DataType.UWORD)) {
checkResult.add(SyntaxError("loop variables over a numeric range can only be ubyte or uword", forLoop.position)) // TODO allow signed range loopvars
}
if(forLoop.decltype!=null) {
val existing = if(forLoop.body.isEmpty()) null else forLoop.body.lookup(forLoop.loopVar.nameInSource, forLoop.body.statements.first())
if(existing==null) {
// create the local scoped for loop variable itself
val vardecl = VarDecl(VarDeclType.VAR, forLoop.decltype, null, varName, null, forLoop.loopVar.position)
vardecl.linkParents(forLoop.body)
forLoop.body.statements.add(0, vardecl)
forLoop.loopVar.parent = forLoop.body // loopvar 'is defined in the body'
}
}
if(forLoop.iterable !is RangeExpr) {
val existing = if(forLoop.body.isEmpty()) null else forLoop.body.lookup(listOf(ForLoop.iteratorLoopcounterVarname), forLoop.body.statements.first())
if(existing==null) {

View File

@ -1603,21 +1603,18 @@ private class StatementTranslator(private val prog: IntermediateProgram,
}
} else {
// ok, must be a literalvalue
val iterableValue: LiteralValue
when {
loop.iterable is LiteralValue -> {
TODO("loop over literal value (move literal to auto-generated heap variable)")
}
loop.iterable is IdentifierReference -> {
val idRef = loop.iterable as IdentifierReference
val vardecl = (idRef.targetStatement(namespace) as VarDecl)
iterableValue = vardecl.value as LiteralValue
val iterableValue = vardecl.value as LiteralValue
if(!iterableValue.isIterable(namespace, heap))
throw CompilerException("loop over something that isn't iterable ${loop.iterable}")
translateForOverIterableVar(loop, loopVarDt, iterableValue)
}
loop.iterable is LiteralValue -> throw CompilerException("literal value in loop must have been moved to heap already $loop")
else -> throw CompilerException("loopvar is something strange ${loop.iterable}")
}
translateForOverIterableVar(loop, loopVarDt, iterableValue)
}
}

View File

@ -413,6 +413,7 @@ _done rts
~ c64flt {
; ---- this block contains C-64 floating point related functions ----
; @todo move to c64fp.p8 and enable float-checkin astchecker.process(decl: VarDecl) again
asmsub FREADS32 () -> clobbers(A,X,Y) -> () {