make address-of dereference work

This commit is contained in:
Irmen de Jong
2025-04-26 17:35:04 +02:00
parent 5e2d0d0dfc
commit b920d553a0
28 changed files with 188 additions and 122 deletions

View File

@@ -177,7 +177,7 @@ private fun PtVariable.prefix(parent: PtNode, st: SymbolTable): PtVariable {
newValue.add(elt) newValue.add(elt)
else { else {
val newAddr = PtAddressOf(elt.position) val newAddr = PtAddressOf(elt.position)
newAddr.children.add(elt.identifier.prefix(newAddr, st)) newAddr.children.add(elt.identifier!!.prefix(newAddr, st))
if (elt.arrayIndexExpr != null) if (elt.arrayIndexExpr != null)
newAddr.children.add(elt.arrayIndexExpr!!) newAddr.children.add(elt.arrayIndexExpr!!)
newAddr.parent = arrayValue newAddr.parent = arrayValue
@@ -1299,8 +1299,10 @@ $repeatLabel""")
if(addrOf!=null && constOffset!=null) { if(addrOf!=null && constOffset!=null) {
if(addrOf.isFromArrayElement) { if(addrOf.isFromArrayElement) {
TODO("address-of array element $addrOf") TODO("address-of array element $addrOf")
} else if(addrOf.dereference!=null) {
throw AssemblyError("write &dereference, makes no sense at ${addrOf.position}")
} else { } else {
out(" sta ${asmSymbolName(addrOf.identifier)}+${constOffset}") out(" sta ${asmSymbolName(addrOf.identifier!!)}+${constOffset}")
return true return true
} }
} }
@@ -1339,8 +1341,10 @@ $repeatLabel""")
if(addrOf!=null && constOffset!=null) { if(addrOf!=null && constOffset!=null) {
if(addrOf.isFromArrayElement) { if(addrOf.isFromArrayElement) {
TODO("address-of array element $addrOf") TODO("address-of array element $addrOf")
} else if(addrOf.dereference!=null) {
TODO("read &dereference")
} else { } else {
out(" lda ${asmSymbolName(addrOf.identifier)}+${constOffset}") out(" lda ${asmSymbolName(addrOf.identifier!!)}+${constOffset}")
return true return true
} }
} }
@@ -1389,8 +1393,10 @@ $repeatLabel""")
if(addrOf!=null && constOffset!=null) { if(addrOf!=null && constOffset!=null) {
if(addrOf.isFromArrayElement) { if(addrOf.isFromArrayElement) {
TODO("address-of array element $addrOf") TODO("address-of array element $addrOf")
} else if(addrOf.dereference!=null) {
throw AssemblyError("write &dereference, makes no sense at ${addrOf.position}")
} else { } else {
out(" sta ${asmSymbolName(addrOf.identifier)}-${constOffset}") out(" sta ${asmSymbolName(addrOf.identifier!!)}-${constOffset}")
return true return true
} }
} }
@@ -1420,8 +1426,10 @@ $repeatLabel""")
if(addrOf!=null && constOffset!=null) { if(addrOf!=null && constOffset!=null) {
if(addrOf.isFromArrayElement) { if(addrOf.isFromArrayElement) {
TODO("address-of array element $addrOf") TODO("address-of array element $addrOf")
} else if(addrOf.dereference!=null) {
TODO("read &dereference")
} else { } else {
out(" lda ${asmSymbolName(addrOf.identifier)}-${constOffset}") out(" lda ${asmSymbolName(addrOf.identifier!!)}-${constOffset}")
return true return true
} }
} }

View File

@@ -799,8 +799,8 @@ _jump jmp (${target.asmLabel})
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY, true) asmgen.assignExpressionToRegister(value, RegisterOrPair.AY, true)
asmgen.out(" cpy #0") asmgen.out(" cpy #0")
} else { } else {
var varname = asmgen.asmVariableName(value.identifier) var varname = asmgen.asmVariableName(value.identifier!!)
if(value.identifier.type.isSplitWordArray) { if(value.identifier!!.type.isSplitWordArray) {
varname += if(value.isMsbForSplitArray) "_msb" else "_lsb" varname += if(value.isMsbForSplitArray) "_msb" else "_lsb"
} }
asmgen.out(" lda #>$varname") asmgen.out(" lda #>$varname")
@@ -1598,10 +1598,10 @@ _jump jmp (${target.asmLabel})
if(left.isFromArrayElement) { if(left.isFromArrayElement) {
fallbackTranslateForSimpleCondition(stmt) fallbackTranslateForSimpleCondition(stmt)
} else { } else {
val varname = if(left.identifier.type.isSplitWordArray) { val varname = if(left.identifier!!.type.isSplitWordArray) {
if(left.isMsbForSplitArray) left.identifier.name+"_msb" else left.identifier.name+"_lsb" if(left.isMsbForSplitArray) left.identifier!!.name+"_msb" else left.identifier!!.name+"_lsb"
} else { } else {
left.identifier.name left.identifier!!.name
} }
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed) asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
translateAYNotEquals("#<$varname", "#>$varname") translateAYNotEquals("#<$varname", "#>$varname")
@@ -1650,10 +1650,10 @@ _jump jmp (${target.asmLabel})
if(left.isFromArrayElement) { if(left.isFromArrayElement) {
fallbackTranslateForSimpleCondition(stmt) fallbackTranslateForSimpleCondition(stmt)
} else { } else {
val varname = if(left.identifier.type.isSplitWordArray) { val varname = if(left.identifier!!.type.isSplitWordArray) {
if(left.isMsbForSplitArray) left.identifier.name+"_msb" else left.identifier.name+"_lsb" if(left.isMsbForSplitArray) left.identifier!!.name+"_msb" else left.identifier!!.name+"_lsb"
} else { } else {
left.identifier.name left.identifier!!.name
} }
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed) asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
translateAYEquals("#<$varname", "#>$varname") translateAYEquals("#<$varname", "#>$varname")

View File

@@ -438,15 +438,19 @@ internal class AssignmentAsmGen(
private fun assignExpression(assign: AsmAssignment, scope: IPtSubroutine?) { private fun assignExpression(assign: AsmAssignment, scope: IPtSubroutine?) {
when(val value = assign.source.expression!!) { when(val value = assign.source.expression!!) {
is PtAddressOf -> { is PtAddressOf -> {
val arrayDt = value.identifier.type if(value.identifier!=null) {
val sourceName = val arrayDt = value.identifier!!.type
if (value.isMsbForSplitArray) val sourceName =
asmgen.asmSymbolName(value.identifier) + "_msb" if (value.isMsbForSplitArray)
else if (arrayDt.isSplitWordArray) asmgen.asmSymbolName(value.identifier!!) + "_msb"
asmgen.asmSymbolName(value.identifier) + "_lsb" // the _lsb split array comes first in memory else if (arrayDt.isSplitWordArray)
else asmgen.asmSymbolName(value.identifier!!) + "_lsb" // the _lsb split array comes first in memory
asmgen.asmSymbolName(value.identifier) else
assignAddressOf(assign.target, sourceName, value.isMsbForSplitArray, arrayDt, value.arrayIndexExpr) asmgen.asmSymbolName(value.identifier!!)
assignAddressOf(assign.target, sourceName, value.isMsbForSplitArray, arrayDt, value.arrayIndexExpr)
} else {
TODO("read &dereference")
}
} }
is PtBool -> throw AssemblyError("source kind should have been literalboolean") is PtBool -> throw AssemblyError("source kind should have been literalboolean")
is PtNumber -> throw AssemblyError("source kind should have been literalnumber") is PtNumber -> throw AssemblyError("source kind should have been literalnumber")
@@ -1384,9 +1388,11 @@ internal class AssignmentAsmGen(
is PtAddressOf -> { is PtAddressOf -> {
if(right.isFromArrayElement) { if(right.isFromArrayElement) {
TODO("address-of array element at ${right.position}") TODO("address-of array element at ${right.position}")
} else if(right.dereference!=null) {
TODO("read &dereference")
} else { } else {
var symbol = asmgen.asmVariableName(right.identifier) var symbol = asmgen.asmVariableName(right.identifier!!)
if(right.identifier.type.isSplitWordArray) { if(right.identifier!!.type.isSplitWordArray) {
symbol = if(right.isMsbForSplitArray) symbol+"_msb" else symbol+"_lsb" symbol = if(right.isMsbForSplitArray) symbol+"_msb" else symbol+"_lsb"
} }
assignExpressionToRegister(left, RegisterOrPair.AY, dt.isSigned) assignExpressionToRegister(left, RegisterOrPair.AY, dt.isSigned)
@@ -4019,8 +4025,10 @@ $endLabel""")
addressOf != null -> { addressOf != null -> {
if(addressOf.isFromArrayElement) { if(addressOf.isFromArrayElement) {
TODO("address-of array element $addressOf") TODO("address-of array element $addressOf")
} else if(addressOf.dereference!=null) {
throw AssemblyError("write &dereference, makes no sense at ${addressOf.position}")
} else { } else {
asmgen.out(" sta ${asmgen.asmSymbolName(addressOf.identifier)}") asmgen.out(" sta ${asmgen.asmSymbolName(addressOf.identifier!!)}")
} }
} }
addressExpr is PtIdentifier -> { addressExpr is PtIdentifier -> {

View File

@@ -511,7 +511,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
else if(targetPointerDeref!=null) { else if(targetPointerDeref!=null) {
val pointerTr = expressionEval.translateExpression(targetPointerDeref.start) val pointerTr = expressionEval.translateExpression(targetPointerDeref.start)
result += pointerTr.chunks result += pointerTr.chunks
result += expressionEval.traverseDerefChain(targetPointerDeref, pointerTr.resultReg) result += expressionEval.traverseDerefChainToCalculateFinalAddress(targetPointerDeref, pointerTr.resultReg)
val instr = when { val instr = when {
targetPointerDeref.type.isByteOrBool -> { targetPointerDeref.type.isByteOrBool -> {
@@ -977,37 +977,33 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
val result = mutableListOf<IRCodeChunkBase>() val result = mutableListOf<IRCodeChunkBase>()
if(vmDt==IRDataType.FLOAT) { if(vmDt==IRDataType.FLOAT) {
if((operand as? PtNumber)?.number==1.0) { if((operand as? PtNumber)?.number==1.0) {
addInstr(result, if(constAddress!=null) addInstr(result, if (constAddress != null)
IRInstruction(Opcode.INCM, vmDt, address = constAddress) IRInstruction(Opcode.INCM, vmDt, address = constAddress)
else else
IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol) IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol) , null)
, null)
} }
else { else {
val tr = expressionEval.translateExpression(operand) val tr = expressionEval.translateExpression(operand)
addToResult(result, tr, -1, tr.resultFpReg) addToResult(result, tr, -1, tr.resultFpReg)
addInstr(result, if(constAddress!=null) addInstr(result, if (constAddress != null)
IRInstruction(Opcode.ADDM, vmDt, fpReg1=tr.resultFpReg, address = constAddress) IRInstruction(Opcode.ADDM, vmDt, fpReg1 = tr.resultFpReg, address = constAddress)
else else
IRInstruction(Opcode.ADDM, vmDt, fpReg1=tr.resultFpReg, labelSymbol = symbol) IRInstruction(Opcode.ADDM, vmDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol) , null)
, null)
} }
} else { } else {
if((operand as? PtNumber)?.number==1.0) { if((operand as? PtNumber)?.number==1.0) {
addInstr(result, if(constAddress!=null) addInstr(result, if (constAddress != null)
IRInstruction(Opcode.INCM, vmDt, address = constAddress) IRInstruction(Opcode.INCM, vmDt, address = constAddress)
else else
IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol) IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol) , null)
, null)
} }
else { else {
val tr = expressionEval.translateExpression(operand) val tr = expressionEval.translateExpression(operand)
addToResult(result, tr, tr.resultReg, -1) addToResult(result, tr, tr.resultReg, -1)
addInstr(result, if(constAddress!=null) addInstr(result, if (constAddress != null)
IRInstruction(Opcode.ADDM, vmDt, reg1=tr.resultReg, address = constAddress) IRInstruction(Opcode.ADDM, vmDt, reg1 = tr.resultReg, address = constAddress)
else else
IRInstruction(Opcode.ADDM, vmDt, reg1=tr.resultReg, labelSymbol = symbol) IRInstruction(Opcode.ADDM, vmDt, reg1 = tr.resultReg, labelSymbol = symbol) , null)
, null)
} }
} }
return result return result

View File

@@ -101,7 +101,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
val result = mutableListOf<IRCodeChunkBase>() val result = mutableListOf<IRCodeChunkBase>()
val tr = translateExpression(deref.start) val tr = translateExpression(deref.start)
result += tr.chunks result += tr.chunks
result += traverseDerefChain(deref, tr.resultReg) result += traverseDerefChainToCalculateFinalAddress(deref, tr.resultReg)
when { when {
deref.type.isByteOrBool -> { deref.type.isByteOrBool -> {
val resultReg = codeGen.registers.next(IRDataType.BYTE) val resultReg = codeGen.registers.next(IRDataType.BYTE)
@@ -199,8 +199,8 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
fun loadAddressOfArrayLabel(reg: Int) { fun loadAddressOfArrayLabel(reg: Int) {
if (expr.isMsbForSplitArray) { if (expr.isMsbForSplitArray) {
addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = reg, labelSymbol = identifier.name + "_msb"), null) addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = reg, labelSymbol = identifier!!.name + "_msb"), null)
} else if (identifier.type.isSplitWordArray) { } else if (identifier!!.type.isSplitWordArray) {
// the _lsb split array comes first in memory // the _lsb split array comes first in memory
addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = reg, labelSymbol = identifier.name + "_lsb"), null) addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = reg, labelSymbol = identifier.name + "_lsb"), null)
} else } else
@@ -213,25 +213,35 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
val indexTr = translateExpression(expr.arrayIndexExpr!!) val indexTr = translateExpression(expr.arrayIndexExpr!!)
addToResult(result, indexTr, indexTr.resultReg, -1) addToResult(result, indexTr, indexTr.resultReg, -1)
val indexWordReg = codeGen.registers.next(IRDataType.WORD) val indexWordReg = codeGen.registers.next(IRDataType.WORD)
addInstr(result, IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=indexWordReg, reg2=indexTr.resultReg), null) addInstr(
if(identifier.type.isUnsignedWord) { result,
IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1 = indexWordReg, reg2 = indexTr.resultReg),
null
)
if (identifier!!.type.isUnsignedWord) {
require(!expr.isMsbForSplitArray) require(!expr.isMsbForSplitArray)
result += IRCodeChunk(null, null).also { result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADM, vmDt, reg1 = resultRegister, labelSymbol = identifier.name) it += IRInstruction(Opcode.LOADM, vmDt, reg1 = resultRegister, labelSymbol = identifier.name)
it += IRInstruction(Opcode.ADDR, IRDataType.WORD, reg1=resultRegister, reg2=indexWordReg) it += IRInstruction(Opcode.ADDR, IRDataType.WORD, reg1 = resultRegister, reg2 = indexWordReg)
} }
} else { } else {
val eltSize = codeGen.program.memsizer.memorySize(identifier.type, 1) val eltSize = codeGen.program.memsizer.memorySize(identifier.type, 1)
result += IRCodeChunk(null, null).also { result += IRCodeChunk(null, null).also {
loadAddressOfArrayLabel(resultRegister) loadAddressOfArrayLabel(resultRegister)
if(eltSize>1 && !identifier.type.isSplitWordArray) { if (eltSize > 1 && !identifier.type.isSplitWordArray) {
it += IRInstruction(Opcode.MUL, IRDataType.WORD, reg1=indexWordReg, immediate = eltSize) it += IRInstruction(Opcode.MUL, IRDataType.WORD, reg1 = indexWordReg, immediate = eltSize)
} }
it += IRInstruction(Opcode.ADDR, IRDataType.WORD, reg1=resultRegister, reg2=indexWordReg) it += IRInstruction(Opcode.ADDR, IRDataType.WORD, reg1 = resultRegister, reg2 = indexWordReg)
} }
} }
} else { } else if(expr.identifier!=null ) {
loadAddressOfArrayLabel(resultRegister) loadAddressOfArrayLabel(resultRegister)
} else {
require(vmDt==IRDataType.WORD)
val pointerTr = translateExpression(expr.dereference!!.start)
result += pointerTr.chunks
result += traverseDerefChainToCalculateFinalAddress(expr.dereference!!, pointerTr.resultReg)
addInstr(result, IRInstruction(Opcode.LOADR, IRDataType.WORD, reg1 = resultRegister, reg2 = pointerTr.resultReg), null)
} }
return ExpressionCodeResult(result, vmDt, resultRegister, -1) return ExpressionCodeResult(result, vmDt, resultRegister, -1)
} }
@@ -1473,7 +1483,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
} }
} }
internal fun traverseDerefChain(targetPointerDeref: PtPointerDeref, pointerReg: Int): IRCodeChunks { internal fun traverseDerefChainToCalculateFinalAddress(targetPointerDeref: PtPointerDeref, pointerReg: Int): IRCodeChunks {
val result = mutableListOf<IRCodeChunkBase>() val result = mutableListOf<IRCodeChunkBase>()
var struct: StStruct? = null var struct: StStruct? = null
if(targetPointerDeref.start.type.subIdentifier!=null) if(targetPointerDeref.start.type.subIdentifier!=null)

View File

@@ -27,8 +27,8 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors:
// @( &thing ) --> thing (but only if thing is a byte type!) // @( &thing ) --> thing (but only if thing is a byte type!)
val addrOf = memread.addressExpression as? AddressOf val addrOf = memread.addressExpression as? AddressOf
if(addrOf!=null) { if(addrOf!=null) {
if(addrOf.identifier.inferType(program).isBytes) if(addrOf.identifier?.inferType(program)?.isBytes==true)
return listOf(IAstModification.ReplaceNode(memread, addrOf.identifier, parent)) return listOf(IAstModification.ReplaceNode(memread, addrOf.identifier!!, parent))
} }
return noModifications return noModifications
} }

View File

@@ -29,7 +29,14 @@ 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) {
if(arg.arrayIndex==null) arg.identifier else null if(arg.arrayIndex==null) {
if(arg.identifier!=null)
arg.identifier
else
null // struct can't have string fields so nothing to look at here
} else {
null
}
} else { } else {
arg as? IdentifierReference arg as? IdentifierReference
} }

View File

@@ -713,7 +713,7 @@ internal class AstChecker(private val program: Program,
override fun visit(addressOf: AddressOf) { override fun visit(addressOf: AddressOf) {
checkLongType(addressOf) checkLongType(addressOf)
val variable=addressOf.identifier.targetVarDecl() val variable=addressOf.identifier?.targetVarDecl()
if (variable!=null) { if (variable!=null) {
if (variable.type == VarDeclType.CONST && addressOf.arrayIndex == null) if (variable.type == VarDeclType.CONST && addressOf.arrayIndex == null)
errors.err("invalid pointer-of operand type", addressOf.position) errors.err("invalid pointer-of operand type", addressOf.position)
@@ -1987,7 +1987,13 @@ internal class AstChecker(private val program: Program,
val array = value.value.map { val array = value.value.map {
when (it) { when (it) {
is NumericLiteral -> it.number.toInt() is NumericLiteral -> it.number.toInt()
is AddressOf -> it.identifier.nameInSource.hashCode() and 0xffff is AddressOf -> {
if(it.identifier!=null)
it.identifier!!.nameInSource.hashCode() and 0xffff
else if(it.dereference!=null)
it.dereference!!.identifier.nameInSource.hashCode() and 0xffff
else 9999999
}
is IdentifierReference -> it.nameInSource.hashCode() and 0xffff is IdentifierReference -> it.nameInSource.hashCode() and 0xffff
is TypecastExpression if it.type.isBasic -> { is TypecastExpression if it.type.isBasic -> {
val constVal = it.expression.constValue(program) val constVal = it.expression.constValue(program)

View File

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

View File

@@ -282,8 +282,8 @@ _after:
val addrOf = memread.addressExpression as? AddressOf val addrOf = memread.addressExpression as? AddressOf
if(addrOf?.arrayIndex!=null) if(addrOf?.arrayIndex!=null)
return noModifications return noModifications
if(addrOf!=null && addrOf.identifier.inferType(program).isWords) { if(addrOf!=null && addrOf.identifier?.inferType(program)?.isWords==true) {
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))
} }
val expr = memread.addressExpression as? BinaryExpression val expr = memread.addressExpression as? BinaryExpression
@@ -291,10 +291,10 @@ _after:
val addressOf = expr.left as? AddressOf val addressOf = expr.left as? AddressOf
val offset = (expr.right as? NumericLiteral)?.number?.toInt() val offset = (expr.right as? NumericLiteral)?.number?.toInt()
if(addressOf!=null && offset==1) { if(addressOf!=null && offset==1) {
val variable = addressOf.identifier.targetVarDecl() val variable = addressOf.identifier?.targetVarDecl()
if(variable!=null && variable.datatype.isWord) { if(variable!=null && variable.datatype.isWord) {
val msb = FunctionCallExpression(IdentifierReference(listOf("msb"), memread.position), mutableListOf( val msb = FunctionCallExpression(IdentifierReference(listOf("msb"), memread.position), mutableListOf(
addressOf.identifier addressOf.identifier!!
), memread.position) ), memread.position)
return listOf(IAstModification.ReplaceNode(memread, msb, parent)) return listOf(IAstModification.ReplaceNode(memread, msb, parent))
} }

View File

@@ -652,9 +652,12 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
private fun transform(src: AddressOf): PtAddressOf { private fun transform(src: AddressOf): PtAddressOf {
val addr = PtAddressOf(src.position, src.msb) val addr = PtAddressOf(src.position, src.msb)
addr.add(transform(src.identifier)) if(src.identifier!=null)
addr.add(transform(src.identifier!!))
if (src.arrayIndex != null) if (src.arrayIndex != null)
addr.add(transformExpression(src.arrayIndex!!.indexExpr)) addr.add(transformExpression(src.arrayIndex!!.indexExpr))
if (src.dereference!=null)
addr.add(transformExpression(src.dereference!!))
return addr return addr
} }

View File

@@ -267,7 +267,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
if(!argDt.isString) { if(!argDt.isString) {
modifications += IAstModification.ReplaceNode( modifications += IAstModification.ReplaceNode(
identifier, identifier,
AddressOf(identifier, null, false, it.second.position), AddressOf(identifier, null, null, false, it.second.position),
call as Node call as Node
) )
} }
@@ -285,7 +285,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
// take the address of the identifier // take the address of the identifier
modifications += IAstModification.ReplaceNode( modifications += IAstModification.ReplaceNode(
identifier, identifier,
AddressOf(identifier, null, false, it.second.position), AddressOf(identifier, null, null, false, it.second.position),
call as Node call as Node
) )
} }
@@ -410,7 +410,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
val eltType = elt.inferType(program) val eltType = elt.inferType(program)
val tgt = elt.targetStatement(program) val tgt = elt.targetStatement(program)
if(eltType.isIterable || tgt is Subroutine || tgt is Label || tgt is Block) { if(eltType.isIterable || tgt is Subroutine || tgt is Label || tgt is Block) {
val addressof = AddressOf(elt, null, false, elt.position) val addressof = AddressOf(elt, null, null, false, elt.position)
addressof.linkParents(array) addressof.linkParents(array)
array.value[index] = addressof array.value[index] = addressof
} }

View File

@@ -61,7 +61,7 @@ class TestCompilerOnImportsAndIncludes: FunSpec({
str0.value shouldBe "main.bar" str0.value shouldBe "main.bar"
str0.definingScope.name shouldBe "main" str0.definingScope.name shouldBe "main"
val id1 = (args[1] as AddressOf).identifier val id1 = (args[1] as AddressOf).identifier!!
val lbl1 = id1.targetStatement(program) as Label val lbl1 = id1.targetStatement(program) as Label
lbl1.name shouldBe "foo_bar" lbl1.name shouldBe "foo_bar"
lbl1.definingScope.name shouldBe "main" lbl1.definingScope.name shouldBe "main"

View File

@@ -325,7 +325,7 @@ main {
val assignAddr = (st[2] as Assignment).value val assignAddr = (st[2] as Assignment).value
(assignAddr as NumericLiteral).number shouldBe 8194.0 (assignAddr as NumericLiteral).number shouldBe 8194.0
val assignAddr2 = ((st[9] as Assignment).value as AddressOf) val assignAddr2 = ((st[9] as Assignment).value as AddressOf)
assignAddr2.identifier.nameInSource shouldBe listOf("buffer") assignAddr2.identifier!!.nameInSource shouldBe listOf("buffer")
assignAddr2.arrayIndex!!.indexExpr shouldBe instanceOf<BinaryExpression>() assignAddr2.arrayIndex!!.indexExpr shouldBe instanceOf<BinaryExpression>()
} }

View File

@@ -60,7 +60,7 @@ class TestIdentifierRef: FunSpec({
val mstmts = (module.statements.single() as Block).statements val mstmts = (module.statements.single() as Block).statements
val stmts = mstmts.filterIsInstance<Subroutine>().single().statements val stmts = mstmts.filterIsInstance<Subroutine>().single().statements
val wwref = (stmts[0] as Assignment).target.identifier!! val wwref = (stmts[0] as Assignment).target.identifier!!
val mainref = ((stmts[1] as Assignment).value as AddressOf).identifier val mainref = ((stmts[1] as Assignment).value as AddressOf).identifier!!
wwref.nameInSource shouldBe listOf("ww") wwref.nameInSource shouldBe listOf("ww")
wwref.wasStringLiteral() shouldBe false wwref.wasStringLiteral() shouldBe false
wwref.targetStatement(program) shouldBe instanceOf<VarDecl>() wwref.targetStatement(program) shouldBe instanceOf<VarDecl>()

View File

@@ -65,13 +65,13 @@ class TestAsmGenSymbols: StringSpec({
position = Position.DUMMY position = 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), null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) val assign2 = Assignment(tgt, AddressOf(IdentifierReference(listOf("locallabel"), Position.DUMMY), null, null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val assign3 = Assignment(tgt, AddressOf(IdentifierReference(listOf("var_outside"), Position.DUMMY), null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) val assign3 = Assignment(tgt, AddressOf(IdentifierReference(listOf("var_outside"), Position.DUMMY), null, null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val assign4 = Assignment(tgt, AddressOf(IdentifierReference(listOf("label_outside"), Position.DUMMY), null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) val assign4 = Assignment(tgt, AddressOf(IdentifierReference(listOf("label_outside"), Position.DUMMY), null, null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val assign5 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","localvar"), Position.DUMMY), null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) val assign5 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","localvar"), Position.DUMMY), null, null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val assign6 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","locallabel"), Position.DUMMY), null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) val assign6 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","locallabel"), Position.DUMMY), null, null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val assign7 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","var_outside"), Position.DUMMY), null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) val assign7 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","var_outside"), Position.DUMMY), null, null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val assign8 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","label_outside"), Position.DUMMY), null, false, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) val assign8 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","label_outside"), Position.DUMMY), null, null, false, 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(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, statements, Position.DUMMY) val subroutine = Subroutine("start", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, statements, Position.DUMMY)
@@ -118,13 +118,13 @@ class TestAsmGenSymbols: StringSpec({
val localvarIdent = sub.children.asSequence().filterIsInstance<PtAssignment>().first { it.value is PtIdentifier }.value as PtIdentifier val localvarIdent = sub.children.asSequence().filterIsInstance<PtAssignment>().first { it.value is PtIdentifier }.value as PtIdentifier
asmgen.asmSymbolName(localvarIdent) shouldBe "localvar" asmgen.asmSymbolName(localvarIdent) shouldBe "localvar"
asmgen.asmVariableName(localvarIdent) shouldBe "localvar" asmgen.asmVariableName(localvarIdent) shouldBe "localvar"
val localvarIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.localvar" }.value as PtAddressOf).identifier val localvarIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.localvar" }.value as PtAddressOf).identifier!!
asmgen.asmSymbolName(localvarIdentScoped) shouldBe "localvar" asmgen.asmSymbolName(localvarIdentScoped) shouldBe "localvar"
asmgen.asmVariableName(localvarIdentScoped) shouldBe "localvar" asmgen.asmVariableName(localvarIdentScoped) shouldBe "localvar"
val scopedVarIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.var_outside" }.value as PtAddressOf).identifier val scopedVarIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.var_outside" }.value as PtAddressOf).identifier!!
asmgen.asmSymbolName(scopedVarIdent) shouldBe "main.var_outside" asmgen.asmSymbolName(scopedVarIdent) shouldBe "main.var_outside"
asmgen.asmVariableName(scopedVarIdent) shouldBe "main.var_outside" asmgen.asmVariableName(scopedVarIdent) shouldBe "main.var_outside"
val scopedVarIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.var_outside" }.value as PtAddressOf).identifier val scopedVarIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.var_outside" }.value as PtAddressOf).identifier!!
asmgen.asmSymbolName(scopedVarIdentScoped) shouldBe "main.var_outside" asmgen.asmSymbolName(scopedVarIdentScoped) shouldBe "main.var_outside"
asmgen.asmVariableName(scopedVarIdentScoped) shouldBe "main.var_outside" asmgen.asmVariableName(scopedVarIdentScoped) shouldBe "main.var_outside"
} }
@@ -134,17 +134,17 @@ class TestAsmGenSymbols: StringSpec({
val asmgen = createTestAsmGen6502(program) val asmgen = createTestAsmGen6502(program)
val sub = asmgen.program.entrypoint()!! val sub = asmgen.program.entrypoint()!!
val localLabelIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.locallabel" }.value as PtAddressOf).identifier val localLabelIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.locallabel" }.value as PtAddressOf).identifier!!
asmgen.asmSymbolName(localLabelIdent) shouldBe "locallabel" asmgen.asmSymbolName(localLabelIdent) shouldBe "locallabel"
asmgen.asmVariableName(localLabelIdent) shouldBe "locallabel" asmgen.asmVariableName(localLabelIdent) shouldBe "locallabel"
val localLabelIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.locallabel" }.value as PtAddressOf).identifier val localLabelIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.locallabel" }.value as PtAddressOf).identifier!!
asmgen.asmSymbolName(localLabelIdentScoped) shouldBe "locallabel" asmgen.asmSymbolName(localLabelIdentScoped) shouldBe "locallabel"
asmgen.asmVariableName(localLabelIdentScoped) shouldBe "locallabel" asmgen.asmVariableName(localLabelIdentScoped) shouldBe "locallabel"
val scopedLabelIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.label_outside" }.value as PtAddressOf).identifier val scopedLabelIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.label_outside" }.value as PtAddressOf).identifier!!
asmgen.asmSymbolName(scopedLabelIdent) shouldBe "main.label_outside" asmgen.asmSymbolName(scopedLabelIdent) shouldBe "main.label_outside"
asmgen.asmVariableName(scopedLabelIdent) shouldBe "main.label_outside" asmgen.asmVariableName(scopedLabelIdent) shouldBe "main.label_outside"
val scopedLabelIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.label_outside" }.value as PtAddressOf).identifier val scopedLabelIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.label_outside" }.value as PtAddressOf).identifier!!
asmgen.asmSymbolName(scopedLabelIdentScoped) shouldBe "main.label_outside" asmgen.asmSymbolName(scopedLabelIdentScoped) shouldBe "main.label_outside"
asmgen.asmVariableName(scopedLabelIdentScoped) shouldBe "main.label_outside" asmgen.asmVariableName(scopedLabelIdentScoped) shouldBe "main.label_outside"
} }

View File

@@ -482,12 +482,13 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
output("&") output("&")
if(addressOf.msb) if(addressOf.msb)
output(">") output(">")
addressOf.identifier.accept(this) addressOf.identifier?.accept(this)
if (addressOf.arrayIndex != null) { if (addressOf.arrayIndex != null) {
output("[") output("[")
addressOf.arrayIndex?.accept(this) addressOf.arrayIndex?.accept(this)
output("]") output("]")
} }
addressOf.dereference?.accept(this)
} }
override fun visit(inlineAssembly: InlineAssembly) { override fun visit(inlineAssembly: InlineAssembly) {

View File

@@ -632,10 +632,10 @@ private fun ExpressionContext.toAst(insideParentheses: Boolean=false) : Expressi
val msb = addressOf.ADDRESS_OF_MSB()!=null val msb = addressOf.ADDRESS_OF_MSB()!=null
// note: &< (ADDRESS_OF_LSB) is equivalent to a regular &. // note: &< (ADDRESS_OF_LSB) is equivalent to a regular &.
return if (identifier != null) return if (identifier != null)
AddressOf(addressof().scoped_identifier().toAst(),null, msb, toPosition()) AddressOf(addressof().scoped_identifier().toAst(),null, null, msb, toPosition())
else { else {
val array = addressOf.arrayindexed() val array = addressOf.arrayindexed()
AddressOf(array.scoped_identifier().toAst(), array.arrayindex().toAst(), msb, toPosition()) AddressOf(array.scoped_identifier().toAst(), array.arrayindex().toAst(), null, msb, toPosition())
} }
} }

View File

@@ -51,7 +51,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.arrayIndex==arrayIndex) (other is AddressOf && other.identifier?.nameInSource == identifier?.nameInSource && other.arrayIndex==arrayIndex && other.dereference==dereference)
} }
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)
@@ -415,13 +415,14 @@ class TypecastExpression(var expression: Expression, var type: DataType, val imp
} }
} }
data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayIndex?, val msb: Boolean, override val position: Position) : Expression() { data class AddressOf(var identifier: IdentifierReference?, var arrayIndex: ArrayIndex?, var dereference: PtrDereference?, val msb: Boolean, 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.linkParents(this) identifier?.linkParents(this)
arrayIndex?.linkParents(this) arrayIndex?.linkParents(this)
dereference?.linkParents(this)
} }
override val isSimple = true override val isSimple = true
@@ -432,8 +433,11 @@ data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayI
if(replacement is IdentifierReference) { if(replacement is IdentifierReference) {
identifier = replacement identifier = replacement
arrayIndex = null arrayIndex = null
dereference = null
} else { } else {
TODO("replacement with $replacement") dereference = replacement as PtrDereference
identifier = null
arrayIndex = null
} }
} }
node===arrayIndex -> { node===arrayIndex -> {
@@ -447,11 +451,11 @@ data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayI
replacement.parent = this replacement.parent = this
} }
override fun copy() = AddressOf(identifier.copy(), arrayIndex?.copy(), msb, position) override fun copy() = AddressOf(identifier?.copy(), arrayIndex?.copy(), dereference?.copy(), msb, position)
override fun constValue(program: Program): NumericLiteral? { override fun constValue(program: Program): NumericLiteral? {
if(msb) if(msb)
return null return null
val target = this.identifier.targetStatement(program) val target = this.identifier?.targetStatement(program)
val targetVar = target as? VarDecl val targetVar = target as? VarDecl
if(targetVar!=null) { if(targetVar!=null) {
if (targetVar.type == VarDeclType.MEMORY || targetVar.type == VarDeclType.CONST) { if (targetVar.type == VarDeclType.MEMORY || targetVar.type == VarDeclType.CONST) {
@@ -482,7 +486,7 @@ data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayI
} }
return null return null
} }
override fun referencesIdentifier(nameInSource: List<String>) = identifier.nameInSource==nameInSource || arrayIndex?.referencesIdentifier(nameInSource)==true override fun referencesIdentifier(nameInSource: List<String>) = identifier?.nameInSource==nameInSource || arrayIndex?.referencesIdentifier(nameInSource)==true || dereference?.referencesIdentifier(nameInSource)==true
override fun inferType(program: Program) = InferredTypes.knownFor(BaseDataType.UWORD) override fun inferType(program: Program) = InferredTypes.knownFor(BaseDataType.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

@@ -269,7 +269,7 @@ class VarDecl(val type: VarDeclType,
// parameter variable memory mapped to a R0-R15 virtual register // parameter variable memory mapped to a R0-R15 virtual register
val regname = param.registerOrPair.asScopedNameVirtualReg(param.type) val regname = param.registerOrPair.asScopedNameVirtualReg(param.type)
decltype = VarDeclType.MEMORY decltype = VarDeclType.MEMORY
value = AddressOf(IdentifierReference(regname, param.position), null, false, param.position) value = AddressOf(IdentifierReference(regname, param.position), null, null, false, param.position)
} }
val dt = if(param.type.isArray) DataType.UWORD else param.type val dt = if(param.type.isArray) DataType.UWORD else param.type
return VarDecl(decltype, VarDeclOrigin.SUBROUTINEPARAM, dt, param.zp, SplitWish.DONTCARE, null, param.name, emptyList(), value, return VarDecl(decltype, VarDeclOrigin.SUBROUTINEPARAM, dt, param.zp, SplitWish.DONTCARE, null, param.name, emptyList(), value,
@@ -667,9 +667,10 @@ data class AssignTarget(
multi != null -> false multi != null -> false
pointerDereference !=null -> { pointerDereference !=null -> {
if(value is PtrDereference) { if(value is PtrDereference) {
if(pointerDereference!!.identifier!=value.identifier || pointerDereference!!.field!=value.field) return if(pointerDereference!!.identifier!=value.identifier || pointerDereference!!.field!=value.field)
return false false
TODO("compare ptrderef chains") else
pointerDereference!!.chain == value.chain
} }
return false return false
} }

View File

@@ -481,8 +481,9 @@ 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) addressOf.arrayIndex?.accept(this)
addressOf.dereference?.accept(this, addressOf)
track(after(addressOf, parent), addressOf, parent) track(after(addressOf, parent), addressOf, parent)
} }

View File

@@ -185,8 +185,9 @@ interface IAstVisitor {
} }
fun visit(addressOf: AddressOf) { fun visit(addressOf: AddressOf) {
addressOf.identifier.accept(this) addressOf.identifier?.accept(this)
addressOf.arrayIndex?.accept(this) addressOf.arrayIndex?.accept(this)
addressOf.dereference?.accept(this)
} }
fun visit(inlineAssembly: InlineAssembly) { fun visit(inlineAssembly: InlineAssembly) {

View File

@@ -101,7 +101,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
} }
override fun visit(addressOf: AddressOf) { override fun visit(addressOf: AddressOf) {
addressOf.identifier.targetSubroutine()?.let { notCalledButReferenced.add(it) } addressOf.identifier?.targetSubroutine()?.let { notCalledButReferenced.add(it) }
super.visit(addressOf) super.visit(addressOf)
} }

View File

@@ -7,13 +7,13 @@ STRUCTS and TYPED POINTERS
'DONE' means working in the 'virtual' compiler target... (no 6502 codegen has been touched yet) 'DONE' means working in the 'virtual' compiler target... (no 6502 codegen has been touched yet)
- DONE: add ast type check for assignments to struct fields; node_ptr.nextnode = enemy_ptr should error - DONE: add ast type check for assignments to struct fields; node_ptr.nextnode = enemy_ptr should error
- ubyte_ptr^^ ++ doesn't get changed to an inplace-assign whereas x++ does
- add IR LOADPIX/STOREPIX instructions for efficient field access through a pointer var? - add IR LOADPIX/STOREPIX instructions for efficient field access through a pointer var?
- change IR instruction LOADI should allow reg1 and reg2 to be the same, so we can remove the extra 'newPointerReg'.
- DONE: declare struct as a separate entity so you can then declare multiple variables (pointers) of the same struct type. Like usual. - DONE: declare struct as a separate entity so you can then declare multiple variables (pointers) of the same struct type. Like usual.
- struct is a 'packed' struct, fields are placed in order of declaration. This guarantees exact size and place of the fields - DONE: struct is a 'packed' struct, fields are placed in order of declaration. This guarantees exact size and place of the fields
- structs only supported as a reference type (uword pointer). This removes a lot of the problems related to introducing a variable length value type. - DONE: structs only supported as a reference type (uword pointer). This removes a lot of the problems related to introducing a variable length value type.
- need to introduce typed pointer datatype in prog8 to allow this to make any sense. + correct code gen - DONE: need to introduce typed pointer datatype in prog8 to allow this to make any sense. + correct code gen
- initially only a pointer-to-struct should actually work, pointer-to-other-type is possible but that can come later. - DONE: initially only a pointer-to-struct should actually work, pointer-to-other-type is possible but that can come later.
- DONE: a struct can contain only numeric type fields (byte,word,float) - no nested structs, no reference types (strings, arrays) inside structs. - DONE: a struct can contain only numeric type fields (byte,word,float) - no nested structs, no reference types (strings, arrays) inside structs.
- DONE: struct might also contain typed pointer fields (because a pointer is just an address word) - DONE: struct might also contain typed pointer fields (because a pointer is just an address word)
- DONE: max 1 page of memory total size to allow regular register indexing - DONE: max 1 page of memory total size to allow regular register indexing
@@ -22,14 +22,16 @@ STRUCTS and TYPED POINTERS
- DONE: dereferencing a pointer to struct could look like Pascal's ptr^.field as well, but the ^ is actually redundant here; compiler already knows it's a pointer type. - DONE: dereferencing a pointer to struct could look like Pascal's ptr^.field as well, but the ^ is actually redundant here; compiler already knows it's a pointer type.
Note that actually dereferencing a pointer to a struct as an explicit operation, conflicts with the third axiom on this list (structs only as reference types) so it can only be done for basic types? Note that actually dereferencing a pointer to a struct as an explicit operation, conflicts with the third axiom on this list (structs only as reference types) so it can only be done for basic types?
So... setting struct fields can simply be ``structvar.field = 42`` and reading them ``a = structvar.field`` So... setting struct fields can simply be ``structvar.field = 42`` and reading them ``a = structvar.field``
- you should be able to get the address of an individual field: ``&structpointer.field`` - DONE: you should be able to get the address of an individual field: ``&structpointer.field``
- arrays of structs? Just an array of uword pointers to said structs. Can even be @split as the only representation form because that's the default for word arrays.
- DONE: need to teach sizeof() how to calculate struct sizes (need unit test + doc) - DONE: need to teach sizeof() how to calculate struct sizes (need unit test + doc)
- arrays of structs? Just an array of uword pointers to said structs. Can even be @split as the only representation form because that's the default for word arrays.
- static initialization of structs may be allowed only at block scope and then behaves like arrays; it won't reset to the original value when program is restarted, so beware. Syntax = TBD - static initialization of structs may be allowed only at block scope and then behaves like arrays; it won't reset to the original value when program is restarted, so beware. Syntax = TBD
- allow memory-mapped structs? Something like &Sprite sprite0 = $9000 basically behaves identically to a typed pointer, but the address is immutable as usual - allow memory-mapped structs? Something like &Sprite sprite0 = $9000 basically behaves identically to a typed pointer, but the address is immutable as usual
- existing STR and ARRAY remain unchanged (don't become typed pointers) so we can keep doing register-indexed addressing directly on them - existing STR and ARRAY remain unchanged (don't become typed pointers) so we can keep doing register-indexed addressing directly on them
- rather than str or uword parameter types for routines with a string argument, use ^str (or ^ubyte maybe? these are more or less identical..?) - rather than str or uword parameter types for routines with a string argument, use ^str (or ^ubyte maybe? these are more or less identical..?)
- same for arrays? pointer-to-array syntax = TBD - same for arrays? pointer-to-array syntax = TBD
- what about pointers to subroutines? should these be typed as well now?
- asm symbol name prefixing should work for dereferences too.
- pointer arithmetic is a pain, but need to follow C? ptr=ptr+10 adds 10*sizeof() instead of just 10. - pointer arithmetic is a pain, but need to follow C? ptr=ptr+10 adds 10*sizeof() instead of just 10.

View File

@@ -75,19 +75,20 @@ main {
node_ptr.nextnode.nextnode.nextnode.nextnode.nextnode.value = 888 node_ptr.nextnode.nextnode.nextnode.nextnode.nextnode.value = 888
cx16.r0=node_ptr.nextnode.nextnode.nextnode.nextnode.value cx16.r0=node_ptr.nextnode.nextnode.nextnode.nextnode.value
; BELOW DOESN'T WORK YET:
; address of fields ; address of fields
txt.print("address of field: ")
txt.print_uw(&enemy_ptr.alive)
txt.spc()
enemy_ptr = 8000
txt.print_uw(&enemy_ptr.alive) txt.print_uw(&enemy_ptr.alive)
txt.nl() txt.nl()
; ubyte_ptr^^ ++ ; BELOW DOESN'T WORK YET:
; pointer arithmetic ; pointer arithmetic
; ubyte_ptr^^ ++
; enemy_ptr ++ ; add 1*sizeof ; enemy_ptr ++ ; add 1*sizeof
; enemy_ptr += 10 ; add 10*sizeof ; enemy_ptr += 10 ; add 10*sizeof
; TODO how to statically allocate/initialize a struct? Difficult.. see TODO in docs ; TODO how to statically allocate/initialize a struct? Difficult.. see TODO in docs
} }
} }

View File

@@ -139,7 +139,7 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp
is PtAddressOf -> { is PtAddressOf -> {
when { when {
it.isFromArrayElement -> TODO("address-of array element $it in initial array value") it.isFromArrayElement -> TODO("address-of array element $it in initial array value")
else -> StArrayElement(null, it.identifier.name, null) else -> StArrayElement(null, it.identifier!!.name, null)
} }
} }
is PtNumber -> StArrayElement(it.number, null, null) is PtNumber -> StArrayElement(it.number, null, null)

View File

@@ -27,7 +27,17 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
return false return false
if (other.type!==type) if (other.type!==type)
return false return false
if(!(other.identifier isSameAs identifier)) if(other.identifier==null && identifier!=null)
return false
if(other.identifier!=null && identifier==null)
return false
if(other.identifier!=null && identifier!=null && !(other.identifier!! isSameAs identifier!!))
return false
if(other.dereference==null && identifier!=dereference)
return false
if(other.dereference!=null && identifier==dereference)
return false
if(other.dereference!=null && dereference!=null && !(other.dereference!! isSameAs dereference!!))
return false return false
if(other.children.size!=children.size) if(other.children.size!=children.size)
return false return false
@@ -141,8 +151,10 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
} }
class PtAddressOf(position: Position, val isMsbForSplitArray: Boolean=false) : PtExpression(DataType.UWORD, position) { class PtAddressOf(position: Position, val isMsbForSplitArray: Boolean=false) : PtExpression(DataType.UWORD, position) {
val identifier: PtIdentifier val identifier: PtIdentifier?
get() = children[0] as PtIdentifier get() = children[0] as? PtIdentifier
val dereference: PtPointerDeref?
get() = children[0] as? PtPointerDeref
val arrayIndexExpr: PtExpression? val arrayIndexExpr: PtExpression?
get() = if(children.size==2) children[1] as PtExpression else null get() = if(children.size==2) children[1] as PtExpression else null

View File

@@ -32,7 +32,12 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni
is PtBool -> it.toString() is PtBool -> it.toString()
is PtNumber -> it.number.toString() is PtNumber -> it.number.toString()
is PtIdentifier -> it.name is PtIdentifier -> it.name
is PtAddressOf -> "& ${it.identifier.name}" is PtAddressOf -> {
if(it.identifier!=null)
"& ${it.identifier!!.name}"
else
"& ${txt(it.dereference!!)}"
}
else -> "invalid array element $it" else -> "invalid array element $it"
} }
} }