allow taking address of array element

This commit is contained in:
Irmen de Jong 2023-09-17 18:30:57 +02:00
parent ccf6e32bf9
commit 237c6dc856
20 changed files with 231 additions and 119 deletions

View File

@ -126,7 +126,11 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp
private fun makeInitialArray(value: PtArray): List<StArrayElement> { private fun makeInitialArray(value: PtArray): List<StArrayElement> {
return value.children.map { return value.children.map {
when(it) { when(it) {
is PtAddressOf -> StArrayElement(null, it.identifier.name) is PtAddressOf -> {
if(it.isFromArrayElement)
TODO("address-of array element $it in initial array value")
StArrayElement(null, it.identifier.name)
}
is PtIdentifier -> StArrayElement(null, it.name) is PtIdentifier -> StArrayElement(null, it.name)
is PtNumber -> StArrayElement(it.number, null) is PtNumber -> StArrayElement(it.number, null)
else -> throw AssemblyError("invalid array element $it") else -> throw AssemblyError("invalid array element $it")

View File

@ -24,7 +24,17 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
infix fun isSameAs(other: PtExpression): Boolean { infix fun isSameAs(other: PtExpression): Boolean {
return when(this) { return when(this) {
is PtAddressOf -> other is PtAddressOf && other.type==type && other.identifier isSameAs identifier is PtAddressOf -> {
if(other !is PtAddressOf)
return false
if (other.type!==type || !(other.identifier isSameAs identifier))
return false
if(other.children.size!=children.size)
return false
if(children.size==1)
return true
return arrayIndexExpr!! isSameAs other.arrayIndexExpr!!
}
is PtArrayIndexer -> other is PtArrayIndexer && other.type==type && other.variable isSameAs variable && other.index isSameAs index && other.splitWords==splitWords is PtArrayIndexer -> other is PtArrayIndexer && other.type==type && other.variable isSameAs variable && other.index isSameAs index && other.splitWords==splitWords
is PtBinaryExpression -> other is PtBinaryExpression && other.left isSameAs left && other.right isSameAs right is PtBinaryExpression -> other is PtBinaryExpression && other.left isSameAs left && other.right isSameAs right
is PtContainmentCheck -> other is PtContainmentCheck && other.type==type && other.element isSameAs element && other.iterable isSameAs iterable is PtContainmentCheck -> other is PtContainmentCheck && other.type==type && other.element isSameAs element && other.iterable isSameAs iterable
@ -105,7 +115,12 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
class PtAddressOf(position: Position) : PtExpression(DataType.UWORD, position) { class PtAddressOf(position: Position) : PtExpression(DataType.UWORD, position) {
val identifier: PtIdentifier val identifier: PtIdentifier
get() = children.single() as PtIdentifier get() = children[0] as PtIdentifier
val arrayIndexExpr: PtExpression?
get() = if(children.size==2) children[1] as PtExpression else null
val isFromArrayElement: Boolean
get() = children.size==2
} }

View File

@ -2417,8 +2417,7 @@ $repeatLabel""")
cmp #<$number cmp #<$number
bne $jumpIfFalseLabel bne $jumpIfFalseLabel
cpy #>$number cpy #>$number
bne $jumpIfFalseLabel bne $jumpIfFalseLabel""")
""")
} }
is PtIdentifier -> { is PtIdentifier -> {
assignExpressionToRegister(left, RegisterOrPair.AY) assignExpressionToRegister(left, RegisterOrPair.AY)
@ -2426,18 +2425,21 @@ $repeatLabel""")
cmp ${asmVariableName(right)} cmp ${asmVariableName(right)}
bne $jumpIfFalseLabel bne $jumpIfFalseLabel
cpy ${asmVariableName(right)}+1 cpy ${asmVariableName(right)}+1
bne $jumpIfFalseLabel bne $jumpIfFalseLabel""")
""")
} }
is PtAddressOf -> { is PtAddressOf -> {
assignExpressionToRegister(left, RegisterOrPair.AY) assignExpressionToRegister(left, RegisterOrPair.AY)
val name = asmSymbolName(right.identifier) val name = asmSymbolName(right.identifier)
out(""" if(right.isFromArrayElement) {
cmp #<$name TODO("address-of array element $name at ${right.position}")
bne $jumpIfFalseLabel // assignmentAsmGen.assignAddressOf(target, name, right.arrayIndexExpr)
cpy #>$name } else {
bne $jumpIfFalseLabel out("""
""") cmp #<$name
bne $jumpIfFalseLabel
cpy #>$name
bne $jumpIfFalseLabel""")
}
} }
else -> { else -> {
if(left.isSimple()) { if(left.isSimple()) {
@ -2518,12 +2520,16 @@ $repeatLabel""")
is PtAddressOf -> { is PtAddressOf -> {
assignExpressionToRegister(left, RegisterOrPair.AY) assignExpressionToRegister(left, RegisterOrPair.AY)
val name = asmSymbolName(right.identifier) val name = asmSymbolName(right.identifier)
out(""" if(right.isFromArrayElement) {
cmp #<$name TODO("address-of array element $name at ${right.position}")
bne + } else {
cpy #>$name out("""
beq $jumpIfFalseLabel cmp #<$name
+""") bne +
cpy #>$name
beq $jumpIfFalseLabel
+""")
}
} }
else -> { else -> {
if(left.isSimple()) { if(left.isSimple()) {
@ -2849,8 +2855,12 @@ $repeatLabel""")
is PtAddressOf -> { is PtAddressOf -> {
assignExpressionToRegister(right, RegisterOrPair.AY) assignExpressionToRegister(right, RegisterOrPair.AY)
val name = asmSymbolName(left.identifier) val name = asmSymbolName(left.identifier)
code("#>$name", "#<$name") if(left.isFromArrayElement) {
return true TODO("address-of array element $name at ${left.position}")
} else {
code("#>$name", "#<$name")
return true
}
} }
is PtIdentifier -> { is PtIdentifier -> {
assignExpressionToRegister(right, RegisterOrPair.AY) assignExpressionToRegister(right, RegisterOrPair.AY)
@ -2898,8 +2908,12 @@ $repeatLabel""")
is PtAddressOf -> { is PtAddressOf -> {
assignExpressionToRegister(left, RegisterOrPair.AY) assignExpressionToRegister(left, RegisterOrPair.AY)
val name = asmSymbolName(right.identifier) val name = asmSymbolName(right.identifier)
code("#>$name", "#<$name") if(right.isFromArrayElement) {
return true TODO("address-of array element $name at ${right.position}")
} else {
code("#>$name", "#<$name")
return true
}
} }
is PtIdentifier -> { is PtIdentifier -> {
assignExpressionToRegister(left, RegisterOrPair.AY) assignExpressionToRegister(left, RegisterOrPair.AY)

View File

@ -49,7 +49,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
DataType.WORD -> assignVariableWord(assign.target, variable, assign.source.datatype) DataType.WORD -> assignVariableWord(assign.target, variable, assign.source.datatype)
DataType.UWORD -> { DataType.UWORD -> {
if(assign.source.datatype in PassByReferenceDatatypes) if(assign.source.datatype in PassByReferenceDatatypes)
assignAddressOf(assign.target, variable) assignAddressOf(assign.target, variable, null, null)
else else
assignVariableWord(assign.target, variable, assign.source.datatype) assignVariableWord(assign.target, variable, assign.source.datatype)
} }
@ -181,7 +181,8 @@ internal class AssignmentAsmGen(private val program: PtProgram,
when(val value = assign.source.expression!!) { when(val value = assign.source.expression!!) {
is PtAddressOf -> { is PtAddressOf -> {
val sourceName = asmgen.asmSymbolName(value.identifier) val sourceName = asmgen.asmSymbolName(value.identifier)
assignAddressOf(assign.target, sourceName) val arrayDt = value.identifier.type
assignAddressOf(assign.target, sourceName, arrayDt, value.arrayIndexExpr)
} }
is PtNumber -> throw AssemblyError("source kind should have been literalnumber") is PtNumber -> throw AssemblyError("source kind should have been literalnumber")
is PtIdentifier -> throw AssemblyError("source kind should have been variable") is PtIdentifier -> throw AssemblyError("source kind should have been variable")
@ -806,28 +807,32 @@ internal class AssignmentAsmGen(private val program: PtProgram,
when (right) { when (right) {
is PtAddressOf -> { is PtAddressOf -> {
assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD)
val symbol = asmgen.asmVariableName(right.identifier) val symbol = asmgen.asmVariableName(right.identifier)
if(expr.operator=="+") if(right.isFromArrayElement) {
asmgen.out(""" TODO("address-of array element $symbol at ${right.position}")
clc } else {
adc #<$symbol assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD)
tax if(expr.operator=="+")
tya asmgen.out("""
adc #>$symbol clc
tay adc #<$symbol
txa""") tax
else tya
asmgen.out(""" adc #>$symbol
sec tay
sbc #<$symbol txa""")
tax else
tya asmgen.out("""
sbc #>$symbol sec
tay sbc #<$symbol
txa""") tax
assignRegisterpairWord(target, RegisterOrPair.AY) tya
return true sbc #>$symbol
tay
txa""")
assignRegisterpairWord(target, RegisterOrPair.AY)
return true
}
} }
is PtIdentifier -> { is PtIdentifier -> {
val symname = asmgen.asmVariableName(right) val symname = asmgen.asmVariableName(right)
@ -1619,7 +1624,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
// use subroutine // use subroutine
assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE) assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE)
asmgen.saveRegisterStack(CpuRegister.A, true) asmgen.saveRegisterStack(CpuRegister.A, true)
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), symbol.astNode.position,"P8ZP_SCRATCH_W1"), varname) assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), symbol.astNode.position,"P8ZP_SCRATCH_W1"), varname, null, null)
asmgen.restoreRegisterStack(CpuRegister.A, false) asmgen.restoreRegisterStack(CpuRegister.A, false)
val stringVal = (variable as PtVariable).value as PtString val stringVal = (variable as PtVariable).value as PtString
asmgen.out(" ldy #${stringVal.value.length}") asmgen.out(" ldy #${stringVal.value.length}")
@ -1632,7 +1637,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
DataType.ARRAY_B, DataType.ARRAY_UB -> { DataType.ARRAY_B, DataType.ARRAY_UB -> {
assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE) assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE)
asmgen.saveRegisterStack(CpuRegister.A, true) asmgen.saveRegisterStack(CpuRegister.A, true)
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), symbol.astNode.position, "P8ZP_SCRATCH_W1"), varname) assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), symbol.astNode.position, "P8ZP_SCRATCH_W1"), varname, null, null)
asmgen.restoreRegisterStack(CpuRegister.A, false) asmgen.restoreRegisterStack(CpuRegister.A, false)
asmgen.out(" ldy #$numElements") asmgen.out(" ldy #$numElements")
asmgen.out(" jsr prog8_lib.containment_bytearray") asmgen.out(" jsr prog8_lib.containment_bytearray")
@ -1640,7 +1645,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
} }
DataType.ARRAY_W, DataType.ARRAY_UW -> { DataType.ARRAY_W, DataType.ARRAY_UW -> {
assignExpressionToVariable(containment.element, "P8ZP_SCRATCH_W1", elementDt) assignExpressionToVariable(containment.element, "P8ZP_SCRATCH_W1", elementDt)
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), symbol.astNode.position, "P8ZP_SCRATCH_W2"), varname) assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), symbol.astNode.position, "P8ZP_SCRATCH_W2"), varname, null, null)
asmgen.out(" ldy #$numElements") asmgen.out(" ldy #$numElements")
asmgen.out(" jsr prog8_lib.containment_wordarray") asmgen.out(" jsr prog8_lib.containment_wordarray")
return return
@ -2167,12 +2172,24 @@ internal class AssignmentAsmGen(private val program: PtProgram,
} }
} }
private fun assignAddressOf(target: AsmAssignTarget, sourceName: String) { private fun assignAddressOf(target: AsmAssignTarget, sourceName: String, arrayDt: DataType?, arrayIndexExpr: PtExpression?) {
val offset = if(arrayIndexExpr!=null) {
val constIndex = arrayIndexExpr.asConstInteger()
if(constIndex!=null) {
if(arrayDt in SplitWordArrayTypes)
constIndex
else
program.memsizer.memorySize(arrayDt!!, constIndex) // add arrayIndexExpr * elementsize to the address of the array variable.
} else {
TODO("address-of array element $sourceName with non-const index at ${target.position}")
}
} else 0
when(target.kind) { when(target.kind) {
TargetStorageKind.VARIABLE -> { TargetStorageKind.VARIABLE -> {
asmgen.out(""" asmgen.out("""
lda #<$sourceName lda #<$sourceName+$offset
ldy #>$sourceName ldy #>$sourceName+$offset
sta ${target.asmVarname} sta ${target.asmVarname}
sty ${target.asmVarname}+1 sty ${target.asmVarname}+1
""") """)
@ -2181,20 +2198,20 @@ internal class AssignmentAsmGen(private val program: PtProgram,
throw AssemblyError("can't store word into memory byte") throw AssemblyError("can't store word into memory byte")
} }
TargetStorageKind.ARRAY -> { TargetStorageKind.ARRAY -> {
asmgen.out(" lda #<$sourceName | ldy #>$sourceName") asmgen.out(" lda #<$sourceName+$offset | ldy #>$sourceName+$offset")
assignRegisterpairWord(target, RegisterOrPair.AY) assignRegisterpairWord(target, RegisterOrPair.AY)
} }
TargetStorageKind.REGISTER -> { TargetStorageKind.REGISTER -> {
when(target.register!!) { when(target.register!!) {
RegisterOrPair.AX -> asmgen.out(" ldx #>$sourceName | lda #<$sourceName") RegisterOrPair.AX -> asmgen.out(" ldx #>$sourceName+$offset | lda #<$sourceName+$offset")
RegisterOrPair.AY -> asmgen.out(" ldy #>$sourceName | lda #<$sourceName") RegisterOrPair.AY -> asmgen.out(" ldy #>$sourceName+$offset | lda #<$sourceName+$offset")
RegisterOrPair.XY -> asmgen.out(" ldy #>$sourceName | ldx #<$sourceName") RegisterOrPair.XY -> asmgen.out(" ldy #>$sourceName+$offset | ldx #<$sourceName+$offset")
in Cx16VirtualRegisters -> { in Cx16VirtualRegisters -> {
asmgen.out( asmgen.out(
""" """
lda #<$sourceName lda #<$sourceName+$offset
sta cx16.${target.register.toString().lowercase()} sta cx16.${target.register.toString().lowercase()}
lda #>$sourceName lda #>$sourceName+$offset
sta cx16.${target.register.toString().lowercase()}+1 sta cx16.${target.register.toString().lowercase()}+1
""") """)
} }
@ -3622,7 +3639,11 @@ internal class AssignmentAsmGen(private val program: PtProgram,
asmgen.out(" sta ${addressLv.number.toHex()}") asmgen.out(" sta ${addressLv.number.toHex()}")
} }
addressOf != null -> { addressOf != null -> {
asmgen.out(" sta ${asmgen.asmSymbolName(addressOf.identifier)}") if(addressOf.isFromArrayElement) {
TODO("address-of array element $addressOf")
} else {
asmgen.out(" sta ${asmgen.asmSymbolName(addressOf.identifier)}")
}
} }
addressExpr is PtIdentifier -> { addressExpr is PtIdentifier -> {
asmgen.storeAIntoPointerVar(addressExpr) asmgen.storeAIntoPointerVar(addressExpr)
@ -3632,8 +3653,12 @@ internal class AssignmentAsmGen(private val program: PtProgram,
val addrOf = addressExpr.left as? PtAddressOf val addrOf = addressExpr.left as? PtAddressOf
val offset = (addressExpr.right as? PtNumber)?.number?.toInt() val offset = (addressExpr.right as? PtNumber)?.number?.toInt()
if(addrOf!=null && offset!=null) { if(addrOf!=null && offset!=null) {
asmgen.out(" sta ${asmgen.asmSymbolName(addrOf.identifier)}${addressExpr.operator}${offset}") if(addrOf.isFromArrayElement) {
return TODO("address-of array element $addrOf")
} else {
asmgen.out(" sta ${asmgen.asmSymbolName(addrOf.identifier)}${addressExpr.operator}${offset}")
return
}
} }
} }
if(!asmgen.tryOptimizedPointerAccessWithA(addressExpr, addressExpr.operator, true)) if(!asmgen.tryOptimizedPointerAccessWithA(addressExpr, addressExpr.operator, true))

View File

@ -3,10 +3,7 @@ package prog8.codegen.intermediate
import prog8.code.StRomSub import prog8.code.StRomSub
import prog8.code.StSub import prog8.code.StSub
import prog8.code.ast.* import prog8.code.ast.*
import prog8.code.core.AssemblyError import prog8.code.core.*
import prog8.code.core.DataType
import prog8.code.core.PassByValueDatatypes
import prog8.code.core.SignedDatatypes
import prog8.intermediate.* import prog8.intermediate.*
internal class ExpressionCodeResult(val chunks: IRCodeChunks, val dt: IRDataType, val resultReg: Int, val resultFpReg: Int) { internal class ExpressionCodeResult(val chunks: IRCodeChunks, val dt: IRDataType, val resultReg: Int, val resultFpReg: Int) {
@ -69,10 +66,28 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
val vmDt = irType(expr.type) val vmDt = irType(expr.type)
val symbol = expr.identifier.name val symbol = expr.identifier.name
// note: LOAD <symbol> gets you the address of the symbol, whereas LOADM <symbol> would get you the value stored at that location // note: LOAD <symbol> gets you the address of the symbol, whereas LOADM <symbol> would get you the value stored at that location
val code = IRCodeChunk(null, null) val result = mutableListOf<IRCodeChunkBase>()
val resultRegister = codeGen.registers.nextFree() val resultRegister = codeGen.registers.nextFree()
code += IRInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, labelSymbol = symbol) addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, labelSymbol = symbol), null)
ExpressionCodeResult(code, vmDt, resultRegister, -1) if(expr.isFromArrayElement) {
val indexTr = translateExpression(expr.arrayIndexExpr!!)
addToResult(result, indexTr, indexTr.resultReg, -1)
if(expr.identifier.type in SplitWordArrayTypes) {
result += IRCodeChunk(null, null).also {
// multiply indexTr resultreg by the eltSize and add this to the resultRegister.
it += IRInstruction(Opcode.ADDR, IRDataType.BYTE, reg1=resultRegister, reg2=indexTr.resultReg)
}
} 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.
if(eltSize>1)
it += IRInstruction(Opcode.MUL, IRDataType.BYTE, reg1=indexTr.resultReg, immediate = eltSize)
it += IRInstruction(Opcode.ADDR, IRDataType.BYTE, reg1=resultRegister, reg2=indexTr.resultReg)
}
}
}
ExpressionCodeResult(result, vmDt, resultRegister, -1)
} }
is PtMemoryByte -> { is PtMemoryByte -> {
val result = mutableListOf<IRCodeChunkBase>() val result = mutableListOf<IRCodeChunkBase>()

View File

@ -30,7 +30,7 @@ class StatementOptimizer(private val program: Program,
if(functionCallStatement.target.nameInSource==listOf("txt", "print")) { if(functionCallStatement.target.nameInSource==listOf("txt", "print")) {
val arg = functionCallStatement.args.single() val arg = functionCallStatement.args.single()
val stringVar: IdentifierReference? = if(arg is AddressOf) { val stringVar: IdentifierReference? = if(arg is AddressOf) {
arg.identifier if(arg.arrayIndex==null) arg.identifier else null
} else { } else {
arg as? IdentifierReference arg as? IdentifierReference
} }

View File

@ -56,7 +56,7 @@ internal class BeforeAsmTypecastCleaner(val program: Program,
listOf( listOf(
IAstModification.ReplaceNode( IAstModification.ReplaceNode(
typecast, typecast,
AddressOf(identifier, typecast.position), AddressOf(identifier, null, typecast.position),
parent parent
) )
) )

View File

@ -219,6 +219,8 @@ _after:
// @(&var+1) --> msb(var) // @(&var+1) --> msb(var)
val addrOf = memread.addressExpression as? AddressOf val addrOf = memread.addressExpression as? AddressOf
if(addrOf?.arrayIndex!=null)
return noModifications
if(addrOf!=null && addrOf.identifier.inferType(program).isWords) { if(addrOf!=null && addrOf.identifier.inferType(program).isWords) {
val lsb = FunctionCallExpression(IdentifierReference(listOf("lsb"), memread.position), mutableListOf(addrOf.identifier), memread.position) val lsb = FunctionCallExpression(IdentifierReference(listOf("lsb"), memread.position), mutableListOf(addrOf.identifier), memread.position)
return listOf(IAstModification.ReplaceNode(memread, lsb, parent)) return listOf(IAstModification.ReplaceNode(memread, lsb, parent))

View File

@ -440,6 +440,8 @@ class IntermediateAstMaker(private val program: Program) {
addr.add(PtIdentifier(name+"_lsb", dt, src.identifier.position)) // NOTE: assumes _lsb is first in memory! (immediately followed by _msb) addr.add(PtIdentifier(name+"_lsb", dt, src.identifier.position)) // NOTE: assumes _lsb is first in memory! (immediately followed by _msb)
else else
addr.add(transform(src.identifier)) addr.add(transform(src.identifier))
if(src.arrayIndex!=null)
addr.add(transformExpression(src.arrayIndex!!.indexExpr))
return addr return addr
} }

View File

@ -304,8 +304,8 @@ internal class StatementReorderer(
val eltsize = program.memsizer.memorySize(ArrayToElementTypes.getValue(sourceVar.datatype)) val eltsize = program.memsizer.memorySize(ArrayToElementTypes.getValue(sourceVar.datatype))
val memcopy = FunctionCallStatement(IdentifierReference(listOf("sys", "memcopy"), assign.position), val memcopy = FunctionCallStatement(IdentifierReference(listOf("sys", "memcopy"), assign.position),
mutableListOf( mutableListOf(
AddressOf(sourceIdent, assign.position), AddressOf(sourceIdent, null, assign.position),
AddressOf(identifier, assign.position), AddressOf(identifier, null, assign.position),
NumericLiteral.optimalInteger(numelements*eltsize, assign.position) NumericLiteral.optimalInteger(numelements*eltsize, assign.position)
), false, assign.position ), false, assign.position
) )

View File

@ -265,7 +265,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
if(identifier?.isSubroutineParameter(program)==false) { if(identifier?.isSubroutineParameter(program)==false) {
modifications += IAstModification.ReplaceNode( modifications += IAstModification.ReplaceNode(
identifier, identifier,
AddressOf(identifier, arg.position), AddressOf(identifier, null, arg.position),
call as Node) call as Node)
} }
} else if(arg is NumericLiteral) { } else if(arg is NumericLiteral) {
@ -286,7 +286,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
if(arg is IdentifierReference && DataType.UWORD == param.type) { if(arg is IdentifierReference && DataType.UWORD == param.type) {
modifications += IAstModification.ReplaceNode( modifications += IAstModification.ReplaceNode(
arg, arg,
AddressOf(arg, arg.position), AddressOf(arg, null, arg.position),
call as Node call as Node
) )
} }
@ -312,7 +312,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
if(identifier?.isSubroutineParameter(program)==false) { if(identifier?.isSubroutineParameter(program)==false) {
modifications += IAstModification.ReplaceNode( modifications += IAstModification.ReplaceNode(
call.args[index], call.args[index],
AddressOf(identifier, pair.second.position), AddressOf(identifier, null, pair.second.position),
call as Node) call as Node)
break break
} }
@ -325,7 +325,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
if(pair.second is IdentifierReference && DataType.UWORD in pair.first.possibleDatatypes) { if(pair.second is IdentifierReference && DataType.UWORD in pair.first.possibleDatatypes) {
modifications += IAstModification.ReplaceNode( modifications += IAstModification.ReplaceNode(
call.args[index], call.args[index],
AddressOf(pair.second as IdentifierReference, pair.second.position), AddressOf(pair.second as IdentifierReference, null, pair.second.position),
call as Node call as Node
) )
} }

View File

@ -52,13 +52,13 @@ class TestAsmGenSymbols: StringSpec({
val tgt = AssignTarget(IdentifierReference(listOf("tgt"), Position.DUMMY), null, null, Position.DUMMY) val tgt = AssignTarget(IdentifierReference(listOf("tgt"), Position.DUMMY), null, null, Position.DUMMY)
val assign1 = Assignment(tgt, IdentifierReference(listOf("localvar"), Position.DUMMY), AssignmentOrigin.USERCODE, 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), 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), 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), 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), 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), 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), 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), 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 statements = mutableListOf(varInSub, var2InSub, labelInSub, assign1, assign2, assign3, assign4, assign5, assign6, assign7, assign8) val statements = mutableListOf(varInSub, var2InSub, labelInSub, assign1, assign2, assign3, assign4, assign5, assign6, assign7, assign8)
val subroutine = Subroutine("start", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, false, statements, Position.DUMMY) val subroutine = Subroutine("start", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, false, statements, Position.DUMMY)

View File

@ -429,6 +429,7 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
override fun visit(addressOf: AddressOf) { override fun visit(addressOf: AddressOf) {
output("&") output("&")
addressOf.identifier.accept(this) addressOf.identifier.accept(this)
addressOf.arrayIndex?.accept(this)
} }
override fun visit(inlineAssembly: InlineAssembly) { override fun visit(inlineAssembly: InlineAssembly) {

View File

@ -469,8 +469,15 @@ private fun Prog8ANTLRParser.ExpressionContext.toAst() : Expression {
if(directmemory()!=null) if(directmemory()!=null)
return DirectMemoryRead(directmemory().expression().toAst(), toPosition()) return DirectMemoryRead(directmemory().expression().toAst(), toPosition())
if(addressof()!=null) if(addressof()!=null) {
return AddressOf(addressof().scoped_identifier().toAst(), toPosition()) val addressOf = addressof()
val identifier = addressOf.scoped_identifier()
val array = addressOf.arrayindexed()
return if(identifier!=null)
AddressOf(addressof().scoped_identifier().toAst(), null, toPosition())
else
AddressOf(array.scoped_identifier().toAst(), array.arrayindex().toAst(), toPosition())
}
throw FatalAstException(text) throw FatalAstException(text)
} }

View File

@ -49,7 +49,7 @@ sealed class Expression: Node {
(other is TypecastExpression && other.implicit==implicit && other.type==type && other.expression isSameAs expression) (other is TypecastExpression && other.implicit==implicit && other.type==type && other.expression isSameAs expression)
} }
is AddressOf -> { is AddressOf -> {
(other is AddressOf && other.identifier.nameInSource == identifier.nameInSource) (other is AddressOf && other.identifier.nameInSource == identifier.nameInSource && other.arrayIndex==arrayIndex)
} }
is RangeExpression -> { is RangeExpression -> {
(other is RangeExpression && other.from==from && other.to==to && other.step==step) (other is RangeExpression && other.from==from && other.to==to && other.step==step)
@ -369,25 +369,34 @@ class TypecastExpression(var expression: Expression, var type: DataType, val imp
} }
} }
data class AddressOf(var identifier: IdentifierReference, override val position: Position) : Expression() { data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayIndex?, override val position: Position) : Expression() {
override lateinit var parent: Node override lateinit var parent: Node
override fun linkParents(parent: Node) { override fun linkParents(parent: Node) {
this.parent = parent this.parent = parent
identifier.parent=this identifier.linkParents(this)
arrayIndex?.linkParents(this)
} }
override val isSimple = true override val isSimple = true
override fun replaceChildNode(node: Node, replacement: Node) { override fun replaceChildNode(node: Node, replacement: Node) {
require(replacement is IdentifierReference && node===identifier) if(node===identifier) {
identifier = replacement require(replacement is IdentifierReference)
replacement.parent = this identifier = replacement
replacement.parent = this
} else if(node===arrayIndex) {
require(replacement is ArrayIndex)
arrayIndex = replacement
replacement.parent = this
} else {
throw FatalAstException("invalid replace, no child node $node")
}
} }
override fun copy() = AddressOf(identifier.copy(), position) override fun copy() = AddressOf(identifier.copy(), arrayIndex?.copy(), position)
override fun constValue(program: Program): NumericLiteral? = null override fun constValue(program: Program): NumericLiteral? = null
override fun referencesIdentifier(nameInSource: List<String>) = identifier.nameInSource==nameInSource override fun referencesIdentifier(nameInSource: List<String>) = identifier.nameInSource==nameInSource || arrayIndex?.referencesIdentifier(nameInSource)==true
override fun inferType(program: Program) = InferredTypes.knownFor(DataType.UWORD) override fun inferType(program: Program) = InferredTypes.knownFor(DataType.UWORD)
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)

View File

@ -458,6 +458,7 @@ abstract class AstWalker {
fun visit(addressOf: AddressOf, parent: Node) { fun visit(addressOf: AddressOf, parent: Node) {
track(before(addressOf, parent), addressOf, parent) track(before(addressOf, parent), addressOf, parent)
addressOf.identifier.accept(this, addressOf) addressOf.identifier.accept(this, addressOf)
addressOf.arrayIndex?.accept(this)
track(after(addressOf, parent), addressOf, parent) track(after(addressOf, parent), addressOf, parent)
} }

View File

@ -173,6 +173,7 @@ interface IAstVisitor {
fun visit(addressOf: AddressOf) { fun visit(addressOf: AddressOf) {
addressOf.identifier.accept(this) addressOf.identifier.accept(this)
addressOf.arrayIndex?.accept(this)
} }
fun visit(inlineAssembly: InlineAssembly) { fun visit(inlineAssembly: InlineAssembly) {

View File

@ -1,7 +1,7 @@
TODO TODO
==== ====
- allow taking address of array variable (now gives parser error) - implement codegen TODO's "address-of array element" (part of: allow taking address of array element (now gives parser error): &array[10] )
- ir: the @split arrays are currently also split in _lsb/_msb arrays in the IR, and operations take multiple (byte) instructions that may lead to verbose and slow operation and machine code generation down the line. - ir: the @split arrays are currently also split in _lsb/_msb arrays in the IR, and operations take multiple (byte) instructions that may lead to verbose and slow operation and machine code generation down the line.
- [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 .... - [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 ....

View File

@ -1,37 +1,53 @@
%import textio %import textio
%import floats
%zeropage basicsafe %zeropage basicsafe
main { main {
sub start() { sub start() {
uword zz = $ea45 ubyte[] barray = [11,22,33]
txt.print_uwhex(zz, true) uword[] warray = [$1234,$5678,$abcd]
uword[] @split split_warray = [$1234,$5678,$abcd]
float[] float_array = [11.11,22.22,33.33]
txt.print("incr of 1: ")
txt.print_uw(&barray)
txt.spc()
txt.print_uw(&barray[0])
txt.spc()
txt.print_uw(&barray[1])
txt.spc()
txt.print_uw(&barray[2])
txt.nl() txt.nl()
;@(&zz) = $11 txt.print("incr of 2: ")
setlsb(zz, 0) txt.print_uw(&warray)
txt.print_uwhex(zz, true) txt.spc()
txt.nl() txt.print_uw(&warray[0])
;@(&zz+1) = $22 txt.spc()
setmsb(zz, 0) txt.print_uw(&warray[1])
txt.print_uwhex(zz, true) txt.spc()
txt.nl() txt.print_uw(&warray[2])
txt.nl() txt.nl()
uword[] @split array = [$1234,$5678,$abcd] ; TODO also with @split txt.print("incr of 1: ")
txt.print_uw(&split_warray)
txt.spc()
txt.print_uw(&split_warray[0])
txt.spc()
txt.print_uw(&split_warray[1])
txt.spc()
txt.print_uw(&split_warray[2])
txt.nl()
ubyte one = 1 txt.print("incr of 4 or 5: ")
ubyte two = 2 txt.print_uw(&float_array)
txt.print_uwhex(array[1], true) txt.spc()
txt.nl() txt.print_uw(&float_array[0])
txt.print_uwhex(array[2], true) txt.spc()
txt.nl() txt.print_uw(&float_array[1])
;@(&array+one*2) = $ff txt.spc()
;@(&array+two*2+1) = $ff txt.print_uw(&float_array[2])
setlsb(array[one],0)
setmsb(array[two],0)
txt.print_uwhex(array[1], true)
txt.nl()
txt.print_uwhex(array[2], true)
txt.nl() txt.nl()
} }
} }

View File

@ -197,7 +197,7 @@ typecast : 'as' datatype;
directmemory : '@' '(' expression ')'; directmemory : '@' '(' expression ')';
addressof : <assoc=right> ADDRESS_OF scoped_identifier ; addressof : <assoc=right> ADDRESS_OF (scoped_identifier | arrayindexed) ;
functioncall : scoped_identifier '(' expression_list? ')' ; functioncall : scoped_identifier '(' expression_list? ')' ;