From 37c2c1bf0bce03b8d215cfb3396384685156bded Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 29 Dec 2024 02:33:29 +0100 Subject: [PATCH] support &, &< and &> on array elements from split word arrays, not just on the array as a whole --- .../cpu6502/assignment/AssignmentAsmGen.kt | 22 ++++---- .../assignment/AugmentableAssignmentAsmGen.kt | 2 +- .../codegen/intermediate/AssignmentGen.kt | 10 ++-- .../codegen/intermediate/BuiltinFuncGen.kt | 3 +- .../codegen/intermediate/ExpressionGen.kt | 34 +++++------ .../compiler/astprocessing/AstChecker.kt | 16 ++---- .../astprocessing/BeforeAsmTypecastCleaner.kt | 2 +- .../astprocessing/IntermediateAstMaker.kt | 9 +-- .../compiler/astprocessing/TypecastsAdder.kt | 6 +- .../test/codegeneration/TestAsmGenSymbols.kt | 14 ++--- .../src/prog8/ast/AstToSourceTextConverter.kt | 7 +-- .../src/prog8/ast/antlr/Antlr2Kotlin.kt | 20 ++----- .../prog8/ast/expressions/AstExpressions.kt | 52 +++-------------- .../src/prog8/ast/statements/AstStatements.kt | 2 +- compilerAst/src/prog8/ast/walk/AstWalker.kt | 8 --- compilerAst/src/prog8/ast/walk/IAstVisitor.kt | 4 -- docs/source/todo.rst | 10 +--- examples/test.p8 | 56 +++++++++++++++++-- 18 files changed, 123 insertions(+), 154 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 08a539253..848152c04 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -231,7 +231,7 @@ internal class AssignmentAsmGen( targetDt.isSignedWord -> assignVariableWord(assign.target, variable, assign.source.datatype) targetDt.isUnsignedWord -> { if(assign.source.datatype.isPassByRef) - assignAddressOf(assign.target, variable, null, null) + assignAddressOf(assign.target, variable, false, null, null) else assignVariableWord(assign.target, variable, assign.source.datatype) } @@ -447,7 +447,7 @@ internal class AssignmentAsmGen( asmgen.asmSymbolName(value.identifier) + "_lsb" // the _lsb split array comes first in memory else asmgen.asmSymbolName(value.identifier) - assignAddressOf(assign.target, sourceName, arrayDt, value.arrayIndexExpr) + assignAddressOf(assign.target, sourceName, value.isMsbForSplitArray, arrayDt, value.arrayIndexExpr) } is PtBool -> throw AssemblyError("source kind should have been literalboolean") is PtNumber -> throw AssemblyError("source kind should have been literalnumber") @@ -1929,21 +1929,21 @@ $endLabel""") dt.isString -> { assignExpressionToRegister(containment.needle, RegisterOrPair.A, elementDt.isSigned) asmgen.out(" pha") // need to keep the scratch var safe so we have to do it in this order - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UWORD), containment.definingISub(), containment.position,"P8ZP_SCRATCH_W1"), symbolName, null, null) + assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UWORD), containment.definingISub(), containment.position,"P8ZP_SCRATCH_W1"), symbolName, false, null, null) asmgen.out(" pla") asmgen.out(" ldy #${numElements-1}") asmgen.out(" jsr prog8_lib.containment_bytearray") } dt.isFloatArray -> { assignExpressionToRegister(containment.needle, RegisterOrPair.FAC1, true) - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UWORD), containment.definingISub(), containment.position, "P8ZP_SCRATCH_W1"), symbolName, null, null) + assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UWORD), containment.definingISub(), containment.position, "P8ZP_SCRATCH_W1"), symbolName, false, null, null) asmgen.out(" ldy #$numElements") asmgen.out(" jsr floats.containment_floatarray") } dt.isByteArray -> { assignExpressionToRegister(containment.needle, RegisterOrPair.A, elementDt.isSigned) asmgen.out(" pha") // need to keep the scratch var safe so we have to do it in this order - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UWORD), containment.definingISub(), containment.position, "P8ZP_SCRATCH_W1"), symbolName, null, null) + assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UWORD), containment.definingISub(), containment.position, "P8ZP_SCRATCH_W1"), symbolName, false, null, null) asmgen.out(" pla") asmgen.out(" ldy #$numElements") asmgen.out(" jsr prog8_lib.containment_bytearray") @@ -1951,11 +1951,11 @@ $endLabel""") dt.isWordArray -> { assignExpressionToVariable(containment.needle, "P8ZP_SCRATCH_W1", elementDt) if(dt.isSplitWordArray) { - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UWORD), containment.definingISub(), containment.position, "P8ZP_SCRATCH_W2"), symbolName+"_lsb", null, null) + assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UWORD), containment.definingISub(), containment.position, "P8ZP_SCRATCH_W2"), symbolName+"_lsb", false, null, null) asmgen.out(" ldy #$numElements") asmgen.out(" jsr prog8_lib.containment_splitwordarray") } else { - assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UWORD), containment.definingISub(), containment.position, "P8ZP_SCRATCH_W2"), symbolName, null, null) + assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UWORD), containment.definingISub(), containment.position, "P8ZP_SCRATCH_W2"), symbolName, false, null, null) asmgen.out(" ldy #$numElements") asmgen.out(" jsr prog8_lib.containment_linearwordarray") } @@ -2576,13 +2576,12 @@ $endLabel""") } } - private fun assignAddressOf(target: AsmAssignTarget, sourceName: String, arrayDt: DataType?, arrayIndexExpr: PtExpression?) { + private fun assignAddressOf(target: AsmAssignTarget, sourceName: String, msb: Boolean, arrayDt: DataType?, arrayIndexExpr: PtExpression?) { if(arrayIndexExpr!=null) { - if(arrayDt?.isSplitWordArray==true) - TODO("address of element of a split word array") val constIndex = arrayIndexExpr.asConstInteger() if(constIndex!=null) { if (arrayDt?.isUnsignedWord==true) { + require(!msb) assignVariableToRegister(sourceName, RegisterOrPair.AY, false, arrayIndexExpr.definingISub(), arrayIndexExpr.position) if(constIndex>0) asmgen.out(""" @@ -2594,7 +2593,7 @@ $endLabel""") } else { if(constIndex>0) { - val offset = program.memsizer.memorySize(arrayDt!!, constIndex) // add arrayIndexExpr * elementsize to the address of the array variable. + val offset = if(arrayDt!!.isSplitWordArray) constIndex else program.memsizer.memorySize(arrayDt, constIndex) // add arrayIndexExpr * elementsize to the address of the array variable. asmgen.out(" lda #<($sourceName + $offset) | ldy #>($sourceName + $offset)") } else { asmgen.out(" lda #<$sourceName | ldy #>$sourceName") @@ -2604,6 +2603,7 @@ $endLabel""") return } else { if (arrayDt?.isUnsignedWord==true) { + require(!msb) assignVariableToRegister(sourceName, RegisterOrPair.AY, false, arrayIndexExpr.definingISub(), arrayIndexExpr.position) asmgen.saveRegisterStack(CpuRegister.A, false) asmgen.saveRegisterStack(CpuRegister.Y, false) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt index 5b345223b..02eeaa562 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt @@ -668,7 +668,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, sbc cx16.r0H sta ${arrayVar}_msb+$index""") } - else -> TODO("in-place modify split-words array value for operator $operator") + else -> TODO("inplace split word array value $operator") } } diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt index 01a382906..e9cd72cb1 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt @@ -879,7 +879,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express } private fun operatorMultiplyInplaceSplitArray(array: PtArrayIndexer, operand: PtExpression): IRCodeChunks? { - return null // TODO("inplace split word array *") + return null // fallback to slow method // TODO("inplace split word array *") } private fun operatorMinusInplaceSplitArray(array: PtArrayIndexer, operand: PtExpression): IRCodeChunks? { @@ -900,10 +900,10 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express } return result } else { - return null // TODO("inplace split word array -") + return null // fallback to slow method // TODO("inplace split word array -") } } - return null // TODO("inplace split word array -") + return null // fallback to slow method // TODO("inplace split word array -") } private fun operatorPlusInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? { @@ -986,10 +986,10 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express result += IRCodeChunk(skip, null) return result } else { - return null // TODO("inplace split word array +") + return null // fallback to slow method // TODO("inplace split word array +") } } - return null // TODO("inplace split word array +") + return null // fallback to slow method // TODO("inplace split word array +") } private fun operatorShiftRightInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): IRCodeChunks? { diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt index 547120891..057dcac31 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt @@ -548,7 +548,8 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe val arr = (arg as? PtArrayIndexer) val index = arr?.index?.asConstInteger() if(arr!=null && index!=null) { - if(arr.splitWords) TODO("IR rol/ror on split words array") + if(arr.splitWords) + TODO("IR rol/ror on split words array") val variable = arr.variable.name val offset = codeGen.program.memsizer.memorySize(arr.type, index) addInstr(result, IRInstruction(opcodeMemAndReg.first, vmDt, labelSymbol = variable, symbolOffset = offset), null) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index 55ec3a141..bd7147579 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -163,15 +163,24 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { // note: LOAD gets you the address of the symbol, whereas LOADM would get you the value stored at that location val result = mutableListOf() val resultRegister = codeGen.registers.next() + + fun loadAddressOfArrayLabel(reg: Int) { + if (expr.isMsbForSplitArray) { + addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = reg, labelSymbol = symbol + "_msb"), null) + } else if (expr.identifier.type.isSplitWordArray) { + // the _lsb split array comes first in memory + addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = reg, labelSymbol = symbol + "_lsb"), null) + } else + addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = reg, labelSymbol = symbol), null) + } + if(expr.isFromArrayElement) { - if(expr.identifier.type.isSplitWordArray) - TODO("address of element of a split word array") - addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, labelSymbol = symbol), null) - val indexTr2 = translateExpression(expr.arrayIndexExpr!!) - addToResult(result, indexTr2, indexTr2.resultReg, -1) + val indexTr = translateExpression(expr.arrayIndexExpr!!) + addToResult(result, indexTr, indexTr.resultReg, -1) val indexWordReg = codeGen.registers.next() - addInstr(result, IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=indexWordReg, reg2=indexTr2.resultReg), null) + addInstr(result, IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=indexWordReg, reg2=indexTr.resultReg), null) if(expr.identifier.type.isUnsignedWord) { + require(!expr.isMsbForSplitArray) result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.LOADM, vmDt, reg1 = resultRegister, labelSymbol = symbol) it += IRInstruction(Opcode.ADDR, IRDataType.WORD, reg1=resultRegister, reg2=indexWordReg) @@ -179,22 +188,15 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } else { val eltSize = codeGen.program.memsizer.memorySize(expr.identifier.type, 1) result += IRCodeChunk(null, null).also { - // multiply indexTr resultreg by the eltSize and add this to the resultRegister. - it += IRInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, labelSymbol = symbol) - if(eltSize>1) { + loadAddressOfArrayLabel(resultRegister) + if(eltSize>1 && !expr.identifier.type.isSplitWordArray) { it += IRInstruction(Opcode.MUL, IRDataType.WORD, reg1=indexWordReg, immediate = eltSize) } it += IRInstruction(Opcode.ADDR, IRDataType.WORD, reg1=resultRegister, reg2=indexWordReg) } } } else { - if(expr.isMsbForSplitArray) { - addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, labelSymbol = symbol+"_msb"), null) - } else if(expr.identifier.type.isSplitWordArray) { - // the _lsb split array comes first in memory - addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, labelSymbol = symbol+"_lsb"), null) - } else - addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, labelSymbol = symbol), null) + loadAddressOfArrayLabel(resultRegister) } return ExpressionCodeResult(result, vmDt, resultRegister, -1) } diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index e256f4fac..1baa1436c 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -702,23 +702,17 @@ internal class AstChecker(private val program: Program, val variable=addressOf.identifier.targetVarDecl(program) if (variable!=null) { if (variable.type == VarDeclType.CONST && addressOf.arrayIndex == null) - errors.err("invalid pointer-of operand type",addressOf.position) + errors.err("invalid pointer-of operand type", addressOf.position) + } - if(addressOf.arrayIndex!=null && variable.datatype.isSplitWordArray) { - errors.err("cannot take the adress of a word element that is in a split-word array", addressOf.position) - } + if(addressOf.msb) { + if(variable!=null && !variable.datatype.isSplitWordArray) + errors.err("$> can only be used on split word arrays", addressOf.position) } super.visit(addressOf) } - override fun visit(addressOfMsb: AddressOfMsb) { - val target = addressOfMsb.identifier.targetVarDecl(program) - if(target==null || !target.datatype.isSplitWordArray) { - errors.err("&> can only be used on split word arrays", addressOfMsb.position) - } - } - override fun visit(ifExpr: IfExpression) { if(!ifExpr.condition.inferType(program).isBool) errors.err("condition should be a boolean", ifExpr.condition.position) diff --git a/compiler/src/prog8/compiler/astprocessing/BeforeAsmTypecastCleaner.kt b/compiler/src/prog8/compiler/astprocessing/BeforeAsmTypecastCleaner.kt index b42da04cb..e742bf347 100644 --- a/compiler/src/prog8/compiler/astprocessing/BeforeAsmTypecastCleaner.kt +++ b/compiler/src/prog8/compiler/astprocessing/BeforeAsmTypecastCleaner.kt @@ -48,7 +48,7 @@ internal class BeforeAsmTypecastCleaner(val program: Program, listOf( IAstModification.ReplaceNode( typecast, - AddressOf(identifier, null, typecast.position), + AddressOf(identifier, null, false, typecast.position), parent ) ) diff --git a/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt b/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt index c56e04bb5..1d2ba6b61 100644 --- a/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt +++ b/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt @@ -82,7 +82,6 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr private fun transformExpression(expr: Expression): PtExpression { return when(expr) { is AddressOf -> transform(expr) - is AddressOfMsb -> transform(expr) is ArrayIndexedExpression -> transform(expr) is ArrayLiteral -> transform(expr) is BinaryExpression -> transform(expr) @@ -603,19 +602,13 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr } private fun transform(src: AddressOf): PtAddressOf { - val addr = PtAddressOf(src.position) + val addr = PtAddressOf(src.position, src.msb) addr.add(transform(src.identifier)) if(src.arrayIndex!=null) addr.add(transformExpression(src.arrayIndex!!.indexExpr)) return addr } - private fun transform(src: AddressOfMsb): PtAddressOf { - val addr = PtAddressOf(src.position, true) - addr.add(transform(src.identifier)) - return addr - } - private fun transform(srcArr: ArrayIndexedExpression): PtArrayIndexer { val dt = srcArr.arrayvar.targetVarDecl(program)!!.datatype if(!dt.isArray && !dt.isString) diff --git a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt index f035c2411..3a3b49086 100644 --- a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt +++ b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt @@ -257,7 +257,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val if(!argDt.isString) { modifications += IAstModification.ReplaceNode( identifier, - AddressOf(identifier, null, it.second.position), + AddressOf(identifier, null, false, it.second.position), call as Node ) } @@ -275,7 +275,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val // take the address of the identifier modifications += IAstModification.ReplaceNode( identifier, - AddressOf(identifier, null, it.second.position), + AddressOf(identifier, null, false, it.second.position), call as Node ) } @@ -397,7 +397,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val val eltType = elt.inferType(program) val tgt = elt.targetStatement(program) if(eltType.isIterable || tgt is Subroutine || tgt is Label || tgt is Block) { - val addressof = AddressOf(elt, null, elt.position) + val addressof = AddressOf(elt, null, false, elt.position) addressof.linkParents(array) array.value[index] = addressof } diff --git a/compiler/test/codegeneration/TestAsmGenSymbols.kt b/compiler/test/codegeneration/TestAsmGenSymbols.kt index 842981121..6d90eb010 100644 --- a/compiler/test/codegeneration/TestAsmGenSymbols.kt +++ b/compiler/test/codegeneration/TestAsmGenSymbols.kt @@ -55,13 +55,13 @@ class TestAsmGenSymbols: StringSpec({ val tgt = AssignTarget(IdentifierReference(listOf("tgt"), Position.DUMMY), null, null, null, false, Position.DUMMY) val assign1 = Assignment(tgt, IdentifierReference(listOf("localvar"), Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) - val assign2 = Assignment(tgt, AddressOf(IdentifierReference(listOf("locallabel"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) - val assign3 = Assignment(tgt, AddressOf(IdentifierReference(listOf("var_outside"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) - val assign4 = Assignment(tgt, AddressOf(IdentifierReference(listOf("label_outside"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) - val assign5 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","localvar"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) - val assign6 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","locallabel"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) - val assign7 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","var_outside"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) - val assign8 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","label_outside"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) + val assign2 = Assignment(tgt, AddressOf(IdentifierReference(listOf("locallabel"), Position.DUMMY), null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) + val assign3 = Assignment(tgt, AddressOf(IdentifierReference(listOf("var_outside"), Position.DUMMY), null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) + val assign4 = Assignment(tgt, AddressOf(IdentifierReference(listOf("label_outside"), Position.DUMMY), null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) + val assign5 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","localvar"), Position.DUMMY), null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) + val assign6 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","locallabel"), Position.DUMMY), null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) + val assign7 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","var_outside"), Position.DUMMY), null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) + val assign8 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","label_outside"), Position.DUMMY), null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) val statements = mutableListOf(varInSub, var2InSub, labelInSub, assign1, assign2, assign3, assign4, assign5, assign6, assign7, assign8) val subroutine = Subroutine("start", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, statements, Position.DUMMY) diff --git a/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt b/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt index 485b1b5c4..e397768fc 100644 --- a/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt +++ b/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt @@ -464,6 +464,8 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program: override fun visit(addressOf: AddressOf) { output("&") + if(addressOf.msb) + output(">") addressOf.identifier.accept(this) if(addressOf.arrayIndex!=null) { output("[") @@ -472,11 +474,6 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program: } } - override fun visit(addressOfMsb: AddressOfMsb) { - output("&>") - addressOfMsb.identifier.accept(this) - } - override fun visit(inlineAssembly: InlineAssembly) { outputlni("%asm {{") outputln(inlineAssembly.assembly) diff --git a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt index b57b3de97..3ba584760 100644 --- a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt +++ b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt @@ -588,20 +588,12 @@ private fun ExpressionContext.toAst(insideParentheses: Boolean=false) : Expressi if(addressof()!=null) { val addressOf = addressof() val identifier = addressOf.scoped_identifier() - if(addressOf.ADDRESS_OF_LSB()!=null && identifier==null) - throw SyntaxError("&< is only valid on array variables", toPosition()) - return if(addressOf.ADDRESS_OF_MSB()!=null) { - if (identifier != null) - AddressOfMsb(addressof().scoped_identifier().toAst(), toPosition()) - else - throw SyntaxError("&> is only valid on array variables", toPosition()) - } else { - if (identifier != null) - AddressOf(addressof().scoped_identifier().toAst(), null, toPosition()) - else { - val array = addressOf.arrayindexed() - AddressOf(array.scoped_identifier().toAst(), array.arrayindex().toAst(), toPosition()) - } + val msb = addressOf.ADDRESS_OF_MSB()!=null + return if (identifier != null) + AddressOf(addressof().scoped_identifier().toAst(), null, msb, toPosition()) + else { + val array = addressOf.arrayindexed() + AddressOf(array.scoped_identifier().toAst(), array.arrayindex().toAst(), msb, toPosition()) } } diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index 0d2587789..dea21db28 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -416,7 +416,7 @@ class TypecastExpression(var expression: Expression, var type: BaseDataType, val } } -data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayIndex?, override val position: Position) : Expression() { +data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayIndex?, val msb: Boolean, override val position: Position) : Expression() { override lateinit var parent: Node override fun linkParents(parent: Node) { @@ -441,8 +441,10 @@ data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayI } } - override fun copy() = AddressOf(identifier.copy(), arrayIndex?.copy(), position) + override fun copy() = AddressOf(identifier.copy(), arrayIndex?.copy(), msb, position) override fun constValue(program: Program): NumericLiteral? { + if(msb) + return null val target = this.identifier.targetStatement(program) val targetVar = target as? VarDecl if(targetVar!=null) { @@ -464,10 +466,11 @@ data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayI } } } + val targetAsmAddress = (target as? Subroutine)?.asmAddress - if(targetAsmAddress!=null) { + if (targetAsmAddress != null) { val constAddress = targetAsmAddress.address.constValue(program) - if(constAddress==null) + if (constAddress == null) return null return NumericLiteral(BaseDataType.UWORD, constAddress.number, position) } @@ -479,47 +482,6 @@ data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayI override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) } -data class AddressOfMsb(var identifier: IdentifierReference, override val position: Position) : Expression() { - override lateinit var parent: Node - - override fun linkParents(parent: Node) { - this.parent = parent - identifier.linkParents(this) - } - - override val isSimple = true - - override fun replaceChildNode(node: Node, replacement: Node) { - if(node===identifier) { - require(replacement is IdentifierReference) - identifier = replacement - replacement.parent = this - } else { - throw FatalAstException("invalid replace, no child node $node") - } - } - - override fun copy() = AddressOfMsb(identifier.copy(), position) - override fun constValue(program: Program): NumericLiteral? { - val target = this.identifier.targetStatement(program) - val targetVar = target as? VarDecl - if(targetVar!=null) { - if (targetVar.type == VarDeclType.MEMORY || targetVar.type == VarDeclType.CONST) { - var address = targetVar.value?.constValue(program)?.number - if (address != null) { - TODO("RETURN CONSTVALUE ADDROF_MSB ") - // return NumericLiteral(BaseDataType.UWORD, address, position) - } - } - } - return null - } - override fun referencesIdentifier(nameInSource: List) = identifier.nameInSource==nameInSource - override fun inferType(program: Program) = InferredTypes.knownFor(BaseDataType.UWORD) - override fun accept(visitor: IAstVisitor) = visitor.visit(this) - override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) -} - class DirectMemoryRead(var addressExpression: Expression, override val position: Position) : Expression() { override lateinit var parent: Node diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index 4fe86dddc..d1d4d2236 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -267,7 +267,7 @@ class VarDecl(val type: VarDeclType, // parameter variable memory mapped to a R0-R15 virtual register val regname = param.registerOrPair.asScopedNameVirtualReg(param.type) decltype = VarDeclType.MEMORY - value = AddressOf(IdentifierReference(regname, param.position), null, param.position) + value = AddressOf(IdentifierReference(regname, param.position), null, false, param.position) } val dt = if(param.type.isArray) DataType.forDt(BaseDataType.UWORD) else param.type return VarDecl(decltype, VarDeclOrigin.SUBROUTINEPARAM, dt, param.zp, SplitWish.DONTCARE, null, param.name, emptyList(), value, diff --git a/compilerAst/src/prog8/ast/walk/AstWalker.kt b/compilerAst/src/prog8/ast/walk/AstWalker.kt index df2e3ebe9..39a2cae59 100644 --- a/compilerAst/src/prog8/ast/walk/AstWalker.kt +++ b/compilerAst/src/prog8/ast/walk/AstWalker.kt @@ -94,7 +94,6 @@ abstract class AstWalker { protected val noModifications = emptyList() open fun before(addressOf: AddressOf, parent: Node): Iterable = noModifications - open fun before(addressOfMsb: AddressOfMsb, parent: Node): Iterable = noModifications open fun before(array: ArrayLiteral, parent: Node): Iterable = noModifications open fun before(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable = noModifications open fun before(assignTarget: AssignTarget, parent: Node): Iterable = noModifications @@ -140,7 +139,6 @@ abstract class AstWalker { open fun before(whileLoop: WhileLoop, parent: Node): Iterable = noModifications open fun after(addressOf: AddressOf, parent: Node): Iterable = noModifications - open fun after(addressOfMsb: AddressOfMsb, parent: Node): Iterable = noModifications open fun after(array: ArrayLiteral, parent: Node): Iterable = noModifications open fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable = noModifications open fun after(assignTarget: AssignTarget, parent: Node): Iterable = noModifications @@ -471,12 +469,6 @@ abstract class AstWalker { track(after(addressOf, parent), addressOf, parent) } - fun visit(addressOfMsb: AddressOfMsb, parent: Node) { - track(before(addressOfMsb, parent), addressOfMsb, parent) - addressOfMsb.identifier.accept(this, addressOfMsb) - track(after(addressOfMsb, parent), addressOfMsb, parent) - } - fun visit(ifExpr: IfExpression, parent: Node) { track(before(ifExpr, parent), ifExpr, parent) ifExpr.condition.accept(this, ifExpr) diff --git a/compilerAst/src/prog8/ast/walk/IAstVisitor.kt b/compilerAst/src/prog8/ast/walk/IAstVisitor.kt index 7f6cb228a..c1f0609d7 100644 --- a/compilerAst/src/prog8/ast/walk/IAstVisitor.kt +++ b/compilerAst/src/prog8/ast/walk/IAstVisitor.kt @@ -182,10 +182,6 @@ interface IAstVisitor { addressOf.arrayIndex?.accept(this) } - fun visit(addressOfMsb: AddressOfMsb) { - addressOfMsb.identifier.accept(this) - } - fun visit(inlineAssembly: InlineAssembly) { } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 8abb443db..9bff013c4 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -10,15 +10,6 @@ TODO Future Things and Ideas ^^^^^^^^^^^^^^^^^^^^^^^ -- why is this code so much larger with charpos variable, than with just using cx16.r0L ? - ubyte charpos - for charpos in DIALOG_TOPX+1 to DIALOG_TOPX+30 { - txt.setchr(charpos, cx16.r1L, txt.getchr(charpos, cx16.r1L) ^ 128) - } - -- support &, &< and &> on array elements from split word arrays too not just the array as a whole (to get rid of the error "&< is only valid on array variables" - and "cannot take the adress of a word element that is in a split-word array" and the TODOS "address of element of a split word array") -- after that: fix leftover asmgen split word array todo's - Kotlin: can we use inline value classes in certain spots? - Improve the SublimeText syntax file for prog8, you can also install this for 'bat': https://github.com/sharkdp/bat?tab=readme-ov-file#adding-new-syntaxes--language-definitions @@ -59,6 +50,7 @@ IR/VM - add BZ and BNZ instructions? To replace CMPI #0 + Branch? - fix TODO("IR rol/ror on split words array") - fix "<< in array" / ">> in array" +- implement fast code paths for TODO("inplace split.... - sometimes source lines get missing in the output p8ir, for example the first assignment is gone in: sub start() { cx16.r0L = cx16.r1 as ubyte diff --git a/examples/test.p8 b/examples/test.p8 index 272053439..414a74e42 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,8 +1,56 @@ +%import textio +%zeropage basicsafe +%option no_sysinit + main { sub start() { - str localstr = "hello" - uword[] words = [1111,2222,"three"] - bool r1 = 'z' in localstr - bool result = 2222 in words + uword[8] @nosplit warr + uword[8] @split swarr + + uword @shared ptr = $1000 + const uword cptr = $2000 + txt.print_uwhex(&ptr[2], true) + txt.spc() + txt.print_uwhex(&cptr[2], true) + txt.nl() + + txt.print_uwhex(&warr, true) + txt.spc() + txt.print_uwhex(&warr[2], true) + txt.nl() + + txt.print("addresses of split word array:\n") + txt.print_uwhex(&swarr, true) + txt.spc() + txt.print_uwhex(&swarr, true) + txt.nl() + txt.print("addresses of normal word array:\n") + txt.print_uwhex(&warr, true) + txt.spc() + txt.print_uwhex(&swarr[4], true) + txt.nl() + txt.print("addresses of split word array element 4 via var:\n") + cx16.r0L=4 + txt.print_uwhex(&swarr[cx16.r0L], true) + txt.spc() + txt.print_uwhex(&swarr[cx16.r0L], true) + txt.nl() + txt.print("addresses of normal word array element 4:\n") + txt.print_uwhex(&warr[4], true) + txt.spc() + txt.print_uwhex(&