for translation improvements

This commit is contained in:
Irmen de Jong 2018-09-17 21:05:33 +02:00
parent dd96ef8ef2
commit 54aeee2676
4 changed files with 117 additions and 44 deletions

View File

@ -34,6 +34,7 @@ sub start() -> () {
_vm_write_str(vs3)
_vm_write_str(vs4)
byte lv = 0
word tx = 0
word ty = 12 % 5
float time = 0.0

View File

@ -898,7 +898,8 @@ class RangeExpr(var from: IExpression,
fromVal = (from as LiteralValue).asIntegerValue!!
toVal = (to as LiteralValue).asIntegerValue!!
}
val stepVal = (step as? LiteralValue)?.asIntegerValue ?: 1
val stepLv = step as? LiteralValue ?: return null
val stepVal = stepLv.asIntegerValue ?: 1
return when {
fromVal <= toVal -> when {
stepVal <= 0 -> IntRange.EMPTY
@ -981,10 +982,7 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
}
}
override val isIterable: Boolean
get() {
TODO("iterable identifierref?")
}
override val isIterable: Boolean = true // should be checked by caller by actually looking up the symbol
}

View File

@ -69,6 +69,8 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
}
override fun process(forLoop: ForLoop): IStatement {
if(forLoop.body.isEmpty())
printWarning("for loop body is empty", forLoop.position)
if(!forLoop.iterable.isIterable) {
checkResult.add(ExpressionError("can only loop over an iterable type", forLoop.position))
} else {
@ -78,11 +80,16 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
// loop register
when (forLoop.loopRegister) {
Register.A, Register.X, Register.Y -> {
if (iterableDt != DataType.BYTE)
if (iterableDt != DataType.BYTE && iterableDt!=DataType.ARRAY && iterableDt!=DataType.MATRIX &&
iterableDt != DataType.STR && iterableDt != DataType.STR_P &&
iterableDt != DataType.STR_S && iterableDt != DataType.STR_PS)
checkResult.add(ExpressionError("register can only loop over bytes", forLoop.position))
}
Register.AX, Register.AY, Register.XY -> {
if (iterableDt != DataType.WORD && iterableDt != DataType.BYTE)
if (iterableDt != DataType.WORD && iterableDt != DataType.BYTE &&
iterableDt != DataType.STR && iterableDt != DataType.STR_P &&
iterableDt != DataType.STR_S && iterableDt != DataType.STR_PS &&
iterableDt !=DataType.ARRAY && iterableDt!=DataType.ARRAY_W && iterableDt!=DataType.MATRIX)
checkResult.add(ExpressionError("register pair can only loop over words", forLoop.position))
}
}
@ -95,11 +102,14 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
} else {
when (loopvar.datatype) {
DataType.BYTE -> {
if(iterableDt!=DataType.BYTE)
if(iterableDt!=DataType.BYTE && iterableDt!=DataType.ARRAY && iterableDt!=DataType.MATRIX &&
iterableDt != DataType.STR && iterableDt != DataType.STR_P &&
iterableDt != DataType.STR_S && iterableDt != DataType.STR_PS)
checkResult.add(ExpressionError("can only loop over bytes", forLoop.position))
}
DataType.WORD -> {
if(iterableDt!=DataType.BYTE && iterableDt!=DataType.WORD)
if(iterableDt!=DataType.BYTE && iterableDt!=DataType.WORD &&
iterableDt !=DataType.ARRAY && iterableDt!=DataType.ARRAY_W && iterableDt!=DataType.MATRIX)
checkResult.add(ExpressionError("can only loop over bytes or words", forLoop.position))
}
else -> checkResult.add(ExpressionError("loop variable must be byte or word type", forLoop.position))

View File

@ -3,7 +3,6 @@ package prog8.compiler
import prog8.ast.*
import prog8.stackvm.*
import java.io.PrintStream
import javax.xml.crypto.Data
import kotlin.math.abs
@ -489,42 +488,31 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, priva
}
private fun translate(loop: ForLoop) {
if(loop.body.isEmpty()) return
stackvmProg.line(loop.position)
val loopVarName: String
val loopVarDt: DataType
if(loop.loopRegister!=null) {
val reg = loop.loopRegister
if(loop.iterable is RangeExpr) {
val range = (loop.iterable as RangeExpr).toConstantIntegerRange()
if(range!=null) {
if (range.isEmpty())
throw CompilerException("loop over empty range")
val varDt =
when (reg) {
Register.A, Register.X, Register.Y -> {
if (range.first < 0 || range.first > 255 || range.last < 0 || range.last > 255)
throw CompilerException("range out of bounds for register")
DataType.BYTE
}
Register.AX, Register.AY, Register.XY -> {
if (range.first < 0 || range.first > 65535 || range.last < 0 || range.last > 65535)
throw CompilerException("range out of bounds for register")
DataType.WORD
}
}
translateForConstantRange(reg.toString(), varDt, range, loop.body)
} else {
TODO("loop over non-constant range: ${loop.iterable}")
}
} else {
TODO("loop over something else as a Range: ${loop.iterable}")
loopVarName = reg.toString()
loopVarDt = when (reg) {
Register.A, Register.X, Register.Y -> DataType.BYTE
Register.AX, Register.AY, Register.XY -> DataType.WORD
}
} else {
val loopvar = (loop.loopVar!!.targetStatement(namespace) as VarDecl)
if(loop.iterable is RangeExpr) {
val range = (loop.iterable as RangeExpr).toConstantIntegerRange()
if(range!=null) {
loopVarName = loopvar.scopedname
loopVarDt = loopvar.datatype
}
if(loop.iterable is RangeExpr) {
val range = (loop.iterable as RangeExpr).toConstantIntegerRange()
when {
range!=null -> {
if (range.isEmpty())
throw CompilerException("loop over empty range")
when (loopvar.datatype) {
when (loopVarDt) {
DataType.BYTE -> {
if (range.first < 0 || range.first > 255 || range.last < 0 || range.last > 255)
throw CompilerException("range out of bounds for byte")
@ -535,21 +523,35 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, priva
}
else -> throw CompilerException("range must be byte or word")
}
translateForConstantRange(loopvar.scopedname, loopvar.datatype, range, loop.body)
} else {
TODO("loop over non-constant range: ${loop.iterable}")
translateForOverConstantRange(loopVarName, loopVarDt, range, loop.body)
}
} else {
TODO("loop over something else as a Range: ${loop.iterable}")
loop.loopRegister!=null ->
translateForOverVariableRange(null, loop.loopRegister, loopVarDt, loop.iterable as RangeExpr, loop.body)
else ->
translateForOverVariableRange(loopVarName, null, loopVarDt, loop.iterable as RangeExpr, loop.body)
}
} else {
val litVal = loop.iterable as? LiteralValue
val ident = loop.iterable as? IdentifierReference
when {
litVal?.strvalue != null -> {
TODO("loop over string $litVal")
}
ident!=null -> {
val symbol = ident.targetStatement(namespace)
TODO("loop over symbol: ${ident.nameInSource} -> $symbol")
}
else -> throw CompilerException("loopvar is something strange ${loop.iterable}")
}
}
}
private fun translateForConstantRange(varname: String, varDt: DataType, range: IntProgression, body: MutableList<IStatement>) {
private fun translateForOverConstantRange(varname: String, varDt: DataType, range: IntProgression, body: MutableList<IStatement>) {
/**
* for LV in start..last { body }
* (and we already know that the range is not empty)
* (also we know that the range's last value is really the exact last occurring value of the range)
* (and finally, start and last are constant integer values)
* ->
* LV = start
* loop:
@ -601,4 +603,66 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, priva
}
stackvmProg.label(breakLabel)
}
private fun translateForOverVariableRange(varname: String?, register: Register?, varDt: DataType, range: RangeExpr, body: MutableList<IStatement>) {
/**
* for LV in start..last { body }
* (and we already know that the range is not empty)
* (also we know that the range's last value is really the exact last occurring value of the range)
* (and finally, start and last are constant integer values)
* ->
* LV = start
* loop:
* ..body..
* ..break statement: goto break
* ..continue statement: goto continue
* ..
* continue:
* LV++ (if step is not given, and is therefore 1)
* LV += step (if step is given)
* if LV<=last goto loop
* break:
*
*/
val assignmentTarget =
if(varname!=null)
AssignTarget(null, IdentifierReference(listOf(varname), range.position), range.position)
else
AssignTarget(register, null, range.position)
val startAssignment = Assignment(assignmentTarget, null, range.from, range.position)
var stepIncrement: PostIncrDecr? = null
var stepAddition: Assignment? = null
if(range.step==null)
stepIncrement = PostIncrDecr(assignmentTarget, "++", range.position)
else
stepAddition = Assignment(
assignmentTarget,
"+=",
range.step ?: LiteralValue(DataType.BYTE, 1, position = range.position),
range.position
)
translate(startAssignment)
val loopLabel = makeLabel("loop")
val continueLabel = makeLabel("continue")
val breakLabel = makeLabel("break")
stackvmProg.label(loopLabel)
translate(body)
stackvmProg.label(continueLabel)
if(stepAddition!=null)
translate(stepAddition)
if(stepIncrement!=null)
translate(stepIncrement)
val comparison = BinaryExpression(
if(varname!=null)
IdentifierReference(listOf(varname), range.position)
else
RegisterExpr(register!!, range.position)
,"<=", range.to, range.position)
translate(comparison)
stackvmProg.instr(Opcode.BNE, callLabel = loopLabel)
stackvmProg.label(breakLabel)
}
}