From b920d553a029318aab84799b0d25db35ca2560da Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 26 Apr 2025 17:35:04 +0200 Subject: [PATCH] make address-of dereference work --- .../src/prog8/codegen/cpu6502/AsmGen.kt | 18 ++++++--- .../src/prog8/codegen/cpu6502/IfElseAsmGen.kt | 16 ++++---- .../cpu6502/assignment/AssignmentAsmGen.kt | 32 ++++++++++------ .../codegen/intermediate/AssignmentGen.kt | 38 +++++++++---------- .../codegen/intermediate/ExpressionGen.kt | 32 ++++++++++------ .../optimizer/ConstantFoldingOptimizer.kt | 4 +- .../src/prog8/optimizer/StatementOptimizer.kt | 9 ++++- .../compiler/astprocessing/AstChecker.kt | 10 ++++- .../astprocessing/BeforeAsmTypecastCleaner.kt | 2 +- .../compiler/astprocessing/CodeDesugarer.kt | 8 ++-- .../astprocessing/SimplifiedAstMaker.kt | 5 ++- .../compiler/astprocessing/TypecastsAdder.kt | 6 +-- .../test/TestCompilerOnImportsAndIncludes.kt | 2 +- compiler/test/ast/TestConst.kt | 2 +- compiler/test/ast/TestIdentifierRef.kt | 2 +- .../test/codegeneration/TestAsmGenSymbols.kt | 28 +++++++------- .../src/prog8/ast/AstToSourceTextConverter.kt | 3 +- .../src/prog8/ast/antlr/Antlr2Kotlin.kt | 4 +- .../prog8/ast/expressions/AstExpressions.kt | 18 +++++---- .../src/prog8/ast/statements/AstStatements.kt | 9 +++-- compilerAst/src/prog8/ast/walk/AstWalker.kt | 3 +- compilerAst/src/prog8/ast/walk/IAstVisitor.kt | 3 +- compilerAst/src/prog8/compiler/CallGraph.kt | 2 +- docs/source/todo.rst | 16 ++++---- examples/test.p8 | 11 +++--- simpleAst/src/prog8/code/SymbolTableMaker.kt | 2 +- .../src/prog8/code/ast/AstExpressions.kt | 18 +++++++-- simpleAst/src/prog8/code/ast/AstPrinter.kt | 7 +++- 28 files changed, 188 insertions(+), 122 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index d3dfccd11..237dbc919 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -177,7 +177,7 @@ private fun PtVariable.prefix(parent: PtNode, st: SymbolTable): PtVariable { newValue.add(elt) else { 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) newAddr.children.add(elt.arrayIndexExpr!!) newAddr.parent = arrayValue @@ -1299,8 +1299,10 @@ $repeatLabel""") if(addrOf!=null && constOffset!=null) { if(addrOf.isFromArrayElement) { TODO("address-of array element $addrOf") + } else if(addrOf.dereference!=null) { + throw AssemblyError("write &dereference, makes no sense at ${addrOf.position}") } else { - out(" sta ${asmSymbolName(addrOf.identifier)}+${constOffset}") + out(" sta ${asmSymbolName(addrOf.identifier!!)}+${constOffset}") return true } } @@ -1339,8 +1341,10 @@ $repeatLabel""") if(addrOf!=null && constOffset!=null) { if(addrOf.isFromArrayElement) { TODO("address-of array element $addrOf") + } else if(addrOf.dereference!=null) { + TODO("read &dereference") } else { - out(" lda ${asmSymbolName(addrOf.identifier)}+${constOffset}") + out(" lda ${asmSymbolName(addrOf.identifier!!)}+${constOffset}") return true } } @@ -1389,8 +1393,10 @@ $repeatLabel""") if(addrOf!=null && constOffset!=null) { if(addrOf.isFromArrayElement) { TODO("address-of array element $addrOf") + } else if(addrOf.dereference!=null) { + throw AssemblyError("write &dereference, makes no sense at ${addrOf.position}") } else { - out(" sta ${asmSymbolName(addrOf.identifier)}-${constOffset}") + out(" sta ${asmSymbolName(addrOf.identifier!!)}-${constOffset}") return true } } @@ -1420,8 +1426,10 @@ $repeatLabel""") if(addrOf!=null && constOffset!=null) { if(addrOf.isFromArrayElement) { TODO("address-of array element $addrOf") + } else if(addrOf.dereference!=null) { + TODO("read &dereference") } else { - out(" lda ${asmSymbolName(addrOf.identifier)}-${constOffset}") + out(" lda ${asmSymbolName(addrOf.identifier!!)}-${constOffset}") return true } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt index 81895e44a..2ef0510b9 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt @@ -799,8 +799,8 @@ _jump jmp (${target.asmLabel}) asmgen.assignExpressionToRegister(value, RegisterOrPair.AY, true) asmgen.out(" cpy #0") } else { - var varname = asmgen.asmVariableName(value.identifier) - if(value.identifier.type.isSplitWordArray) { + var varname = asmgen.asmVariableName(value.identifier!!) + if(value.identifier!!.type.isSplitWordArray) { varname += if(value.isMsbForSplitArray) "_msb" else "_lsb" } asmgen.out(" lda #>$varname") @@ -1598,10 +1598,10 @@ _jump jmp (${target.asmLabel}) if(left.isFromArrayElement) { fallbackTranslateForSimpleCondition(stmt) } else { - val varname = if(left.identifier.type.isSplitWordArray) { - if(left.isMsbForSplitArray) left.identifier.name+"_msb" else left.identifier.name+"_lsb" + val varname = if(left.identifier!!.type.isSplitWordArray) { + if(left.isMsbForSplitArray) left.identifier!!.name+"_msb" else left.identifier!!.name+"_lsb" } else { - left.identifier.name + left.identifier!!.name } asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed) translateAYNotEquals("#<$varname", "#>$varname") @@ -1650,10 +1650,10 @@ _jump jmp (${target.asmLabel}) if(left.isFromArrayElement) { fallbackTranslateForSimpleCondition(stmt) } else { - val varname = if(left.identifier.type.isSplitWordArray) { - if(left.isMsbForSplitArray) left.identifier.name+"_msb" else left.identifier.name+"_lsb" + val varname = if(left.identifier!!.type.isSplitWordArray) { + if(left.isMsbForSplitArray) left.identifier!!.name+"_msb" else left.identifier!!.name+"_lsb" } else { - left.identifier.name + left.identifier!!.name } asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed) translateAYEquals("#<$varname", "#>$varname") diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 00f82e15d..8b5927268 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -438,15 +438,19 @@ internal class AssignmentAsmGen( private fun assignExpression(assign: AsmAssignment, scope: IPtSubroutine?) { when(val value = assign.source.expression!!) { is PtAddressOf -> { - val arrayDt = value.identifier.type - val sourceName = - if (value.isMsbForSplitArray) - asmgen.asmSymbolName(value.identifier) + "_msb" - else if (arrayDt.isSplitWordArray) - asmgen.asmSymbolName(value.identifier) + "_lsb" // the _lsb split array comes first in memory - else - asmgen.asmSymbolName(value.identifier) - assignAddressOf(assign.target, sourceName, value.isMsbForSplitArray, arrayDt, value.arrayIndexExpr) + if(value.identifier!=null) { + val arrayDt = value.identifier!!.type + val sourceName = + if (value.isMsbForSplitArray) + asmgen.asmSymbolName(value.identifier!!) + "_msb" + else if (arrayDt.isSplitWordArray) + asmgen.asmSymbolName(value.identifier!!) + "_lsb" // the _lsb split array comes first in memory + else + 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 PtNumber -> throw AssemblyError("source kind should have been literalnumber") @@ -1384,9 +1388,11 @@ internal class AssignmentAsmGen( is PtAddressOf -> { if(right.isFromArrayElement) { TODO("address-of array element at ${right.position}") + } else if(right.dereference!=null) { + TODO("read &dereference") } else { - var symbol = asmgen.asmVariableName(right.identifier) - if(right.identifier.type.isSplitWordArray) { + var symbol = asmgen.asmVariableName(right.identifier!!) + if(right.identifier!!.type.isSplitWordArray) { symbol = if(right.isMsbForSplitArray) symbol+"_msb" else symbol+"_lsb" } assignExpressionToRegister(left, RegisterOrPair.AY, dt.isSigned) @@ -4019,8 +4025,10 @@ $endLabel""") addressOf != null -> { if(addressOf.isFromArrayElement) { TODO("address-of array element $addressOf") + } else if(addressOf.dereference!=null) { + throw AssemblyError("write &dereference, makes no sense at ${addressOf.position}") } else { - asmgen.out(" sta ${asmgen.asmSymbolName(addressOf.identifier)}") + asmgen.out(" sta ${asmgen.asmSymbolName(addressOf.identifier!!)}") } } addressExpr is PtIdentifier -> { diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt index 7379e5dcb..ece2f4e3b 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt @@ -511,7 +511,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express else if(targetPointerDeref!=null) { val pointerTr = expressionEval.translateExpression(targetPointerDeref.start) result += pointerTr.chunks - result += expressionEval.traverseDerefChain(targetPointerDeref, pointerTr.resultReg) + result += expressionEval.traverseDerefChainToCalculateFinalAddress(targetPointerDeref, pointerTr.resultReg) val instr = when { targetPointerDeref.type.isByteOrBool -> { @@ -977,37 +977,33 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express val result = mutableListOf() if(vmDt==IRDataType.FLOAT) { if((operand as? PtNumber)?.number==1.0) { - addInstr(result, if(constAddress!=null) - IRInstruction(Opcode.INCM, vmDt, address = constAddress) - else - IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol) - , null) + addInstr(result, if (constAddress != null) + IRInstruction(Opcode.INCM, vmDt, address = constAddress) + else + IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol) , null) } else { val tr = expressionEval.translateExpression(operand) addToResult(result, tr, -1, tr.resultFpReg) - addInstr(result, if(constAddress!=null) - IRInstruction(Opcode.ADDM, vmDt, fpReg1=tr.resultFpReg, address = constAddress) - else - IRInstruction(Opcode.ADDM, vmDt, fpReg1=tr.resultFpReg, labelSymbol = symbol) - , null) + addInstr(result, if (constAddress != null) + IRInstruction(Opcode.ADDM, vmDt, fpReg1 = tr.resultFpReg, address = constAddress) + else + IRInstruction(Opcode.ADDM, vmDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol) , null) } } else { if((operand as? PtNumber)?.number==1.0) { - addInstr(result, if(constAddress!=null) - IRInstruction(Opcode.INCM, vmDt, address = constAddress) - else - IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol) - , null) + addInstr(result, if (constAddress != null) + IRInstruction(Opcode.INCM, vmDt, address = constAddress) + else + IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol) , null) } else { val tr = expressionEval.translateExpression(operand) addToResult(result, tr, tr.resultReg, -1) - addInstr(result, if(constAddress!=null) - IRInstruction(Opcode.ADDM, vmDt, reg1=tr.resultReg, address = constAddress) - else - IRInstruction(Opcode.ADDM, vmDt, reg1=tr.resultReg, labelSymbol = symbol) - , null) + addInstr(result, if (constAddress != null) + IRInstruction(Opcode.ADDM, vmDt, reg1 = tr.resultReg, address = constAddress) + else + IRInstruction(Opcode.ADDM, vmDt, reg1 = tr.resultReg, labelSymbol = symbol) , null) } } return result diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index 7649c260c..a7de6b26e 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -101,7 +101,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { val result = mutableListOf() val tr = translateExpression(deref.start) result += tr.chunks - result += traverseDerefChain(deref, tr.resultReg) + result += traverseDerefChainToCalculateFinalAddress(deref, tr.resultReg) when { deref.type.isByteOrBool -> { val resultReg = codeGen.registers.next(IRDataType.BYTE) @@ -199,8 +199,8 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { fun loadAddressOfArrayLabel(reg: Int) { if (expr.isMsbForSplitArray) { - addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = reg, labelSymbol = identifier.name + "_msb"), null) - } else if (identifier.type.isSplitWordArray) { + addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = reg, labelSymbol = identifier!!.name + "_msb"), null) + } else if (identifier!!.type.isSplitWordArray) { // the _lsb split array comes first in memory addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = reg, labelSymbol = identifier.name + "_lsb"), null) } else @@ -213,25 +213,35 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { val indexTr = translateExpression(expr.arrayIndexExpr!!) addToResult(result, indexTr, indexTr.resultReg, -1) val indexWordReg = codeGen.registers.next(IRDataType.WORD) - addInstr(result, IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=indexWordReg, reg2=indexTr.resultReg), null) - if(identifier.type.isUnsignedWord) { + addInstr( + result, + IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1 = indexWordReg, reg2 = indexTr.resultReg), + null + ) + if (identifier!!.type.isUnsignedWord) { require(!expr.isMsbForSplitArray) result += IRCodeChunk(null, null).also { 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 { val eltSize = codeGen.program.memsizer.memorySize(identifier.type, 1) result += IRCodeChunk(null, null).also { loadAddressOfArrayLabel(resultRegister) - if(eltSize>1 && !identifier.type.isSplitWordArray) { - it += IRInstruction(Opcode.MUL, IRDataType.WORD, reg1=indexWordReg, immediate = eltSize) + if (eltSize > 1 && !identifier.type.isSplitWordArray) { + 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) + } 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) } @@ -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() var struct: StStruct? = null if(targetPointerDeref.start.type.subIdentifier!=null) diff --git a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt index 9023aa73d..e4f65391f 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt @@ -27,8 +27,8 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors: // @( &thing ) --> thing (but only if thing is a byte type!) val addrOf = memread.addressExpression as? AddressOf if(addrOf!=null) { - if(addrOf.identifier.inferType(program).isBytes) - return listOf(IAstModification.ReplaceNode(memread, addrOf.identifier, parent)) + if(addrOf.identifier?.inferType(program)?.isBytes==true) + return listOf(IAstModification.ReplaceNode(memread, addrOf.identifier!!, parent)) } return noModifications } diff --git a/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt b/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt index 73e5257e7..f58b1cd47 100644 --- a/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt @@ -29,7 +29,14 @@ class StatementOptimizer(private val program: Program, if(functionCallStatement.target.nameInSource==listOf("txt", "print")) { val arg = functionCallStatement.args.single() val stringVar: IdentifierReference? = if(arg is AddressOf) { - 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 { arg as? IdentifierReference } diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 90d92cd93..6ccdfdfbb 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -713,7 +713,7 @@ internal class AstChecker(private val program: Program, override fun visit(addressOf: AddressOf) { checkLongType(addressOf) - val variable=addressOf.identifier.targetVarDecl() + val variable=addressOf.identifier?.targetVarDecl() if (variable!=null) { if (variable.type == VarDeclType.CONST && addressOf.arrayIndex == null) 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 { when (it) { 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 TypecastExpression if it.type.isBasic -> { val constVal = it.expression.constValue(program) diff --git a/compiler/src/prog8/compiler/astprocessing/BeforeAsmTypecastCleaner.kt b/compiler/src/prog8/compiler/astprocessing/BeforeAsmTypecastCleaner.kt index d95677440..e9c33cc50 100644 --- a/compiler/src/prog8/compiler/astprocessing/BeforeAsmTypecastCleaner.kt +++ b/compiler/src/prog8/compiler/astprocessing/BeforeAsmTypecastCleaner.kt @@ -47,7 +47,7 @@ internal class BeforeAsmTypecastCleaner(val program: Program, listOf( IAstModification.ReplaceNode( typecast, - AddressOf(identifier, null, false, typecast.position), + AddressOf(identifier, null, null, false, typecast.position), parent ) ) diff --git a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt index 81ef0e4e1..0d1f9c10d 100644 --- a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt +++ b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt @@ -282,8 +282,8 @@ _after: val addrOf = memread.addressExpression as? AddressOf if(addrOf?.arrayIndex!=null) return noModifications - if(addrOf!=null && addrOf.identifier.inferType(program).isWords) { - val lsb = FunctionCallExpression(IdentifierReference(listOf("lsb"), memread.position), mutableListOf(addrOf.identifier), memread.position) + if(addrOf!=null && addrOf.identifier?.inferType(program)?.isWords==true) { + val lsb = FunctionCallExpression(IdentifierReference(listOf("lsb"), memread.position), mutableListOf(addrOf.identifier!!), memread.position) return listOf(IAstModification.ReplaceNode(memread, lsb, parent)) } val expr = memread.addressExpression as? BinaryExpression @@ -291,10 +291,10 @@ _after: val addressOf = expr.left as? AddressOf val offset = (expr.right as? NumericLiteral)?.number?.toInt() if(addressOf!=null && offset==1) { - val variable = addressOf.identifier.targetVarDecl() + val variable = addressOf.identifier?.targetVarDecl() if(variable!=null && variable.datatype.isWord) { val msb = FunctionCallExpression(IdentifierReference(listOf("msb"), memread.position), mutableListOf( - addressOf.identifier + addressOf.identifier!! ), memread.position) return listOf(IAstModification.ReplaceNode(memread, msb, parent)) } diff --git a/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt b/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt index 3acb811f3..b8139dfac 100644 --- a/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt +++ b/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt @@ -652,9 +652,12 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro private fun transform(src: AddressOf): PtAddressOf { 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) addr.add(transformExpression(src.arrayIndex!!.indexExpr)) + if (src.dereference!=null) + addr.add(transformExpression(src.dereference!!)) return addr } diff --git a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt index d3d0d9135..2e6297b30 100644 --- a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt +++ b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt @@ -267,7 +267,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val if(!argDt.isString) { modifications += IAstModification.ReplaceNode( identifier, - AddressOf(identifier, null, false, it.second.position), + AddressOf(identifier, null, null, false, it.second.position), call as Node ) } @@ -285,7 +285,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val // take the address of the identifier modifications += IAstModification.ReplaceNode( identifier, - AddressOf(identifier, null, false, it.second.position), + AddressOf(identifier, null, null, false, it.second.position), call as Node ) } @@ -410,7 +410,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val val eltType = elt.inferType(program) val tgt = elt.targetStatement(program) 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) array.value[index] = addressof } diff --git a/compiler/test/TestCompilerOnImportsAndIncludes.kt b/compiler/test/TestCompilerOnImportsAndIncludes.kt index ca29afb4a..22a8f88c1 100644 --- a/compiler/test/TestCompilerOnImportsAndIncludes.kt +++ b/compiler/test/TestCompilerOnImportsAndIncludes.kt @@ -61,7 +61,7 @@ class TestCompilerOnImportsAndIncludes: FunSpec({ str0.value shouldBe "main.bar" 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 lbl1.name shouldBe "foo_bar" lbl1.definingScope.name shouldBe "main" diff --git a/compiler/test/ast/TestConst.kt b/compiler/test/ast/TestConst.kt index b94c55d40..ceabe1796 100644 --- a/compiler/test/ast/TestConst.kt +++ b/compiler/test/ast/TestConst.kt @@ -325,7 +325,7 @@ main { val assignAddr = (st[2] as Assignment).value (assignAddr as NumericLiteral).number shouldBe 8194.0 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() } diff --git a/compiler/test/ast/TestIdentifierRef.kt b/compiler/test/ast/TestIdentifierRef.kt index e5a4cf4b6..cfc8a8c45 100644 --- a/compiler/test/ast/TestIdentifierRef.kt +++ b/compiler/test/ast/TestIdentifierRef.kt @@ -60,7 +60,7 @@ class TestIdentifierRef: FunSpec({ val mstmts = (module.statements.single() as Block).statements val stmts = mstmts.filterIsInstance().single().statements 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.wasStringLiteral() shouldBe false wwref.targetStatement(program) shouldBe instanceOf() diff --git a/compiler/test/codegeneration/TestAsmGenSymbols.kt b/compiler/test/codegeneration/TestAsmGenSymbols.kt index 8c4ac1243..07543687f 100644 --- a/compiler/test/codegeneration/TestAsmGenSymbols.kt +++ b/compiler/test/codegeneration/TestAsmGenSymbols.kt @@ -65,13 +65,13 @@ class TestAsmGenSymbols: StringSpec({ position = 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 assign3 = Assignment(tgt, AddressOf(IdentifierReference(listOf("var_outside"), Position.DUMMY), 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 assign5 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","start","localvar"), Position.DUMMY), 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 assign7 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","var_outside"), Position.DUMMY), 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 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, 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, 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, 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 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().first { it.value is PtIdentifier }.value as PtIdentifier asmgen.asmSymbolName(localvarIdent) shouldBe "localvar" asmgen.asmVariableName(localvarIdent) shouldBe "localvar" - val localvarIdentScoped = (sub.children.asSequence().filterIsInstance().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.localvar" }.value as PtAddressOf).identifier + val localvarIdentScoped = (sub.children.asSequence().filterIsInstance().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.localvar" }.value as PtAddressOf).identifier!! asmgen.asmSymbolName(localvarIdentScoped) shouldBe "localvar" asmgen.asmVariableName(localvarIdentScoped) shouldBe "localvar" - val scopedVarIdent = (sub.children.asSequence().filterIsInstance().first { (it.value as? PtAddressOf)?.identifier?.name=="main.var_outside" }.value as PtAddressOf).identifier + val scopedVarIdent = (sub.children.asSequence().filterIsInstance().first { (it.value as? PtAddressOf)?.identifier?.name=="main.var_outside" }.value as PtAddressOf).identifier!! asmgen.asmSymbolName(scopedVarIdent) shouldBe "main.var_outside" asmgen.asmVariableName(scopedVarIdent) shouldBe "main.var_outside" - val scopedVarIdentScoped = (sub.children.asSequence().filterIsInstance().first { (it.value as? PtAddressOf)?.identifier?.name=="main.var_outside" }.value as PtAddressOf).identifier + val scopedVarIdentScoped = (sub.children.asSequence().filterIsInstance().first { (it.value as? PtAddressOf)?.identifier?.name=="main.var_outside" }.value as PtAddressOf).identifier!! asmgen.asmSymbolName(scopedVarIdentScoped) shouldBe "main.var_outside" asmgen.asmVariableName(scopedVarIdentScoped) shouldBe "main.var_outside" } @@ -134,17 +134,17 @@ class TestAsmGenSymbols: StringSpec({ val asmgen = createTestAsmGen6502(program) val sub = asmgen.program.entrypoint()!! - val localLabelIdent = (sub.children.asSequence().filterIsInstance().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.locallabel" }.value as PtAddressOf).identifier + val localLabelIdent = (sub.children.asSequence().filterIsInstance().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.locallabel" }.value as PtAddressOf).identifier!! asmgen.asmSymbolName(localLabelIdent) shouldBe "locallabel" asmgen.asmVariableName(localLabelIdent) shouldBe "locallabel" - val localLabelIdentScoped = (sub.children.asSequence().filterIsInstance().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.locallabel" }.value as PtAddressOf).identifier + val localLabelIdentScoped = (sub.children.asSequence().filterIsInstance().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.locallabel" }.value as PtAddressOf).identifier!! asmgen.asmSymbolName(localLabelIdentScoped) shouldBe "locallabel" asmgen.asmVariableName(localLabelIdentScoped) shouldBe "locallabel" - val scopedLabelIdent = (sub.children.asSequence().filterIsInstance().first { (it.value as? PtAddressOf)?.identifier?.name=="main.label_outside" }.value as PtAddressOf).identifier + val scopedLabelIdent = (sub.children.asSequence().filterIsInstance().first { (it.value as? PtAddressOf)?.identifier?.name=="main.label_outside" }.value as PtAddressOf).identifier!! asmgen.asmSymbolName(scopedLabelIdent) shouldBe "main.label_outside" asmgen.asmVariableName(scopedLabelIdent) shouldBe "main.label_outside" - val scopedLabelIdentScoped = (sub.children.asSequence().filterIsInstance().first { (it.value as? PtAddressOf)?.identifier?.name=="main.label_outside" }.value as PtAddressOf).identifier + val scopedLabelIdentScoped = (sub.children.asSequence().filterIsInstance().first { (it.value as? PtAddressOf)?.identifier?.name=="main.label_outside" }.value as PtAddressOf).identifier!! asmgen.asmSymbolName(scopedLabelIdentScoped) shouldBe "main.label_outside" asmgen.asmVariableName(scopedLabelIdentScoped) shouldBe "main.label_outside" } diff --git a/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt b/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt index bec361e25..7f5327256 100644 --- a/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt +++ b/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt @@ -482,12 +482,13 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program: output("&") if(addressOf.msb) output(">") - addressOf.identifier.accept(this) + addressOf.identifier?.accept(this) if (addressOf.arrayIndex != null) { output("[") addressOf.arrayIndex?.accept(this) output("]") } + addressOf.dereference?.accept(this) } override fun visit(inlineAssembly: InlineAssembly) { diff --git a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt index 683172b54..cdb0c443c 100644 --- a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt +++ b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt @@ -632,10 +632,10 @@ private fun ExpressionContext.toAst(insideParentheses: Boolean=false) : Expressi val msb = addressOf.ADDRESS_OF_MSB()!=null // note: &< (ADDRESS_OF_LSB) is equivalent to a regular &. return if (identifier != null) - AddressOf(addressof().scoped_identifier().toAst(),null, msb, toPosition()) + AddressOf(addressof().scoped_identifier().toAst(),null, null, msb, toPosition()) else { 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()) } } diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index 1adb0f81b..d62fa1da5 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -51,7 +51,7 @@ sealed class Expression: Node { (other is TypecastExpression && other.implicit==implicit && other.type==type && other.expression isSameAs expression) } is AddressOf -> { - (other is AddressOf && other.identifier.nameInSource == identifier.nameInSource && other.arrayIndex==arrayIndex) + (other is AddressOf && other.identifier?.nameInSource == identifier?.nameInSource && other.arrayIndex==arrayIndex && other.dereference==dereference) } is RangeExpression -> { (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 fun linkParents(parent: Node) { this.parent = parent - identifier.linkParents(this) + identifier?.linkParents(this) arrayIndex?.linkParents(this) + dereference?.linkParents(this) } override val isSimple = true @@ -432,8 +433,11 @@ data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayI if(replacement is IdentifierReference) { identifier = replacement arrayIndex = null + dereference = null } else { - TODO("replacement with $replacement") + dereference = replacement as PtrDereference + identifier = null + arrayIndex = null } } node===arrayIndex -> { @@ -447,11 +451,11 @@ data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayI 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? { if(msb) return null - val target = this.identifier.targetStatement(program) + val target = this.identifier?.targetStatement(program) val targetVar = target as? VarDecl if(targetVar!=null) { if (targetVar.type == VarDeclType.MEMORY || targetVar.type == VarDeclType.CONST) { @@ -482,7 +486,7 @@ data class AddressOf(var identifier: IdentifierReference, var arrayIndex: ArrayI } return null } - override fun referencesIdentifier(nameInSource: List) = identifier.nameInSource==nameInSource || arrayIndex?.referencesIdentifier(nameInSource)==true + override fun referencesIdentifier(nameInSource: List) = identifier?.nameInSource==nameInSource || arrayIndex?.referencesIdentifier(nameInSource)==true || dereference?.referencesIdentifier(nameInSource)==true override fun inferType(program: Program) = InferredTypes.knownFor(BaseDataType.UWORD) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index 877a21a62..060e23e11 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -269,7 +269,7 @@ class VarDecl(val type: VarDeclType, // parameter variable memory mapped to a R0-R15 virtual register val regname = param.registerOrPair.asScopedNameVirtualReg(param.type) 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 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 pointerDereference !=null -> { if(value is PtrDereference) { - if(pointerDereference!!.identifier!=value.identifier || pointerDereference!!.field!=value.field) - return false - TODO("compare ptrderef chains") + return if(pointerDereference!!.identifier!=value.identifier || pointerDereference!!.field!=value.field) + false + else + pointerDereference!!.chain == value.chain } return false } diff --git a/compilerAst/src/prog8/ast/walk/AstWalker.kt b/compilerAst/src/prog8/ast/walk/AstWalker.kt index 19ded6436..6a9931a93 100644 --- a/compilerAst/src/prog8/ast/walk/AstWalker.kt +++ b/compilerAst/src/prog8/ast/walk/AstWalker.kt @@ -481,8 +481,9 @@ abstract class AstWalker { fun visit(addressOf: AddressOf, parent: Node) { track(before(addressOf, parent), addressOf, parent) - addressOf.identifier.accept(this, addressOf) + addressOf.identifier?.accept(this, addressOf) addressOf.arrayIndex?.accept(this) + addressOf.dereference?.accept(this, addressOf) track(after(addressOf, parent), addressOf, parent) } diff --git a/compilerAst/src/prog8/ast/walk/IAstVisitor.kt b/compilerAst/src/prog8/ast/walk/IAstVisitor.kt index 76fde94c6..46fb8e0e7 100644 --- a/compilerAst/src/prog8/ast/walk/IAstVisitor.kt +++ b/compilerAst/src/prog8/ast/walk/IAstVisitor.kt @@ -185,8 +185,9 @@ interface IAstVisitor { } fun visit(addressOf: AddressOf) { - addressOf.identifier.accept(this) + addressOf.identifier?.accept(this) addressOf.arrayIndex?.accept(this) + addressOf.dereference?.accept(this) } fun visit(inlineAssembly: InlineAssembly) { diff --git a/compilerAst/src/prog8/compiler/CallGraph.kt b/compilerAst/src/prog8/compiler/CallGraph.kt index 5dab08a11..9f48fc315 100644 --- a/compilerAst/src/prog8/compiler/CallGraph.kt +++ b/compilerAst/src/prog8/compiler/CallGraph.kt @@ -101,7 +101,7 @@ class CallGraph(private val program: Program) : IAstVisitor { } override fun visit(addressOf: AddressOf) { - addressOf.identifier.targetSubroutine()?.let { notCalledButReferenced.add(it) } + addressOf.identifier?.targetSubroutine()?.let { notCalledButReferenced.add(it) } super.visit(addressOf) } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 895a8a843..2e72a875f 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -7,13 +7,13 @@ STRUCTS and TYPED POINTERS '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 -- 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? +- 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. -- 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. -- 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: struct is a 'packed' struct, fields are placed in order of declaration. This guarantees exact size and place of the fields +- 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. +- DONE: need to introduce typed pointer datatype in prog8 to allow this to make any sense. + correct code gen +- 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: 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 @@ -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. 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`` -- 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: you should be able to get the address of an individual field: ``&structpointer.field`` - 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 - 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 - 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 +- 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. diff --git a/examples/test.p8 b/examples/test.p8 index 4f316b74c..26bea8479 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -75,19 +75,20 @@ main { node_ptr.nextnode.nextnode.nextnode.nextnode.nextnode.value = 888 cx16.r0=node_ptr.nextnode.nextnode.nextnode.nextnode.value - ; BELOW DOESN'T WORK YET: ; 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.nl() -; ubyte_ptr^^ ++ - - + ; BELOW DOESN'T WORK YET: ; pointer arithmetic +; ubyte_ptr^^ ++ ; enemy_ptr ++ ; add 1*sizeof ; enemy_ptr += 10 ; add 10*sizeof - ; TODO how to statically allocate/initialize a struct? Difficult.. see TODO in docs } } diff --git a/simpleAst/src/prog8/code/SymbolTableMaker.kt b/simpleAst/src/prog8/code/SymbolTableMaker.kt index 467882c61..8b543bc19 100644 --- a/simpleAst/src/prog8/code/SymbolTableMaker.kt +++ b/simpleAst/src/prog8/code/SymbolTableMaker.kt @@ -139,7 +139,7 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp is PtAddressOf -> { when { 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) diff --git a/simpleAst/src/prog8/code/ast/AstExpressions.kt b/simpleAst/src/prog8/code/ast/AstExpressions.kt index 87a6d9e9b..4baa88bdc 100644 --- a/simpleAst/src/prog8/code/ast/AstExpressions.kt +++ b/simpleAst/src/prog8/code/ast/AstExpressions.kt @@ -27,7 +27,17 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit return false if (other.type!==type) 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 if(other.children.size!=children.size) 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) { - val identifier: PtIdentifier - get() = children[0] as PtIdentifier + val identifier: PtIdentifier? + get() = children[0] as? PtIdentifier + val dereference: PtPointerDeref? + get() = children[0] as? PtPointerDeref val arrayIndexExpr: PtExpression? get() = if(children.size==2) children[1] as PtExpression else null diff --git a/simpleAst/src/prog8/code/ast/AstPrinter.kt b/simpleAst/src/prog8/code/ast/AstPrinter.kt index 4cce4ae78..947633c71 100644 --- a/simpleAst/src/prog8/code/ast/AstPrinter.kt +++ b/simpleAst/src/prog8/code/ast/AstPrinter.kt @@ -32,7 +32,12 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni is PtBool -> it.toString() is PtNumber -> it.number.toString() 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" } }