From 7d20458e826054c222c26d7f8208125ff3e0def4 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 10 Mar 2022 00:21:25 +0100 Subject: [PATCH] fixed arrayliteral regression --- .../codegen/cpu6502/ProgramAndVarsGen.kt | 59 ++++++++++--------- .../astprocessing/SymbolTableMaker.kt | 21 +++---- compiler/test/ast/TestVarious.kt | 25 ++++++++ .../prog8/compilerinterface/SymbolTable.kt | 13 ++-- docs/source/programming.rst | 6 +- docs/source/todo.rst | 5 +- 6 files changed, 80 insertions(+), 49 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt index fcf684e31..b53b55e8f 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt @@ -439,7 +439,7 @@ internal class ProgramAndVarsGen( private class ZpArrayWithInitial( val name: List, val alloc: Zeropage.ZpAllocation, - val value: DoubleArray + val value: StArray ) private fun getZpStringVarsWithInitvalue(): Collection { @@ -518,7 +518,7 @@ internal class ProgramAndVarsGen( } } - private fun arrayVariable2asm(varname: String, dt: DataType, value: DoubleArray?, orNumberOfZeros: Int?) { + private fun arrayVariable2asm(varname: String, dt: DataType, value: StArray?, orNumberOfZeros: Int?) { when(dt) { DataType.ARRAY_UB -> { val data = makeArrayFillDataUnsigned(dt, value, orNumberOfZeros) @@ -561,9 +561,9 @@ internal class ProgramAndVarsGen( } } DataType.ARRAY_F -> { - val array = value ?: DoubleArray(orNumberOfZeros!!) + val array = value ?: zeroFilledArray(orNumberOfZeros!!) val floatFills = array.map { - compTarget.machine.getFloat(it).makeFloatFillAsm() + compTarget.machine.getFloat(it.number!!).makeFloatFillAsm() } asmgen.out(varname) for (f in array.zip(floatFills)) @@ -573,6 +573,14 @@ internal class ProgramAndVarsGen( } } + private fun zeroFilledArray(numElts: Int): StArray { + val values = mutableListOf() + repeat(numElts) { + values.add(StArrayElement(0.0, null)) + } + return values + } + private fun memdefsAndConsts2asm(memvars: Collection, consts: Collection) { memvars.forEach { asmgen.out(" ${it.name} = ${it.address.toHex()}") @@ -602,48 +610,41 @@ internal class ProgramAndVarsGen( asmgen.out(" .byte " + chunk.joinToString()) } - private fun makeArrayFillDataUnsigned(dt: DataType, value: DoubleArray?, orNumberOfZeros: Int?): List { - val array = value ?: DoubleArray(orNumberOfZeros!!) + private fun makeArrayFillDataUnsigned(dt: DataType, value: StArray?, orNumberOfZeros: Int?): List { + val array = value ?: zeroFilledArray(orNumberOfZeros!!) return when (dt) { DataType.ARRAY_UB -> // byte array can never contain pointer-to types, so treat values as all integers array.map { - val number = it.toInt() + val number = it.number!!.toInt() "$"+number.toString(16).padStart(2, '0') } DataType.ARRAY_UW -> array.map { - "$" + it.toInt().toString(16).padStart(4, '0') - // TODO: initial array literals with address-of, or just variable references, are no longer possible at this time -// when (it) { -// is NumericLiteral -> { -// "$" + it.number.toInt().toString(16).padStart(4, '0') -// } -// is AddressOf -> { -// asmgen.asmSymbolName(it.identifier) -// } -// is IdentifierReference -> { -// asmgen.asmSymbolName(it) -// } -// else -> throw AssemblyError("weird array elt dt") -// } + if(it.number!=null) { + "$" + it.number!!.toInt().toString(16).padStart(4, '0') + } + else if(it.addressOf!=null) { + asmgen.asmSymbolName(it.addressOf!!) + } + else + throw AssemblyError("weird array elt") } else -> throw AssemblyError("invalid dt") } } - private fun makeArrayFillDataSigned(dt: DataType, value: DoubleArray?, orNumberOfZeros: Int?): List { - val array = value ?: DoubleArray(orNumberOfZeros!!) + private fun makeArrayFillDataSigned(dt: DataType, value: StArray?, orNumberOfZeros: Int?): List { + val array = value ?: zeroFilledArray(orNumberOfZeros!!) return when (dt) { + // byte array can never contain pointer-to types, so treat values as all integers DataType.ARRAY_UB -> - // byte array can never contain pointer-to types, so treat values as all integers array.map { - val number = it.toInt() + val number = it.number!!.toInt() "$"+number.toString(16).padStart(2, '0') } DataType.ARRAY_B -> - // byte array can never contain pointer-to types, so treat values as all integers array.map { - val number = it.toInt() + val number = it.number!!.toInt() val hexnum = number.absoluteValue.toString(16).padStart(2, '0') if(number>=0) "$$hexnum" @@ -651,11 +652,11 @@ internal class ProgramAndVarsGen( "-$$hexnum" } DataType.ARRAY_UW -> array.map { - val number = it.toInt() + val number = it.number!!.toInt() "$" + number.toString(16).padStart(4, '0') } DataType.ARRAY_W -> array.map { - val number = it.toInt() + val number = it.number!!.toInt() val hexnum = number.absoluteValue.toString(16).padStart(4, '0') if(number>=0) "$$hexnum" diff --git a/compiler/src/prog8/compiler/astprocessing/SymbolTableMaker.kt b/compiler/src/prog8/compiler/astprocessing/SymbolTableMaker.kt index 3f43b6814..b286bc32e 100644 --- a/compiler/src/prog8/compiler/astprocessing/SymbolTableMaker.kt +++ b/compiler/src/prog8/compiler/astprocessing/SymbolTableMaker.kt @@ -1,11 +1,10 @@ package prog8.compiler.astprocessing import prog8.ast.Program +import prog8.ast.base.FatalAstException import prog8.ast.base.Position import prog8.ast.base.VarDeclType -import prog8.ast.expressions.ArrayLiteral -import prog8.ast.expressions.NumericLiteral -import prog8.ast.expressions.StringLiteral +import prog8.ast.expressions.* import prog8.ast.statements.Block import prog8.ast.statements.Label import prog8.ast.statements.Subroutine @@ -66,15 +65,17 @@ internal class SymbolTableMaker: IAstVisitor { st.origAstLinks[decl] = node } - private fun makeInitialArray(arrayLit: ArrayLiteral?): DoubleArray? { + private fun makeInitialArray(arrayLit: ArrayLiteral?): StArray? { if(arrayLit==null) return null return arrayLit.value.map { - if(it !is NumericLiteral) - TODO("ability to have addressof or variables inside array literal currently not possible @ ${arrayLit.position}") - else - it.number - }.toDoubleArray() + when(it){ + is AddressOf -> StArrayElement(null, it.identifier.nameInSource) + is IdentifierReference -> StArrayElement(null, it.nameInSource) + is NumericLiteral -> StArrayElement(it.number, null) + else -> throw FatalAstException("weird element dt in array literal") + } + }.toList() } override fun visit(label: Label) { @@ -82,4 +83,4 @@ internal class SymbolTableMaker: IAstVisitor { scopestack.peek().add(node) st.origAstLinks[label] = node } -} \ No newline at end of file +} diff --git a/compiler/test/ast/TestVarious.kt b/compiler/test/ast/TestVarious.kt index 414da0af0..8e40f4ed0 100644 --- a/compiler/test/ast/TestVarious.kt +++ b/compiler/test/ast/TestVarious.kt @@ -2,8 +2,12 @@ package prog8tests.ast import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe +import io.kotest.matchers.shouldNotBe import prog8.ast.base.Position import prog8.ast.statements.InlineAssembly +import prog8.codegen.target.C64Target +import prog8.compiler.compileProgram +import prog8tests.helpers.compileText class TestVarious: FunSpec({ test("symbol names in inline assembly blocks") { @@ -25,5 +29,26 @@ label2: names2 shouldBe setOf("label", "lda", "sta", "ea", "value", "label2", "othervalue", "valid", "words") } + + test("array literals") { + val text=""" +%zeropage basicsafe + +main { + sub start() { + ubyte b1 + ubyte b2 + ubyte[] array1 = [1,2,3] + ubyte[] array2 = [9,8,7] + + uword[] @shared addresses1 = [&b1, &b2] + uword[] @shared addresses2 = [array1, array2] + uword[] @shared addresses3 = [&array1, &array2] + uword[] @shared addresses4 = ["string1", "string2"] + uword[] @shared addresses5 = [1111, 2222] + } +}""" + compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null + } }) diff --git a/compilerInterfaces/src/prog8/compilerinterface/SymbolTable.kt b/compilerInterfaces/src/prog8/compilerinterface/SymbolTable.kt index 7f0a7a6cc..5f389e0cd 100644 --- a/compilerInterfaces/src/prog8/compilerinterface/SymbolTable.kt +++ b/compilerInterfaces/src/prog8/compilerinterface/SymbolTable.kt @@ -4,7 +4,6 @@ import prog8.ast.Node import prog8.ast.base.DataType import prog8.ast.base.Position import prog8.ast.statements.ZeropageWish -import prog8.ast.toHex /** @@ -123,8 +122,8 @@ open class StNode(val name: String, class StStaticVariable(name: String, val dt: DataType, val initialNumericValue: Double?, - val initialStringValue: Pair?, - val initialArrayValue: DoubleArray?, + val initialStringValue: StString?, + val initialArrayValue: StArray?, val arraysize: Int?, val zpw: ZeropageWish, position: Position) : StNode(name, StNodeType.STATICVAR, position) { @@ -153,6 +152,12 @@ class StMemVar(name: String, val dt: DataType, val address: UInt, position: Posi StNode(name, StNodeType.MEMVAR, position ) { override fun printProperties() { - print("$name dt=$dt address=${address.toHex()}") + print("$name dt=$dt address=${address.toString(16).padStart(4,'0')}") } } + + +class StArrayElement(val number: Double?, val addressOf: List?) + +typealias StString = Pair +typealias StArray = List diff --git a/docs/source/programming.rst b/docs/source/programming.rst index 34e1180c4..3885163b2 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -260,8 +260,10 @@ 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, strings, and other arrays -(although the usefulness of the latter is very limited for now):: +Array types are also supported. They can be formed from a list of bytes, words, floats, or addresses of other variables +(such as explicit address-of expressions, strings, or other array variables) - values in an array literal +always have to be constants. Putting variables inside an array has to be done on a value-by-value basis. +Here are some examples of arrays:: byte[10] array ; array of 10 bytes, initially set to 0 byte[] array = [1, 2, 3, 4] ; initialize the array, size taken from value diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 5347e84f9..ea063da15 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,13 +3,10 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- make 'intermediate' module containing the SymbolTable and dumbed down version of the Ast. +- make an intermediate representation containing the SymbolTable and dumbed down version of the Ast. no vardecls in it anymore (these are part of the symboltable) and baked types, so no inferType too. no name lookup in the Ast, always do this in the symbol table. -- codegen makeInitialArray()/makeArrayFillDataUnsigned(): - initial array literals with address-of, or just variable references, are no longer possible at this time!! - ...