mirror of
https://github.com/irmen/prog8.git
synced 2024-09-30 15:57:06 +00:00
implemented floating-point arrays
This commit is contained in:
parent
0cdae48ce7
commit
38e7d48492
@ -4,18 +4,54 @@
|
|||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
|
|
||||||
byte[100] array
|
byte[10] barray1
|
||||||
byte[4,5] mvar
|
byte[10] barray2 = 11
|
||||||
|
byte[10] barray3 = [1,2,3,4,5,6,7,8,9,255]
|
||||||
|
|
||||||
A=AX[2]
|
word[10] warray1
|
||||||
A=AY[2]
|
word[10] warray2 = 112233
|
||||||
A=XY[2]
|
word[10] warray3 = [1,2,3,4,5,6,7,8,9, 65535]
|
||||||
|
|
||||||
|
byte[4,5] mvar1
|
||||||
|
byte[4,5] mvar2 = 22
|
||||||
|
byte[2,3] mvar3 = [1,2,3,4,5,6]
|
||||||
|
|
||||||
|
float[3] farray1
|
||||||
|
float[3] farray2 = 33.44
|
||||||
|
float[3] farray2b = 33
|
||||||
|
float[3] farray3 = [1,2,3]
|
||||||
|
float[3] farray4 = [1,2,35566]
|
||||||
|
float[3] farray5 = [1,2.22334,3.1415]
|
||||||
|
|
||||||
|
|
||||||
|
byte i
|
||||||
|
word w
|
||||||
|
|
||||||
|
for i in 0 to 2 {
|
||||||
|
_vm_write_num(farray5[i])
|
||||||
|
_vm_write_char('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
for w in [1,2,3777] { ;@todo loop over array literal
|
||||||
|
_vm_write_num(w)
|
||||||
|
_vm_write_char('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in barray3 { ; @todo loop over symbol
|
||||||
|
_vm_write_num(i)
|
||||||
|
_vm_write_char('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in "hello" { ; @todo loop over string
|
||||||
|
_vm_write_num(i)
|
||||||
|
_vm_write_char('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
for w in "hello" { ; @todo loop over string
|
||||||
|
_vm_write_num(w)
|
||||||
|
_vm_write_char('\n')
|
||||||
|
}
|
||||||
|
|
||||||
A=array[98]
|
|
||||||
A=array[99]
|
|
||||||
A=mvar[13]
|
|
||||||
A=mvar[2,3]
|
|
||||||
A=mvar[Y,X]
|
|
||||||
return
|
return
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package prog8.ast
|
|||||||
import org.antlr.v4.runtime.ParserRuleContext
|
import org.antlr.v4.runtime.ParserRuleContext
|
||||||
import org.antlr.v4.runtime.tree.TerminalNode
|
import org.antlr.v4.runtime.tree.TerminalNode
|
||||||
import prog8.compiler.HeapValues
|
import prog8.compiler.HeapValues
|
||||||
|
import prog8.compiler.target.c64.Mflpt5
|
||||||
import prog8.compiler.target.c64.Petscii
|
import prog8.compiler.target.c64.Petscii
|
||||||
import prog8.compiler.unescape
|
import prog8.compiler.unescape
|
||||||
import prog8.functions.BuiltinFunctions
|
import prog8.functions.BuiltinFunctions
|
||||||
@ -26,6 +27,7 @@ enum class DataType {
|
|||||||
STR_PS,
|
STR_PS,
|
||||||
ARRAY,
|
ARRAY,
|
||||||
ARRAY_W,
|
ARRAY_W,
|
||||||
|
ARRAY_F,
|
||||||
MATRIX
|
MATRIX
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +62,9 @@ enum class BranchCondition {
|
|||||||
POS
|
POS
|
||||||
}
|
}
|
||||||
|
|
||||||
val IterableDatatypes = setOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX)
|
val IterableDatatypes = setOf(
|
||||||
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
|
||||||
|
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX)
|
||||||
|
|
||||||
class FatalAstException (override var message: String) : Exception(message)
|
class FatalAstException (override var message: String) : Exception(message)
|
||||||
|
|
||||||
@ -599,8 +603,9 @@ class VarDecl(val type: VarDeclType,
|
|||||||
else -> when (declaredDatatype) {
|
else -> when (declaredDatatype) {
|
||||||
DataType.BYTE -> DataType.ARRAY
|
DataType.BYTE -> DataType.ARRAY
|
||||||
DataType.WORD -> DataType.ARRAY_W
|
DataType.WORD -> DataType.ARRAY_W
|
||||||
|
DataType.FLOAT -> DataType.ARRAY_F
|
||||||
else -> {
|
else -> {
|
||||||
datatypeErrors.add(SyntaxError("array can only contain bytes or words", position))
|
datatypeErrors.add(SyntaxError("array can only contain bytes/words/floats", position))
|
||||||
DataType.BYTE
|
DataType.BYTE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -620,7 +625,7 @@ class VarDecl(val type: VarDeclType,
|
|||||||
get() = when(datatype) {
|
get() = when(datatype) {
|
||||||
DataType.BYTE -> 1
|
DataType.BYTE -> 1
|
||||||
DataType.WORD -> 2
|
DataType.WORD -> 2
|
||||||
DataType.FLOAT -> 5 // MFLPT5
|
DataType.FLOAT -> Mflpt5.MemorySize
|
||||||
DataType.STR,
|
DataType.STR,
|
||||||
DataType.STR_P,
|
DataType.STR_P,
|
||||||
DataType.STR_S,
|
DataType.STR_S,
|
||||||
@ -636,6 +641,10 @@ class VarDecl(val type: VarDeclType,
|
|||||||
val aX = arrayspec?.x as? LiteralValue ?: throw ExpressionError("need constant value expression for arrayspec", position)
|
val aX = arrayspec?.x as? LiteralValue ?: throw ExpressionError("need constant value expression for arrayspec", position)
|
||||||
2*aX.asIntegerValue!!
|
2*aX.asIntegerValue!!
|
||||||
}
|
}
|
||||||
|
DataType.ARRAY_F -> {
|
||||||
|
val aX = arrayspec?.x as? LiteralValue ?: throw ExpressionError("need constant value expression for arrayspec", position)
|
||||||
|
Mflpt5.MemorySize*aX.asIntegerValue!!
|
||||||
|
}
|
||||||
DataType.MATRIX -> {
|
DataType.MATRIX -> {
|
||||||
val aX = arrayspec?.x as? LiteralValue ?: throw ExpressionError("need constant value expression for arrayspec", position)
|
val aX = arrayspec?.x as? LiteralValue ?: throw ExpressionError("need constant value expression for arrayspec", position)
|
||||||
val aY = arrayspec.y as? LiteralValue ?: throw ExpressionError("need constant value expression for arrayspec", position)
|
val aY = arrayspec.y as? LiteralValue ?: throw ExpressionError("need constant value expression for arrayspec", position)
|
||||||
@ -833,10 +842,11 @@ class ArrayIndexedExpression(val identifier: IdentifierReference?,
|
|||||||
val target = identifier?.targetStatement(namespace)
|
val target = identifier?.targetStatement(namespace)
|
||||||
if (target is VarDecl) {
|
if (target is VarDecl) {
|
||||||
return when (target.datatype) {
|
return when (target.datatype) {
|
||||||
|
DataType.BYTE, DataType.WORD, DataType.FLOAT -> null
|
||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.BYTE
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.BYTE
|
||||||
DataType.ARRAY, DataType.MATRIX -> DataType.BYTE
|
DataType.ARRAY, DataType.MATRIX -> DataType.BYTE
|
||||||
DataType.ARRAY_W -> DataType.WORD
|
DataType.ARRAY_W -> DataType.WORD
|
||||||
else -> null
|
DataType.ARRAY_F -> DataType.FLOAT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw FatalAstException("cannot get indexed element on $target")
|
throw FatalAstException("cannot get indexed element on $target")
|
||||||
@ -861,7 +871,7 @@ class LiteralValue(val type: DataType,
|
|||||||
|
|
||||||
val isString = type==DataType.STR || type==DataType.STR_P || type==DataType.STR_S || type==DataType.STR_PS
|
val isString = type==DataType.STR || type==DataType.STR_P || type==DataType.STR_S || type==DataType.STR_PS
|
||||||
val isNumeric = type==DataType.BYTE || type==DataType.WORD || type==DataType.FLOAT
|
val isNumeric = type==DataType.BYTE || type==DataType.WORD || type==DataType.FLOAT
|
||||||
val isArray = type==DataType.ARRAY || type==DataType.ARRAY_W || type==DataType.MATRIX
|
val isArray = type==DataType.ARRAY || type==DataType.ARRAY_W || type==DataType.ARRAY_F || type==DataType.MATRIX
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun fromBoolean(bool: Boolean, position: Position) =
|
fun fromBoolean(bool: Boolean, position: Position) =
|
||||||
@ -908,7 +918,7 @@ class LiteralValue(val type: DataType,
|
|||||||
DataType.FLOAT -> if(floatvalue==null) throw FatalAstException("literal value missing floatvalue")
|
DataType.FLOAT -> if(floatvalue==null) throw FatalAstException("literal value missing floatvalue")
|
||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS ->
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS ->
|
||||||
if(strvalue==null && heapId==null) throw FatalAstException("literal value missing strvalue/heapId")
|
if(strvalue==null && heapId==null) throw FatalAstException("literal value missing strvalue/heapId")
|
||||||
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX ->
|
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX ->
|
||||||
if(arrayvalue==null && heapId==null) throw FatalAstException("literal value missing arrayvalue/heapId")
|
if(arrayvalue==null && heapId==null) throw FatalAstException("literal value missing arrayvalue/heapId")
|
||||||
}
|
}
|
||||||
if(bytevalue==null && wordvalue==null && floatvalue==null && arrayvalue==null && strvalue==null && heapId==null)
|
if(bytevalue==null && wordvalue==null && floatvalue==null && arrayvalue==null && strvalue==null && heapId==null)
|
||||||
@ -952,7 +962,7 @@ class LiteralValue(val type: DataType,
|
|||||||
if(heapId!=null) "str:#$heapId"
|
if(heapId!=null) "str:#$heapId"
|
||||||
else "str:$strvalue"
|
else "str:$strvalue"
|
||||||
}
|
}
|
||||||
DataType.ARRAY, DataType.ARRAY_W -> {
|
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F -> {
|
||||||
if(heapId!=null) "array:#$heapId"
|
if(heapId!=null) "array:#$heapId"
|
||||||
else "array:$arrayvalue"
|
else "array:$arrayvalue"
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ package prog8.ast
|
|||||||
|
|
||||||
import prog8.compiler.CompilationOptions
|
import prog8.compiler.CompilationOptions
|
||||||
import prog8.compiler.HeapValues
|
import prog8.compiler.HeapValues
|
||||||
|
import prog8.compiler.target.c64.FLOAT_MAX_NEGATIVE
|
||||||
|
import prog8.compiler.target.c64.FLOAT_MAX_POSITIVE
|
||||||
import prog8.functions.BuiltinFunctions
|
import prog8.functions.BuiltinFunctions
|
||||||
import prog8.parser.ParsingFailedError
|
import prog8.parser.ParsingFailedError
|
||||||
|
|
||||||
@ -111,7 +113,7 @@ class AstChecker(private val namespace: INameScope,
|
|||||||
if (iterableDt != DataType.WORD && iterableDt != DataType.BYTE &&
|
if (iterableDt != DataType.WORD && iterableDt != DataType.BYTE &&
|
||||||
iterableDt != DataType.STR && iterableDt != DataType.STR_P &&
|
iterableDt != DataType.STR && iterableDt != DataType.STR_P &&
|
||||||
iterableDt != DataType.STR_S && iterableDt != DataType.STR_PS &&
|
iterableDt != DataType.STR_S && iterableDt != DataType.STR_PS &&
|
||||||
iterableDt !=DataType.ARRAY && iterableDt!=DataType.ARRAY_W && iterableDt!=DataType.MATRIX)
|
iterableDt !=DataType.ARRAY && iterableDt!=DataType.ARRAY_W && iterableDt!=DataType.ARRAY_F && 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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,13 +129,16 @@ class AstChecker(private val namespace: INameScope,
|
|||||||
if(iterableDt!=DataType.BYTE && iterableDt!=DataType.ARRAY && iterableDt!=DataType.MATRIX &&
|
if(iterableDt!=DataType.BYTE && iterableDt!=DataType.ARRAY && iterableDt!=DataType.MATRIX &&
|
||||||
iterableDt != DataType.STR && iterableDt != DataType.STR_P &&
|
iterableDt != DataType.STR && iterableDt != DataType.STR_P &&
|
||||||
iterableDt != DataType.STR_S && iterableDt != DataType.STR_PS)
|
iterableDt != DataType.STR_S && iterableDt != DataType.STR_PS)
|
||||||
checkResult.add(ExpressionError("can only loop over bytes", forLoop.position))
|
checkResult.add(ExpressionError("byte loop variable 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)
|
iterableDt !=DataType.ARRAY && iterableDt!=DataType.ARRAY_W && iterableDt!=DataType.MATRIX &&
|
||||||
checkResult.add(ExpressionError("can only loop over bytes or words", forLoop.position))
|
iterableDt != DataType.STR && iterableDt != DataType.STR_P &&
|
||||||
|
iterableDt != DataType.STR_S && iterableDt != DataType.STR_PS)
|
||||||
|
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))
|
else -> checkResult.add(ExpressionError("loop variable must be byte or word type", forLoop.position))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -331,7 +336,7 @@ class AstChecker(private val namespace: INameScope,
|
|||||||
litVal.parent = decl
|
litVal.parent = decl
|
||||||
decl.value = litVal
|
decl.value = litVal
|
||||||
}
|
}
|
||||||
else -> err("var/const declaration needs a compile-time constant initializer value for this type")
|
else -> err("var/const declaration needs a compile-time constant initializer value for this type") // const fold should have provided it!
|
||||||
}
|
}
|
||||||
return super.process(decl)
|
return super.process(decl)
|
||||||
}
|
}
|
||||||
@ -438,11 +443,11 @@ class AstChecker(private val namespace: INameScope,
|
|||||||
if(lv.heapId==null)
|
if(lv.heapId==null)
|
||||||
throw FatalAstException("string should have been moved to heap at ${lv.position}")
|
throw FatalAstException("string should have been moved to heap at ${lv.position}")
|
||||||
}
|
}
|
||||||
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> {
|
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> {
|
||||||
if(lv.heapId==null)
|
if(lv.heapId==null)
|
||||||
throw FatalAstException("array/matrix should have been moved to heap at ${lv.position}")
|
throw FatalAstException("array/matrix should have been moved to heap at ${lv.position}")
|
||||||
}
|
}
|
||||||
else -> {}
|
DataType.BYTE, DataType.WORD, DataType.FLOAT -> {}
|
||||||
}
|
}
|
||||||
return lv
|
return lv
|
||||||
}
|
}
|
||||||
@ -626,7 +631,7 @@ class AstChecker(private val namespace: INameScope,
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> {
|
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> {
|
||||||
// range and length check bytes
|
// range and length check bytes
|
||||||
val expectedSize = arrayspec!!.size()
|
val expectedSize = arrayspec!!.size()
|
||||||
val rangeSize=range.size()
|
val rangeSize=range.size()
|
||||||
@ -721,17 +726,39 @@ class AstChecker(private val namespace: INameScope,
|
|||||||
return err("value '$number' out of range for unsigned word")
|
return err("value '$number' out of range for unsigned word")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DataType.ARRAY_F -> {
|
||||||
|
// value may be either a single float, or a float array
|
||||||
|
if(value.type==DataType.ARRAY || value.type==DataType.ARRAY_W || value.type==DataType.ARRAY_F) {
|
||||||
|
val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).doubleArray!!.size
|
||||||
|
if(arrayspec!=null) {
|
||||||
|
// arrayspec is not always known when checking
|
||||||
|
val constX = arrayspec.x.constValue(namespace, heap)
|
||||||
|
if(constX?.asIntegerValue==null)
|
||||||
|
return err("array size specifier must be constant integer value")
|
||||||
|
val expectedSize = constX.asIntegerValue
|
||||||
|
if (arraySize != expectedSize)
|
||||||
|
return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val number = value.asNumericValue!!.toDouble()
|
||||||
|
if (number < FLOAT_MAX_NEGATIVE || number > FLOAT_MAX_POSITIVE)
|
||||||
|
return err("value '$number' out of range for mfplt5 floating point")
|
||||||
|
}
|
||||||
|
}
|
||||||
DataType.MATRIX -> {
|
DataType.MATRIX -> {
|
||||||
// value can only be a single byte, or a byte array (which represents the matrix)
|
// value can only be a single byte, or a byte array (which represents the matrix)
|
||||||
if(value.type==DataType.ARRAY || value.type==DataType.MATRIX) {
|
if(value.type==DataType.ARRAY || value.type==DataType.MATRIX) {
|
||||||
val constX = arrayspec!!.x.constValue(namespace, heap)
|
if(arrayspec!=null) {
|
||||||
val constY = arrayspec.y!!.constValue(namespace, heap)
|
// arrayspec is not always known when checking
|
||||||
if(constX?.asIntegerValue==null || constY?.asIntegerValue==null)
|
val constX = arrayspec.x.constValue(namespace, heap)
|
||||||
return err("matrix size specifiers must be constant integer values")
|
val constY = arrayspec.y!!.constValue(namespace, heap)
|
||||||
val matrix = heap.get(value.heapId!!).array!!
|
if (constX?.asIntegerValue == null || constY?.asIntegerValue == null)
|
||||||
val expectedSize = constX.asIntegerValue * constY.asIntegerValue
|
return err("matrix size specifiers must be constant integer values")
|
||||||
if (matrix.size != expectedSize)
|
val matrix = heap.get(value.heapId!!).array!!
|
||||||
return err("initializer matrix size mismatch (expecting $expectedSize, got ${matrix.size} elements)")
|
val expectedSize = constX.asIntegerValue * constY.asIntegerValue
|
||||||
|
if (matrix.size != expectedSize)
|
||||||
|
return err("initializer matrix size mismatch (expecting $expectedSize, got ${matrix.size} elements)")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
val number = value.bytevalue
|
val number = value.bytevalue
|
||||||
?: return err("unsigned byte value expected")
|
?: return err("unsigned byte value expected")
|
||||||
|
@ -51,18 +51,19 @@ fun String.unescape(): String {
|
|||||||
|
|
||||||
|
|
||||||
class HeapValues {
|
class HeapValues {
|
||||||
data class HeapValue(val type: DataType, val str: String?, val array: IntArray?) {
|
data class HeapValue(val type: DataType, val str: String?, val array: IntArray?, val doubleArray: DoubleArray?) {
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (javaClass != other?.javaClass) return false
|
if (javaClass != other?.javaClass) return false
|
||||||
other as HeapValue
|
other as HeapValue
|
||||||
return type==other.type && str==other.str && Arrays.equals(array, other.array)
|
return type==other.type && str==other.str && Arrays.equals(array, other.array) && Arrays.equals(doubleArray, other.doubleArray)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
var result = type.hashCode()
|
var result = type.hashCode()
|
||||||
result = 31 * result + (str?.hashCode() ?: 0)
|
result = 31 * result + (str?.hashCode() ?: 0)
|
||||||
result = 31 * result + (array?.let { Arrays.hashCode(it) } ?: 0)
|
result = 31 * result + (array?.let { Arrays.hashCode(it) } ?: 0)
|
||||||
|
result = 31 * result + (doubleArray?.let { Arrays.hashCode(it) } ?: 0)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,7 +75,7 @@ class HeapValues {
|
|||||||
throw IllegalArgumentException("string length must be 1-255")
|
throw IllegalArgumentException("string length must be 1-255")
|
||||||
|
|
||||||
// strings are 'interned' and shared if they're the same
|
// strings are 'interned' and shared if they're the same
|
||||||
val value = HeapValue(type, str, null)
|
val value = HeapValue(type, str, null, null)
|
||||||
val existing = heap.indexOf(value)
|
val existing = heap.indexOf(value)
|
||||||
if(existing>=0)
|
if(existing>=0)
|
||||||
return existing
|
return existing
|
||||||
@ -84,7 +85,13 @@ class HeapValues {
|
|||||||
|
|
||||||
fun add(type: DataType, array: IntArray): Int {
|
fun add(type: DataType, array: IntArray): Int {
|
||||||
// arrays are never shared
|
// arrays are never shared
|
||||||
heap.add(HeapValue(type, null, array))
|
heap.add(HeapValue(type, null, array, null))
|
||||||
|
return heap.size-1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun add(type: DataType, darray: DoubleArray): Int {
|
||||||
|
// arrays are never shared
|
||||||
|
heap.add(HeapValue(type, null, null, darray))
|
||||||
return heap.size-1
|
return heap.size-1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,21 +109,15 @@ class HeapValues {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun update(heapId: Int, array: IntArray) {
|
fun update(heapId: Int, heapval: HeapValue) {
|
||||||
when(heap[heapId].type){
|
heap[heapId] = heapval
|
||||||
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> {
|
|
||||||
if(heap[heapId].array!!.size != array.size)
|
|
||||||
throw IllegalArgumentException("heap array length mismatch")
|
|
||||||
heap[heapId] = heap[heapId].copy(array=array)
|
|
||||||
}
|
|
||||||
else-> throw IllegalArgumentException("heap data type mismatch")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun get(heapId: Int): HeapValue = heap[heapId]
|
fun get(heapId: Int): HeapValue = heap[heapId]
|
||||||
|
|
||||||
fun allStrings() = heap.asSequence().withIndex().filter { it.value.str!=null }.toList()
|
fun allStrings() = heap.asSequence().withIndex().filter { it.value.str!=null }.toList()
|
||||||
fun allArrays() = heap.asSequence().withIndex().filter { it.value.array!=null }.toList()
|
fun allArrays() = heap.asSequence().withIndex().filter { it.value.array!=null }.toList()
|
||||||
|
fun allDoubleArrays() = heap.asSequence().withIndex().filter { it.value.doubleArray!=null }.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -146,7 +147,7 @@ class StackVmProgram(val name: String, val heap: HeapValues) {
|
|||||||
throw CompilerException("string should already be in the heap")
|
throw CompilerException("string should already be in the heap")
|
||||||
Value(decl.datatype, litval.heapId)
|
Value(decl.datatype, litval.heapId)
|
||||||
}
|
}
|
||||||
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> {
|
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> {
|
||||||
val litval = (decl.value as LiteralValue)
|
val litval = (decl.value as LiteralValue)
|
||||||
if(litval.heapId==null)
|
if(litval.heapId==null)
|
||||||
throw CompilerException("array/matrix should already be in the heap")
|
throw CompilerException("array/matrix should already be in the heap")
|
||||||
@ -458,7 +459,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
throw CompilerException("string should have been moved into heap ${lv.position}")
|
throw CompilerException("string should have been moved into heap ${lv.position}")
|
||||||
stackvmProg.instr(Opcode.PUSH, Value(lv.type, lv.heapId))
|
stackvmProg.instr(Opcode.PUSH, Value(lv.type, lv.heapId))
|
||||||
}
|
}
|
||||||
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> {
|
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> {
|
||||||
if(lv.heapId==null)
|
if(lv.heapId==null)
|
||||||
throw CompilerException("array/matrix should have been moved into heap ${lv.position}")
|
throw CompilerException("array/matrix should have been moved into heap ${lv.position}")
|
||||||
stackvmProg.instr(Opcode.PUSH, Value(lv.type, lv.heapId))
|
stackvmProg.instr(Opcode.PUSH, Value(lv.type, lv.heapId))
|
||||||
@ -688,7 +689,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
|
||||||
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
|
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
|
||||||
// todo: maybe if you assign byte or word to array/matrix, clear it with that value?
|
// todo: maybe if you assign byte or word to array/matrix, clear it with that value?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -799,18 +800,21 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val litVal = loop.iterable as? LiteralValue
|
val iterableValue: LiteralValue?
|
||||||
val ident = loop.iterable as? IdentifierReference
|
if(loop.iterable is LiteralValue) {
|
||||||
when {
|
if (!loop.iterable.isIterable(namespace, heap))
|
||||||
litVal?.strvalue != null -> {
|
throw CompilerException("loop over something that isn't iterable ${loop.iterable}")
|
||||||
TODO("loop over string $litVal")
|
iterableValue = loop.iterable as LiteralValue
|
||||||
}
|
} else if(loop.iterable is IdentifierReference) {
|
||||||
ident!=null -> {
|
val idRef = loop.iterable as IdentifierReference
|
||||||
val symbol = ident.targetStatement(namespace)
|
iterableValue = ((idRef.targetStatement(namespace) as? VarDecl)?.value as? LiteralValue)
|
||||||
TODO("loop over symbol: ${ident.nameInSource} -> $symbol")
|
if(iterableValue!=null && !iterableValue.isIterable(namespace, heap))
|
||||||
}
|
throw CompilerException("loop over something that isn't iterable ${loop.iterable}")
|
||||||
else -> throw CompilerException("loopvar is something strange ${loop.iterable}")
|
} else {
|
||||||
|
throw CompilerException("loopvar is something strange ${loop.iterable}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TODO("LOOP OVER ITERABLE VALUE (array/matrix/string) $iterableValue")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +54,8 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
|
|||||||
data class Mflpt5(val b0: Short, val b1: Short, val b2: Short, val b3: Short, val b4: Short) {
|
data class Mflpt5(val b0: Short, val b1: Short, val b2: Short, val b3: Short, val b4: Short) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
const val MemorySize = 5
|
||||||
|
|
||||||
val zero = Mflpt5(0, 0,0,0,0)
|
val zero = Mflpt5(0, 0,0,0,0)
|
||||||
fun fromNumber(num: Number): Mflpt5 {
|
fun fromNumber(num: Number): Mflpt5 {
|
||||||
// see https://en.wikipedia.org/wiki/Microsoft_Binary_Format
|
// see https://en.wikipedia.org/wiki/Microsoft_Binary_Format
|
||||||
|
@ -33,17 +33,17 @@ val BuiltinFunctions = mapOf(
|
|||||||
"sqrt" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArg(a, p, n, h, Math::sqrt) },
|
"sqrt" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArg(a, p, n, h, Math::sqrt) },
|
||||||
"rad" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArg(a, p, n, h, Math::toRadians) },
|
"rad" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArg(a, p, n, h, Math::toRadians) },
|
||||||
"deg" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArg(a, p, n, h, Math::toDegrees) },
|
"deg" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArg(a, p, n, h, Math::toDegrees) },
|
||||||
"avg" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX))), DataType.FLOAT, ::builtinAvg),
|
"avg" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX))), DataType.FLOAT, ::builtinAvg),
|
||||||
"abs" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), DataType.FLOAT, ::builtinAbs),
|
"abs" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), DataType.FLOAT, ::builtinAbs),
|
||||||
"round" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), null) { a, p, n, h -> oneDoubleArgOutputInt(a, p, n, h, Math::round) }, // type depends on arg
|
"round" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), null) { a, p, n, h -> oneDoubleArgOutputInt(a, p, n, h, Math::round) }, // type depends on arg
|
||||||
"floor" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), null) { a, p, n, h -> oneDoubleArgOutputInt(a, p, n, h, Math::floor) }, // type depends on arg
|
"floor" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), null) { a, p, n, h -> oneDoubleArgOutputInt(a, p, n, h, Math::floor) }, // type depends on arg
|
||||||
"ceil" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), null) { a, p, n, h -> oneDoubleArgOutputInt(a, p, n, h, Math::ceil) }, // type depends on arg
|
"ceil" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), null) { a, p, n, h -> oneDoubleArgOutputInt(a, p, n, h, Math::ceil) }, // type depends on arg
|
||||||
"max" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX))), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.max()!! }}, // type depends on args
|
"max" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX))), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.max()!! }}, // type depends on args
|
||||||
"min" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX))), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.min()!! }}, // type depends on args
|
"min" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX))), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.min()!! }}, // type depends on args
|
||||||
"sum" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX))), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.sum() }}, // type depends on args
|
"sum" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX))), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.sum() }}, // type depends on args
|
||||||
"len" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX))), null, ::builtinLen), // type depends on args
|
"len" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX))), null, ::builtinLen), // type depends on args
|
||||||
"any" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX))), DataType.BYTE) { a, p, n, h -> collectionArgOutputBoolean(a, p, n, h) { it.any { v -> v != 0.0} }},
|
"any" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX))), DataType.BYTE) { a, p, n, h -> collectionArgOutputBoolean(a, p, n, h) { it.any { v -> v != 0.0} }},
|
||||||
"all" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX))), DataType.BYTE) { a, p, n, h -> collectionArgOutputBoolean(a, p, n, h) { it.all { v -> v != 0.0} }},
|
"all" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX))), DataType.BYTE) { a, p, n, h -> collectionArgOutputBoolean(a, p, n, h) { it.all { v -> v != 0.0} }},
|
||||||
"lsb" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.WORD))), DataType.BYTE) { a, p, n, h -> oneIntArgOutputInt(a, p, n, h) { x: Int -> x and 255 }},
|
"lsb" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.WORD))), DataType.BYTE) { a, p, n, h -> oneIntArgOutputInt(a, p, n, h) { x: Int -> x and 255 }},
|
||||||
"msb" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.WORD))), DataType.BYTE) { a, p, n, h -> oneIntArgOutputInt(a, p, n, h) { x: Int -> x ushr 8 and 255}},
|
"msb" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.WORD))), DataType.BYTE) { a, p, n, h -> oneIntArgOutputInt(a, p, n, h) { x: Int -> x ushr 8 and 255}},
|
||||||
"flt" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.BYTE, DataType.WORD))), DataType.FLOAT, ::builtinFlt),
|
"flt" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.BYTE, DataType.WORD))), DataType.FLOAT, ::builtinFlt),
|
||||||
@ -87,7 +87,7 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
|
|||||||
|
|
||||||
fun datatypeFromListArg(arglist: IExpression): DataType {
|
fun datatypeFromListArg(arglist: IExpression): DataType {
|
||||||
if(arglist is LiteralValue) {
|
if(arglist is LiteralValue) {
|
||||||
if(arglist.type==DataType.ARRAY || arglist.type==DataType.ARRAY_W || arglist.type==DataType.MATRIX) {
|
if(arglist.type==DataType.ARRAY || arglist.type==DataType.ARRAY_W || arglist.type==DataType.ARRAY_F || arglist.type==DataType.MATRIX) {
|
||||||
val dt = arglist.arrayvalue!!.map {it.resultingDatatype(namespace, heap)}
|
val dt = arglist.arrayvalue!!.map {it.resultingDatatype(namespace, heap)}
|
||||||
if(dt.any { it!=DataType.BYTE && it!=DataType.WORD && it!=DataType.FLOAT}) {
|
if(dt.any { it!=DataType.BYTE && it!=DataType.WORD && it!=DataType.FLOAT}) {
|
||||||
throw FatalAstException("fuction $function only accepts array of numeric values")
|
throw FatalAstException("fuction $function only accepts array of numeric values")
|
||||||
@ -104,6 +104,7 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
|
|||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> dt
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> dt
|
||||||
DataType.ARRAY -> DataType.BYTE
|
DataType.ARRAY -> DataType.BYTE
|
||||||
DataType.ARRAY_W -> DataType.WORD
|
DataType.ARRAY_W -> DataType.WORD
|
||||||
|
DataType.ARRAY_F -> DataType.FLOAT
|
||||||
DataType.MATRIX -> DataType.BYTE
|
DataType.MATRIX -> DataType.BYTE
|
||||||
null -> throw FatalAstException("function requires one argument which is an array $function")
|
null -> throw FatalAstException("function requires one argument which is an array $function")
|
||||||
}
|
}
|
||||||
@ -124,6 +125,7 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
|
|||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.BYTE
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.BYTE
|
||||||
DataType.ARRAY -> DataType.BYTE
|
DataType.ARRAY -> DataType.BYTE
|
||||||
DataType.ARRAY_W -> DataType.WORD
|
DataType.ARRAY_W -> DataType.WORD
|
||||||
|
DataType.ARRAY_F -> DataType.FLOAT
|
||||||
DataType.MATRIX -> DataType.BYTE
|
DataType.MATRIX -> DataType.BYTE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -142,6 +144,7 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
|
|||||||
DataType.BYTE, DataType.WORD -> DataType.WORD
|
DataType.BYTE, DataType.WORD -> DataType.WORD
|
||||||
DataType.FLOAT -> DataType.FLOAT
|
DataType.FLOAT -> DataType.FLOAT
|
||||||
DataType.ARRAY, DataType.ARRAY_W -> DataType.WORD
|
DataType.ARRAY, DataType.ARRAY_W -> DataType.WORD
|
||||||
|
DataType.ARRAY_F -> DataType.FLOAT
|
||||||
DataType.MATRIX -> DataType.WORD
|
DataType.MATRIX -> DataType.WORD
|
||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.WORD
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.WORD
|
||||||
}
|
}
|
||||||
@ -306,15 +309,21 @@ private fun builtinLen(args: List<IExpression>, position: Position, namespace:IN
|
|||||||
?: throw SyntaxError("len over weird argument ${args[0]}", position)
|
?: throw SyntaxError("len over weird argument ${args[0]}", position)
|
||||||
}
|
}
|
||||||
return when(argument.type) {
|
return when(argument.type) {
|
||||||
DataType.ARRAY, DataType.ARRAY_W -> {
|
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> {
|
||||||
val arraySize = argument.arrayvalue?.size ?: heap.get(argument.heapId!!).array!!.size
|
val arraySize = argument.arrayvalue?.size ?: heap.get(argument.heapId!!).array!!.size
|
||||||
numericLiteral(arraySize, args[0].position)
|
numericLiteral(arraySize, args[0].position)
|
||||||
}
|
}
|
||||||
|
DataType.ARRAY_F -> {
|
||||||
|
val arraySize = argument.arrayvalue?.size ?: heap.get(argument.heapId!!).doubleArray!!.size
|
||||||
|
numericLiteral(arraySize, args[0].position)
|
||||||
|
}
|
||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
||||||
val str = argument.strvalue ?: heap.get(argument.heapId!!).str!!
|
val str = argument.strvalue ?: heap.get(argument.heapId!!).str!!
|
||||||
numericLiteral(str.length, args[0].position)
|
numericLiteral(str.length, args[0].position)
|
||||||
}
|
}
|
||||||
else -> throw SyntaxError("len of weird argument ${args[0]}", position)
|
DataType.BYTE,
|
||||||
|
DataType.WORD,
|
||||||
|
DataType.FLOAT -> throw SyntaxError("len of weird argument ${args[0]}", position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,8 @@ package prog8.optimizing
|
|||||||
|
|
||||||
import prog8.ast.*
|
import prog8.ast.*
|
||||||
import prog8.compiler.HeapValues
|
import prog8.compiler.HeapValues
|
||||||
|
import prog8.compiler.target.c64.FLOAT_MAX_NEGATIVE
|
||||||
|
import prog8.compiler.target.c64.FLOAT_MAX_POSITIVE
|
||||||
import prog8.compiler.target.c64.Petscii
|
import prog8.compiler.target.c64.Petscii
|
||||||
|
|
||||||
|
|
||||||
@ -52,12 +54,41 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
|||||||
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> {
|
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> {
|
||||||
val litval = decl.value as? LiteralValue
|
val litval = decl.value as? LiteralValue
|
||||||
val size = decl.arrayspec!!.size()
|
val size = decl.arrayspec!!.size()
|
||||||
if (size != null) {
|
if(litval!=null && litval.isArray) {
|
||||||
|
// array initializer value is an array already, keep as-is
|
||||||
|
if(litval.heapId!=null) {
|
||||||
|
if (decl.datatype == DataType.MATRIX && litval.type != DataType.MATRIX) {
|
||||||
|
val array = heap.get(litval.heapId).copy(type = DataType.MATRIX)
|
||||||
|
heap.update(litval.heapId, array)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (size != null) {
|
||||||
|
// array initializer is empty or a single int, and we know the size; create the array.
|
||||||
val fillvalue = if (litval == null) 0 else litval.asIntegerValue ?: 0
|
val fillvalue = if (litval == null) 0 else litval.asIntegerValue ?: 0
|
||||||
val fillArray = IntArray(size) { _ -> fillvalue }
|
val fillArray = IntArray(size) { _ -> fillvalue }
|
||||||
val heapId = heap.add(decl.datatype, fillArray)
|
val heapId = heap.add(decl.datatype, fillArray)
|
||||||
val valType = if(decl.datatype==DataType.MATRIX) DataType.ARRAY else decl.datatype
|
decl.value = LiteralValue(decl.datatype, heapId = heapId, position = litval?.position ?: decl.position)
|
||||||
decl.value = LiteralValue(valType, heapId = heapId, position = litval?.position ?: decl.position)
|
}
|
||||||
|
}
|
||||||
|
DataType.ARRAY_F -> {
|
||||||
|
val litval = decl.value as? LiteralValue
|
||||||
|
val size = decl.arrayspec!!.size()
|
||||||
|
if(litval!=null && litval.isArray) {
|
||||||
|
// array initializer value is an array already, make sure to convert to floats
|
||||||
|
if(litval.heapId!=null) {
|
||||||
|
val array = heap.get(litval.heapId)
|
||||||
|
if (array.doubleArray == null) {
|
||||||
|
val doubleArray = array.array!!.map { it.toDouble() }.toDoubleArray()
|
||||||
|
heap.update(litval.heapId, HeapValues.HeapValue(DataType.ARRAY_F, null, null, doubleArray))
|
||||||
|
decl.value = LiteralValue(decl.datatype, heapId = litval.heapId, position = litval.position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (size != null) {
|
||||||
|
// array initializer is empty or a single int, and we know the size; create the array.
|
||||||
|
val fillvalue = if (litval == null) 0.0 else litval.asNumericValue?.toDouble() ?: 0.0
|
||||||
|
val fillArray = DoubleArray(size) { _ -> fillvalue }
|
||||||
|
val heapId = heap.add(decl.datatype, fillArray)
|
||||||
|
decl.value = LiteralValue(decl.datatype, heapId = heapId, position = litval?.position ?: decl.position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> return result
|
else -> return result
|
||||||
@ -66,21 +97,6 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createArrayInitValue(decl: VarDecl, intvalue: Int, position: Position) {
|
|
||||||
val size = decl.arrayspec!!.size()
|
|
||||||
if (size != null) {
|
|
||||||
val newArray = Array<IExpression>(size) { _ ->
|
|
||||||
if (decl.datatype == DataType.ARRAY)
|
|
||||||
LiteralValue(DataType.BYTE, bytevalue = intvalue.toShort(), position = position)
|
|
||||||
else
|
|
||||||
LiteralValue(DataType.WORD, wordvalue = intvalue, position = position)
|
|
||||||
}
|
|
||||||
decl.value = LiteralValue(decl.datatype, arrayvalue = newArray, position = position)
|
|
||||||
} else {
|
|
||||||
addError(SyntaxError("array size must be a constant integer value", position))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* replace identifiers that refer to const value, with the value itself
|
* replace identifiers that refer to const value, with the value itself
|
||||||
*/
|
*/
|
||||||
@ -289,48 +305,54 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
|||||||
}
|
}
|
||||||
} else if(literalValue.arrayvalue!=null) {
|
} else if(literalValue.arrayvalue!=null) {
|
||||||
val newArray = literalValue.arrayvalue.map { it.process(this) }.toTypedArray()
|
val newArray = literalValue.arrayvalue.map { it.process(this) }.toTypedArray()
|
||||||
// determine if the values are all bytes or that we need a word array instead
|
|
||||||
var arrayDt = DataType.ARRAY
|
var arrayDt = DataType.ARRAY
|
||||||
var allElementsAreConstant = true
|
if(newArray.any { it.resultingDatatype(namespace, heap) == DataType.WORD })
|
||||||
for (expr in newArray) {
|
arrayDt = DataType.ARRAY_W
|
||||||
allElementsAreConstant = allElementsAreConstant and (expr is LiteralValue)
|
if(newArray.any { it.resultingDatatype(namespace, heap) == DataType.FLOAT })
|
||||||
val valueDt = expr.resultingDatatype(namespace, heap)
|
arrayDt = DataType.ARRAY_F
|
||||||
if(valueDt==DataType.BYTE)
|
|
||||||
continue
|
|
||||||
else {
|
|
||||||
arrayDt = DataType.ARRAY_W
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the values are all constants, the array is moved to the heap
|
// if the values are all constants, the array is moved to the heap
|
||||||
|
val allElementsAreConstant = newArray.fold(true) { c, expr-> c and (expr is LiteralValue)}
|
||||||
if(allElementsAreConstant) {
|
if(allElementsAreConstant) {
|
||||||
val array = newArray.map {
|
val litArray = newArray.map{ it as? LiteralValue }
|
||||||
val litval = it as? LiteralValue
|
if(null in litArray) {
|
||||||
if(litval==null) {
|
addError(ExpressionError("array/matrix literal can contain only constant values", literalValue.position))
|
||||||
addError(ExpressionError("array/matrix literal can contain only constant values", literalValue.position))
|
return super.process(literalValue)
|
||||||
return super.process(literalValue)
|
}
|
||||||
}
|
if(arrayDt==DataType.ARRAY || arrayDt==DataType.MATRIX) {
|
||||||
if(litval.bytevalue==null && litval.wordvalue==null) {
|
// all values should be bytes
|
||||||
if(arrayDt==DataType.ARRAY)
|
val integerArray = litArray.map { (it as LiteralValue).bytevalue }
|
||||||
addError(ExpressionError("byte array elements must all be integers 0..255", literalValue.position))
|
if(integerArray.any { it==null || it.toInt() !in 0..255 }) {
|
||||||
else
|
|
||||||
addError(ExpressionError("word array elements must all be integers 0..65535", literalValue.position))
|
|
||||||
return super.process(literalValue)
|
|
||||||
}
|
|
||||||
val integer = litval.asIntegerValue!!
|
|
||||||
if(arrayDt==DataType.ARRAY && integer !in 0..255) {
|
|
||||||
addError(ExpressionError("byte array elements must all be integers 0..255", literalValue.position))
|
addError(ExpressionError("byte array elements must all be integers 0..255", literalValue.position))
|
||||||
return super.process(literalValue)
|
return super.process(literalValue)
|
||||||
} else if(arrayDt==DataType.ARRAY_W && integer !in 0..65535) {
|
}
|
||||||
|
val array = integerArray.mapNotNull { it?.toInt() }.toIntArray()
|
||||||
|
val heapId = heap.add(arrayDt, array)
|
||||||
|
val newValue = LiteralValue(arrayDt, heapId=heapId, position = literalValue.position)
|
||||||
|
return super.process(newValue)
|
||||||
|
} else if(arrayDt==DataType.ARRAY_W) {
|
||||||
|
// all values should be bytes or words
|
||||||
|
val integerArray = litArray.map { (it as LiteralValue).asIntegerValue }
|
||||||
|
if(integerArray.any {it==null || it !in 0..65535 }) {
|
||||||
addError(ExpressionError("word array elements must all be integers 0..65535", literalValue.position))
|
addError(ExpressionError("word array elements must all be integers 0..65535", literalValue.position))
|
||||||
return super.process(literalValue)
|
return super.process(literalValue)
|
||||||
}
|
}
|
||||||
integer
|
val array = integerArray.filterNotNull().toIntArray()
|
||||||
}.toIntArray()
|
val heapId = heap.add(arrayDt, array)
|
||||||
val heapId = heap.add(arrayDt, array)
|
val newValue = LiteralValue(DataType.ARRAY_W, heapId=heapId, position = literalValue.position)
|
||||||
val newValue = LiteralValue(arrayDt, heapId=heapId, position = literalValue.position)
|
return super.process(newValue)
|
||||||
return super.process(newValue)
|
} else if(arrayDt==DataType.ARRAY_F) {
|
||||||
|
// all values should be bytes, words or floats
|
||||||
|
val doubleArray = litArray.map { (it as LiteralValue).asNumericValue?.toDouble() }
|
||||||
|
if(doubleArray.any { it==null || it !in FLOAT_MAX_NEGATIVE..FLOAT_MAX_POSITIVE }) {
|
||||||
|
addError(ExpressionError("float array elements must all be floats in the acceptable range", literalValue.position))
|
||||||
|
return super.process(literalValue)
|
||||||
|
}
|
||||||
|
val array = doubleArray.filterNotNull().toDoubleArray()
|
||||||
|
val heapId = heap.add(arrayDt, array)
|
||||||
|
val newValue = LiteralValue(DataType.ARRAY_F, heapId=heapId, position = literalValue.position)
|
||||||
|
return super.process(newValue)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
addError(ExpressionError("array/matrix literal can contain only constant values", literalValue.position))
|
addError(ExpressionError("array/matrix literal can contain only constant values", literalValue.position))
|
||||||
}
|
}
|
||||||
@ -338,6 +360,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
|||||||
val newValue = LiteralValue(arrayDt, arrayvalue = newArray, position = literalValue.position)
|
val newValue = LiteralValue(arrayDt, arrayvalue = newArray, position = literalValue.position)
|
||||||
return super.process(newValue)
|
return super.process(newValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.process(literalValue)
|
return super.process(literalValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,9 +372,11 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
|||||||
if(arrayIndexedExpression.identifier!=null) {
|
if(arrayIndexedExpression.identifier!=null) {
|
||||||
val x = (arrayIndexedExpression.array.x as LiteralValue).asIntegerValue!!
|
val x = (arrayIndexedExpression.array.x as LiteralValue).asIntegerValue!!
|
||||||
val y = (arrayIndexedExpression.array.y as LiteralValue).asIntegerValue!!
|
val y = (arrayIndexedExpression.array.y as LiteralValue).asIntegerValue!!
|
||||||
val variable = arrayIndexedExpression.identifier.targetStatement(namespace) as VarDecl
|
val variable = arrayIndexedExpression.identifier.targetStatement(namespace) as? VarDecl
|
||||||
val index = x + y*(variable.arrayspec!!.x as LiteralValue).asIntegerValue!!
|
if(variable!=null) {
|
||||||
arrayIndexedExpression.array = ArraySpec(LiteralValue.optimalInteger(index, arrayIndexedExpression.array.position), null, arrayIndexedExpression.array.position)
|
val index = x + y * (variable.arrayspec!!.x as LiteralValue).asIntegerValue!!
|
||||||
|
arrayIndexedExpression.array = ArraySpec(LiteralValue.optimalInteger(index, arrayIndexedExpression.array.position), null, arrayIndexedExpression.array.position)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,12 @@ class Program (val name: String,
|
|||||||
val intarray = numbers.map{number->number.trim().toInt()}.toIntArray()
|
val intarray = numbers.map{number->number.trim().toInt()}.toIntArray()
|
||||||
heap.add(it.second, intarray)
|
heap.add(it.second, intarray)
|
||||||
}
|
}
|
||||||
else -> throw VmExecutionException("invalid heap value type $it.second")
|
DataType.ARRAY_F -> {
|
||||||
|
val numbers = it.third.substring(1, it.third.length-1).split(',')
|
||||||
|
val doublearray = numbers.map{number->number.trim().toDouble()}.toDoubleArray()
|
||||||
|
heap.add(it.second, doublearray)
|
||||||
|
}
|
||||||
|
DataType.BYTE, DataType.WORD, DataType.FLOAT -> throw VmExecutionException("invalid heap value type ${it.second}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -172,6 +177,7 @@ class Program (val name: String,
|
|||||||
}
|
}
|
||||||
DataType.ARRAY,
|
DataType.ARRAY,
|
||||||
DataType.ARRAY_W,
|
DataType.ARRAY_W,
|
||||||
|
DataType.ARRAY_F,
|
||||||
DataType.MATRIX -> {
|
DataType.MATRIX -> {
|
||||||
if(!valueStr.startsWith("heap:"))
|
if(!valueStr.startsWith("heap:"))
|
||||||
throw VmExecutionException("invalid array/matrix value, should be a heap reference")
|
throw VmExecutionException("invalid array/matrix value, should be a heap reference")
|
||||||
@ -281,6 +287,9 @@ class Program (val name: String,
|
|||||||
heap.allArrays().forEach {
|
heap.allArrays().forEach {
|
||||||
out.println("${it.index} ${it.value.type.toString().toLowerCase()} ${it.value.array!!.toList()}")
|
out.println("${it.index} ${it.value.type.toString().toLowerCase()} ${it.value.array!!.toList()}")
|
||||||
}
|
}
|
||||||
|
heap.allDoubleArrays().forEach {
|
||||||
|
out.println("${it.index} ${it.value.type.toString().toLowerCase()} ${it.value.doubleArray!!.toList()}")
|
||||||
|
}
|
||||||
out.println("%end_heap")
|
out.println("%end_heap")
|
||||||
out.println("%variables")
|
out.println("%variables")
|
||||||
// just flatten all block vars into one global list for now...
|
// just flatten all block vars into one global list for now...
|
||||||
|
@ -483,6 +483,7 @@ class StackVm(private var traceOutputFile: String?) {
|
|||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> print(heap.get(value.heapId).str)
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> print(heap.get(value.heapId).str)
|
||||||
DataType.ARRAY, DataType.ARRAY_W -> print(heap.get(value.heapId).array!!.toList())
|
DataType.ARRAY, DataType.ARRAY_W -> print(heap.get(value.heapId).array!!.toList())
|
||||||
DataType.MATRIX -> print(heap.get(value.heapId).array!!.toList())
|
DataType.MATRIX -> print(heap.get(value.heapId).array!!.toList())
|
||||||
|
DataType.ARRAY_F -> print(heap.get(value.heapId).doubleArray!!.toList())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Syscall.INPUT_STR -> {
|
Syscall.INPUT_STR -> {
|
||||||
@ -573,7 +574,8 @@ class StackVm(private var traceOutputFile: String?) {
|
|||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.BYTE
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.BYTE
|
||||||
DataType.ARRAY, DataType.MATRIX -> DataType.BYTE
|
DataType.ARRAY, DataType.MATRIX -> DataType.BYTE
|
||||||
DataType.ARRAY_W -> DataType.WORD
|
DataType.ARRAY_W -> DataType.WORD
|
||||||
else -> throw VmExecutionException("uniterable value $iterable")
|
DataType.ARRAY_F -> DataType.FLOAT
|
||||||
|
DataType.BYTE, DataType.WORD, DataType.FLOAT -> throw VmExecutionException("uniterable value $iterable")
|
||||||
}
|
}
|
||||||
if(value.str!=null) {
|
if(value.str!=null) {
|
||||||
val result = Petscii.encodePetscii(value.str.max().toString(), true)[0]
|
val result = Petscii.encodePetscii(value.str.max().toString(), true)[0]
|
||||||
@ -590,7 +592,8 @@ class StackVm(private var traceOutputFile: String?) {
|
|||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.BYTE
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.BYTE
|
||||||
DataType.ARRAY, DataType.MATRIX -> DataType.BYTE
|
DataType.ARRAY, DataType.MATRIX -> DataType.BYTE
|
||||||
DataType.ARRAY_W -> DataType.WORD
|
DataType.ARRAY_W -> DataType.WORD
|
||||||
else -> throw VmExecutionException("uniterable value $iterable")
|
DataType.ARRAY_F -> DataType.FLOAT
|
||||||
|
DataType.BYTE, DataType.WORD, DataType.FLOAT -> throw VmExecutionException("uniterable value $iterable")
|
||||||
}
|
}
|
||||||
if(value.str!=null) {
|
if(value.str!=null) {
|
||||||
val result = Petscii.encodePetscii(value.str.min().toString(), true)[0]
|
val result = Petscii.encodePetscii(value.str.min().toString(), true)[0]
|
||||||
@ -917,11 +920,17 @@ class StackVm(private var traceOutputFile: String?) {
|
|||||||
} else {
|
} else {
|
||||||
// get indexed element from the array
|
// get indexed element from the array
|
||||||
val array = heap.get(variable.heapId)
|
val array = heap.get(variable.heapId)
|
||||||
val result = array.array!![index]
|
|
||||||
when(array.type) {
|
when(array.type) {
|
||||||
DataType.ARRAY, DataType.MATRIX -> evalstack.push(Value(DataType.BYTE, result))
|
DataType.ARRAY, DataType.MATRIX -> evalstack.push(Value(DataType.BYTE, array.array!![index]))
|
||||||
DataType.ARRAY_W -> evalstack.push(Value(DataType.WORD, result))
|
DataType.ARRAY_W -> evalstack.push(Value(DataType.WORD, array.array!![index]))
|
||||||
else -> throw VmExecutionException("not a proper array/matrix var")
|
DataType.ARRAY_F -> evalstack.push(Value(DataType.FLOAT, array.doubleArray!![index]))
|
||||||
|
DataType.BYTE,
|
||||||
|
DataType.WORD,
|
||||||
|
DataType.FLOAT,
|
||||||
|
DataType.STR,
|
||||||
|
DataType.STR_P,
|
||||||
|
DataType.STR_S,
|
||||||
|
DataType.STR_PS -> throw VmExecutionException("not a proper array/matrix var")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,8 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
|||||||
return false
|
return false
|
||||||
if(type==other.type) {
|
if(type==other.type) {
|
||||||
return when (type) {
|
return when (type) {
|
||||||
DataType.STR, DataType.STR_S, DataType.STR_P, DataType.STR_PS, DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> heapId==other.heapId
|
DataType.STR, DataType.STR_S, DataType.STR_P, DataType.STR_PS,
|
||||||
|
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> heapId==other.heapId
|
||||||
DataType.BYTE, DataType.WORD, DataType.FLOAT -> compareTo(other)==0
|
DataType.BYTE, DataType.WORD, DataType.FLOAT -> compareTo(other)==0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,9 +86,17 @@ class TestStackVmValue {
|
|||||||
assertFalse(sameValueAndType(Value(DataType.STR, 999), Value(DataType.STR_P, 999)))
|
assertFalse(sameValueAndType(Value(DataType.STR, 999), Value(DataType.STR_P, 999)))
|
||||||
assertFalse(sameValueAndType(Value(DataType.STR, 999), Value(DataType.STR, 222)))
|
assertFalse(sameValueAndType(Value(DataType.STR, 999), Value(DataType.STR, 222)))
|
||||||
|
|
||||||
|
assertTrue(sameValueAndType(Value(DataType.ARRAY, 99), Value(DataType.ARRAY, 99)))
|
||||||
|
assertFalse(sameValueAndType(Value(DataType.ARRAY, 99), Value(DataType.MATRIX, 99)))
|
||||||
|
assertFalse(sameValueAndType(Value(DataType.ARRAY, 99), Value(DataType.ARRAY, 22)))
|
||||||
|
|
||||||
assertTrue(sameValueAndType(Value(DataType.ARRAY_W, 999), Value(DataType.ARRAY_W, 999)))
|
assertTrue(sameValueAndType(Value(DataType.ARRAY_W, 999), Value(DataType.ARRAY_W, 999)))
|
||||||
assertFalse(sameValueAndType(Value(DataType.ARRAY_W, 999), Value(DataType.MATRIX, 999)))
|
assertFalse(sameValueAndType(Value(DataType.ARRAY_W, 999), Value(DataType.MATRIX, 999)))
|
||||||
assertFalse(sameValueAndType(Value(DataType.ARRAY_W, 999), Value(DataType.ARRAY_W, 222)))
|
assertFalse(sameValueAndType(Value(DataType.ARRAY_W, 999), Value(DataType.ARRAY_W, 222)))
|
||||||
|
|
||||||
|
assertTrue(sameValueAndType(Value(DataType.ARRAY_F, 999), Value(DataType.ARRAY_F, 999)))
|
||||||
|
assertFalse(sameValueAndType(Value(DataType.ARRAY_F, 999), Value(DataType.ARRAY_W, 999)))
|
||||||
|
assertFalse(sameValueAndType(Value(DataType.ARRAY_F, 999), Value(DataType.ARRAY_F, 222)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -180,7 +180,8 @@ Values will usually be part of an expression or assignment statement::
|
|||||||
byte counter = 42 ; variable of size 8 bits, with initial value 42
|
byte counter = 42 ; variable of size 8 bits, with initial value 42
|
||||||
|
|
||||||
|
|
||||||
Array and Matrix (2-dimensional array) types are also supported like this::
|
Array and Matrix (2-dimensional array) types are also supported.
|
||||||
|
Arrays can be made of bytes, words and floats. Matrixes can oly be made of bytes::
|
||||||
|
|
||||||
byte[4] array = [1, 2, 3, 4] ; initialize the array
|
byte[4] array = [1, 2, 3, 4] ; initialize the array
|
||||||
byte[99] array = 255 ; initialize array with all 255's [255, 255, 255, 255, ...]
|
byte[99] array = 255 ; initialize array with all 255's [255, 255, 255, 255, ...]
|
||||||
@ -313,7 +314,8 @@ Loops
|
|||||||
-----
|
-----
|
||||||
|
|
||||||
The *for*-loop is used to let a variable (or register) iterate over a range of values. Iteration is done in steps of 1, but you can change this.
|
The *for*-loop is used to let a variable (or register) iterate over a range of values. Iteration is done in steps of 1, but you can change this.
|
||||||
The loop variable must be declared as byte or word earlier. Floating point iteration is not supported.
|
The loop variable must be declared as byte or word earlier. Floating point iteration is not supported,
|
||||||
|
if you want to loop over a floating-point array, use a loop with an integer index variable instead.
|
||||||
|
|
||||||
The *while*-loop is used to repeat a piece of code while a certain condition is still true.
|
The *while*-loop is used to repeat a piece of code while a certain condition is still true.
|
||||||
The *repeat--until* loop is used to repeat a piece of code until a certain condition is true.
|
The *repeat--until* loop is used to repeat a piece of code until a certain condition is true.
|
||||||
|
@ -235,6 +235,7 @@ type identifier type storage size example var declara
|
|||||||
stored in 5-byte cbm MFLPT format
|
stored in 5-byte cbm MFLPT format
|
||||||
``byte[x]`` unsigned byte array x bytes ``byte[4] myvar = [1, 2, 3, 4]``
|
``byte[x]`` unsigned byte array x bytes ``byte[4] myvar = [1, 2, 3, 4]``
|
||||||
``word[x]`` unsigned word array 2*x bytes ``word[4] myvar = [1, 2, 3, 4]``
|
``word[x]`` unsigned word array 2*x bytes ``word[4] myvar = [1, 2, 3, 4]``
|
||||||
|
``float[x]`` floating-point array 5*x bytes ``float[4] myvar = [1.1, 2.2, 3.3, 4.4]``
|
||||||
``byte[x,y]`` unsigned byte matrix x*y bytes ``byte[40,25] myvar = @todo``
|
``byte[x,y]`` unsigned byte matrix x*y bytes ``byte[40,25] myvar = @todo``
|
||||||
word-matrix not supported
|
word-matrix not supported
|
||||||
``str`` string (petscii) varies ``str myvar = "hello."``
|
``str`` string (petscii) varies ``str myvar = "hello."``
|
||||||
@ -450,9 +451,9 @@ Loops
|
|||||||
for loop
|
for loop
|
||||||
^^^^^^^^
|
^^^^^^^^
|
||||||
|
|
||||||
The loop variable must be a register or a variable defined in the local scope.
|
The loop variable must be a register or a byte/word variable defined in the local scope.
|
||||||
The expression that you loop over can be anything that supports iteration (such as ranges like ``0 to 100``,
|
The expression that you loop over can be anything that supports iteration (such as ranges like ``0 to 100``,
|
||||||
array variables and strings).
|
array variables and strings) *except* floating-point arrays (because a floating-point loop variable is not supported).
|
||||||
|
|
||||||
You can use a single statement, or a statement block like in the example below::
|
You can use a single statement, or a statement block like in the example below::
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user