From c75b1581d25e76c084f5bb148d764a7e7cbe064a Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 4 Feb 2023 00:02:50 +0100 Subject: [PATCH] lookup via new ST --- codeCore/src/prog8/code/SymbolTable.kt | 26 ++- codeCore/src/prog8/code/SymbolTableMaker.kt | 212 ++++++++++++++++++ codeCore/src/prog8/code/ast/AstExpressions.kt | 13 +- codeCore/src/prog8/code/ast/AstStatements.kt | 1 + .../src/prog8/codegen/cpu6502/AsmGen.kt | 15 +- .../codegen/cpu6502/BuiltinFunctionsAsmGen.kt | 19 +- .../codegen/cpu6502/ExpressionsAsmGen.kt | 5 +- .../src/prog8/codegen/cpu6502/Extensions.kt | 74 +----- .../prog8/codegen/cpu6502/ForLoopsAsmGen.kt | 3 +- .../codegen/cpu6502/FunctionCallAsmGen.kt | 9 +- .../cpu6502/assignment/AsmAssignment.kt | 14 +- .../cpu6502/assignment/AssignmentAsmGen.kt | 7 +- compiler/src/prog8/compiler/Compiler.kt | 12 +- .../astprocessing/IntermediateAstMaker.kt | 7 +- .../astprocessing/SymbolTableMaker.kt | 150 ------------- compiler/test/TestSymbolTable.kt | 13 +- compiler/test/ast/TestIntermediateAst.kt | 4 +- .../codegeneration/TestArrayInplaceAssign.kt | 3 +- .../test/codegeneration/TestAsmGenSymbols.kt | 6 +- compiler/test/codegeneration/TestVarious.kt | 37 +++ examples/test.p8 | 3 + .../src/prog8/intermediate/IRFileReader.kt | 14 +- .../src/prog8/intermediate/IRSymbolTable.kt | 13 +- 23 files changed, 369 insertions(+), 291 deletions(-) create mode 100644 codeCore/src/prog8/code/SymbolTableMaker.kt delete mode 100644 compiler/src/prog8/compiler/astprocessing/SymbolTableMaker.kt diff --git a/codeCore/src/prog8/code/SymbolTable.kt b/codeCore/src/prog8/code/SymbolTable.kt index fca4c2675..b2daceb4f 100644 --- a/codeCore/src/prog8/code/SymbolTable.kt +++ b/codeCore/src/prog8/code/SymbolTable.kt @@ -1,5 +1,6 @@ package prog8.code +import prog8.code.ast.PtNode import prog8.code.core.* @@ -7,7 +8,7 @@ import prog8.code.core.* * Tree structure containing all symbol definitions in the program * (blocks, subroutines, variables (all types), memoryslabs, and labels). */ -class SymbolTable : StNode("", StNodeType.GLOBAL, Position.DUMMY) { +class SymbolTable(astNode: PtNode) : StNode("", StNodeType.GLOBAL, Position.DUMMY, astNode) { /** * The table as a flat mapping of scoped names to the StNode. * This gives the fastest lookup possible (no need to traverse tree nodes) @@ -77,6 +78,7 @@ enum class StNodeType { open class StNode(val name: String, val type: StNodeType, val position: Position, + val astNode: PtNode, // TODO keep reference to the node in the AST val children: MutableMap = mutableMapOf() ) { @@ -151,7 +153,8 @@ class StStaticVariable(name: String, val onetimeInitializationArrayValue: StArray?, val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte val zpwish: ZeropageWish, - position: Position) : StNode(name, StNodeType.STATICVAR, position) { + astNode: PtNode, + position: Position) : StNode(name, StNodeType.STATICVAR, position, astNode = astNode) { init { if(bss) { @@ -180,8 +183,8 @@ class StStaticVariable(name: String, } -class StConstant(name: String, val dt: DataType, val value: Double, position: Position) : - StNode(name, StNodeType.CONSTANT, position) { +class StConstant(name: String, val dt: DataType, val value: Double, astNode: PtNode, position: Position) : + StNode(name, StNodeType.CONSTANT, position, astNode) { } @@ -189,21 +192,23 @@ class StMemVar(name: String, val dt: DataType, val address: UInt, val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte + astNode: PtNode, position: Position) : - StNode(name, StNodeType.MEMVAR, position) { + StNode(name, StNodeType.MEMVAR, position, astNode) { } class StMemorySlab( name: String, val size: UInt, val align: UInt, + astNode: PtNode, position: Position ): - StNode(name, StNodeType.MEMORYSLAB, position) { + StNode(name, StNodeType.MEMORYSLAB, position, astNode) { } -class StSub(name: String, val parameters: List, val returnType: DataType?, position: Position) : - StNode(name, StNodeType.SUBROUTINE, position) { +class StSub(name: String, val parameters: List, val returnType: DataType?, astNode: PtNode, position: Position) : + StNode(name, StNodeType.SUBROUTINE, position, astNode) { } @@ -211,9 +216,10 @@ class StRomSub(name: String, val address: UInt, val parameters: List, val returns: List, + astNode: PtNode, position: Position) : - StNode(name, StNodeType.ROMSUB, position) { -} + StNode(name, StNodeType.ROMSUB, position, astNode) + class StSubroutineParameter(val name: String, val type: DataType) diff --git a/codeCore/src/prog8/code/SymbolTableMaker.kt b/codeCore/src/prog8/code/SymbolTableMaker.kt new file mode 100644 index 000000000..8bd140be9 --- /dev/null +++ b/codeCore/src/prog8/code/SymbolTableMaker.kt @@ -0,0 +1,212 @@ +package prog8.code + +import prog8.code.ast.* +import prog8.code.core.* +import prog8.code.target.VMTarget +import java.util.* + +class SymbolTableMaker(private val program: PtProgram, private val options: CompilationOptions) { + fun make(): SymbolTable { + val st = SymbolTable(program) + + BuiltinFunctions.forEach { + st.add(StNode(it.key, StNodeType.BUILTINFUNC, Position.DUMMY, PtIdentifier(it.key, it.value.returnType ?: DataType.UNDEFINED, Position.DUMMY))) + } + + val scopestack = Stack() + scopestack.push(st) + program.children.forEach { + addToSt(it, scopestack) + } + require(scopestack.size==1) + + if(options.compTarget.name != VMTarget.NAME) { + listOf( + PtMemMapped("P8ZP_SCRATCH_B1", DataType.UBYTE, options.compTarget.machine.zeropage.SCRATCH_B1, Position.DUMMY), + PtMemMapped("P8ZP_SCRATCH_REG", DataType.UBYTE, options.compTarget.machine.zeropage.SCRATCH_REG, Position.DUMMY), + PtMemMapped("P8ZP_SCRATCH_W1", DataType.UWORD, options.compTarget.machine.zeropage.SCRATCH_W1, Position.DUMMY), + PtMemMapped("P8ZP_SCRATCH_W2", DataType.UWORD, options.compTarget.machine.zeropage.SCRATCH_W2, Position.DUMMY), + PtMemMapped("P8ESTACK_LO", DataType.UBYTE, options.compTarget.machine.ESTACK_LO, Position.DUMMY), + PtMemMapped("P8ESTACK_HI", DataType.UBYTE, options.compTarget.machine.ESTACK_HI, Position.DUMMY) + ).forEach { + st.add(StMemVar(it.name, it.type, it.address, null, it, Position.DUMMY)) + } + } + + return st + } + + // TODO INITIAL VALUES / BSS + + private fun addToSt(node: PtNode, scope: Stack) { + val stNode = when(node) { + is PtAsmSub -> { + if(node.address==null) { + val params = node.parameters.map { StSubroutineParameter(it.first.name, it.first.type) } + StSub(node.name, params, node.returnTypes.singleOrNull(), node, node.position) + } else { + val parameters = node.parameters.map { StRomSubParameter(it.second, it.first.type) } + StRomSub(node.name, node.address, parameters, node.retvalRegisters, node, node.position) + } + } + is PtBlock -> { + StNode(node.name, StNodeType.BLOCK, node.position, node) + } + is PtConstant -> { + StConstant(node.name, node.type, node.value, node, node.position) + } + is PtLabel -> { + StNode(node.name, StNodeType.LABEL, node.position, node) + } + is PtMemMapped -> { + StMemVar(node.name, node.type, node.address, null, node, node.position) // TODO missing node.length + } + is PtSub -> { + val params = node.parameters.map {StSubroutineParameter(it.name, it.type) } + StSub(node.name, params, node.returntype, node, node.position) + } + is PtVariable -> { + val bss = when (node.type) { + // TODO should bss be a computed property on PtVariable? + DataType.STR -> false + in ArrayDatatypes -> node.value==null || node.arraySize==0u + else -> node.value==null + } + val initialNumeric: Double? + val initialString: StString? + val initialArray: StArray? + val numElements: Int? + val value = node.value + if(value!=null) { + initialNumeric = (value as? PtNumber)?.number + when (value) { + is PtString -> { + initialString = StString(value.value, value.encoding) + initialArray = null + numElements = value.value.length + 1 // include the terminating 0-byte + } + is PtArray -> { + initialArray = makeInitialArray(value) + initialString = null + numElements = initialArray.size + require(node.arraySize?.toInt()==numElements) + } + else -> { + initialString = null + initialArray = null + numElements = node.arraySize?.toInt() + } + } + } else { + initialNumeric = null + initialArray = null + initialString = null + numElements = node.arraySize?.toInt() + } + val zeropage = ZeropageWish.DONTCARE // TODO how, can this be removed from the ST perhaps? Or is it required in the variable allocator later + StStaticVariable(node.name, node.type, bss, initialNumeric, initialString, initialArray, numElements, zeropage, node, node.position) + } + is PtBuiltinFunctionCall -> { + if(node.name=="memory") { + // memory slab allocations are a builtin functioncall in the program, but end up named as well in the symboltable + require(node.name.all { it.isLetterOrDigit() || it=='_' }) {"memory name should be a valid symbol name"} + val slabname = (node.args[0] as PtString).value + val size = (node.args[1] as PtNumber).number.toUInt() + val align = (node.args[2] as PtNumber).number.toUInt() + // don't add memory slabs in nested scope, just put them in the top level of the ST + scope.firstElement().add(StMemorySlab("prog8_memoryslab_$slabname", size, align, node, node.position)) + } + null + } + else -> null // node is not present in the ST + } + + if(stNode!=null) { + scope.peek().add(stNode) + scope.push(stNode) + } + node.children.forEach { + addToSt(it, scope) + } + if(stNode!=null) + scope.pop() + } + + private fun makeInitialArray(value: PtArray): List { + return value.children.map { + when(it) { + is PtAddressOf -> StArrayElement(null, it.identifier.name) + is PtIdentifier -> StArrayElement(null, it.name) + is PtNumber -> StArrayElement(it.number, null) + else -> throw AssemblyError("invalid array element $it") + } + } + } + +} + +// override fun visit(decl: VarDecl) { +// val node = +// when(decl.type) { +// VarDeclType.VAR -> { +// var initialNumeric = (decl.value as? NumericLiteral)?.number +// if(initialNumeric==0.0) +// initialNumeric=null // variable will go into BSS and this will be set to 0 +// val initialStringLit = decl.value as? StringLiteral +// val initialString = if(initialStringLit==null) null else Pair(initialStringLit.value, initialStringLit.encoding) +// val initialArrayLit = decl.value as? ArrayLiteral +// val initialArray = makeInitialArray(initialArrayLit) +// if(decl.isArray && decl.datatype !in ArrayDatatypes) +// throw FatalAstException("array vardecl has mismatched dt ${decl.datatype}") +// val numElements = +// if(decl.isArray) +// decl.arraysize!!.constIndex() +// else if(initialStringLit!=null) +// initialStringLit.value.length+1 // include the terminating 0-byte +// else +// null +// val bss = if(decl.datatype==DataType.STR) +// false +// else if(decl.isArray) +// initialArray.isNullOrEmpty() +// else +// initialNumeric == null +// val astNode = PtVariable(decl.name, decl.datatype, null, null, decl.position) +// StStaticVariable(decl.name, decl.datatype, bss, initialNumeric, initialString, initialArray, numElements, decl.zeropage, astNode, decl.position) +// } +// VarDeclType.CONST -> { +// val astNode = PtVariable(decl.name, decl.datatype, null, null, decl.position) +// StConstant(decl.name, decl.datatype, (decl.value as NumericLiteral).number, astNode, decl.position) +// } +// VarDeclType.MEMORY -> { +// val numElements = +// if(decl.datatype in ArrayDatatypes) +// decl.arraysize!!.constIndex() +// else null +// val astNode = PtVariable(decl.name, decl.datatype, null, null, decl.position) +// StMemVar(decl.name, decl.datatype, (decl.value as NumericLiteral).number.toUInt(), numElements, astNode, decl.position) +// } +// } +// scopestack.peek().add(node) +// // st.origAstLinks[decl] = node +// } +// +// private fun makeInitialArray(arrayLit: ArrayLiteral?): StArray? { +// if(arrayLit==null) +// return null +// return arrayLit.value.map { +// when(it){ +// is AddressOf -> { +// val scopedName = it.identifier.targetNameAndType(program).first +// StArrayElement(null, scopedName) +// } +// is IdentifierReference -> { +// val scopedName = it.targetNameAndType(program).first +// StArrayElement(null, scopedName) +// } +// is NumericLiteral -> StArrayElement(it.number, null) +// else -> throw FatalAstException("weird element dt in array literal") +// } +// }.toList() +// } +// \ No newline at end of file diff --git a/codeCore/src/prog8/code/ast/AstExpressions.kt b/codeCore/src/prog8/code/ast/AstExpressions.kt index a0b88b594..d2ff95ab2 100644 --- a/codeCore/src/prog8/code/ast/AstExpressions.kt +++ b/codeCore/src/prog8/code/ast/AstExpressions.kt @@ -1,8 +1,6 @@ package prog8.code.ast -import prog8.code.core.DataType -import prog8.code.core.Encoding -import prog8.code.core.Position +import prog8.code.core.* import java.util.* import kotlin.math.round @@ -66,11 +64,15 @@ class PtAddressOf(position: Position) : PtExpression(DataType.UWORD, position) { } -class PtArrayIndexer(type: DataType, position: Position): PtExpression(type, position) { +class PtArrayIndexer(elementType: DataType, position: Position): PtExpression(elementType, position) { val variable: PtIdentifier get() = children[0] as PtIdentifier val index: PtExpression get() = children[1] as PtExpression + + init { + require(elementType in NumericDatatypes) + } } @@ -82,7 +84,8 @@ class PtArray(type: DataType, position: Position): PtExpression(type, position) return type==other.type && children == other.children } - val size: Int = children.size + val size: Int + get() = children.size } diff --git a/codeCore/src/prog8/code/ast/AstStatements.kt b/codeCore/src/prog8/code/ast/AstStatements.kt index 2cb29c771..b57eab7b3 100644 --- a/codeCore/src/prog8/code/ast/AstStatements.kt +++ b/codeCore/src/prog8/code/ast/AstStatements.kt @@ -214,6 +214,7 @@ class PtConstant(name: String, override val type: DataType, val value: Double, p } +// TODO what about memory mapped arrays that have a length? missing property! class PtMemMapped(name: String, override val type: DataType, val address: UInt, position: Position) : PtNamedNode(name, position), IPtVariable { override fun printProperties() { print("&$type $name = ${address.toHex()}") diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index 9f6048848..a45ac2a7e 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -107,7 +107,8 @@ class AsmGen( internal fun loadByteFromPointerIntoA(pointervar: PtIdentifier): String { // returns the source name of the zero page pointervar if it's already in the ZP, // otherwise returns "P8ZP_SCRATCH_W1" which is the intermediary - when (val target = pointervar.targetStatement(program)) { + val symbol = symbolTable.lookup(pointervar.name) + when (val target = symbol!!.astNode) { is PtLabel -> { val sourceName = asmSymbolName(pointervar) out(" lda $sourceName") @@ -559,7 +560,8 @@ class AsmGen( } } is PtIdentifier -> { - val vardecl = (stmt.count as PtIdentifier).targetStatement(program) as PtVariable + val symbol = symbolTable.lookup((stmt.count as PtIdentifier).name) + val vardecl = symbol!!.astNode as PtVariable val name = asmVariableName(stmt.count as PtIdentifier) when(vardecl.type) { DataType.UBYTE, DataType.BYTE -> { @@ -820,8 +822,8 @@ $repeatLabel lda $counterVar return when { ident!=null -> { // can be a label, or a pointer variable - val target = ident.targetVarDecl(program) - if(target!=null) + val symbol = symbolTable.lookup(ident.name) + if(symbol!=null) Pair(asmSymbolName(ident), true) // indirect else Pair(asmSymbolName(ident), false) @@ -989,10 +991,11 @@ $repeatLabel lda $counterVar val ptrAndIndex = pointerViaIndexRegisterPossible(expr) if(ptrAndIndex!=null) { val pointervar = ptrAndIndex.first as? PtIdentifier - when(pointervar?.targetStatement(program)) { + val target = if(pointervar==null) null else symbolTable.lookup(pointervar.name)!!.astNode + when(target) { is PtLabel -> { assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y) - out(" lda ${asmSymbolName(pointervar)},y") + out(" lda ${asmSymbolName(pointervar!!)},y") return true } is IPtVariable, null -> { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt index f0d13c5f6..ca4339177 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt @@ -52,15 +52,17 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, require(fcall.args[0] is PtIdentifier) { "attempt to pop a value into a differently typed variable, or in something else that isn't supported ${fcall.position}" } - val target = (fcall.args[0] as PtIdentifier).targetVarDecl(program) - asmgen.popCpuStack(DataType.UBYTE, target!!, fcall.definingISub()) + val symbol = asmgen.symbolTable.lookup((fcall.args[0] as PtIdentifier).name) + val target = symbol!!.astNode as IPtVariable + asmgen.popCpuStack(DataType.UBYTE, target, fcall.definingISub()) } "popw" -> { require(fcall.args[0] is PtIdentifier) { "attempt to pop a value into a differently typed variable, or in something else that isn't supported ${fcall.position}" } - val target = (fcall.args[0] as PtIdentifier).targetVarDecl(program) - asmgen.popCpuStack(DataType.UWORD, target!!, fcall.definingISub()) + val symbol = asmgen.symbolTable.lookup((fcall.args[0] as PtIdentifier).name) + val target = symbol!!.astNode as IPtVariable + asmgen.popCpuStack(DataType.UWORD, target, fcall.definingISub()) } "rsave" -> funcRsave() "rsavex" -> funcRsaveX() @@ -349,7 +351,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, private fun funcReverse(fcall: PtBuiltinFunctionCall) { val variable = fcall.args.single() if (variable is PtIdentifier) { - val decl = variable.targetVarDecl(program) as PtVariable + val symbol = asmgen.symbolTable.lookup(variable.name) + val decl = symbol!!.astNode as PtVariable val varName = asmgen.asmVariableName(variable) val numElements = decl.arraySize!! when (decl.type) { @@ -388,7 +391,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, private fun funcSort(fcall: PtBuiltinFunctionCall) { val variable = fcall.args.single() if (variable is PtIdentifier) { - val decl = variable.targetVarDecl(program) as PtVariable + val symbol = asmgen.symbolTable.lookup(variable.name) + val decl = symbol!!.astNode as PtVariable val varName = asmgen.asmVariableName(variable) val numElements = decl.arraySize!! when (decl.type) { @@ -1007,7 +1011,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, private fun outputAddressAndLenghtOfArray(arg: PtExpression) { // address in P8ZP_SCRATCH_W1, number of elements in A arg as PtIdentifier - val arrayVar = arg.targetVarDecl(program)!! as PtVariable + val symbol = asmgen.symbolTable.lookup(arg.name) + val arrayVar = symbol!!.astNode as PtVariable if(arrayVar.arraySize==null) throw AssemblyError("length of non-array requested") val size = arrayVar.arraySize!! diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt index 774a4b5c6..702bda059 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt @@ -44,7 +44,8 @@ internal class ExpressionsAsmGen(private val program: PtProgram, private fun translateFunctionCallResultOntoStack(call: PtFunctionCall) { // only for use in nested expression evaluation - val sub = call.targetSubroutine(program) + val symbol = asmgen.symbolTable.lookup(call.name) + val sub = symbol!!.astNode as IPtSubroutine asmgen.saveXbeforeCall(call) asmgen.translateFunctionCall(call, true) if(sub.regXasResult()) { @@ -725,7 +726,7 @@ internal class ExpressionsAsmGen(private val program: PtProgram, val elementDt = arrayExpr.type val arrayVarName = asmgen.asmVariableName(arrayExpr.variable) - if(arrayExpr.type==DataType.UWORD) { + if(arrayExpr.variable.type==DataType.UWORD) { // indexing a pointer var instead of a real array or string if(elementDt !in ByteDatatypes) throw AssemblyError("non-array var indexing requires bytes dt") diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt index 0bc10496c..03ab3b5ab 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt @@ -58,60 +58,6 @@ fun PtExpression.isSimple(): Boolean { } } -internal fun PtIdentifier.targetStatement(program: PtProgram): PtNode { - return if(name in BuiltinFunctions) - this // just reuse the node itself to refer to the builtin function - else - program.lookup(name) -} - -internal fun PtProgram.lookup(name: String): PtNode { - // TODO should be cached? - fun searchLocalSymbol(node: PtNode, namePart: String): PtNode? { - when(node) { - is PtProgram -> { - return node.allBlocks().single { it.name==namePart } - } - is PtNamedNode -> { - if(node.name==namePart) - return node - } - is PtNodeGroup -> { - node.children.forEach { - val found = searchLocalSymbol(it, namePart) - if(found!=null) - return found - } - } - is PtIdentifier -> { - if(node.name==namePart) - return node - } - is PtSubroutineParameter -> { - if(node.name==namePart) - return node - } - else -> { - // NOTE: when other nodes containing scopes are introduced, - // these should be added here as well to look into! - } - } - - node.children.forEach { - val found = searchLocalSymbol(it, namePart) - if(found!=null) - return found - } - return null - } - - val remainder = name.splitToSequence('.') - return remainder.fold(this as PtNode) { acc, namePart -> searchLocalSymbol(acc, namePart)!! } -} - -internal fun PtIdentifier.targetVarDecl(program: PtProgram): IPtVariable? = - this.targetStatement(program) as? IPtVariable - internal fun IPtSubroutine.regXasResult(): Boolean = (this is PtAsmSub) && this.retvalRegisters.any { it.registerOrPair in arrayOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) } @@ -132,16 +78,6 @@ internal fun PtAsmSub.shouldKeepA(): KeepAresult { return KeepAresult(false, saveAonReturn) } -internal fun PtFunctionCall.targetSubroutine(program: PtProgram): IPtSubroutine = - this.targetStatement(program) as IPtSubroutine - -internal fun PtFunctionCall.targetStatement(program: PtProgram): PtNode { - return if(name in BuiltinFunctions) - this // just reuse the node itself to refer to the builtin function - else - program.lookup(name) -} - internal fun IPtSubroutine.returnsWhatWhere(): List> { when(this) { is PtAsmSub -> { @@ -196,4 +132,12 @@ internal fun PtSub.returnRegister(): RegisterOrStatusflag? { null -> null else -> RegisterOrStatusflag(RegisterOrPair.AY, null) } -} \ No newline at end of file +} + +// TODO move into AsmGen: +internal fun findSubroutineParameter(name: String, asmgen: AsmGen): PtSubroutineParameter? { + val node = asmgen.symbolTable.lookup(name)!!.astNode + if(node is PtSubroutineParameter) + return node + return node.definingSub()?.parameters?.singleOrNull { it.name===name } +} diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt index 21a42764b..59bf011b2 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt @@ -239,7 +239,8 @@ $endLabel""") val endLabel = asmgen.makeLabel("for_end") asmgen.loopEndLabels.push(endLabel) val iterableName = asmgen.asmVariableName(ident) - val decl = ident.targetVarDecl(program)!! as PtVariable + val symbol = asmgen.symbolTable.lookup(ident.name) + val decl = symbol!!.astNode as PtVariable when(iterableDt) { DataType.STR -> { asmgen.out(""" diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt index 2a2427010..dc26f9f19 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt @@ -18,7 +18,8 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as } internal fun saveXbeforeCall(stmt: PtFunctionCall) { - val sub = stmt.targetSubroutine(program) + val symbol = asmgen.symbolTable.lookup(stmt.name) + val sub = symbol!!.astNode as IPtSubroutine if(sub.shouldSaveX()) { if(sub is PtAsmSub) { val regSaveOnStack = sub.address == null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls @@ -32,7 +33,8 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as } internal fun restoreXafterCall(stmt: PtFunctionCall) { - val sub = stmt.targetSubroutine(program) + val symbol = asmgen.symbolTable.lookup(stmt.name) + val sub = symbol!!.astNode as IPtSubroutine if(sub.shouldSaveX()) { if(sub is PtAsmSub) { val regSaveOnStack = sub.address == null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls @@ -55,7 +57,8 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as // NOTE: does NOT output code to save/restore the X register for this call! Every caller should deal with this in their own way!! // (you can use subroutine.shouldSaveX() and saveX()/restoreX() routines as a help for this) - val sub: IPtSubroutine = call.targetSubroutine(program) + val symbol = asmgen.symbolTable.lookup(call.name) + val sub = symbol!!.astNode as IPtSubroutine val subAsmName = asmgen.asmSymbolName(call.name) if(sub is PtAsmSub) { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt index 26a309f24..7f4601c90 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt @@ -2,7 +2,10 @@ package prog8.codegen.cpu6502.assignment import prog8.code.ast.* import prog8.code.core.* -import prog8.codegen.cpu6502.* +import prog8.codegen.cpu6502.AsmGen +import prog8.codegen.cpu6502.asConstInteger +import prog8.codegen.cpu6502.findSubroutineParameter +import prog8.codegen.cpu6502.returnsWhatWhere internal enum class TargetStorageKind { @@ -54,8 +57,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind, with(assign.target) { when { identifier != null -> { - val paramName = identifier!!.targetVarDecl(program)?.name - val parameter = identifier!!.targetStatement(program).definingSub()?.parameters?.singleOrNull { it.name===paramName } + val parameter = findSubroutineParameter(identifier!!.name, asmgen) if (parameter!=null) { val sub = parameter.definingAsmSub() if (sub!=null) { @@ -134,8 +136,7 @@ internal class AsmAssignSource(val kind: SourceStorageKind, is PtString -> throw AssemblyError("string literal value should not occur anymore for asm generation") is PtArray -> throw AssemblyError("array literal value should not occur anymore for asm generation") is PtIdentifier -> { - val paramName = value.targetVarDecl(program)?.name - val parameter = value.targetStatement(program).definingSub()?.parameters?.singleOrNull { it.name===paramName } + val parameter = findSubroutineParameter(value.name, asmgen) if(parameter?.definingAsmSub() != null) throw AssemblyError("can't assign from a asmsub register parameter $value ${value.position}") val varName=asmgen.asmVariableName(value) @@ -158,7 +159,8 @@ internal class AsmAssignSource(val kind: SourceStorageKind, AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, value.type, expression = value) } is PtFunctionCall -> { - val sub = value.targetSubroutine(program) + val symbol = asmgen.symbolTable.lookup(value.name) + val sub = symbol!!.astNode as IPtSubroutine val returnType = sub.returnsWhatWhere().firstOrNull { rr -> rr.second.registerOrPair != null || rr.second.statusflag!=null }?.first ?: throw AssemblyError("can't translate zero return values in assignment") diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 73314612d..83a1669a3 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -13,7 +13,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, fun translate(assignment: PtAssignment) { val target = AsmAssignTarget.fromAstAssignment(assignment, program, asmgen) val source = AsmAssignSource.fromAstSource(assignment.value, program, asmgen).adjustSignedUnsigned(target) - val assign = AsmAssignment(source, target, assignment.isInplaceAssign, program.memsizer, assignment.position) target.origAssign = assign @@ -178,7 +177,8 @@ internal class AssignmentAsmGen(private val program: PtProgram, is PtMemoryByte -> throw AssemblyError("source kind should have been memory") is PtTypeCast -> assignTypeCastedValue(assign.target, value.type, value.value, value) is PtFunctionCall -> { - val sub = value.targetSubroutine(program) + val symbol = asmgen.symbolTable.lookup(value.name) + val sub = symbol!!.astNode as IPtSubroutine asmgen.saveXbeforeCall(value) asmgen.translateFunctionCall(value, true) val returnValue = sub.returnsWhatWhere().singleOrNull() { it.second.registerOrPair!=null } ?: sub.returnsWhatWhere().single() { it.second.statusflag!=null } @@ -807,7 +807,8 @@ internal class AssignmentAsmGen(private val program: PtProgram, private fun containmentCheckIntoA(containment: PtContainmentCheck) { val elementDt = containment.element.type - val variable = (containment.iterable as? PtIdentifier)?.targetVarDecl(program) as PtVariable + val symbol = asmgen.symbolTable.lookup(containment.iterable.name) + val variable = symbol!!.astNode as PtVariable val varname = asmgen.asmVariableName(containment.iterable) when(variable.type) { DataType.STR -> { diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 8a884819b..9090d8acc 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -11,7 +11,7 @@ import prog8.ast.expressions.NumericLiteral import prog8.ast.statements.Directive import prog8.ast.statements.VarDecl import prog8.ast.walk.IAstVisitor -import prog8.code.SymbolTable +import prog8.code.SymbolTableMaker import prog8.code.core.* import prog8.code.target.* import prog8.codegen.vm.VmCodeGen @@ -392,7 +392,6 @@ private fun createAssemblyAndAssemble(program: Program, compilerOptions.compTarget.machine.initializeMemoryAreas(compilerOptions) program.processAstBeforeAsmGeneration(compilerOptions, errors) errors.report() - val symbolTable = SymbolTableMaker(program, compilerOptions).make() // TODO make removing all VarDecls work, but this needs inferType to be able to get its information from somewhere else as the VarDecl nodes in the Ast, // or don't use inferType at all anymore and "bake the type information" into the Ast somehow. @@ -403,7 +402,7 @@ private fun createAssemblyAndAssemble(program: Program, // println("*********** COMPILER AST RIGHT BEFORE ASM GENERATION *************") // printProgram(program) - val assembly = asmGeneratorFor(program, errors, symbolTable, compilerOptions).compileToAssembly() + val assembly = asmGeneratorFor(program, errors, compilerOptions).compileToAssembly() errors.report() return if(assembly!=null && errors.noErrors()) { @@ -442,10 +441,13 @@ fun printProgram(program: Program) { internal fun asmGeneratorFor(program: Program, errors: IErrorReporter, - symbolTable: SymbolTable, options: CompilationOptions): IAssemblyGenerator { - val intermediateAst = IntermediateAstMaker(program, symbolTable, options).transform() + val intermediateAst = IntermediateAstMaker(program, options).transform() + + val stMaker = SymbolTableMaker(intermediateAst, options) + val symbolTable = stMaker.make() + if(options.experimentalCodegen) return prog8.codegen.experimental.CodeGen(intermediateAst, symbolTable, options, errors) else if (options.compTarget.machine.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02)) diff --git a/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt b/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt index 63b2cf914..ffb41c680 100644 --- a/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt +++ b/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt @@ -8,7 +8,6 @@ import prog8.ast.Program import prog8.ast.base.FatalAstException import prog8.ast.expressions.* import prog8.ast.statements.* -import prog8.code.SymbolTable import prog8.code.ast.* import prog8.code.core.BuiltinFunctions import prog8.code.core.CompilationOptions @@ -23,7 +22,7 @@ import kotlin.io.path.isRegularFile /** * Convert 'old' compiler-AST into the 'new' simplified AST with baked types. */ -class IntermediateAstMaker(private val program: Program, private val symbolTable: SymbolTable, private val options: CompilationOptions) { +class IntermediateAstMaker(private val program: Program, private val options: CompilationOptions) { fun transform(): PtProgram { val ptProgram = PtProgram( program.name, @@ -386,8 +385,8 @@ class IntermediateAstMaker(private val program: Program, private val symbolTable } private fun transform(srcArr: ArrayIndexedExpression): PtArrayIndexer { - val type = srcArr.inferType(program).getOrElse { throw FatalAstException("unknown dt") } - val array = PtArrayIndexer(type, srcArr.position) + val arrayVarType = srcArr.inferType(program).getOrElse { throw FatalAstException("unknown dt") } + val array = PtArrayIndexer(arrayVarType, srcArr.position) array.add(transform(srcArr.arrayvar)) array.add(transformExpression(srcArr.indexer.indexExpr)) return array diff --git a/compiler/src/prog8/compiler/astprocessing/SymbolTableMaker.kt b/compiler/src/prog8/compiler/astprocessing/SymbolTableMaker.kt deleted file mode 100644 index e4b3b661e..000000000 --- a/compiler/src/prog8/compiler/astprocessing/SymbolTableMaker.kt +++ /dev/null @@ -1,150 +0,0 @@ -package prog8.compiler.astprocessing - -import prog8.ast.Program -import prog8.ast.base.FatalAstException -import prog8.ast.expressions.* -import prog8.ast.statements.* -import prog8.ast.walk.IAstVisitor -import prog8.code.* -import prog8.code.core.ArrayDatatypes -import prog8.code.core.CompilationOptions -import prog8.code.core.DataType -import prog8.code.core.Position -import prog8.code.target.VMTarget -import java.util.* - -internal class SymbolTableMaker(private val program: Program, private val options: CompilationOptions): IAstVisitor { - - private val st = SymbolTable() - private val scopestack = Stack() - private var dontReinitGlobals = false - - fun make(): SymbolTable { - scopestack.clear() - st.children.clear() - dontReinitGlobals = options.dontReinitGlobals - this.visit(program) - program.builtinFunctions.names.forEach { - val node = StNode(it, StNodeType.BUILTINFUNC, Position.DUMMY) - st.add(node) - } - require(scopestack.isEmpty()) - - if(options.compTarget.name!=VMTarget.NAME) { - // add the hardcoded temporary zeropage variables for targets that use them - st.add(StMemVar("P8ZP_SCRATCH_B1", DataType.UBYTE, options.compTarget.machine.zeropage.SCRATCH_B1, null, Position.DUMMY)) - st.add(StMemVar("P8ZP_SCRATCH_REG", DataType.UBYTE, options.compTarget.machine.zeropage.SCRATCH_REG, null, Position.DUMMY)) - st.add(StMemVar("P8ZP_SCRATCH_W1", DataType.UWORD, options.compTarget.machine.zeropage.SCRATCH_W1, null, Position.DUMMY)) - st.add(StMemVar("P8ZP_SCRATCH_W2", DataType.UWORD, options.compTarget.machine.zeropage.SCRATCH_W2, null, Position.DUMMY)) - st.add(StMemVar("P8ESTACK_LO", DataType.UBYTE, options.compTarget.machine.ESTACK_LO, null, Position.DUMMY)) - st.add(StMemVar("P8ESTACK_HI", DataType.UBYTE, options.compTarget.machine.ESTACK_HI, null, Position.DUMMY)) - } - - return st - } - - override fun visit(block: Block) { - val node = StNode(block.name, StNodeType.BLOCK, block.position) - st.add(node) - scopestack.push(node) - super.visit(block) - scopestack.pop() - // st.origAstLinks[block] = node - } - - override fun visit(subroutine: Subroutine) { - if(subroutine.asmAddress!=null) { - val parameters = subroutine.parameters.zip(subroutine.asmParameterRegisters).map { StRomSubParameter(it.second, it.first.type) } - val node = StRomSub(subroutine.name, subroutine.asmAddress!!, parameters, subroutine.asmReturnvaluesRegisters, subroutine.position) - scopestack.peek().add(node) - // st.origAstLinks[subroutine] = node - } else { - val parameters = subroutine.parameters.map { StSubroutineParameter(it.name, it.type) } - val returnType = if(subroutine.returntypes.isEmpty()) null else subroutine.returntypes.first() - val node = StSub(subroutine.name, parameters, returnType, subroutine.position) - scopestack.peek().add(node) - scopestack.push(node) - super.visit(subroutine) - scopestack.pop() - // st.origAstLinks[subroutine] = node - } - } - - override fun visit(decl: VarDecl) { - val node = - when(decl.type) { - VarDeclType.VAR -> { - var initialNumeric = (decl.value as? NumericLiteral)?.number - if(initialNumeric==0.0) - initialNumeric=null // variable will go into BSS and this will be set to 0 - val initialStringLit = decl.value as? StringLiteral - val initialString = if(initialStringLit==null) null else Pair(initialStringLit.value, initialStringLit.encoding) - val initialArrayLit = decl.value as? ArrayLiteral - val initialArray = makeInitialArray(initialArrayLit) - if(decl.isArray && decl.datatype !in ArrayDatatypes) - throw FatalAstException("array vardecl has mismatched dt ${decl.datatype}") - val numElements = - if(decl.isArray) - decl.arraysize!!.constIndex() - else if(initialStringLit!=null) - initialStringLit.value.length+1 // include the terminating 0-byte - else - null - val bss = if(decl.datatype==DataType.STR) - false - else if(decl.isArray) - initialArray.isNullOrEmpty() - else - initialNumeric == null - StStaticVariable(decl.name, decl.datatype, bss, initialNumeric, initialString, initialArray, numElements, decl.zeropage, decl.position) - } - VarDeclType.CONST -> StConstant(decl.name, decl.datatype, (decl.value as NumericLiteral).number, decl.position) - VarDeclType.MEMORY -> { - val numElements = - if(decl.datatype in ArrayDatatypes) - decl.arraysize!!.constIndex() - else null - StMemVar(decl.name, decl.datatype, (decl.value as NumericLiteral).number.toUInt(), numElements, decl.position) - } - } - scopestack.peek().add(node) - // st.origAstLinks[decl] = node - } - - private fun makeInitialArray(arrayLit: ArrayLiteral?): StArray? { - if(arrayLit==null) - return null - return arrayLit.value.map { - when(it){ - is AddressOf -> { - val scopedName = it.identifier.targetNameAndType(program).first - StArrayElement(null, scopedName) - } - is IdentifierReference -> { - val scopedName = it.targetNameAndType(program).first - StArrayElement(null, scopedName) - } - is NumericLiteral -> StArrayElement(it.number, null) - else -> throw FatalAstException("weird element dt in array literal") - } - }.toList() - } - - override fun visit(label: Label) { - val node = StNode(label.name, StNodeType.LABEL, label.position) - scopestack.peek().add(node) - // st.origAstLinks[label] = node - } - - override fun visit(bfc: BuiltinFunctionCall) { - if(bfc.name=="memory") { - // memory slab allocations are a builtin functioncall in the program, but end up named as well in the symboltable - val name = (bfc.args[0] as StringLiteral).value - require(name.all { it.isLetterOrDigit() || it=='_' }) {"memory name should be a valid symbol name"} - val size = (bfc.args[1] as NumericLiteral).number.toUInt() - val align = (bfc.args[2] as NumericLiteral).number.toUInt() - st.add(StMemorySlab("prog8_memoryslab_$name", size, align, bfc.position)) - } - super.visit(bfc) - } -} diff --git a/compiler/test/TestSymbolTable.kt b/compiler/test/TestSymbolTable.kt index 8ac9f0385..563815928 100644 --- a/compiler/test/TestSymbolTable.kt +++ b/compiler/test/TestSymbolTable.kt @@ -1,14 +1,9 @@ package prog8tests -import io.kotest.assertions.fail -import io.kotest.core.spec.style.FunSpec -import io.kotest.matchers.shouldBe -import io.kotest.matchers.shouldNotBe -import prog8.code.* -import prog8.code.core.DataType -import prog8.code.core.Position -import prog8.code.core.ZeropageWish +// TODO new unit tests for Symbol Table on new Ast Nodes + +/* class TestSymbolTable: FunSpec({ test("empty symboltable") { val st = SymbolTable() @@ -98,4 +93,4 @@ private fun makeSt(): SymbolTable { st.add(block2) st.add(builtinfunc) return st -} \ No newline at end of file +}*/ diff --git a/compiler/test/ast/TestIntermediateAst.kt b/compiler/test/ast/TestIntermediateAst.kt index db806b5bc..034e2e5d0 100644 --- a/compiler/test/ast/TestIntermediateAst.kt +++ b/compiler/test/ast/TestIntermediateAst.kt @@ -8,7 +8,6 @@ import prog8.code.ast.* import prog8.code.core.* import prog8.code.target.C64Target import prog8.compiler.astprocessing.IntermediateAstMaker -import prog8.compiler.astprocessing.SymbolTableMaker import prog8tests.helpers.compileText class TestIntermediateAst: FunSpec({ @@ -38,8 +37,7 @@ class TestIntermediateAst: FunSpec({ loadAddress = target.machine.PROGRAM_LOAD_ADDRESS ) val result = compileText(target, false, text, writeAssembly = false)!! - val st = SymbolTableMaker(result.program, options).make() - val ast = IntermediateAstMaker(result.program, st, options).transform() + val ast = IntermediateAstMaker(result.program, options).transform() ast.name shouldBe result.program.name ast.allBlocks().any() shouldBe true val entry = ast.entrypoint() ?: fail("no main.start() found") diff --git a/compiler/test/codegeneration/TestArrayInplaceAssign.kt b/compiler/test/codegeneration/TestArrayInplaceAssign.kt index 119b44119..3b8f09dd4 100644 --- a/compiler/test/codegeneration/TestArrayInplaceAssign.kt +++ b/compiler/test/codegeneration/TestArrayInplaceAssign.kt @@ -56,8 +56,7 @@ main { compileText(VMTarget(), false, text, writeAssembly = true) shouldNotBe null } - // TODO implement this in 6502 codegen and re-enable test - xtest("array in-place negation (float type) 6502 target") { + test("array in-place negation (float type) 6502 target") { val text = """ %import floats diff --git a/compiler/test/codegeneration/TestAsmGenSymbols.kt b/compiler/test/codegeneration/TestAsmGenSymbols.kt index 90e7555fe..0eb7f549f 100644 --- a/compiler/test/codegeneration/TestAsmGenSymbols.kt +++ b/compiler/test/codegeneration/TestAsmGenSymbols.kt @@ -9,6 +9,7 @@ import prog8.ast.expressions.AddressOf import prog8.ast.expressions.IdentifierReference import prog8.ast.expressions.NumericLiteral import prog8.ast.statements.* +import prog8.code.SymbolTableMaker import prog8.code.ast.PtAddressOf import prog8.code.ast.PtAssignment import prog8.code.ast.PtIdentifier @@ -17,7 +18,6 @@ import prog8.code.target.C64Target import prog8.code.target.VMTarget import prog8.codegen.cpu6502.AsmGen import prog8.compiler.astprocessing.IntermediateAstMaker -import prog8.compiler.astprocessing.SymbolTableMaker import prog8tests.helpers.* class TestAsmGenSymbols: StringSpec({ @@ -74,8 +74,8 @@ class TestAsmGenSymbols: StringSpec({ fun createTestAsmGen(program: Program): AsmGen { val errors = ErrorReporterForTests() val options = CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, true, C64Target(), 999u) - val st = SymbolTableMaker(program, options).make() - val ptProgram = IntermediateAstMaker(program, st, options).transform() + val ptProgram = IntermediateAstMaker(program, options).transform() + val st = SymbolTableMaker(ptProgram, options).make() return AsmGen(ptProgram, st, options, errors) } diff --git a/compiler/test/codegeneration/TestVarious.kt b/compiler/test/codegeneration/TestVarious.kt index 0da463989..96210f04b 100644 --- a/compiler/test/codegeneration/TestVarious.kt +++ b/compiler/test/codegeneration/TestVarious.kt @@ -21,4 +21,41 @@ main { compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null } + test("nested scoping") { + val text=""" +main { + sub start() { + testscope.duplicate() + cx16.r0L = testscope.duplicate2() + } +} + +testscope { + + sub sub1() { + ubyte @shared duplicate + ubyte @shared duplicate2 + } + + sub duplicate() { + ; do nothing + } + + sub duplicate2() -> ubyte { + return cx16.r0L + } +}""" + compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null + } + + test("word array indexing") { + val text=""" +main { + sub start() { + uword[3] seed + cx16.r0 = seed[0] + seed[1] + seed[2] + } +}""" + compileText(C64Target(), false, text, writeAssembly = true) shouldNotBe null + } }) \ No newline at end of file diff --git a/examples/test.p8 b/examples/test.p8 index 4f0ad75cc..2c1244cdc 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,6 +1,9 @@ main { + sub start() { + cx16.r0 = memory("slab", $c000, 0) + cx16.r1 = memory("slab", $c000, 0) testscope.duplicate() cx16.r0L = testscope.duplicate2() } diff --git a/intermediate/src/prog8/intermediate/IRFileReader.kt b/intermediate/src/prog8/intermediate/IRFileReader.kt index f3782b138..043725009 100644 --- a/intermediate/src/prog8/intermediate/IRFileReader.kt +++ b/intermediate/src/prog8/intermediate/IRFileReader.kt @@ -1,6 +1,7 @@ package prog8.intermediate import prog8.code.* +import prog8.code.ast.PtVariable import prog8.code.core.* import prog8.code.target.* import java.io.StringReader @@ -170,7 +171,9 @@ class IRFileReader { val arraysize = if(arrayspec.isNotBlank()) arrayspec.substring(1, arrayspec.length-1).toInt() else null val dt: DataType = parseDatatype(type, arraysize!=null) val zp = if(zpwish.isBlank()) ZeropageWish.DONTCARE else ZeropageWish.valueOf(zpwish) - bssVariables.add(StStaticVariable(name, dt, true, null, null, null, arraysize, zp, Position.DUMMY)) + val dummyNode = PtVariable(name, dt, null, null, Position.DUMMY) + val newVar = StStaticVariable(name, dt, true, null, null, null, arraysize, zp, dummyNode, Position.DUMMY) + bssVariables.add(newVar) } return bssVariables } @@ -231,7 +234,8 @@ class IRFileReader { else -> throw IRParseException("weird dt") } require(!bss) { "bss var should be in BSS section" } - variables.add(StStaticVariable(name, dt, bss, initNumeric, null, initArray, arraysize, zp, Position.DUMMY)) + val dummyNode = PtVariable(name, dt, null, null, Position.DUMMY) + variables.add(StStaticVariable(name, dt, bss, initNumeric, null, initArray, arraysize, zp, dummyNode, Position.DUMMY)) } return variables } @@ -257,7 +261,8 @@ class IRFileReader { val (type, arrayspec, name, address) = match.destructured val arraysize = if(arrayspec.isNotBlank()) arrayspec.substring(1, arrayspec.length-1).toInt() else null val dt: DataType = parseDatatype(type, arraysize!=null) - memvars.add(StMemVar(name, dt, parseIRValue(address).toUInt(), arraysize, Position.DUMMY)) + val dummyNode = PtVariable(name, dt, null, null, Position.DUMMY) + memvars.add(StMemVar(name, dt, parseIRValue(address).toUInt(), arraysize, dummyNode, Position.DUMMY)) } memvars } @@ -279,7 +284,8 @@ class IRFileReader { // example: "SLAB slabname 4096 0" val match = slabPattern.matchEntire(line) ?: throw IRParseException("invalid SLAB $line") val (name, size, align) = match.destructured - slabs.add(StMemorySlab(name, size.toUInt(), align.toUInt(), Position.DUMMY)) + val dummyNode = PtVariable(name, DataType.ARRAY_UB, null, null, Position.DUMMY) + slabs.add(StMemorySlab(name, size.toUInt(), align.toUInt(), dummyNode, Position.DUMMY)) } slabs } diff --git a/intermediate/src/prog8/intermediate/IRSymbolTable.kt b/intermediate/src/prog8/intermediate/IRSymbolTable.kt index 454873f86..f4a929319 100644 --- a/intermediate/src/prog8/intermediate/IRSymbolTable.kt +++ b/intermediate/src/prog8/intermediate/IRSymbolTable.kt @@ -1,6 +1,8 @@ package prog8.intermediate import prog8.code.* +import prog8.code.ast.PtVariable +import prog8.code.core.DataType // In the Intermediate Representation, all nesting has been removed. @@ -71,12 +73,14 @@ class IRSymbolTable(sourceSt: SymbolTable?) { return newArray } scopedName = variable.scopedName + val dummyNode = PtVariable(scopedName, variable.dt, null, null, variable.position) varToadd = StStaticVariable(scopedName, variable.dt, variable.bss, variable.onetimeInitializationNumericValue, variable.onetimeInitializationStringValue, fixupAddressOfInArray(variable.onetimeInitializationArrayValue), variable.length, variable.zpwish, + dummyNode, variable.position ) } @@ -92,7 +96,8 @@ class IRSymbolTable(sourceSt: SymbolTable?) { varToadd = variable } else { scopedName = variable.scopedName - varToadd = StMemVar(scopedName, variable.dt, variable.address, variable.length, variable.position) + val dummyNode = PtVariable(scopedName, variable.dt, null, null, variable.position) + varToadd = StMemVar(scopedName, variable.dt, variable.address, variable.length, dummyNode, variable.position) } table[scopedName] = varToadd } @@ -100,8 +105,10 @@ class IRSymbolTable(sourceSt: SymbolTable?) { fun add(variable: StMemorySlab) { val varToadd = if('.' in variable.name) variable - else - StMemorySlab("prog8_slabs.${variable.name}", variable.size, variable.align, variable.position) + else { + val dummyNode = PtVariable(variable.name, DataType.ARRAY_UB, null, null, variable.position) + StMemorySlab("prog8_slabs.${variable.name}", variable.size, variable.align, dummyNode, variable.position) + } table[varToadd.name] = varToadd }