From 3f93b8774534fe48bd51f4e9b470580f29e566db Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 12 Apr 2019 00:04:15 +0200 Subject: [PATCH] fix array processing and ASM code gen of arrays with addressOf in them --- compiler/src/prog8/ast/AST.kt | 3 +++ compiler/src/prog8/ast/AstChecker.kt | 4 +++- .../src/prog8/ast/AstIdentifiersChecker.kt | 10 ++++++++- compiler/src/prog8/ast/StmtReorderer.kt | 3 ++- compiler/src/prog8/compiler/Compiler.kt | 17 ++++++++------- .../intermediate/IntermediateProgram.kt | 11 +++++++--- .../src/prog8/compiler/target/c64/AsmGen.kt | 9 ++++---- .../src/prog8/optimizing/ConstantFolding.kt | 19 ++++++++++------- compiler/src/prog8/stackvm/Program.kt | 16 ++++++++++++-- compiler/src/prog8/stackvm/StackVm.kt | 21 +++++++++++++++---- examples/test.p8 | 10 ++++++++- 11 files changed, 92 insertions(+), 31 deletions(-) diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index cdfc8a1de..55fd1c7e7 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -210,6 +210,7 @@ interface IAstProcessor { } fun process(literalValue: LiteralValue): LiteralValue { + literalValue.arrayvalue?.forEach { it.process(this) } return literalValue } @@ -290,6 +291,7 @@ interface IAstProcessor { } fun process(addressOf: AddressOf): IExpression { + process(addressOf.identifier) return addressOf } } @@ -1018,6 +1020,7 @@ data class AddressOf(val identifier: IdentifierReference, override val position: identifier.parent=this } + var scopedname: String? = null // will be set in a later state by the compiler override fun isIterable(namespace: INameScope, heap: HeapValues) = false override fun constValue(namespace: INameScope, heap: HeapValues): LiteralValue? = null override fun referencesIdentifier(name: String) = false diff --git a/compiler/src/prog8/ast/AstChecker.kt b/compiler/src/prog8/ast/AstChecker.kt index aa1b4b759..58f022792 100644 --- a/compiler/src/prog8/ast/AstChecker.kt +++ b/compiler/src/prog8/ast/AstChecker.kt @@ -464,7 +464,9 @@ private class AstChecker(private val namespace: INameScope, if(variable.datatype !in ArrayDatatypes && variable.datatype !in StringDatatypes) checkResult.add(ExpressionError("pointer-of operand must be the name of a string or array heap variable", addressOf.position)) } - return addressOf + if(addressOf.scopedname==null) + throw FatalAstException("the scopedname of AddressOf should have been set by now $addressOf") + return super.process(addressOf) } /** diff --git a/compiler/src/prog8/ast/AstIdentifiersChecker.kt b/compiler/src/prog8/ast/AstIdentifiersChecker.kt index a91830e95..97e0b12db 100644 --- a/compiler/src/prog8/ast/AstIdentifiersChecker.kt +++ b/compiler/src/prog8/ast/AstIdentifiersChecker.kt @@ -20,7 +20,7 @@ fun Module.checkIdentifiers(namespace: INameScope) { val parent = variable.first.parent when { parent is Assignment && parent.value === variable.first -> { - val idref = IdentifierReference(listOf("$${variable.first.heapId}"), variable.first.position) + val idref = IdentifierReference(listOf("$autoHeapValuePrefix${variable.first.heapId}"), variable.first.position) idref.linkParents(parent) parent.value = idref } @@ -229,6 +229,14 @@ private class AstIdentifiersChecker(private val namespace: INameScope) : IAstPro } return super.process(literalValue) } + + override fun process(addressOf: AddressOf): IExpression { + // register the scoped name of the referenced identifier + val variable= addressOf.identifier.targetStatement(namespace) as? VarDecl ?: return addressOf + addressOf.scopedname = variable.scopedname + return super.process(addressOf) + } + } internal const val autoHeapValuePrefix = "auto_heap_value_" diff --git a/compiler/src/prog8/ast/StmtReorderer.kt b/compiler/src/prog8/ast/StmtReorderer.kt index c0c08ff1d..66f3f0d14 100644 --- a/compiler/src/prog8/ast/StmtReorderer.kt +++ b/compiler/src/prog8/ast/StmtReorderer.kt @@ -279,6 +279,7 @@ private class VarInitValueAndAddressOfCreator(private val namespace: INameScope) val variable = idref.targetStatement(namespace) as? VarDecl if(variable!=null && (variable.datatype in StringDatatypes || variable.datatype in ArrayDatatypes)) { val pointerExpr = AddressOf(idref, idref.position) + pointerExpr.scopedname = (idref.parent as IStatement).makeScopedName(idref.nameInSource.single()) pointerExpr.linkParents(arglist[argparam.first.index].parent) arglist[argparam.first.index] = pointerExpr } @@ -289,6 +290,7 @@ private class VarInitValueAndAddressOfCreator(private val namespace: INameScope) val autoVarName = "$autoHeapValuePrefix${strvalue.heapId}" val autoHeapvarRef = IdentifierReference(listOf(autoVarName), strvalue.position) val pointerExpr = AddressOf(autoHeapvarRef, strvalue.position) + pointerExpr.scopedname = (strvalue.parent as IStatement).makeScopedName(autoVarName) pointerExpr.linkParents(arglist[argparam.first.index].parent) arglist[argparam.first.index] = pointerExpr // add a vardecl so that the autovar can be resolved in later lookups @@ -296,7 +298,6 @@ private class VarInitValueAndAddressOfCreator(private val namespace: INameScope) addVarDecl(strvalue.definingScope(), variable) } } - else throw FatalAstException("expected either an identifier or a literal as argument to $subroutine") } } } diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 57aa84d2b..3022993a6 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -13,6 +13,7 @@ import prog8.stackvm.Syscall import java.io.File import java.nio.file.Path import java.util.* +import javax.lang.model.type.ArrayType import kotlin.math.abs @@ -81,15 +82,17 @@ class HeapValues { fun addIntegerArray(type: DataType, array: Array): Int { // arrays are never shared, don't check for existing + if(type !in ArrayDatatypes) + throw CompilerException("wrong array type") val newId = heapId++ heap[newId] = HeapValue(type, null, array, null) return newId } - fun addDoublesArray(type: DataType, darray: DoubleArray): Int { + fun addDoublesArray(darray: DoubleArray): Int { // arrays are never shared, don't check for existing val newId = heapId++ - heap[newId] = HeapValue(type, null, null, darray) + heap[newId] = HeapValue(DataType.ARRAY_F, null, null, darray) return newId } @@ -2134,16 +2137,16 @@ internal class Compiler(private val rootModule: Module, } } - private fun translate(ptrof: AddressOf) { - val target = ptrof.identifier.targetStatement(namespace) as VarDecl + private fun translate(addrof: AddressOf) { + val target = addrof.identifier.targetStatement(namespace) as VarDecl if(target.datatype in ArrayDatatypes || target.datatype in StringDatatypes|| target.datatype==DataType.FLOAT) { - pushHeapVarAddress(ptrof.identifier, false) + pushHeapVarAddress(addrof.identifier, false) } else if(target.datatype==DataType.FLOAT) { - pushFloatAddress(ptrof.identifier) + pushFloatAddress(addrof.identifier) } else - throw CompilerException("cannot take memory pointer $ptrof") + throw CompilerException("cannot take memory pointer $addrof") } private fun translateAsmInclude(args: List, importedFrom: Path) { diff --git a/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt b/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt index 5186ea75e..913d80bd0 100644 --- a/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt +++ b/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt @@ -14,9 +14,9 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap class ProgramBlock(val name: String, var address: Int?, val instructions: MutableList = mutableListOf(), - val variables: MutableMap = mutableMapOf(), + val variables: MutableMap = mutableMapOf(), // names are fully scoped val memoryPointers: MutableMap> = mutableMapOf(), - val labels: MutableMap = mutableMapOf(), + val labels: MutableMap = mutableMapOf(), // names are fully scoped val force_output: Boolean) { val numVariables: Int @@ -468,7 +468,12 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap val arrayvalues = it.value.array!!.map { av -> when { av.integer!=null -> av.integer.toString() - av.addressOf!=null -> "&${av.addressOf.identifier}" + av.addressOf!=null -> { + if(av.addressOf.scopedname==null) + throw CompilerException("AddressOf scopedname should have been set") + else + "&${av.addressOf.scopedname}" + } else -> throw CompilerException("weird array value") } } diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index 240a34c6e..e3c2a60a1 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -364,10 +364,11 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, // byte array can never contain pointer-to types, so treat values as all integers array.map { "$"+it.integer!!.toString(16).padStart(2, '0') } value.type==DataType.ARRAY_UW -> array.map { - if(it.integer!=null) - "$"+it.integer.toString(16).padStart(2, '0') - else - TODO("deal with addressOf") + when { + it.integer!=null -> "$"+it.integer.toString(16).padStart(2, '0') + it.addressOf!=null -> symname(it.addressOf.scopedname!!, block) + else -> throw AssemblyError("weird type in array") + } } else -> throw AssemblyError("invalid arrayspec type") } diff --git a/compiler/src/prog8/optimizing/ConstantFolding.kt b/compiler/src/prog8/optimizing/ConstantFolding.kt index 5b996fcd1..d78c63d86 100644 --- a/compiler/src/prog8/optimizing/ConstantFolding.kt +++ b/compiler/src/prog8/optimizing/ConstantFolding.kt @@ -82,8 +82,8 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV if(fillvalue< FLOAT_MAX_NEGATIVE || fillvalue> FLOAT_MAX_POSITIVE) errors.add(ExpressionError("float value overflow", litval?.position ?: decl.position)) else { - val heapId = heap.addDoublesArray(decl.datatype, DoubleArray(size) { fillvalue }) - decl.value = LiteralValue(decl.datatype, heapId = heapId, position = litval?.position ?: decl.position) + val heapId = heap.addDoublesArray(DoubleArray(size) { fillvalue }) + decl.value = LiteralValue(DataType.ARRAY_F, heapId = heapId, position = litval?.position ?: decl.position) } } } @@ -551,10 +551,15 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV addError(ExpressionError("array literal can only consist of constant primitive numerical values or memory pointers", arraylit.position)) return arraylit } else if(array.any {it is AddressOf}) { - val arrayDt = DataType.UWORD - val intArrayWithAddressOfs = mutableListOf() - // TODO AddressOf: FILL THIS ARRAY - val heapId = heap.addIntegerArray(DataType.UWORD, intArrayWithAddressOfs.toTypedArray()) + val arrayDt = DataType.ARRAY_UW + val intArrayWithAddressOfs = array.map { + when (it) { + is AddressOf -> IntegerOrAddressOf(null, it) + is LiteralValue -> IntegerOrAddressOf(it.asIntegerValue, null) + else -> throw CompilerException("invalid datatype in array") + } + } + val heapId = heap.addIntegerArray(arrayDt, intArrayWithAddressOfs.toTypedArray()) return LiteralValue(arrayDt, heapId = heapId, position = arraylit.position) } else { // array is only constant numerical values @@ -594,7 +599,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W -> heap.addIntegerArray(arrayDt, integerArray.map { IntegerOrAddressOf(it, null) }.toTypedArray()) - DataType.ARRAY_F -> heap.addDoublesArray(arrayDt, doubleArray) + DataType.ARRAY_F -> heap.addDoublesArray(doubleArray) else -> throw CompilerException("invalid arrayspec type") } return LiteralValue(arrayDt, heapId = heapId, position = arraylit.position) diff --git a/compiler/src/prog8/stackvm/Program.kt b/compiler/src/prog8/stackvm/Program.kt index 699703d6f..562cd0609 100644 --- a/compiler/src/prog8/stackvm/Program.kt +++ b/compiler/src/prog8/stackvm/Program.kt @@ -92,13 +92,25 @@ class Program (val name: String, DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W -> { val numbers = it.third.substring(1, it.third.length-1).split(',') - val intarray = numbers.map{number->IntegerOrAddressOf(number.trim().toInt(), null)}.toTypedArray() + val intarray = numbers.map{number-> + val num=number.trim() + if(num.startsWith("&")) { + // it's AddressOf + val scopedname = num.substring(1) + val iref = IdentifierReference(scopedname.split('.'), Position("", 0,0,0)) + val addrOf = AddressOf(iref, Position("", 0,0,0)) + addrOf.scopedname=scopedname + IntegerOrAddressOf(null, addrOf) + } else { + IntegerOrAddressOf(num.toInt(), null) + } + }.toTypedArray() heap.addIntegerArray(it.second, intarray) } DataType.ARRAY_F -> { val numbers = it.third.substring(1, it.third.length-1).split(',') val doublearray = numbers.map{number->number.trim().toDouble()}.toDoubleArray() - heap.addDoublesArray(it.second, doublearray) + heap.addDoublesArray(doublearray) } in NumericDatatypes -> throw VmExecutionException("invalid heap value type ${it.second}") else -> throw VmExecutionException("weird datatype") diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index 859f75cac..cd0f7397e 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -1659,10 +1659,16 @@ class StackVm(private var traceOutputFile: String?) { when(array.type){ DataType.ARRAY_UW -> { val value = array.array!![index] - if(value.integer!=null) - Value(DataType.UWORD, value.integer) - else - TODO("deal with addressOf $value") + when { + value.integer!=null -> Value(DataType.UWORD, value.integer) + value.addressOf!=null -> { + val heapId = variables.getValue(value.addressOf.scopedname!!).heapId + if(heapId<0) + throw VmExecutionException("expected variable on heap") + evalstack.push(Value(DataType.UWORD, heapId)) // push the "address" of the string or array variable (this is taken care of properly in the assembly code generator) + } + else -> throw VmExecutionException("strange array value") + } } DataType.ARRAY_W -> Value(DataType.WORD, array.array!![index].integer!!) else -> throw VmExecutionException("not a proper arrayspec var with word elements") @@ -2287,6 +2293,13 @@ class StackVm(private var traceOutputFile: String?) { val number = lo+256*hi canvas?.printText(number.toString(), 1, true) } + Syscall.SYSASM_c64scr_print_uwhex -> { + val prefix = if(this.P_carry) "$" else "" + val lo = variables.getValue("A").integerValue() + val hi = variables.getValue("Y").integerValue() + val number = lo+256*hi + canvas?.printText("$prefix${number.toString(16).padStart(4, '0')}", 1, true) + } Syscall.SYSASM_c64scr_print_w -> { val lo = variables.getValue("A").integerValue() val hi = variables.getValue("Y").integerValue() diff --git a/examples/test.p8 b/examples/test.p8 index 8cddc4d7c..31da717b3 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -23,7 +23,7 @@ pointer2 = &array2 pointer3 = &string1 - ; uword[4] pointers = [&array1, &array2, &string1, &string2] ; @todo make it possible to initialize array with pointers + uword[4] pointers = [&array1, &array2, &string1, &string2] ; @todo make it possible to initialize array with pointers ptrsubasm("moet werken") @@ -72,3 +72,11 @@ } } + +~ test { + + sub testsub() { + uword[4] pointers = [&main.start.array1, &main.start.array2, &main.start.string1, &main.start.string2] ; @todo make it possible to initialize array with pointers + + } +}