various for loops

This commit is contained in:
Irmen de Jong 2019-07-31 21:31:44 +02:00
parent 50aa286d3a
commit 299ea72d70
3 changed files with 182 additions and 20 deletions

View File

@ -119,10 +119,11 @@ internal class AstChecker(private val program: Program,
checkResult.add(ExpressionError("can only loop over an iterable type", forLoop.position)) checkResult.add(ExpressionError("can only loop over an iterable type", forLoop.position))
} else { } else {
if (forLoop.loopRegister != null) { if (forLoop.loopRegister != null) {
printWarning("using a register as loop variable is risky (it could get clobbered)", forLoop.position)
// loop register // loop register
if (iterableDt != DataType.UBYTE && iterableDt!= DataType.ARRAY_UB && iterableDt !in StringDatatypes) if (iterableDt != DataType.UBYTE && iterableDt!= DataType.ARRAY_UB && iterableDt !in StringDatatypes)
checkResult.add(ExpressionError("register can only loop over bytes", forLoop.position)) checkResult.add(ExpressionError("register can only loop over bytes", forLoop.position))
if(forLoop.loopRegister!=Register.A)
checkResult.add(ExpressionError("it's only possible to use A as a loop register", forLoop.position))
} else { } else {
// loop variable // loop variable
val loopvar = forLoop.loopVar!!.targetVarDecl(program.namespace) val loopvar = forLoop.loopVar!!.targetVarDecl(program.namespace)

View File

@ -339,9 +339,9 @@ internal class AsmGen2(val program: Program,
.filter {it.datatype in StringDatatypes } .filter {it.datatype in StringDatatypes }
.map { it to encodeStr((it.value as ReferenceLiteralValue).str!!, it.datatype) } .map { it to encodeStr((it.value as ReferenceLiteralValue).str!!, it.datatype) }
.groupBy({it.second}, {it.first}) .groupBy({it.second}, {it.first})
for((encoded, vars) in encodedstringVars) { for((encoded, variables) in encodedstringVars) {
vars.dropLast(1).forEach { out(it.name) } variables.dropLast(1).forEach { out(it.name) }
val lastvar = vars.last() val lastvar = variables.last()
outputStringvar(lastvar, encoded) outputStringvar(lastvar, encoded)
} }
@ -953,35 +953,178 @@ internal class AsmGen2(val program: Program,
private fun translate(stmt: ForLoop) { private fun translate(stmt: ForLoop) {
val iterableDt = stmt.iterable.inferType(program) val iterableDt = stmt.iterable.inferType(program)
val loopLabel = makeLabel("for_loop")
val endLabel = makeLabel("for_end")
when(stmt.iterable) { when(stmt.iterable) {
is RangeExpr -> { is RangeExpr -> {
val range = (stmt.iterable as RangeExpr).toConstantIntegerRange()
if(range==null)
TODO("non-const range loop")
if(range.isEmpty())
throw AssemblyError("empty range")
when(iterableDt) { when(iterableDt) {
in ByteDatatypes -> { in ByteDatatypes -> {
println("forloop over byte range $stmt") // TODO if(stmt.loopRegister!=null) {
// loop register
if(stmt.loopRegister!=Register.A)
throw AssemblyError("can only use A")
when {
range.step==1 -> {
val counterLabel = makeLabel("for_counter")
out("""
lda #${range.first}
sta $loopLabel+1
lda #${range.last-range.first+1 and 255}
sta $counterLabel
$loopLabel lda #0 ; modified""")
translate(stmt.body)
out("""
dec $counterLabel
beq $endLabel
inc $loopLabel+1
jmp $loopLabel
$counterLabel .byte 0
$endLabel""")
}
range.step==-1 -> {
val counterLabel = makeLabel("for_counter")
out("""
lda #${range.first}
sta $loopLabel+1
lda #${range.first-range.last+1 and 255}
sta $counterLabel
$loopLabel lda #0 ; modified """)
translate(stmt.body)
out("""
dec $counterLabel
beq $endLabel
dec $loopLabel+1
jmp $loopLabel
$counterLabel .byte 0
$endLabel""")
}
range.step>0 -> {
val counterLabel = makeLabel("for_counter")
out("""
lda #${(range.last-range.first) / range.step + 1}
sta $counterLabel
lda #${range.first}
$loopLabel pha""")
translate(stmt.body)
out("""
pla
dec $counterLabel
beq $endLabel
clc
adc #${range.step}
jmp $loopLabel
$counterLabel .byte 0
$endLabel""")
}
else -> {
val counterLabel = makeLabel("for_counter")
out("""
lda #${(range.first-range.last) / range.step.absoluteValue + 1}
sta $counterLabel
lda #${range.first}
$loopLabel pha""")
translate(stmt.body)
out("""
pla
dec $counterLabel
beq $endLabel
sec
sbc #${range.step.absoluteValue}
jmp $loopLabel
$counterLabel .byte 0
$endLabel""")
}
}
} else {
TODO("loop over byte range via loopvar $stmt")
}
} }
in WordDatatypes -> { in WordDatatypes -> {
println("forloop over word range $stmt") // TODO TODO("forloop over word range $stmt") // TODO
} }
else -> throw AssemblyError("range expression can only be byte or word") else -> throw AssemblyError("range expression can only be byte or word")
} }
} }
is IdentifierReference -> { is IdentifierReference -> {
val decl = (stmt.iterable as IdentifierReference).targetVarDecl(program.namespace)!! val ident = (stmt.iterable as IdentifierReference)
val iterableName = asmIdentifierName(ident)
val decl = ident.targetVarDecl(program.namespace)!!
when(iterableDt) { when(iterableDt) {
DataType.STR, DataType.STR_S -> { DataType.STR, DataType.STR_S -> {
println("forloop over string $stmt") // TODO (ends at 0 byte) if(stmt.loopRegister!=null) {
// loop register
if(stmt.loopRegister!=Register.A)
throw AssemblyError("can only use A")
out("""
lda #<$iterableName
ldy #>$iterableName
sta $loopLabel+1
sty $loopLabel+2
$loopLabel lda ${65535.toHex()} ; modified
beq $endLabel""")
translate(stmt.body)
out("""
inc $loopLabel+1
bne $loopLabel
inc $loopLabel+2
bne $loopLabel
$endLabel""")
} else {
TODO("loop over string via loopvar $stmt")
}
} }
DataType.ARRAY_UB, DataType.ARRAY_B -> { DataType.ARRAY_UB, DataType.ARRAY_B -> {
val size = decl.arraysize!!.size() val length = decl.arraysize!!.size()
println("forloop over byte array of len $size $stmt") // TODO (ends at length of array) if(stmt.loopRegister!=null) {
// loop register
if(stmt.loopRegister!=Register.A)
throw AssemblyError("can only use A")
val counterLabel = makeLabel("for_counter")
val modifiedLabel = makeLabel("for_modified")
out("""
lda #<$iterableName
ldy #>$iterableName
sta $modifiedLabel+1
sty $modifiedLabel+2
ldy #0
$loopLabel sty $counterLabel
cpy #$length
beq $endLabel
$modifiedLabel lda ${65535.toHex()},y ; modified
""")
translate(stmt.body)
out("""
ldy $counterLabel
iny
jmp $loopLabel
$counterLabel .byte 0
$endLabel""")
} else {
TODO("loop variable over bytearray of len $length")
}
} }
DataType.ARRAY_W, DataType.ARRAY_UW -> { DataType.ARRAY_W, DataType.ARRAY_UW -> {
val size = decl.arraysize!!.size() val length = decl.arraysize!!.size()
println("forloop over word array len $size $stmt") // TODO println("forloop over word array len $length $stmt") // TODO
if(stmt.loopRegister!=null) {
TODO("loop register over wordarray of len $length")
} else {
TODO("loop variable over wordarray of len $length")
}
} }
DataType.ARRAY_F -> { DataType.ARRAY_F -> {
val size = decl.arraysize!!.size() val length = decl.arraysize!!.size()
println("forloop over float array len $size $stmt") // TODO println("forloop over float array len $length $stmt") // TODO
if(stmt.loopRegister!=null) {
throw AssemblyError("can't use register to loop over floats")
} else {
TODO("loop variable over floatarray of len $length")
}
} }
else -> throw AssemblyError("can't iterate over $iterableDt") else -> throw AssemblyError("can't iterate over $iterableDt")
} }

View File

@ -19,12 +19,30 @@ main {
c64.CHROUT(',') c64.CHROUT(',')
} }
c64.CHROUT('\n') c64.CHROUT('\n')
;
; for A in 10 to 20 { for A in 10 to 20 {
; c64scr.print_ub(A) c64scr.print_ub(A)
; c64.CHROUT(',') c64.CHROUT(',')
; } }
; c64.CHROUT('\n') c64.CHROUT('\n')
for A in 20 to 10 step -1 {
c64scr.print_ub(A)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for A in 10 to 21 step 3 {
c64scr.print_ub(A)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for A in 24 to 10 step -3 {
c64scr.print_ub(A)
c64.CHROUT(',')
}
c64.CHROUT('\n')
; for var2 in 10 to 20 { ; for var2 in 10 to 20 {
; c64scr.print_ub(var2) ; c64scr.print_ub(var2)