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 880c0a5da8
21 changed files with 233 additions and 122 deletions

View File

@ -126,7 +126,11 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp
private fun makeInitialArray(value: PtArray): List<StArrayElement> {
return value.children.map {
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 PtNumber -> StArrayElement(it.number, null)
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 {
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 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
@ -105,7 +115,12 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
class PtAddressOf(position: Position) : PtExpression(DataType.UWORD, position) {
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
bne $jumpIfFalseLabel
cpy #>$number
bne $jumpIfFalseLabel
""")
bne $jumpIfFalseLabel""")
}
is PtIdentifier -> {
assignExpressionToRegister(left, RegisterOrPair.AY)
@ -2426,18 +2425,21 @@ $repeatLabel""")
cmp ${asmVariableName(right)}
bne $jumpIfFalseLabel
cpy ${asmVariableName(right)}+1
bne $jumpIfFalseLabel
""")
bne $jumpIfFalseLabel""")
}
is PtAddressOf -> {
assignExpressionToRegister(left, RegisterOrPair.AY)
val name = asmSymbolName(right.identifier)
out("""
cmp #<$name
bne $jumpIfFalseLabel
cpy #>$name
bne $jumpIfFalseLabel
""")
if(right.isFromArrayElement) {
TODO("address-of array element $name at ${right.position}")
// assignmentAsmGen.assignAddressOf(target, name, right.arrayIndexExpr)
} else {
out("""
cmp #<$name
bne $jumpIfFalseLabel
cpy #>$name
bne $jumpIfFalseLabel""")
}
}
else -> {
if(left.isSimple()) {
@ -2518,12 +2520,16 @@ $repeatLabel""")
is PtAddressOf -> {
assignExpressionToRegister(left, RegisterOrPair.AY)
val name = asmSymbolName(right.identifier)
out("""
cmp #<$name
bne +
cpy #>$name
beq $jumpIfFalseLabel
+""")
if(right.isFromArrayElement) {
TODO("address-of array element $name at ${right.position}")
} else {
out("""
cmp #<$name
bne +
cpy #>$name
beq $jumpIfFalseLabel
+""")
}
}
else -> {
if(left.isSimple()) {
@ -2849,8 +2855,12 @@ $repeatLabel""")
is PtAddressOf -> {
assignExpressionToRegister(right, RegisterOrPair.AY)
val name = asmSymbolName(left.identifier)
code("#>$name", "#<$name")
return true
if(left.isFromArrayElement) {
TODO("address-of array element $name at ${left.position}")
} else {
code("#>$name", "#<$name")
return true
}
}
is PtIdentifier -> {
assignExpressionToRegister(right, RegisterOrPair.AY)
@ -2898,8 +2908,12 @@ $repeatLabel""")
is PtAddressOf -> {
assignExpressionToRegister(left, RegisterOrPair.AY)
val name = asmSymbolName(right.identifier)
code("#>$name", "#<$name")
return true
if(right.isFromArrayElement) {
TODO("address-of array element $name at ${right.position}")
} else {
code("#>$name", "#<$name")
return true
}
}
is PtIdentifier -> {
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.UWORD -> {
if(assign.source.datatype in PassByReferenceDatatypes)
assignAddressOf(assign.target, variable)
assignAddressOf(assign.target, variable, null, null)
else
assignVariableWord(assign.target, variable, assign.source.datatype)
}
@ -181,7 +181,8 @@ internal class AssignmentAsmGen(private val program: PtProgram,
when(val value = assign.source.expression!!) {
is PtAddressOf -> {
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 PtIdentifier -> throw AssemblyError("source kind should have been variable")
@ -806,28 +807,32 @@ internal class AssignmentAsmGen(private val program: PtProgram,
when (right) {
is PtAddressOf -> {
assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD)
val symbol = asmgen.asmVariableName(right.identifier)
if(expr.operator=="+")
asmgen.out("""
clc
adc #<$symbol
tax
tya
adc #>$symbol
tay
txa""")
else
asmgen.out("""
sec
sbc #<$symbol
tax
tya
sbc #>$symbol
tay
txa""")
assignRegisterpairWord(target, RegisterOrPair.AY)
return true
if(right.isFromArrayElement) {
TODO("address-of array element $symbol at ${right.position}")
} else {
assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD)
if(expr.operator=="+")
asmgen.out("""
clc
adc #<$symbol
tax
tya
adc #>$symbol
tay
txa""")
else
asmgen.out("""
sec
sbc #<$symbol
tax
tya
sbc #>$symbol
tay
txa""")
assignRegisterpairWord(target, RegisterOrPair.AY)
return true
}
}
is PtIdentifier -> {
val symname = asmgen.asmVariableName(right)
@ -1619,7 +1624,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
// use subroutine
assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE)
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)
val stringVal = (variable as PtVariable).value as PtString
asmgen.out(" ldy #${stringVal.value.length}")
@ -1632,7 +1637,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
DataType.ARRAY_B, DataType.ARRAY_UB -> {
assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE)
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.out(" ldy #$numElements")
asmgen.out(" jsr prog8_lib.containment_bytearray")
@ -1640,7 +1645,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
}
DataType.ARRAY_W, DataType.ARRAY_UW -> {
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(" jsr prog8_lib.containment_wordarray")
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) {
TargetStorageKind.VARIABLE -> {
asmgen.out("""
lda #<$sourceName
ldy #>$sourceName
lda #<$sourceName+$offset
ldy #>$sourceName+$offset
sta ${target.asmVarname}
sty ${target.asmVarname}+1
""")
@ -2181,20 +2198,20 @@ internal class AssignmentAsmGen(private val program: PtProgram,
throw AssemblyError("can't store word into memory byte")
}
TargetStorageKind.ARRAY -> {
asmgen.out(" lda #<$sourceName | ldy #>$sourceName")
asmgen.out(" lda #<$sourceName+$offset | ldy #>$sourceName+$offset")
assignRegisterpairWord(target, RegisterOrPair.AY)
}
TargetStorageKind.REGISTER -> {
when(target.register!!) {
RegisterOrPair.AX -> asmgen.out(" ldx #>$sourceName | lda #<$sourceName")
RegisterOrPair.AY -> asmgen.out(" ldy #>$sourceName | lda #<$sourceName")
RegisterOrPair.XY -> asmgen.out(" ldy #>$sourceName | ldx #<$sourceName")
RegisterOrPair.AX -> asmgen.out(" ldx #>$sourceName+$offset | lda #<$sourceName+$offset")
RegisterOrPair.AY -> asmgen.out(" ldy #>$sourceName+$offset | lda #<$sourceName+$offset")
RegisterOrPair.XY -> asmgen.out(" ldy #>$sourceName+$offset | ldx #<$sourceName+$offset")
in Cx16VirtualRegisters -> {
asmgen.out(
"""
lda #<$sourceName
lda #<$sourceName+$offset
sta cx16.${target.register.toString().lowercase()}
lda #>$sourceName
lda #>$sourceName+$offset
sta cx16.${target.register.toString().lowercase()}+1
""")
}
@ -3622,7 +3639,11 @@ internal class AssignmentAsmGen(private val program: PtProgram,
asmgen.out(" sta ${addressLv.number.toHex()}")
}
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 -> {
asmgen.storeAIntoPointerVar(addressExpr)
@ -3632,8 +3653,12 @@ internal class AssignmentAsmGen(private val program: PtProgram,
val addrOf = addressExpr.left as? PtAddressOf
val offset = (addressExpr.right as? PtNumber)?.number?.toInt()
if(addrOf!=null && offset!=null) {
asmgen.out(" sta ${asmgen.asmSymbolName(addrOf.identifier)}${addressExpr.operator}${offset}")
return
if(addrOf.isFromArrayElement) {
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))

View File

@ -3,10 +3,7 @@ package prog8.codegen.intermediate
import prog8.code.StRomSub
import prog8.code.StSub
import prog8.code.ast.*
import prog8.code.core.AssemblyError
import prog8.code.core.DataType
import prog8.code.core.PassByValueDatatypes
import prog8.code.core.SignedDatatypes
import prog8.code.core.*
import prog8.intermediate.*
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 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
val code = IRCodeChunk(null, null)
val result = mutableListOf<IRCodeChunkBase>()
val resultRegister = codeGen.registers.nextFree()
code += IRInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, labelSymbol = symbol)
ExpressionCodeResult(code, vmDt, resultRegister, -1)
addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, labelSymbol = symbol), null)
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 -> {
val result = mutableListOf<IRCodeChunkBase>()

View File

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

View File

@ -42,7 +42,7 @@ private fun compileMain(args: Array<String>): Boolean {
val startEmulator2 by cli.option(ArgType.Boolean, fullName = "emu2", description = "auto-start alternative emulator after successful compilation")
val experimentalCodegen by cli.option(ArgType.Boolean, fullName = "expericodegen", description = "use experimental/alternative codegen")
val dontWriteAssembly by cli.option(ArgType.Boolean, fullName = "noasm", description="don't create assembly code")
val dontOptimize by cli.option(ArgType.Boolean, fullName = "noopt", description = "don't perform any optimizations")
val dontOptimize by cli.option(ArgType.Boolean, fullName = "noopt", description = "don't perform code optimizations")
val outputDir by cli.option(ArgType.String, fullName = "out", description = "directory for output files instead of current directory").default(".")
val quietAssembler by cli.option(ArgType.Boolean, fullName = "quietasm", description = "don't print assembler output results")
val warnSymbolShadowing by cli.option(ArgType.Boolean, fullName = "warnshadow", description="show assembler warnings about symbol shadowing")

View File

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

View File

@ -219,6 +219,8 @@ _after:
// @(&var+1) --> msb(var)
val addrOf = memread.addressExpression as? AddressOf
if(addrOf?.arrayIndex!=null)
return noModifications
if(addrOf!=null && addrOf.identifier.inferType(program).isWords) {
val lsb = FunctionCallExpression(IdentifierReference(listOf("lsb"), memread.position), mutableListOf(addrOf.identifier), memread.position)
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)
else
addr.add(transform(src.identifier))
if(src.arrayIndex!=null)
addr.add(transformExpression(src.arrayIndex!!.indexExpr))
return addr
}

View File

@ -304,8 +304,8 @@ internal class StatementReorderer(
val eltsize = program.memsizer.memorySize(ArrayToElementTypes.getValue(sourceVar.datatype))
val memcopy = FunctionCallStatement(IdentifierReference(listOf("sys", "memcopy"), assign.position),
mutableListOf(
AddressOf(sourceIdent, assign.position),
AddressOf(identifier, assign.position),
AddressOf(sourceIdent, null, assign.position),
AddressOf(identifier, null, assign.position),
NumericLiteral.optimalInteger(numelements*eltsize, 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) {
modifications += IAstModification.ReplaceNode(
identifier,
AddressOf(identifier, arg.position),
AddressOf(identifier, null, arg.position),
call as Node)
}
} 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) {
modifications += IAstModification.ReplaceNode(
arg,
AddressOf(arg, arg.position),
AddressOf(arg, null, arg.position),
call as Node
)
}
@ -312,7 +312,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
if(identifier?.isSubroutineParameter(program)==false) {
modifications += IAstModification.ReplaceNode(
call.args[index],
AddressOf(identifier, pair.second.position),
AddressOf(identifier, null, pair.second.position),
call as Node)
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) {
modifications += IAstModification.ReplaceNode(
call.args[index],
AddressOf(pair.second as IdentifierReference, pair.second.position),
AddressOf(pair.second as IdentifierReference, null, pair.second.position),
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 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 assign3 = Assignment(tgt, AddressOf(IdentifierReference(listOf("var_outside"), Position.DUMMY), Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val assign4 = Assignment(tgt, AddressOf(IdentifierReference(listOf("label_outside"), Position.DUMMY), 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 assign6 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","locallabel"), Position.DUMMY), 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 assign8 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","label_outside"), 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), 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 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)

View File

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

View File

@ -469,8 +469,15 @@ private fun Prog8ANTLRParser.ExpressionContext.toAst() : Expression {
if(directmemory()!=null)
return DirectMemoryRead(directmemory().expression().toAst(), toPosition())
if(addressof()!=null)
return AddressOf(addressof().scoped_identifier().toAst(), toPosition())
if(addressof()!=null) {
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)
}

View File

@ -49,7 +49,7 @@ sealed class Expression: Node {
(other is TypecastExpression && other.implicit==implicit && other.type==type && other.expression isSameAs expression)
}
is AddressOf -> {
(other is AddressOf && other.identifier.nameInSource == identifier.nameInSource)
(other is AddressOf && other.identifier.nameInSource == identifier.nameInSource && other.arrayIndex==arrayIndex)
}
is RangeExpression -> {
(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 fun linkParents(parent: Node) {
this.parent = parent
identifier.parent=this
identifier.linkParents(this)
arrayIndex?.linkParents(this)
}
override val isSimple = true
override fun replaceChildNode(node: Node, replacement: Node) {
require(replacement is IdentifierReference && node===identifier)
identifier = replacement
replacement.parent = this
if(node===identifier) {
require(replacement is IdentifierReference)
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 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 accept(visitor: IAstVisitor) = visitor.visit(this)
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) {
track(before(addressOf, parent), addressOf, parent)
addressOf.identifier.accept(this, addressOf)
addressOf.arrayIndex?.accept(this)
track(after(addressOf, parent), addressOf, parent)
}

View File

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

View File

@ -1,9 +1,6 @@
TODO
====
- allow taking address of array variable (now gives parser error)
- 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 ....
- IR: reduce the number of branch instructions such as BEQ, BEQR, etc (gradually), replace with CMP(I) + status branch instruction
- IR: reduce amount of CMP/CMPI after instructions that set the status bits correctly (LOADs? INC? etc), but only after setting the status bits is verified!
@ -40,6 +37,8 @@ Compiler:
Variables replaced include all subroutine parameters! So the only variables that remain as variables are arrays and strings.
- ir: add more optimizations in IRPeepholeOptimizer
- ir: for expressions with array indexes that occur multiple times, can we avoid loading them into new virtualregs everytime and just reuse a single virtualreg as indexer? (simple form of common subexpression elimination)
- 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.
maybe another representation is needed once actual codegeneration is done from the IR...?
- PtAst/IR: more complex common subexpression eliminations
- [problematic due to using 64tass:] better support for building library programs, where unused .proc shouldn't be deleted from the assembly?
Perhaps replace all uses of .proc/.pend/.endproc by .block/.bend will fix that with a compiler flag?

View File

@ -1,37 +1,53 @@
%import textio
%import floats
%zeropage basicsafe
main {
sub start() {
uword zz = $ea45
txt.print_uwhex(zz, true)
ubyte[] barray = [11,22,33]
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()
;@(&zz) = $11
setlsb(zz, 0)
txt.print_uwhex(zz, true)
txt.nl()
;@(&zz+1) = $22
setmsb(zz, 0)
txt.print_uwhex(zz, true)
txt.nl()
txt.print("incr of 2: ")
txt.print_uw(&warray)
txt.spc()
txt.print_uw(&warray[0])
txt.spc()
txt.print_uw(&warray[1])
txt.spc()
txt.print_uw(&warray[2])
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
ubyte two = 2
txt.print_uwhex(array[1], true)
txt.nl()
txt.print_uwhex(array[2], true)
txt.nl()
;@(&array+one*2) = $ff
;@(&array+two*2+1) = $ff
setlsb(array[one],0)
setmsb(array[two],0)
txt.print_uwhex(array[1], true)
txt.nl()
txt.print_uwhex(array[2], true)
txt.print("incr of 4 or 5: ")
txt.print_uw(&float_array)
txt.spc()
txt.print_uw(&float_array[0])
txt.spc()
txt.print_uw(&float_array[1])
txt.spc()
txt.print_uw(&float_array[2])
txt.nl()
}
}

View File

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