allow creating string arrays. Fixed array index scaling for word arrays.

This commit is contained in:
Irmen de Jong 2020-09-28 02:23:36 +02:00
parent 066233eee8
commit af0fb88adf
8 changed files with 104 additions and 15 deletions

View File

@ -569,6 +569,7 @@ class ArrayLiteralValue(val type: InferredTypes.InferredType, // inferred be
val dts = datatypesInArray.map { it.typeOrElse(DataType.STRUCT) }
return when {
DataType.FLOAT in dts -> InferredTypes.InferredType.known(DataType.ARRAY_F)
DataType.STR in dts -> InferredTypes.InferredType.known(DataType.ARRAY_UW)
DataType.WORD in dts -> InferredTypes.InferredType.known(DataType.ARRAY_W)
DataType.UWORD in dts -> InferredTypes.InferredType.known(DataType.ARRAY_UW)
DataType.BYTE in dts -> InferredTypes.InferredType.known(DataType.ARRAY_B)

View File

@ -742,7 +742,15 @@ internal class AstChecker(private val program: Program,
checkValueTypeAndRangeArray(array.type.typeOrElse(DataType.STRUCT), null, arrayspec, array)
}
if(!array.value.all { it is NumericLiteralValue || it is AddressOf || it is StringLiteralValue }) {
fun isStringElement(e: Expression): Boolean {
if(e is IdentifierReference) {
val decl = e.targetVarDecl(program.namespace)!!
return decl.datatype==DataType.STR
}
return e is StringLiteralValue
}
if(!array.value.all { it is NumericLiteralValue || it is AddressOf || isStringElement(it) }) {
// TODO for now, array literals have to consist of all compile time constant values...
errors.err("array literal doesn't consist of only compile time constant values", array.position)
}

View File

@ -26,6 +26,19 @@ class VerifyFunctionArgTypes(val program: Program) : IAstVisitor {
}
companion object {
private fun argTypeCompatible(argDt: DataType, paramDt: DataType): Boolean {
if(argDt==paramDt)
return true
// there are some exceptions that are considered compatible, such as STR <> UWORD
if(argDt==DataType.STR && paramDt==DataType.UWORD ||
argDt==DataType.UWORD && paramDt==DataType.STR)
return true
return false
}
fun checkTypes(call: IFunctionCall, scope: INameScope, program: Program): String? {
val argtypes = call.args.map { it.inferType(program).typeOrElse(DataType.STRUCT) }
val target = call.target.targetStatement(scope)
@ -34,7 +47,7 @@ class VerifyFunctionArgTypes(val program: Program) : IAstVisitor {
if(call.args.size != target.parameters.size)
return "invalid number of arguments"
val paramtypes = target.parameters.map { it.type }
val mismatch = argtypes.zip(paramtypes).indexOfFirst { it.first != it.second}
val mismatch = argtypes.zip(paramtypes).indexOfFirst { !argTypeCompatible(it.first, it.second) }
if(mismatch>=0) {
val actual = argtypes[mismatch].toString()
val expected = paramtypes[mismatch].toString()
@ -47,7 +60,8 @@ class VerifyFunctionArgTypes(val program: Program) : IAstVisitor {
return "invalid number of arguments"
val paramtypes = func.parameters.map { it.possibleDatatypes }
for (x in argtypes.zip(paramtypes).withIndex()) {
if (x.value.first !in x.value.second) {
val anyCompatible = x.value.second.any { argTypeCompatible(x.value.first, it) }
if (!anyCompatible) {
val actual = x.value.first.toString()
val expected = x.value.second.toString()
return "argument ${x.index + 1} type mismatch, was: $actual expected: $expected"

View File

@ -214,8 +214,9 @@ open class VarDecl(val type: VarDeclType,
DataType.UWORD -> DataType.ARRAY_UW
DataType.WORD -> DataType.ARRAY_W
DataType.FLOAT -> DataType.ARRAY_F
DataType.STR -> DataType.ARRAY_UW // use memory address of the string instead
else -> {
datatypeErrors.add(SyntaxError("array can only contain bytes/words/floats", position))
datatypeErrors.add(SyntaxError("array can only contain bytes/words/floats/strings(ptrs)", position))
DataType.ARRAY_UB
}
}

View File

@ -406,10 +406,17 @@ internal class AsmGen(private val program: Program,
"$"+number.toString(16).padStart(2, '0')
}
DataType.ARRAY_UW -> array.map {
if(it is NumericLiteralValue) {
"$" + it.number.toInt().toString(16).padStart(4, '0')
} else {
(it as AddressOf).identifier.nameInSource.joinToString(".")
when (it) {
is NumericLiteralValue -> {
"$" + it.number.toInt().toString(16).padStart(4, '0')
}
is AddressOf -> {
it.identifier.nameInSource.joinToString(".")
}
is IdentifierReference -> {
it.nameInSource.joinToString(".")
}
else -> throw AssemblyError("weird array elt dt")
}
}
else -> throw AssemblyError("invalid arraysize type")
@ -711,10 +718,40 @@ internal class AsmGen(private val program: Program,
}
else {
expressionsAsmGen.translateExpression(index)
when(register) {
CpuRegister.A -> out(" inx | lda P8ESTACK_LO,x")
CpuRegister.X -> out(" inx | lda P8ESTACK_LO,x | tax")
CpuRegister.Y -> out(" inx | ldy P8ESTACK_LO,x")
when(elementDt) {
in ByteDatatypes -> {
when (register) {
CpuRegister.A -> out(" inx | lda P8ESTACK_LO,x")
CpuRegister.X -> out(" inx | lda P8ESTACK_LO,x | tax")
CpuRegister.Y -> out(" inx | ldy P8ESTACK_LO,x")
}
}
in WordDatatypes -> {
out("""
inx
lda P8ESTACK_LO,x
asl a""")
when (register) {
CpuRegister.A -> {}
CpuRegister.X -> out(" tax")
CpuRegister.Y -> out(" tay")
}
}
DataType.FLOAT -> {
require(DataType.FLOAT.memorySize()==5)
out("""
inx
lda P8ESTACK_LO,x
asl a
asl a
clc
adc P8ESTACK_LO,x""")
when (register) {
CpuRegister.A -> {}
CpuRegister.X -> out(" tax")
CpuRegister.Y -> out(" tay")
}
}
}
}
}

View File

@ -236,12 +236,13 @@ The largest 5-byte MFLPT float that can be stored is: **1.7014118345e+38** (ne
Arrays
^^^^^^
Array types are also supported. They can be made of bytes, words or floats::
Array types are also supported. They can be made of bytes, words or floats, and strings::
byte[10] array ; array of 10 bytes, initially set to 0
byte[] array = [1, 2, 3, 4] ; initialize the array, size taken from value
byte[99] array = 255 ; initialize array with 99 times 255 [255, 255, 255, 255, ...]
byte[] array = 100 to 199 ; initialize array with [100, 101, ..., 198, 199]
str[] names = ["ally", "pete"] ; array of string pointers/addresses (equivalent to uword)
value = array[3] ; the fourth value in the array (index is 0-based)
char = string[4] ; the fifth character (=byte) in the string
@ -293,6 +294,12 @@ large enough to contain the new value::
string1 = "new value"
.. info::
Strings and uwords (=memory address) can often be interchanged.
An array of strings is actually an array of uwords where every element is the memory
address of the string. You can pass a memory address to assembly functions
that require a string as an argument.
.. caution::
It's probably best to avoid changing strings after they've been created. This
includes changing certain letters by index, or by assigning a new value, or by
@ -718,7 +725,7 @@ sort(array)
floating point values.
reverse(array)
Reverse the values in the array (in-place). Supports all data types including floats.
Reverse the values in the array (in-place).
Can be used after sort() to sort an array in descending order.
len(x)

View File

@ -281,6 +281,7 @@ type identifier type storage size example var declara
``word[]`` signed word array depends on value ``word[] myvar = [1, 2, 3, 4]``
``uword[]`` unsigned word array depends on value ``uword[] myvar = [1, 2, 3, 4]``
``float[]`` floating-point array depends on value ``float[] myvar = [1.1, 2.2, 3.3, 4.4]``
``str[]`` array with string ptrs 2*x bytes + strs ``str[] names = ["ally", "pete"]``
``str`` string (petscii) varies ``str myvar = "hello."``
implicitly terminated by a 0-byte
=============== ======================= ================= =========================================

View File

@ -4,8 +4,28 @@
main {
str[] names = ["aap", "noot", "mies", "vuur"]
uword[] names3 = ["aap", "noot", "mies", "vuur"]
ubyte[] values = [11,22,33,44]
sub start() {
txt.print("hello\n")
uword s
for s in names {
txt.print(s)
txt.chrout('\n')
}
txt.chrout('\n')
txt.print(names[2])
txt.chrout('\n')
txt.print(names[3])
txt.chrout('\n')
repeat {
txt.print(names3[rnd()&3]) ; TODO doesn't show correct names? only shows 'aap' and 'noot' works fine if idx in separate var
txt.chrout(' ')
}
}
}