mirror of
				https://github.com/irmen/prog8.git
				synced 2025-11-04 10:16:13 +00:00 
			
		
		
		
	make address-of dereference work
This commit is contained in:
		@@ -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
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 arrayDt = value.identifier!!.type
 | 
				
			||||||
                    val sourceName =
 | 
					                    val sourceName =
 | 
				
			||||||
                        if (value.isMsbForSplitArray)
 | 
					                        if (value.isMsbForSplitArray)
 | 
				
			||||||
                        asmgen.asmSymbolName(value.identifier) + "_msb"
 | 
					                            asmgen.asmSymbolName(value.identifier!!) + "_msb"
 | 
				
			||||||
                        else if (arrayDt.isSplitWordArray)
 | 
					                        else if (arrayDt.isSplitWordArray)
 | 
				
			||||||
                        asmgen.asmSymbolName(value.identifier) + "_lsb"  // the _lsb split array comes first in memory
 | 
					                            asmgen.asmSymbolName(value.identifier!!) + "_lsb"  // the _lsb split array comes first in memory
 | 
				
			||||||
                        else
 | 
					                        else
 | 
				
			||||||
                        asmgen.asmSymbolName(value.identifier)
 | 
					                            asmgen.asmSymbolName(value.identifier!!)
 | 
				
			||||||
                    assignAddressOf(assign.target, sourceName, value.isMsbForSplitArray, arrayDt, value.arrayIndexExpr)
 | 
					                    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 -> {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
                            )
 | 
					                            )
 | 
				
			||||||
                        )
 | 
					                        )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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))
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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>()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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>()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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())
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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"
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user