mirror of
https://github.com/irmen/prog8.git
synced 2024-12-22 18:30:01 +00:00
allow taking address of array element
This commit is contained in:
parent
ccf6e32bf9
commit
880c0a5da8
@ -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")
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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))
|
||||
|
@ -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>()
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -56,7 +56,7 @@ internal class BeforeAsmTypecastCleaner(val program: Program,
|
||||
listOf(
|
||||
IAstModification.ReplaceNode(
|
||||
typecast,
|
||||
AddressOf(identifier, typecast.position),
|
||||
AddressOf(identifier, null, typecast.position),
|
||||
parent
|
||||
)
|
||||
)
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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
|
||||
)
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -173,6 +173,7 @@ interface IAstVisitor {
|
||||
|
||||
fun visit(addressOf: AddressOf) {
|
||||
addressOf.identifier.accept(this)
|
||||
addressOf.arrayIndex?.accept(this)
|
||||
}
|
||||
|
||||
fun visit(inlineAssembly: InlineAssembly) {
|
||||
|
@ -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?
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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? ')' ;
|
||||
|
Loading…
Reference in New Issue
Block a user