mirror of
https://github.com/irmen/prog8.git
synced 2025-08-16 05:27:31 +00:00
for translation improvements
This commit is contained in:
@@ -34,6 +34,7 @@ sub start() -> () {
|
|||||||
_vm_write_str(vs3)
|
_vm_write_str(vs3)
|
||||||
_vm_write_str(vs4)
|
_vm_write_str(vs4)
|
||||||
|
|
||||||
|
byte lv = 0
|
||||||
word tx = 0
|
word tx = 0
|
||||||
word ty = 12 % 5
|
word ty = 12 % 5
|
||||||
float time = 0.0
|
float time = 0.0
|
||||||
|
@@ -898,7 +898,8 @@ class RangeExpr(var from: IExpression,
|
|||||||
fromVal = (from as LiteralValue).asIntegerValue!!
|
fromVal = (from as LiteralValue).asIntegerValue!!
|
||||||
toVal = (to 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 {
|
return when {
|
||||||
fromVal <= toVal -> when {
|
fromVal <= toVal -> when {
|
||||||
stepVal <= 0 -> IntRange.EMPTY
|
stepVal <= 0 -> IntRange.EMPTY
|
||||||
@@ -981,10 +982,7 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val isIterable: Boolean
|
override val isIterable: Boolean = true // should be checked by caller by actually looking up the symbol
|
||||||
get() {
|
|
||||||
TODO("iterable identifierref?")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -69,6 +69,8 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun process(forLoop: ForLoop): IStatement {
|
override fun process(forLoop: ForLoop): IStatement {
|
||||||
|
if(forLoop.body.isEmpty())
|
||||||
|
printWarning("for loop body is empty", forLoop.position)
|
||||||
if(!forLoop.iterable.isIterable) {
|
if(!forLoop.iterable.isIterable) {
|
||||||
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 {
|
||||||
@@ -78,11 +80,16 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
|
|||||||
// loop register
|
// loop register
|
||||||
when (forLoop.loopRegister) {
|
when (forLoop.loopRegister) {
|
||||||
Register.A, Register.X, Register.Y -> {
|
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))
|
checkResult.add(ExpressionError("register can only loop over bytes", forLoop.position))
|
||||||
}
|
}
|
||||||
Register.AX, Register.AY, Register.XY -> {
|
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))
|
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 {
|
} else {
|
||||||
when (loopvar.datatype) {
|
when (loopvar.datatype) {
|
||||||
DataType.BYTE -> {
|
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))
|
checkResult.add(ExpressionError("can only loop over bytes", forLoop.position))
|
||||||
}
|
}
|
||||||
DataType.WORD -> {
|
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))
|
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))
|
else -> checkResult.add(ExpressionError("loop variable must be byte or word type", forLoop.position))
|
||||||
|
@@ -3,7 +3,6 @@ package prog8.compiler
|
|||||||
import prog8.ast.*
|
import prog8.ast.*
|
||||||
import prog8.stackvm.*
|
import prog8.stackvm.*
|
||||||
import java.io.PrintStream
|
import java.io.PrintStream
|
||||||
import javax.xml.crypto.Data
|
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
|
||||||
@@ -489,42 +488,31 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, priva
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun translate(loop: ForLoop) {
|
private fun translate(loop: ForLoop) {
|
||||||
|
if(loop.body.isEmpty()) return
|
||||||
stackvmProg.line(loop.position)
|
stackvmProg.line(loop.position)
|
||||||
|
val loopVarName: String
|
||||||
|
val loopVarDt: DataType
|
||||||
|
|
||||||
if(loop.loopRegister!=null) {
|
if(loop.loopRegister!=null) {
|
||||||
val reg = loop.loopRegister
|
val reg = loop.loopRegister
|
||||||
if(loop.iterable is RangeExpr) {
|
loopVarName = reg.toString()
|
||||||
val range = (loop.iterable as RangeExpr).toConstantIntegerRange()
|
loopVarDt = when (reg) {
|
||||||
if(range!=null) {
|
Register.A, Register.X, Register.Y -> DataType.BYTE
|
||||||
if (range.isEmpty())
|
Register.AX, Register.AY, Register.XY -> DataType.WORD
|
||||||
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}")
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val loopvar = (loop.loopVar!!.targetStatement(namespace) as VarDecl)
|
val loopvar = (loop.loopVar!!.targetStatement(namespace) as VarDecl)
|
||||||
if(loop.iterable is RangeExpr) {
|
loopVarName = loopvar.scopedname
|
||||||
val range = (loop.iterable as RangeExpr).toConstantIntegerRange()
|
loopVarDt = loopvar.datatype
|
||||||
if(range!=null) {
|
}
|
||||||
|
|
||||||
|
if(loop.iterable is RangeExpr) {
|
||||||
|
val range = (loop.iterable as RangeExpr).toConstantIntegerRange()
|
||||||
|
when {
|
||||||
|
range!=null -> {
|
||||||
if (range.isEmpty())
|
if (range.isEmpty())
|
||||||
throw CompilerException("loop over empty range")
|
throw CompilerException("loop over empty range")
|
||||||
when (loopvar.datatype) {
|
when (loopVarDt) {
|
||||||
DataType.BYTE -> {
|
DataType.BYTE -> {
|
||||||
if (range.first < 0 || range.first > 255 || range.last < 0 || range.last > 255)
|
if (range.first < 0 || range.first > 255 || range.last < 0 || range.last > 255)
|
||||||
throw CompilerException("range out of bounds for byte")
|
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")
|
else -> throw CompilerException("range must be byte or word")
|
||||||
}
|
}
|
||||||
translateForConstantRange(loopvar.scopedname, loopvar.datatype, range, loop.body)
|
translateForOverConstantRange(loopVarName, loopVarDt, range, loop.body)
|
||||||
} else {
|
|
||||||
TODO("loop over non-constant range: ${loop.iterable}")
|
|
||||||
}
|
}
|
||||||
} else {
|
loop.loopRegister!=null ->
|
||||||
TODO("loop over something else as a Range: ${loop.iterable}")
|
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 }
|
* for LV in start..last { body }
|
||||||
* (and we already know that the range is not empty)
|
* (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)
|
* (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
|
* LV = start
|
||||||
* loop:
|
* loop:
|
||||||
@@ -601,4 +603,66 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, priva
|
|||||||
}
|
}
|
||||||
stackvmProg.label(breakLabel)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user