cleaning up pointer indexing

This commit is contained in:
Irmen de Jong
2025-05-25 02:56:32 +02:00
parent 51269257ea
commit aaa81210ce
26 changed files with 382 additions and 417 deletions

View File

@@ -409,7 +409,6 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
val targetMemory = assignment.target.memory val targetMemory = assignment.target.memory
val targetArray = assignment.target.array val targetArray = assignment.target.array
val targetPointerDeref = assignment.target.pointerDeref val targetPointerDeref = assignment.target.pointerDeref
val targetPointerIndexedDeref = assignment.target.pointerIndexedDeref
val valueDt = irType(assignment.value.type) val valueDt = irType(assignment.value.type)
val targetDt = irType(assignment.target.type) val targetDt = irType(assignment.target.type)
val result = mutableListOf<IRCodeChunkBase>() val result = mutableListOf<IRCodeChunkBase>()
@@ -604,9 +603,6 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
codeGen.storeValueAtPointersLocation(result, addressReg, targetPointerDeref.type, zero, actualValueReg) codeGen.storeValueAtPointersLocation(result, addressReg, targetPointerDeref.type, zero, actualValueReg)
return result return result
} }
else if(targetPointerIndexedDeref!=null) {
TODO("assign to pointer indexed $targetPointerIndexedDeref")
}
else else
throw AssemblyError("weird assigntarget") throw AssemblyError("weird assigntarget")
} }

View File

@@ -87,70 +87,12 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
is PtFunctionCall -> translate(expr) is PtFunctionCall -> translate(expr)
is PtContainmentCheck -> translate(expr) is PtContainmentCheck -> translate(expr)
is PtPointerDeref -> translate(expr) is PtPointerDeref -> translate(expr)
is PtPointerIndexedDeref -> translate(expr)
is PtRange, is PtRange,
is PtArray, is PtArray,
is PtString -> throw AssemblyError("range/arrayliteral/string should no longer occur as expression") is PtString -> throw AssemblyError("range/arrayliteral/string should no longer occur as expression")
} }
} }
private fun translate(idxderef: PtPointerIndexedDeref): ExpressionCodeResult {
if (idxderef.type.isStructInstance)
throw AssemblyError("cannot translate POINTER[x] resulting in a struct instance (only when it results in a basic type); this is likely part of a larger expression POINTER[x].field and that has to be translated earlier as a whole")
val eltSize = codeGen.program.memsizer.memorySize(idxderef.type, null)
val result = mutableListOf<IRCodeChunkBase>()
if(!idxderef.variable.type.isPointer) {
TODO("expression: indexing non-pointer field ${idxderef.variable}")
}
TODO("expression: evaluate address of pointer dereference ${idxderef.position}")
val pointerReg = -1 // pointerTr.resultReg
val constIndex = idxderef.index.asConstInteger()
if(constIndex!=null) {
val offset = constIndex * eltSize
addInstr(result, IRInstruction(Opcode.ADD, IRDataType.WORD, reg1 = pointerReg, immediate = offset), null)
} else {
val indexTr = translateExpression(idxderef.index)
result += indexTr.chunks
result += IRCodeChunk(null, null).also {
val indexReg: Int
if (idxderef.index.type.isByte) {
// extend array index to word
indexReg = codeGen.registers.next(IRDataType.WORD)
it += IRInstruction(Opcode.EXT, IRDataType.BYTE, indexReg, indexTr.resultReg)
} else {
indexReg = indexTr.resultReg
}
it += codeGen.multiplyByConst(DataType.UWORD, indexReg, eltSize)
it += IRInstruction(Opcode.ADDR, IRDataType.WORD, reg1 = pointerReg, reg2 = indexReg)
}
}
when {
idxderef.type.isByteOrBool -> {
val resultReg = codeGen.registers.next(IRDataType.BYTE)
addInstr(result, IRInstruction(Opcode.LOADI, IRDataType.BYTE, reg1 = resultReg, reg2 = pointerReg), null)
return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1)
}
idxderef.type.isWord || idxderef.type.isPointer -> {
// LOADI has an exception to allow reg1 and reg2 to be the same, so we can avoid using extra temporary registers and LOADS
addInstr(result, IRInstruction(Opcode.LOADI, IRDataType.WORD, reg1 = pointerReg, reg2 = pointerReg), null)
return ExpressionCodeResult(result, IRDataType.WORD, pointerReg, -1)
}
idxderef.type.isFloat -> {
val resultReg = codeGen.registers.next(IRDataType.FLOAT)
addInstr(result, IRInstruction(Opcode.LOADI, IRDataType.FLOAT, fpReg1 = resultReg, reg1 = pointerReg), null)
return ExpressionCodeResult(result, IRDataType.FLOAT, -1, resultReg)
}
else -> throw AssemblyError("unsupported dereference type ${idxderef.type} at ${idxderef.position}")
}
}
private fun translate(deref: PtPointerDeref): ExpressionCodeResult { private fun translate(deref: PtPointerDeref): ExpressionCodeResult {
val result = mutableListOf<IRCodeChunkBase>() val result = mutableListOf<IRCodeChunkBase>()
var actualDeref = deref var actualDeref = deref

View File

@@ -332,7 +332,8 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors:
val constIndex = arrayIndexedExpression.indexer.constIndex() val constIndex = arrayIndexedExpression.indexer.constIndex()
if (constIndex != null) { if (constIndex != null) {
val arrayVar = arrayIndexedExpression.arrayvar.targetVarDecl() if(arrayIndexedExpression.plainarrayvar!=null) {
val arrayVar = arrayIndexedExpression.plainarrayvar!!.targetVarDecl()
if(arrayVar!=null) { if(arrayVar!=null) {
val array =arrayVar.value as? ArrayLiteral val array =arrayVar.value as? ArrayLiteral
if(array!=null) { if(array!=null) {
@@ -342,6 +343,9 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors:
} }
} }
} }
} else if(arrayIndexedExpression.pointerderef!=null) {
TODO("constant fold pointer[i]")
}
} }
} }
return noModifications return noModifications

View File

@@ -424,29 +424,28 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr
} }
override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> { override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> {
if(parent is PtrIndexedDereference)
return noModifications
if(arrayIndexedExpression.indexer.constIndex()==0) { if(arrayIndexedExpression.indexer.constIndex()==0) {
val dt = arrayIndexedExpression.arrayvar.inferType(program).getOrUndef() if(arrayIndexedExpression.plainarrayvar!=null) {
val dt = arrayIndexedExpression.plainarrayvar!!.inferType(program).getOrUndef()
if(dt.isPointer) { if(dt.isPointer) {
// pointer[0] --> pointer^^ // pointer[0] --> pointer^^
if(dt.sub==null) { val deref = PtrDereference(arrayIndexedExpression.plainarrayvar!!, emptyList(), null, true, arrayIndexedExpression.plainarrayvar!!.position)
val parentExpr = parent as? BinaryExpression
if(parentExpr?.operator=="." && parentExpr.right is IdentifierReference) {
// we're part of an expression: pointer[x].ptr.ptr.field
val chain = (parentExpr.right as? IdentifierReference)?.nameInSource?.toMutableList() ?: mutableListOf()
val field = chain.removeLastOrNull()
val deref = PtrDereference(arrayIndexedExpression.arrayvar, chain, field, field==null, arrayIndexedExpression.position)
return listOf(IAstModification.ReplaceNode(parent, deref, parent.parent))
} else
throw FatalAstException("cannot dereference a 'bare' pointer to a struct, only to a basic type at ${arrayIndexedExpression.position}")
} else {
// points to a simple type, can simply dereference the pointer itself directly
val deref = PtrDereference(arrayIndexedExpression.arrayvar, emptyList(), null, true,arrayIndexedExpression.position)
return listOf(IAstModification.ReplaceNode(arrayIndexedExpression,deref, parent)) return listOf(IAstModification.ReplaceNode(arrayIndexedExpression,deref, parent))
} }
} }
val ptrDeref = arrayIndexedExpression.pointerderef
if(ptrDeref!=null) {
val dt = ptrDeref.inferType(program).getOrUndef()
if(dt.isPointer) {
if(ptrDeref.field!=null) {
// pointer[0] --> pointer^^
val deref = PtrDereference(ptrDeref.identifier, ptrDeref.chain + ptrDeref.field!!, null, true, ptrDeref.position)
return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, deref, parent))
} else {
TODO("ptr[0] rewrite")
}
}
}
} }
return noModifications return noModifications
} }

View File

@@ -88,9 +88,6 @@ internal class AstChecker(private val program: Program,
val ppExpr = identifier.parent.parent as? BinaryExpression val ppExpr = identifier.parent.parent as? BinaryExpression
if(ppExpr?.operator==".") if(ppExpr?.operator==".")
return // identifiers will be checked over at the BinaryExpression itself return // identifiers will be checked over at the BinaryExpression itself
val ppIdxExpr = identifier.parent.parent as? PtrIndexedDereference
if(ppIdxExpr!=null)
return // identifiers will be checked over at the PtrIndexedDereference itself
} }
errors.undefined(identifier.nameInSource, identifier.position) errors.undefined(identifier.nameInSource, identifier.position)
} }
@@ -770,13 +767,16 @@ internal class AstChecker(private val program: Program,
fun checkRomTarget(target: AssignTarget) { fun checkRomTarget(target: AssignTarget) {
val idx=target.arrayindexed val idx=target.arrayindexed
if(idx!=null) { if(idx!=null) {
val decl = idx.arrayvar.targetVarDecl()!! // cannot check pointer deref for rom target, assume no there.
if(idx.plainarrayvar!=null) {
val decl = idx.plainarrayvar!!.targetVarDecl()!!
if(decl.type!=VarDeclType.MEMORY && decl.zeropage!=ZeropageWish.REQUIRE_ZEROPAGE) { if(decl.type!=VarDeclType.MEMORY && decl.zeropage!=ZeropageWish.REQUIRE_ZEROPAGE) {
// memory mapped arrays are assumed to be in RAM. If they're not.... well, POOF // memory mapped arrays are assumed to be in RAM. If they're not.... well, POOF
errors.err("cannot assign to an array or string that is located in ROM (option romable is enabled)", assignTarget.position) errors.err("cannot assign to an array or string that is located in ROM (option romable is enabled)", assignTarget.position)
} }
} }
} }
}
if(compilerOptions.romable) { if(compilerOptions.romable) {
if (assignTarget.multi != null) if (assignTarget.multi != null)
@@ -1336,7 +1336,8 @@ internal class AstChecker(private val program: Program,
leftIdentfier.targetVarDecl()?.datatype?.subType as? StructDecl leftIdentfier.targetVarDecl()?.datatype?.subType as? StructDecl
} else if(leftIndexer!=null) { } else if(leftIndexer!=null) {
// ARRAY[x].NAME --> maybe it's a pointer dereference // ARRAY[x].NAME --> maybe it's a pointer dereference
leftIndexer.arrayvar.targetVarDecl()?.datatype?.subType as? StructDecl TODO("array[x].name pointer check?")
// leftIndexer.arrayvar.targetVarDecl()?.datatype?.subType as? StructDecl
} }
else null else null
if (struct != null) { if (struct != null) {
@@ -1366,21 +1367,22 @@ internal class AstChecker(private val program: Program,
} else if(rightIndexer!=null) { } else if(rightIndexer!=null) {
val leftDt = expr.left.inferType(program) val leftDt = expr.left.inferType(program)
if(leftDt.isStructInstance) { if(leftDt.isStructInstance) {
// pointer[x].field[y] --> type is the dt of 'field' TODO("pointer[x].field[y] ??")
var struct = leftDt.getOrUndef().subType as? StructDecl // // pointer[x].field[y] --> type is the dt of 'field'
if (struct==null) { // var struct = leftDt.getOrUndef().subType as? StructDecl
errors.err("cannot find struct type", expr.position) // if (struct==null) {
} else { // errors.err("cannot find struct type", expr.position)
var fieldDt = struct.getFieldType(rightIndexer.arrayvar.nameInSource.single()) // } else {
if (fieldDt == null) // var fieldDt = struct.getFieldType(rightIndexer.arrayvar.nameInSource.single())
errors.err("no such field '${rightIndexer.arrayvar.nameInSource.single()}' in struct '${(leftDt.getOrUndef().subType as? StructDecl)?.name}'", expr.position) // if (fieldDt == null)
else { // errors.err("no such field '${rightIndexer.arrayvar.nameInSource.single()}' in struct '${(leftDt.getOrUndef().subType as? StructDecl)?.name}'", expr.position)
struct = fieldDt.subType as StructDecl // else {
fieldDt = struct.getFieldType(rightIndexer.arrayvar.nameInSource.single()) // struct = fieldDt.subType as StructDecl
if(fieldDt==null) // fieldDt = struct.getFieldType(rightIndexer.arrayvar.nameInSource.single())
errors.err("no such field '${rightIndexer.arrayvar.nameInSource.single()}' in struct '${struct.name}'", expr.position) // if(fieldDt==null)
} // errors.err("no such field '${rightIndexer.arrayvar.nameInSource.single()}' in struct '${struct.name}'", expr.position)
} // }
// }
} else { } else {
errors.err("at the moment it is not possible to chain array syntax on pointers like ...p1[x].p2[y]... use separate expressions for the time being", expr.right.position) // TODO add support for chained array syntax on pointers (rewrite ast?) errors.err("at the moment it is not possible to chain array syntax on pointers like ...p1[x].p2[y]... use separate expressions for the time being", expr.right.position) // TODO add support for chained array syntax on pointers (rewrite ast?)
// TODO I don't think we can evaluate this because it could end up in as a struct instance, which we don't support yet... rewrite or just give an error? // TODO I don't think we can evaluate this because it could end up in as a struct instance, which we don't support yet... rewrite or just give an error?
@@ -1843,7 +1845,7 @@ internal class AstChecker(private val program: Program,
override fun visit(arrayIndexedExpression: ArrayIndexedExpression) { override fun visit(arrayIndexedExpression: ArrayIndexedExpression) {
checkLongType(arrayIndexedExpression) checkLongType(arrayIndexedExpression)
val target = arrayIndexedExpression.arrayvar.targetStatement(program.builtinFunctions) val target = arrayIndexedExpression.plainarrayvar?.targetStatement(program.builtinFunctions)
if(target is VarDecl) { if(target is VarDecl) {
if (!target.datatype.isIterable && !target.datatype.isUnsignedWord && !target.datatype.isPointer) if (!target.datatype.isIterable && !target.datatype.isUnsignedWord && !target.datatype.isPointer)
errors.err( errors.err(
@@ -1875,26 +1877,36 @@ internal class AstChecker(private val program: Program,
} else if (index != null && index < 0) { } else if (index != null && index < 0) {
errors.err("index out of bounds", arrayIndexedExpression.indexer.position) errors.err("index out of bounds", arrayIndexedExpression.indexer.position)
} }
} else if(target is StructFieldRef) { } else if(target!=null) {
if(!target.type.isPointer && !target.type.isUnsignedWord) throw FatalAstException("target is not a variable")
errors.err("cannot array index on this field type", arrayIndexedExpression.indexer.position)
} else {
val parentExpr = arrayIndexedExpression.parent
if(parentExpr is BinaryExpression) {
if (parentExpr.operator != ".")
errors.err("indexing requires a variable to act upon", arrayIndexedExpression.position)
} else if(parentExpr is PtrIndexedDereference) {
// all is fine
} else {
errors.err("indexing requires a variable to act upon", arrayIndexedExpression.position)
} }
if(arrayIndexedExpression.pointerderef!=null) {
val dt = arrayIndexedExpression.pointerderef!!.inferType(program)
if(!dt.isPointer && !dt.isUnsignedWord && !dt.isIterable) {
errors.err("cannot array index on this field type", arrayIndexedExpression.indexer.position)
}
// else if(target is StructFieldRef) {
// if(!target.type.isPointer && !target.type.isUnsignedWord)
// errors.err("cannot array index on this field type", arrayIndexedExpression.indexer.position)
// } else {
// val parentExpr = arrayIndexedExpression.parent
// if(parentExpr is BinaryExpression) {
// if (parentExpr.operator != ".")
// errors.err("indexing requires a variable to act upon", arrayIndexedExpression.position)
// } else if(parentExpr is PtrIndexedDereference) {
// // all is fine
// } else {
// errors.err("indexing requires a variable to act upon", arrayIndexedExpression.position)
// }
// }
} }
// check index value 0..255 if the index variable is not a pointer // check index value 0..255 if the index variable is not a pointer
val dtxNum = arrayIndexedExpression.indexer.indexExpr.inferType(program) val dtxNum = arrayIndexedExpression.indexer.indexExpr.inferType(program)
if(dtxNum.isKnown) { if(dtxNum.isKnown) {
val arrayVarDt = arrayIndexedExpression.arrayvar.inferType(program) val arrayVarDt = arrayIndexedExpression.plainarrayvar?.inferType(program)
if (!arrayVarDt.isPointer && !(dtxNum issimpletype BaseDataType.UBYTE) && !(dtxNum issimpletype BaseDataType.BYTE)) if (arrayVarDt!=null && !arrayVarDt.isPointer && !(dtxNum issimpletype BaseDataType.UBYTE) && !(dtxNum issimpletype BaseDataType.BYTE))
errors.err("array indexing is limited to byte size 0..255", arrayIndexedExpression.position) errors.err("array indexing is limited to byte size 0..255", arrayIndexedExpression.position)
} }
@@ -1999,12 +2011,12 @@ internal class AstChecker(private val program: Program,
private fun allowedMemoryAccessAddressExpression(addressExpression: Expression, program: Program): Boolean { private fun allowedMemoryAccessAddressExpression(addressExpression: Expression, program: Program): Boolean {
val dt = addressExpression.inferType(program) val dt = addressExpression.inferType(program)
if(dt.isUnsignedWord || (dt.isPointer && dt.getOrUndef().sub==BaseDataType.UBYTE)) if(dt.isUnsignedWord || (dt.isPointer && dt.getOrUndef().sub?.isByte==true))
return true return true
val tc = addressExpression as? TypecastExpression val tc = addressExpression as? TypecastExpression
if(tc!=null && tc.implicit) { if(tc!=null && tc.implicit) {
val dt = tc.expression.inferType(program) val dt = tc.expression.inferType(program)
if(dt.isUnsignedWord || (dt.isPointer && dt.getOrUndef().sub==BaseDataType.UBYTE)) if(dt.isUnsignedWord || (dt.isPointer && dt.getOrUndef().sub?.isByte==true))
return true return true
} }
return false return false
@@ -2372,12 +2384,6 @@ internal class AstChecker(private val program: Program,
errors.err("on..goto index must be an unsigned byte", onGoto.index.position) errors.err("on..goto index must be an unsigned byte", onGoto.index.position)
} }
} }
override fun visit(idxderef: PtrIndexedDereference) {
val dt = idxderef.indexed.arrayvar.inferType(program)
if(!dt.isUnsignedWord && !dt.isPointer)
errors.err("cannot array index on this field type", idxderef.indexed.position)
}
} }
internal fun checkUnusedReturnValues(call: FunctionCallStatement, target: Statement, errors: IErrorReporter) { internal fun checkUnusedReturnValues(call: FunctionCallStatement, target: Statement, errors: IErrorReporter) {

View File

@@ -216,12 +216,17 @@ _after:
override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> { override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> {
// replace pointervar[word] by @(pointervar+word) to avoid the // replace pointervar[word] by @(pointervar+word) to avoid the
// "array indexing is limited to byte size 0..255" error for pointervariables. // "array indexing is limited to byte size 0..255" error for pointervariables.
if(arrayIndexedExpression.pointerderef!=null) {
return noModifications
}
val indexExpr = arrayIndexedExpression.indexer.indexExpr val indexExpr = arrayIndexedExpression.indexer.indexExpr
val arrayVar = arrayIndexedExpression.arrayvar.targetVarDecl() val arrayVar = arrayIndexedExpression.plainarrayvar!!.targetVarDecl()
if(arrayVar!=null && (arrayVar.datatype.isUnsignedWord || (arrayVar.datatype.isPointer && arrayVar.datatype.sub==BaseDataType.UBYTE))) { if(arrayVar!=null && (arrayVar.datatype.isUnsignedWord || (arrayVar.datatype.isPointer && arrayVar.datatype.sub==BaseDataType.UBYTE))) {
val wordIndex = TypecastExpression(indexExpr, DataType.UWORD, true, indexExpr.position) val wordIndex = TypecastExpression(indexExpr, DataType.UWORD, true, indexExpr.position)
val address = BinaryExpression( val address = BinaryExpression(
arrayIndexedExpression.arrayvar.copy(), arrayIndexedExpression.plainarrayvar!!.copy(),
"+", "+",
wordIndex, wordIndex,
arrayIndexedExpression.position arrayIndexedExpression.position
@@ -243,23 +248,24 @@ _after:
val memread = DirectMemoryRead(address, arrayIndexedExpression.position) val memread = DirectMemoryRead(address, arrayIndexedExpression.position)
listOf(IAstModification.ReplaceNode(arrayIndexedExpression, memread, parent)) listOf(IAstModification.ReplaceNode(arrayIndexedExpression, memread, parent))
} }
} else if(arrayVar!=null && (arrayVar.datatype.isPointer || arrayVar.datatype.isArray)) { } else if(arrayVar!=null && (arrayVar.type==VarDeclType.MEMORY || arrayVar.datatype.isString || arrayVar.datatype.isPointer || arrayVar.datatype.isArray)) {
return noModifications return noModifications
} else { } else if(arrayVar!=null) {
// it could be a pointer dereference instead of a simple array variable // it could be a pointer dereference instead of a simple array variable
val dt = arrayIndexedExpression.arrayvar.traverseDerefChainForDt(null) TODO("deref[word] rewrite ???? $arrayIndexedExpression")
if(dt.isUnsignedWord) { // val dt = arrayIndexedExpression.plainarrayvar!!.traverseDerefChainForDt(null)
// ptr.field[index] --> @(ptr.field + index) // if(dt.isUnsignedWord) {
val index = arrayIndexedExpression.indexer.indexExpr // // ptr.field[index] --> @(ptr.field + index)
val address = BinaryExpression(arrayIndexedExpression.arrayvar.copy(), "+", index, arrayIndexedExpression.position) // val index = arrayIndexedExpression.indexer.indexExpr
if(parent is AssignTarget) { // val address = BinaryExpression(arrayIndexedExpression.arrayvar.copy(), "+", index, arrayIndexedExpression.position)
val memwrite = DirectMemoryWrite(address, arrayIndexedExpression.position) // if(parent is AssignTarget) {
return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, memwrite, parent)) // val memwrite = DirectMemoryWrite(address, arrayIndexedExpression.position)
} else { // return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, memwrite, parent))
val memread = DirectMemoryRead(address, arrayIndexedExpression.position) // } else {
return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, memread, parent)) // val memread = DirectMemoryRead(address, arrayIndexedExpression.position)
} // return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, memread, parent))
} // }
// }
} }
return noModifications return noModifications
} }
@@ -396,9 +402,6 @@ _after:
override fun after(identifier: IdentifierReference, parent: Node): Iterable<IAstModification> { override fun after(identifier: IdentifierReference, parent: Node): Iterable<IAstModification> {
if(parent is PtrIndexedDereference || parent.parent is PtrIndexedDereference)
return noModifications
if(identifier.nameInSource.size>1 && (identifier.firstTarget() as? VarDecl)?.datatype?.isPointer==true) { if(identifier.nameInSource.size>1 && (identifier.firstTarget() as? VarDecl)?.datatype?.isPointer==true) {
// the a.b.c.d is be a pointer dereference chain ending in a struct field; a^^.b^^.c^^.d // the a.b.c.d is be a pointer dereference chain ending in a struct field; a^^.b^^.c^^.d
@@ -426,13 +429,7 @@ _after:
struct = fieldDt.subType as StructDecl struct = fieldDt.subType as StructDecl
} }
if(parent is ArrayIndexedExpression) { if (parent !is PtrDereference) {
if(struct.getFieldType(field!!)!!.isUnsignedWord) {
return noModifications
}
val deref = PtrIndexedDereference(parent, parent.position)
return listOf(IAstModification.ReplaceNode(parent, deref, parent.parent))
} else if (parent !is PtrDereference) {
val deref = PtrDereference(IdentifierReference(identifier.nameInSource.take(i), identifier.position), chain, field, false, identifier.position) val deref = PtrDereference(IdentifierReference(identifier.nameInSource.take(i), identifier.position), chain, field, false, identifier.position)
return listOf(IAstModification.ReplaceNode(identifier, deref, parent)) return listOf(IAstModification.ReplaceNode(identifier, deref, parent))
} }
@@ -472,7 +469,12 @@ _after:
assignIndex = Assignment(varTarget, ongoto.index, AssignmentOrigin.USERCODE, ongoto.position) assignIndex = Assignment(varTarget, ongoto.index, AssignmentOrigin.USERCODE, ongoto.position)
} }
val callTarget = ArrayIndexedExpression(IdentifierReference(listOf(jumplistArray.name), jumplistArray.position), ArrayIndex(indexValue.copy(), indexValue.position), ongoto.position) val callTarget = ArrayIndexedExpression(
IdentifierReference(listOf(jumplistArray.name), jumplistArray.position),
null,
ArrayIndex(indexValue.copy(), indexValue.position),
ongoto.position
)
val callIndexed = AnonymousScope(mutableListOf(), ongoto.position) val callIndexed = AnonymousScope(mutableListOf(), ongoto.position)
if(ongoto.isCall) { if(ongoto.isCall) {
callIndexed.statements.add(FunctionCallStatement(IdentifierReference(listOf("call"), ongoto.position), mutableListOf(callTarget), true, ongoto.position)) callIndexed.statements.add(FunctionCallStatement(IdentifierReference(listOf("call"), ongoto.position), mutableListOf(callTarget), true, ongoto.position))

View File

@@ -1,9 +1,6 @@
package prog8.compiler.astprocessing package prog8.compiler.astprocessing
import prog8.ast.IFunctionCall import prog8.ast.*
import prog8.ast.IStatementContainer
import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.ast.walk.AstWalker import prog8.ast.walk.AstWalker
@@ -169,10 +166,14 @@ internal class LiteralsToAutoVarsAndRecombineIdentifiers(private val program: Pr
// maybe recombine IDENTIFIER . ARRAY[IDX] --> COMBINEDIDENTIFIER[IDX] // maybe recombine IDENTIFIER . ARRAY[IDX] --> COMBINEDIDENTIFIER[IDX]
val leftTarget = leftIdent.targetStatement() val leftTarget = leftIdent.targetStatement()
if(leftTarget==null || leftTarget !is StructDecl) { if(leftTarget==null || leftTarget !is StructDecl) {
val combinedName = leftIdent.nameInSource + rightIndex.arrayvar.nameInSource if(rightIndex.plainarrayvar!=null) {
val combinedName = leftIdent.nameInSource + rightIndex.plainarrayvar!!.nameInSource
val combined = IdentifierReference(combinedName, leftIdent.position) val combined = IdentifierReference(combinedName, leftIdent.position)
val indexer = ArrayIndexedExpression(combined, rightIndex.indexer, leftIdent.position) val indexer = ArrayIndexedExpression(combined, null, rightIndex.indexer, leftIdent.position)
return listOf(IAstModification.ReplaceNode(expr, indexer, parent)) return listOf(IAstModification.ReplaceNode(expr, indexer, parent))
} else {
throw FatalAstException("didn't expect pointer[idx] in this phase already")
}
} }
} }
} }

View File

@@ -100,22 +100,9 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
is TypecastExpression -> transform(expr) is TypecastExpression -> transform(expr)
is IfExpression -> transform(expr) is IfExpression -> transform(expr)
is PtrDereference -> transform(expr) is PtrDereference -> transform(expr)
is PtrIndexedDereference -> transform(expr)
} }
} }
private fun transform(idxderef: PtrIndexedDereference): PtPointerIndexedDeref {
val type = idxderef.inferType(program).getOrElse {
throw FatalAstException("unknown dt")
}
val derefType = if(type.isPointer) DataType.forDt(type.sub!!) else type
val deref = PtPointerIndexedDeref(derefType, idxderef.position)
val identifier = PtIdentifier(idxderef.indexed.arrayvar.nameInSource.joinToString("."), DataType.pointer(derefType), idxderef.indexed.arrayvar.position)
deref.add(identifier)
deref.add(transformExpression(idxderef.indexed.indexer.indexExpr))
return deref
}
private fun transform(deref: PtrDereference): PtPointerDeref { private fun transform(deref: PtrDereference): PtPointerDeref {
val type = deref.inferType(program).getOrElse { val type = deref.inferType(program).getOrElse {
throw FatalAstException("unknown dt") throw FatalAstException("unknown dt")
@@ -244,7 +231,6 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
srcTarget.arrayindexed!=null -> target.add(transform(srcTarget.arrayindexed!!)) srcTarget.arrayindexed!=null -> target.add(transform(srcTarget.arrayindexed!!))
srcTarget.memoryAddress!=null -> target.add(transform(srcTarget.memoryAddress!!)) srcTarget.memoryAddress!=null -> target.add(transform(srcTarget.memoryAddress!!))
srcTarget.pointerDereference !=null -> target.add(transform(srcTarget.pointerDereference!!)) srcTarget.pointerDereference !=null -> target.add(transform(srcTarget.pointerDereference!!))
srcTarget.pointerIndexedDeref!=null -> target.add(transform(srcTarget.pointerIndexedDeref!!))
!srcTarget.void -> throw FatalAstException("invalid AssignTarget") !srcTarget.void -> throw FatalAstException("invalid AssignTarget")
} }
return target return target
@@ -699,15 +685,21 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
} }
private fun transform(srcArr: ArrayIndexedExpression): PtArrayIndexer { private fun transform(srcArr: ArrayIndexedExpression): PtArrayIndexer {
val dt = srcArr.arrayvar.inferType(program) if(srcArr.plainarrayvar!=null) {
val dt = srcArr.plainarrayvar!!.inferType(program)
if (!dt.isArray && !dt.isString && !dt.isPointer) if (!dt.isArray && !dt.isString && !dt.isPointer)
throw FatalAstException("array indexing can only be used on array, string or pointer variables ${srcArr.position}") throw FatalAstException("array indexing can only be used on array, string or pointer variables ${srcArr.position}")
val eltType = srcArr.inferType(program).getOrElse { throw FatalAstException("unknown dt") } val eltType = srcArr.inferType(program).getOrElse { throw FatalAstException("unknown dt") }
val array = PtArrayIndexer(eltType, srcArr.position) val array = PtArrayIndexer(eltType, srcArr.position)
array.add(transform(srcArr.arrayvar)) array.add(transform(srcArr.plainarrayvar!!))
array.add(transformExpression(srcArr.indexer.indexExpr)) array.add(transformExpression(srcArr.indexer.indexExpr))
return array return array
} }
if(srcArr.pointerderef!=null) {
TODO("transform pointer index")
}
throw FatalAstException("expected plain array variable or pointer dereference")
}
private fun transform(srcArr: ArrayLiteral): PtArray { private fun transform(srcArr: ArrayLiteral): PtArray {
val arr = PtArray(srcArr.inferType(program).getOrElse { throw FatalAstException("array must know its type") }, srcArr.position) val arr = PtArray(srcArr.inferType(program).getOrElse { throw FatalAstException("array must know its type") }, srcArr.position)

View File

@@ -28,7 +28,6 @@ private fun checkForPointerTypesOn6502(program: PtProgram, errors: IErrorReporte
//is PtBinaryExpression -> if(node.left.type.isPointer || node.right.type.isPointer) errors.err("cannot do pointer arithmetic yet on 6502 target $node", node.position) //is PtBinaryExpression -> if(node.left.type.isPointer || node.right.type.isPointer) errors.err("cannot do pointer arithmetic yet on 6502 target $node", node.position)
is PtIdentifier -> if(node.type.isPointer) errors.err("cannot use pointer type yet on 6502 target $node", node.position) is PtIdentifier -> if(node.type.isPointer) errors.err("cannot use pointer type yet on 6502 target $node", node.position)
is PtPointerDeref -> errors.err("cannot use pointer type yet on 6502 target $node", node.position) is PtPointerDeref -> errors.err("cannot use pointer type yet on 6502 target $node", node.position)
is PtPointerIndexedDeref -> errors.err("cannot use pointer type yet on 6502 target $node", node.position)
is PtPrefix -> if(node.type.isPointer) errors.err("cannot use pointer type yet on 6502 target $node", node.position) is PtPrefix -> if(node.type.isPointer) errors.err("cannot use pointer type yet on 6502 target $node", node.position)
is PtTypeCast -> if(node.type.isPointer) errors.err("cannot use pointer type yet on 6502 target $node", node.position) is PtTypeCast -> if(node.type.isPointer) errors.err("cannot use pointer type yet on 6502 target $node", node.position)
is PtStructDecl -> errors.err("cannot use struct type yet on 6502 target $node", node.position) is PtStructDecl -> errors.err("cannot use struct type yet on 6502 target $node", node.position)
@@ -62,7 +61,6 @@ private fun processSubtypesIntoStReferences(program: PtProgram, st: SymbolTable)
when(node) { when(node) {
is IPtVariable -> fixSubtype(node.type) is IPtVariable -> fixSubtype(node.type)
is PtPointerDeref -> fixSubtype(node.type) is PtPointerDeref -> fixSubtype(node.type)
is PtPointerIndexedDeref -> fixSubtype(node.type)
is PtStructDecl -> node.fields.forEach { fixSubtype(it.first) } is PtStructDecl -> node.fields.forEach { fixSubtype(it.first) }
is PtAsmSub -> node.returns.forEach { fixSubtype(it.second) } is PtAsmSub -> node.returns.forEach { fixSubtype(it.second) }
is PtExpression -> fixSubtype(node.type) is PtExpression -> fixSubtype(node.type)

View File

@@ -636,7 +636,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
val idxDt = arrayIndexedExpression.indexer.indexExpr.inferType(program).getOrUndef() val idxDt = arrayIndexedExpression.indexer.indexExpr.inferType(program).getOrUndef()
if(idxDt.base.largerSizeThan(smaller.type)) { if(idxDt.base.largerSizeThan(smaller.type)) {
val newIdx = ArrayIndex(smaller, smaller.position) val newIdx = ArrayIndex(smaller, smaller.position)
val newIndexer = ArrayIndexedExpression(arrayIndexedExpression.arrayvar, newIdx, arrayIndexedExpression.position) val newIndexer = ArrayIndexedExpression(arrayIndexedExpression.plainarrayvar, arrayIndexedExpression.pointerderef, newIdx, arrayIndexedExpression.position)
return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, newIndexer, parent)) return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, newIndexer, parent))
} }
} }

View File

@@ -428,7 +428,8 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> { override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> {
val index = arrayIndexedExpression.indexer.constIndex() val index = arrayIndexedExpression.indexer.constIndex()
if(index!=null && index<0) { if(index!=null && index<0) {
val target = arrayIndexedExpression.arrayvar.targetVarDecl() if(arrayIndexedExpression.plainarrayvar!=null) {
val target = arrayIndexedExpression.plainarrayvar!!.targetVarDecl()
val arraysize = target?.arraysize?.constIndex() val arraysize = target?.arraysize?.constIndex()
if(arraysize!=null) { if(arraysize!=null) {
if(arraysize+index < 0) { if(arraysize+index < 0) {
@@ -440,6 +441,9 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
arrayIndexedExpression.indexer.indexExpr = newIndex arrayIndexedExpression.indexer.indexExpr = newIndex
newIndex.linkParents(arrayIndexedExpression.indexer) newIndex.linkParents(arrayIndexedExpression.indexer)
} }
} else if(arrayIndexedExpression.pointerderef!=null) {
TODO("cleanup pointer indexing")
}
} }
return noModifications return noModifications
} }

View File

@@ -322,7 +322,7 @@ class TestMemory: FunSpec({
test("array not in mapped IO ram") { test("array not in mapped IO ram") {
val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.arrayFor(BaseDataType.UBYTE), ZeropageWish.DONTCARE, val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.arrayFor(BaseDataType.UBYTE), ZeropageWish.DONTCARE,
SplitWish.DONTCARE, null, "address", emptyList(), null, false, 0u, false, Position.DUMMY) SplitWish.DONTCARE, null, "address", emptyList(), null, false, 0u, false, Position.DUMMY)
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY) val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), null, ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
val target = AssignTarget(null, arrayindexed, null, null, false, position = Position.DUMMY) val target = AssignTarget(null, arrayindexed, null, null, false, position = Position.DUMMY)
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY) val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
@@ -336,7 +336,7 @@ class TestMemory: FunSpec({
val address = 0x1000u val address = 0x1000u
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.arrayFor(BaseDataType.UBYTE), ZeropageWish.DONTCARE, val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.arrayFor(BaseDataType.UBYTE), ZeropageWish.DONTCARE,
SplitWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, 0u, false, Position.DUMMY) SplitWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, 0u, false, Position.DUMMY)
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY) val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), null, ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
val target = AssignTarget(null, arrayindexed, null, null, false, position = Position.DUMMY) val target = AssignTarget(null, arrayindexed, null, null, false, position = Position.DUMMY)
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY) val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
@@ -350,7 +350,7 @@ class TestMemory: FunSpec({
val address = 0xd800u val address = 0xd800u
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.arrayFor(BaseDataType.UBYTE), ZeropageWish.DONTCARE, val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.arrayFor(BaseDataType.UBYTE), ZeropageWish.DONTCARE,
SplitWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, 0u, false, Position.DUMMY) SplitWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, 0u, false, Position.DUMMY)
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY) val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), null, ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
val target = AssignTarget(null, arrayindexed, null, null, false, position = Position.DUMMY) val target = AssignTarget(null, arrayindexed, null, null, false, position = Position.DUMMY)
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY) val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)

View File

@@ -7,6 +7,8 @@ import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe import io.kotest.matchers.shouldNotBe
import io.kotest.matchers.string.shouldContain import io.kotest.matchers.string.shouldContain
import io.kotest.matchers.types.instanceOf import io.kotest.matchers.types.instanceOf
import prog8.ast.expressions.ArrayIndexedExpression
import prog8.ast.expressions.DirectMemoryRead
import prog8.ast.expressions.PtrDereference import prog8.ast.expressions.PtrDereference
import prog8.ast.statements.Assignment import prog8.ast.statements.Assignment
import prog8.ast.statements.VarDecl import prog8.ast.statements.VarDecl
@@ -193,6 +195,8 @@ main {
cx16.r1 = matchstate^^.next^^.next^^.ptr cx16.r1 = matchstate^^.next^^.next^^.ptr
cx16.r2 = matchstate.ptr cx16.r2 = matchstate.ptr
cx16.r3 = matchstate.next.next.ptr cx16.r3 = matchstate.next.next.ptr
cx16.r4 = matchstate.ptr^^
cx16.r5 = matchstate.next.next.ptr^^
matchstate^^.ptr = 2222 matchstate^^.ptr = 2222
matchstate^^.next^^.next^^.ptr = 2222 matchstate^^.next^^.next^^.ptr = 2222
@@ -203,7 +207,7 @@ main {
val result = compileText(VMTarget(), false, src, outputDir, writeAssembly = false)!! val result = compileText(VMTarget(), false, src, outputDir, writeAssembly = false)!!
val st = result.compilerAst.entrypoint.statements val st = result.compilerAst.entrypoint.statements
st.size shouldBe 11 st.size shouldBe 13
val a0v = (st[2] as Assignment).value as PtrDereference val a0v = (st[2] as Assignment).value as PtrDereference
a0v.identifier.nameInSource shouldBe listOf("matchstate") a0v.identifier.nameInSource shouldBe listOf("matchstate")
a0v.chain.size shouldBe 0 a0v.chain.size shouldBe 0
@@ -228,31 +232,98 @@ main {
a3v.field shouldBe "ptr" a3v.field shouldBe "ptr"
a3v.derefPointerValue shouldBe false a3v.derefPointerValue shouldBe false
val t0 = (st[6] as Assignment).target.pointerDereference!! val a4v = (st[6] as Assignment).value as PtrDereference
a4v.identifier.nameInSource shouldBe listOf("matchstate")
a4v.chain shouldBe listOf("ptr")
a4v.field shouldBe null
a4v.derefPointerValue shouldBe true
val a5v = (st[7] as Assignment).value as PtrDereference
a5v.identifier.nameInSource shouldBe listOf("matchstate")
a5v.chain shouldBe listOf("next", "next", "ptr")
a5v.field shouldBe null
a5v.derefPointerValue shouldBe true
val t0 = (st[8] as Assignment).target.pointerDereference!!
t0.derefPointerValue shouldBe false t0.derefPointerValue shouldBe false
t0.identifier.nameInSource shouldBe listOf("matchstate") t0.identifier.nameInSource shouldBe listOf("matchstate")
t0.chain.size shouldBe 0 t0.chain.size shouldBe 0
t0.field shouldBe "ptr" t0.field shouldBe "ptr"
val t1 = (st[7] as Assignment).target.pointerDereference!! val t1 = (st[9] as Assignment).target.pointerDereference!!
t1.derefPointerValue shouldBe false t1.derefPointerValue shouldBe false
t1.identifier.nameInSource shouldBe listOf("matchstate") t1.identifier.nameInSource shouldBe listOf("matchstate")
t1.chain shouldBe listOf("next", "next") t1.chain shouldBe listOf("next", "next")
t1.field shouldBe "ptr" t1.field shouldBe "ptr"
val t2 = (st[8] as Assignment).target.pointerDereference!! val t2 = (st[10] as Assignment).target.pointerDereference!!
t2.derefPointerValue shouldBe false t2.derefPointerValue shouldBe false
t2.identifier.nameInSource shouldBe listOf("matchstate") t2.identifier.nameInSource shouldBe listOf("matchstate")
t2.chain.size shouldBe 0 t2.chain.size shouldBe 0
t2.field shouldBe "ptr" t2.field shouldBe "ptr"
val t3 = (st[9] as Assignment).target.pointerDereference!! val t3 = (st[11] as Assignment).target.pointerDereference!!
t3.derefPointerValue shouldBe false t3.derefPointerValue shouldBe false
t3.identifier.nameInSource shouldBe listOf("matchstate") t3.identifier.nameInSource shouldBe listOf("matchstate")
t3.chain shouldBe listOf("next", "next") t3.chain shouldBe listOf("next", "next")
t3.field shouldBe "ptr" t3.field shouldBe "ptr"
} }
test("word size pointer indexing on pointers") {
val src="""
%option enable_floats
main {
struct List {
^^uword s
ubyte n
^^List next
}
sub start() {
ubyte[10] array
uword @shared wordptr
^^bool @shared boolptr
^^float @shared floatptr
^^byte @shared byteptr
^^ubyte @shared ubyteptr
^^List @shared listptr
^^List @shared listptr2
bool @shared zz
float @shared fl
byte @shared bb
zz = boolptr[999]
fl = floatptr[999]
bb = byteptr[999]
cx16.r0L = ubyteptr[999]
cx16.r1L = wordptr[999]
cx16.r2L = array[9]
listptr2 = listptr[999]
}
}"""
val result = compileText(VMTarget(), false, src, outputDir, writeAssembly = false)!!
val st = result.compilerAst.entrypoint.statements
st.size shouldBe 28
val a_zz = (st[20] as Assignment).value
a_zz shouldBe instanceOf<ArrayIndexedExpression>()
val a_fl = (st[21] as Assignment).value
a_fl shouldBe instanceOf<ArrayIndexedExpression>()
val a_bb = (st[22] as Assignment).value
a_bb shouldBe instanceOf<ArrayIndexedExpression>()
val a_r0 = (st[23] as Assignment).value
a_r0 shouldBe instanceOf<DirectMemoryRead>()
val a_r1 = (st[24] as Assignment).value
a_r1 shouldBe instanceOf<DirectMemoryRead>()
val a_r2 = (st[25] as Assignment).value
a_r2 shouldBe instanceOf<ArrayIndexedExpression>()
val a_lptr2 = (st[25] as Assignment).value
a_lptr2 shouldBe instanceOf<ArrayIndexedExpression>()
}
test("block scoping still parsed correctly") { test("block scoping still parsed correctly") {
val src=""" val src="""
main { main {
@@ -551,6 +622,9 @@ main {
} }
sub start() { sub start() {
^^List @shared l1 = List() ^^List @shared l1 = List()
bool ss = l1.s[1]
ubyte ub = l1.n[1]
uword uw = l1.ptr[1]
l1.s[1] = 4444 l1.s[1] = 4444
l1.n[1] = true l1.n[1] = true
l1.ptr[1] = 4444 l1.ptr[1] = 4444
@@ -559,10 +633,15 @@ main {
val errors = ErrorReporterForTests() val errors = ErrorReporterForTests()
compileText(VMTarget(), false, src, outputDir, errors=errors) shouldBe null compileText(VMTarget(), false, src, outputDir, errors=errors) shouldBe null
errors.errors.size shouldBe 4 errors.errors.size shouldBe 8
errors.errors[0] shouldContain "cannot array index" errors.errors[0] shouldContain "invalid assignment value"
errors.errors[1] shouldContain "cannot array index" errors.errors[1] shouldContain "cannot array index"
errors.errors[2] shouldContain "out of range" errors.errors[2] shouldContain "invalid assignment value"
errors.errors[3] shouldContain "cannot array index"
errors.errors[4] shouldContain "cannot array index"
errors.errors[5] shouldContain "cannot array index"
errors.errors[6] shouldContain "out of range"
errors.errors[7] shouldContain "cannot assign word to byte"
} }
test("dereferences of ptr variables mark those as used in the callgraph") { test("dereferences of ptr variables mark those as used in the callgraph") {
@@ -604,24 +683,26 @@ main {
} }
sub start() { sub start() {
^^List l1 = List() ^^List l1 = List()
^^word @shared wptr
cx16.r1 = l1.s^^
cx16.r0 = l1.s[0] cx16.r0 = l1.s[0]
cx16.r2 = l1^^.s^^
l1.s[0] = 4242 l1.s[0] = 4242
cx16.r1 = l1.s^^ cx16.r1 = l1.s^^
^^word @shared wptr
cx16.r0s = wptr[0] cx16.r0s = wptr[0]
cx16.r1s = wptr^^ cx16.r1s = wptr^^
wptr[0] = 4242 wptr[0] = 4242
} }
}""" }"""
val result = compileText(VMTarget(), true, src, outputDir, writeAssembly = false)!! val result = compileText(VMTarget(), true, src, outputDir, writeAssembly = false)!!
val st = result.compilerAst.entrypoint.statements val st = result.compilerAst.entrypoint.statements
st.size shouldBe 11 st.size shouldBe 11
val dr0 = (st[2] as Assignment).value as PtrDereference val dr0 = (st[4] as Assignment).value as PtrDereference
val dr1 = (st[3] as Assignment).target.pointerDereference!! val dr1 = (st[5] as Assignment).target.pointerDereference!!
val dr2 = (st[4] as Assignment).value as PtrDereference val dr2 = (st[6] as Assignment).value as PtrDereference
val dr3 = (st[7] as Assignment).value as PtrDereference val dr3 = (st[7] as Assignment).value as PtrDereference
val dr4 = (st[8] as Assignment).value as PtrDereference val dr4 = (st[8] as Assignment).value as PtrDereference

View File

@@ -124,16 +124,17 @@ class TestAstChecks: FunSpec({
main { main {
sub start() { sub start() {
&ubyte a = 10000 &ubyte a = 10000
uword @shared z = 500 cx16.r0L = a[4]
a[4] = (z % 3) as ubyte a[4] = cx16.r1L
} }
} }
""" """
val errors = ErrorReporterForTests(keepMessagesAfterReporting = true) val errors = ErrorReporterForTests(keepMessagesAfterReporting = true)
compileText(C64Target(), true, text, outputDir, writeAssembly = true, errors=errors) compileText(C64Target(), true, text, outputDir, writeAssembly = true, errors=errors)
errors.errors.size shouldBe 1 errors.errors.size shouldBe 2
errors.warnings.size shouldBe 0 errors.warnings.size shouldBe 0
errors.errors[0] shouldContain "indexing requires" errors.errors[0] shouldContain "indexing requires"
errors.errors[1] shouldContain "indexing requires"
} }
test("unicode in identifier names is working") { test("unicode in identifier names is working") {

View File

@@ -420,7 +420,8 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
} }
override fun visit(arrayIndexedExpression: ArrayIndexedExpression) { override fun visit(arrayIndexedExpression: ArrayIndexedExpression) {
arrayIndexedExpression.arrayvar.accept(this) arrayIndexedExpression.plainarrayvar?.accept(this)
arrayIndexedExpression.pointerderef?.accept(this)
output("[") output("[")
arrayIndexedExpression.indexer.indexExpr.accept(this) arrayIndexedExpression.indexer.indexExpr.accept(this)
output("]") output("]")
@@ -434,7 +435,6 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
assignTarget.identifier?.accept(this) assignTarget.identifier?.accept(this)
assignTarget.arrayindexed?.accept(this) assignTarget.arrayindexed?.accept(this)
assignTarget.pointerDereference?.accept(this) assignTarget.pointerDereference?.accept(this)
assignTarget.pointerIndexedDeref?.accept(this)
val multi = assignTarget.multi val multi = assignTarget.multi
if (multi != null) { if (multi != null) {
multi.dropLast(1).forEach { target -> multi.dropLast(1).forEach { target ->
@@ -558,11 +558,6 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
output(".${deref.field}") output(".${deref.field}")
} }
override fun visit(idxderef: PtrIndexedDereference) {
idxderef.indexed.accept(this)
output("^^")
}
override fun visit(field: StructFieldRef) { override fun visit(field: StructFieldRef) {
throw FatalAstException("struct field ref shouldn't occur as part of the AST tree ") throw FatalAstException("struct field ref shouldn't occur as part of the AST tree ")
} }

View File

@@ -402,9 +402,9 @@ private fun Assign_targetContext.toAst() : AssignTarget {
) )
is ArrayindexedTargetContext -> { is ArrayindexedTargetContext -> {
val ax = arrayindexed() val ax = arrayindexed()
val arrayvar = ax.scoped_identifier().toAst() val plainarrayvar = ax.scoped_identifier().toAst()
val index = ax.arrayindex().toAst() val index = ax.arrayindex().toAst()
val arrayindexed = ArrayIndexedExpression(arrayvar, index, ax.toPosition()) val arrayindexed = ArrayIndexedExpression(plainarrayvar, null, index, ax.toPosition())
AssignTarget(null, arrayindexed, null, null, false, position = toPosition()) AssignTarget(null, arrayindexed, null, null, false, position = toPosition())
} }
is VoidTargetContext -> { is VoidTargetContext -> {
@@ -412,11 +412,7 @@ private fun Assign_targetContext.toAst() : AssignTarget {
} }
is PointerDereferenceTargetContext -> { is PointerDereferenceTargetContext -> {
val deref = this.pointerdereference().toAst() val deref = this.pointerdereference().toAst()
AssignTarget(null, null, null, null, false, deref, null, deref.position) AssignTarget(null, null, null, null, false, deref, deref.position)
}
is PointerIndexedDerefTargetContext -> {
val deref = this.pointerindexedderef().toAst()
AssignTarget(null, null, null, null, false, null, deref, deref.position)
} }
else -> throw FatalAstException("weird assign target node $this") else -> throw FatalAstException("weird assign target node $this")
} }
@@ -602,9 +598,9 @@ private fun ExpressionContext.toAst(insideParentheses: Boolean=false) : Expressi
if(arrayindexed()!=null) { if(arrayindexed()!=null) {
val ax = arrayindexed() val ax = arrayindexed()
val identifier = ax.scoped_identifier().toAst() val plainarrayvar = ax.scoped_identifier().toAst()
val index = ax.arrayindex().toAst() val index = ax.arrayindex().toAst()
return ArrayIndexedExpression(identifier, index, ax.toPosition()) return ArrayIndexedExpression(plainarrayvar, null, index, ax.toPosition())
} }
if(scoped_identifier()!=null) if(scoped_identifier()!=null)
@@ -666,21 +662,10 @@ private fun ExpressionContext.toAst(insideParentheses: Boolean=false) : Expressi
val deref = pointerdereference()?.toAst() val deref = pointerdereference()?.toAst()
if(deref!=null) return deref if(deref!=null) return deref
val indexedderef = pointerindexedderef()?.toAst()
if(indexedderef!=null) return indexedderef
throw FatalAstException(text) throw FatalAstException(text)
} }
private fun PointerindexedderefContext.toAst(): PtrIndexedDereference {
val ax = arrayindexed()
val arrayvar = ax.scoped_identifier().toAst()
val index = ax.arrayindex().toAst()
val arrayindexed = ArrayIndexedExpression(arrayvar, index, ax.toPosition())
return PtrIndexedDereference(arrayindexed, toPosition())
}
private fun PointerdereferenceContext.toAst(): PtrDereference { private fun PointerdereferenceContext.toAst(): PtrDereference {
val scopeprefix = prefix?.toAst() val scopeprefix = prefix?.toAst()
val derefchain = derefchain()!!.singlederef()!!.map { it.identifier().text } val derefchain = derefchain()!!.singlederef()!!.map { it.identifier().text }

View File

@@ -40,10 +40,7 @@ sealed class Expression: Node {
else else
other.left isSameAs left && other.right isSameAs right other.left isSameAs left && other.right isSameAs right
} }
is ArrayIndexedExpression -> { is ArrayIndexedExpression -> isSameArrayIndexedAs(other)
(other is ArrayIndexedExpression && other.arrayvar.nameInSource == arrayvar.nameInSource
&& other.indexer isSameAs indexer)
}
is DirectMemoryRead -> { is DirectMemoryRead -> {
(other is DirectMemoryRead && other.addressExpression isSameAs addressExpression) (other is DirectMemoryRead && other.addressExpression isSameAs addressExpression)
} }
@@ -242,9 +239,12 @@ class BinaryExpression(
if (leftIdentfier != null) { if (leftIdentfier != null) {
// PTR . FIELD // PTR . FIELD
leftIdentfier.targetVarDecl()?.datatype?.subType as? StructDecl leftIdentfier.targetVarDecl()?.datatype?.subType as? StructDecl
} else if(leftIndexer!=null) { } else if(leftIndexer!=null && rightIdentifier.nameInSource.size==1) {
// ARRAY[x].NAME --> maybe it's a pointer dereference // ARRAY[x].NAME --> maybe it's a pointer dereference
leftIndexer.arrayvar.targetVarDecl()?.datatype?.subType as? StructDecl val dt = leftIndexer.inferType(program).getOrUndef()
if(dt.isPointer) {
dt.dereference().subType as? StructDecl
} else null
} else if(leftExpr!=null) { } else if(leftExpr!=null) {
// SOMEEXPRESSION . NAME // SOMEEXPRESSION . NAME
val leftDt = leftExpr.inferType(program) val leftDt = leftExpr.inferType(program)
@@ -269,17 +269,18 @@ class BinaryExpression(
} else if(rightIndexer!=null) { } else if(rightIndexer!=null) {
if(leftDt.isStructInstance) { if(leftDt.isStructInstance) {
// pointer[x].field[y] --> type is the dt of 'field' // pointer[x].field[y] --> type is the dt of 'field'
var fieldDt = (leftDt.getOrUndef().subType as? StructDecl)?.getFieldType(rightIndexer.arrayvar.nameInSource.single()) TODO("pointer[x].field[y] ?????")
if (fieldDt == null) // var fieldDt = (leftDt.getOrUndef().subType as? StructDecl)?.getFieldType(rightIndexer.arrayvar.nameInSource.single())
InferredTypes.unknown() // if (fieldDt == null)
else { // InferredTypes.unknown()
val struct = fieldDt.subType as StructDecl // else {
fieldDt = struct.getFieldType(rightIndexer.arrayvar.nameInSource.single()) // val struct = fieldDt.subType as StructDecl
if(fieldDt!=null) // fieldDt = struct.getFieldType(rightIndexer.arrayvar.nameInSource.single())
if(fieldDt.isUndefined) InferredTypes.unknown() else InferredTypes.knownFor(fieldDt) // if(fieldDt!=null)
else // if(fieldDt.isUndefined) InferredTypes.unknown() else InferredTypes.knownFor(fieldDt)
InferredTypes.unknown() // else
} // InferredTypes.unknown()
// }
} else } else
InferredTypes.unknown() // TODO("something.field[x] at ${right.position}") InferredTypes.unknown() // TODO("something.field[x] at ${right.position}")
// TODO I don't think we can evaluate this type because it could end up in as a struct instance, which we don't support yet... rewrite or just give an error? // TODO I don't think we can evaluate this type because it could end up in as a struct instance, which we don't support yet... rewrite or just give an error?
@@ -386,21 +387,30 @@ class BinaryExpression(
} }
} }
class ArrayIndexedExpression(var arrayvar: IdentifierReference, class ArrayIndexedExpression(var plainarrayvar: IdentifierReference?,
var pointerderef: PtrDereference?,
val indexer: ArrayIndex, val indexer: ArrayIndex,
override val position: Position) : Expression() { 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
arrayvar.linkParents(this) plainarrayvar?.linkParents(this)
pointerderef?.linkParents(this)
indexer.linkParents(this) indexer.linkParents(this)
} }
override val isSimple = indexer.indexExpr is NumericLiteral || indexer.indexExpr is IdentifierReference override val isSimple = indexer.indexExpr is NumericLiteral || indexer.indexExpr is IdentifierReference
override fun replaceChildNode(node: Node, replacement: Node) { override fun replaceChildNode(node: Node, replacement: Node) {
when { when (replacement) {
node===arrayvar -> arrayvar = replacement as IdentifierReference is IdentifierReference -> {
plainarrayvar = replacement
pointerderef = null
}
is PtrDereference -> {
plainarrayvar = null
pointerderef = replacement
}
else -> throw FatalAstException("invalid replace") else -> throw FatalAstException("invalid replace")
} }
replacement.parent = this replacement.parent = this
@@ -410,39 +420,58 @@ class ArrayIndexedExpression(var arrayvar: IdentifierReference,
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)
override fun referencesIdentifier(nameInSource: List<String>) = arrayvar.referencesIdentifier(nameInSource) || indexer.referencesIdentifier(nameInSource) override fun referencesIdentifier(nameInSource: List<String>) =
plainarrayvar?.referencesIdentifier(nameInSource)==true || pointerderef?.referencesIdentifier(nameInSource)==true || indexer.referencesIdentifier(nameInSource)
override fun inferType(program: Program): InferredTypes.InferredType { override fun inferType(program: Program): InferredTypes.InferredType {
val target = arrayvar.targetStatement(program.builtinFunctions) if(plainarrayvar!=null) {
val target = plainarrayvar!!.targetStatement()
if(target is VarDecl) { if(target is VarDecl) {
return when { return when {
target.datatype.isString || target.datatype.isUnsignedWord -> InferredTypes.knownFor(BaseDataType.UBYTE) target.datatype.isString || target.datatype.isUnsignedWord -> InferredTypes.knownFor(BaseDataType.UBYTE)
target.datatype.isArray -> InferredTypes.knownFor(target.datatype.elementType()) target.datatype.isArray -> InferredTypes.knownFor(target.datatype.elementType())
target.datatype.isPointer -> { target.datatype.isPointer -> InferredTypes.knownFor(target.datatype.dereference())
if(target.datatype.subType!=null)
InferredTypes.knownFor(DataType.structInstance(target.datatype.subType))
else if(target.datatype.subTypeFromAntlr!=null)
InferredTypes.unknown()
else
InferredTypes.knownFor(target.datatype.sub!!)
}
else -> InferredTypes.knownFor(target.datatype) else -> InferredTypes.knownFor(target.datatype)
} }
} else { } else if(target is StructFieldRef) {
val dt = arrayvar.inferType(program).getOrUndef() return InferredTypes.knownFor(target.type)
if(dt.isPointer) { } else if(target==null) {
if(dt.sub!=null) return InferredTypes.unknown()
return InferredTypes.knownFor(dt.sub!!) } else
TODO("infer type from target $target")
} else if(pointerderef!=null) {
val dt= pointerderef!!.inferType(program).getOrUndef()
return when {
dt.isString || dt.isUnsignedWord -> InferredTypes.knownFor(BaseDataType.UBYTE)
dt.isArray -> InferredTypes.knownFor(dt.elementType())
dt.isPointer -> InferredTypes.knownFor(dt.dereference())
else -> InferredTypes.unknown()
} }
} }
return InferredTypes.unknown() return InferredTypes.unknown()
} }
override fun toString(): String { override fun toString(): String {
return "ArrayIndexed(ident=$arrayvar, idx=$indexer; pos=$position)" return if(plainarrayvar!=null)
"ArrayIndexed(arrayvar=$plainarrayvar, idx=$indexer; pos=$position)"
else if(pointerderef!=null)
"ArrayIndexed(ptr=$pointerderef, idx=$indexer; pos=$position)"
else
"??????"
}
override fun copy() = ArrayIndexedExpression(plainarrayvar?.copy(), pointerderef?.copy(), indexer.copy(), position)
fun isSameArrayIndexedAs(other: Expression): Boolean {
if(other !is ArrayIndexedExpression || other.indexer!=indexer)
return false
if(plainarrayvar?.nameInSource != other.plainarrayvar?.nameInSource)
return false
if(pointerderef!=null)
return pointerderef!!.isSamePointerDeref(other.pointerderef)
return true
} }
override fun copy() = ArrayIndexedExpression(arrayvar.copy(), indexer.copy(), position)
} }
class TypecastExpression(var expression: Expression, var type: DataType, val implicit: Boolean, override val position: Position) : Expression() { class TypecastExpression(var expression: Expression, var type: DataType, val implicit: Boolean, override val position: Position) : Expression() {
@@ -1618,46 +1647,6 @@ class IfExpression(var condition: Expression, var truevalue: Expression, var fal
} }
} }
class PtrIndexedDereference(val indexed: ArrayIndexedExpression, override val position: Position) : Expression() {
override lateinit var parent: Node
override fun linkParents(parent: Node) {
this.parent = parent
indexed.linkParents(this)
}
override val isSimple = false
override fun copy() = PtrIndexedDereference(indexed.copy(), position)
override fun constValue(program: Program): NumericLiteral? = null
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun inferType(program: Program): InferredTypes.InferredType {
val parentExpr = parent as? BinaryExpression
if(parentExpr?.operator==".") {
TODO("cannot determine type of dereferenced indexed pointer(?) as part of a larger dereference expression")
}
val vardecl = indexed.arrayvar.targetVarDecl()
if(vardecl!=null &&vardecl.datatype.isPointer)
return InferredTypes.knownFor(vardecl.datatype.dereference())
if(parent is AssignTarget || parent is Assignment) {
val dt = indexed.arrayvar.traverseDerefChainForDt(null)
return when {
dt.isUndefined -> InferredTypes.unknown()
dt.isUnsignedWord -> InferredTypes.knownFor(BaseDataType.UBYTE)
dt.isPointer -> InferredTypes.knownFor(dt.dereference())
else -> InferredTypes.unknown()
}
}
return InferredTypes.unknown()
}
override fun replaceChildNode(node: Node, replacement: Node) =
throw FatalAstException("can't replace here")
override fun referencesIdentifier(nameInSource: List<String>) = indexed.referencesIdentifier(nameInSource)
}
class PtrDereference( class PtrDereference(
val identifier: IdentifierReference, val identifier: IdentifierReference,
val chain: List<String>, val chain: List<String>,
@@ -1666,6 +1655,7 @@ class PtrDereference(
override val position: Position override val position: Position
) : Expression() { ) : Expression() {
// TODO why both identifier and chain? // TODO why both identifier and chain?
// TODO why both chain and field? field is just the last entry of chain?
override lateinit var parent: Node override lateinit var parent: Node
@@ -1731,6 +1721,19 @@ class PtrDereference(
override fun replaceChildNode(node: Node, replacement: Node) = override fun replaceChildNode(node: Node, replacement: Node) =
throw FatalAstException("can't replace here") throw FatalAstException("can't replace here")
override fun referencesIdentifier(nameInSource: List<String>) = identifier.referencesIdentifier(nameInSource) override fun referencesIdentifier(nameInSource: List<String>) = identifier.referencesIdentifier(nameInSource)
fun isSamePointerDeref(other: Expression?): Boolean {
if(other==null || other !is PtrDereference)
return false
if(derefPointerValue != other.derefPointerValue)
return false
if(identifier.nameInSource != other.identifier.nameInSource)
return false
if(chain != other.chain)
return false
if(field != other.field)
return false
return true
}
} }
fun invertCondition(cond: Expression, program: Program): Expression { fun invertCondition(cond: Expression, program: Program): Expression {

View File

@@ -593,7 +593,6 @@ data class AssignTarget(
val multi: List<AssignTarget>?, val multi: List<AssignTarget>?,
val void: Boolean, val void: Boolean,
var pointerDereference: PtrDereference? = null, var pointerDereference: PtrDereference? = null,
var pointerIndexedDeref : PtrIndexedDereference? = null,
override val position: Position override val position: Position
) : Node { ) : Node {
override lateinit var parent: Node override lateinit var parent: Node
@@ -604,7 +603,6 @@ data class AssignTarget(
arrayindexed?.linkParents(this) arrayindexed?.linkParents(this)
memoryAddress?.linkParents(this) memoryAddress?.linkParents(this)
pointerDereference?.linkParents(this) pointerDereference?.linkParents(this)
pointerIndexedDeref?.linkParents(this)
multi?.forEach { it.linkParents(this) } multi?.forEach { it.linkParents(this) }
} }
@@ -614,22 +612,18 @@ data class AssignTarget(
identifier = null identifier = null
arrayindexed = null arrayindexed = null
pointerDereference = null pointerDereference = null
pointerIndexedDeref = null
when (replacement) { when (replacement) {
is IdentifierReference -> identifier = replacement is IdentifierReference -> identifier = replacement
is PtrDereference -> pointerDereference = replacement is PtrDereference -> pointerDereference = replacement
is PtrIndexedDereference -> pointerIndexedDeref = replacement
else -> throw FatalAstException("invalid replacement for AssignTarget.identifier: $replacement") else -> throw FatalAstException("invalid replacement for AssignTarget.identifier: $replacement")
} }
} }
node === arrayindexed -> { node === arrayindexed -> {
identifier = null identifier = null
pointerDereference = null pointerDereference = null
pointerIndexedDeref = null
arrayindexed = null arrayindexed = null
memoryAddress = null memoryAddress = null
when (replacement) { when (replacement) {
is PtrIndexedDereference -> pointerIndexedDeref = replacement
is ArrayIndexedExpression -> arrayindexed = replacement is ArrayIndexedExpression -> arrayindexed = replacement
is DirectMemoryWrite -> memoryAddress = replacement is DirectMemoryWrite -> memoryAddress = replacement
is PtrDereference -> pointerDereference = replacement is PtrDereference -> pointerDereference = replacement
@@ -651,7 +645,6 @@ data class AssignTarget(
multi?.toList(), multi?.toList(),
void, void,
pointerDereference?.copy(), pointerDereference?.copy(),
pointerIndexedDeref?.copy(),
position position
) )
override fun referencesIdentifier(nameInSource: List<String>): Boolean = override fun referencesIdentifier(nameInSource: List<String>): Boolean =
@@ -659,7 +652,6 @@ data class AssignTarget(
arrayindexed?.referencesIdentifier(nameInSource)==true || arrayindexed?.referencesIdentifier(nameInSource)==true ||
memoryAddress?.referencesIdentifier(nameInSource)==true || memoryAddress?.referencesIdentifier(nameInSource)==true ||
pointerDereference?.referencesIdentifier(nameInSource)==true || pointerDereference?.referencesIdentifier(nameInSource)==true ||
pointerIndexedDeref?.referencesIdentifier(nameInSource)==true ||
multi?.any { it.referencesIdentifier(nameInSource)}==true multi?.any { it.referencesIdentifier(nameInSource)}==true
fun inferType(program: Program): InferredTypes.InferredType { fun inferType(program: Program): InferredTypes.InferredType {
@@ -672,7 +664,6 @@ data class AssignTarget(
arrayindexed != null -> arrayindexed!!.inferType(program) arrayindexed != null -> arrayindexed!!.inferType(program)
memoryAddress != null -> InferredTypes.knownFor(BaseDataType.UBYTE) memoryAddress != null -> InferredTypes.knownFor(BaseDataType.UBYTE)
pointerDereference != null -> pointerDereference!!.inferType(program) pointerDereference != null -> pointerDereference!!.inferType(program)
pointerIndexedDeref != null -> pointerIndexedDeref!!.inferType(program)
else -> InferredTypes.unknown() // a multi-target has no 1 particular type else -> InferredTypes.unknown() // a multi-target has no 1 particular type
} }
} }
@@ -685,7 +676,6 @@ data class AssignTarget(
memoryAddress != null -> DirectMemoryRead(memoryAddress!!.addressExpression.copy(), memoryAddress!!.position) memoryAddress != null -> DirectMemoryRead(memoryAddress!!.addressExpression.copy(), memoryAddress!!.position)
multi != null -> throw FatalAstException("cannot turn a multi-assign into a single source expression") multi != null -> throw FatalAstException("cannot turn a multi-assign into a single source expression")
pointerDereference != null -> pointerDereference!!.copy() pointerDereference != null -> pointerDereference!!.copy()
pointerIndexedDeref != null -> pointerIndexedDeref!!.copy()
else -> throw FatalAstException("invalid assignment target") else -> throw FatalAstException("invalid assignment target")
} }
} }
@@ -700,12 +690,7 @@ data class AssignTarget(
false false
} }
identifier != null -> value is IdentifierReference && value.nameInSource == identifier!!.nameInSource identifier != null -> value is IdentifierReference && value.nameInSource == identifier!!.nameInSource
arrayindexed != null -> { arrayindexed != null -> value is ArrayIndexedExpression && arrayindexed!!.isSameArrayIndexedAs(value)
if(value is ArrayIndexedExpression && value.arrayvar.nameInSource == arrayindexed!!.arrayvar.nameInSource)
arrayindexed!!.indexer isSameAs value.indexer
else
false
}
multi != null -> false multi != null -> false
pointerDereference !=null -> { pointerDereference !=null -> {
if(value is PtrDereference) { if(value is PtrDereference) {
@@ -716,11 +701,6 @@ data class AssignTarget(
} }
return false return false
} }
pointerIndexedDeref !=null -> {
if(value is PtrIndexedDereference)
return pointerIndexedDeref!!.indexed == value.indexed
return false
}
else -> false else -> false
} }
} }
@@ -736,20 +716,19 @@ data class AssignTarget(
return addr1 != null && addr2 != null && addr1 == addr2 return addr1 != null && addr2 != null && addr1 == addr2
} }
this.arrayindexed != null && other.arrayindexed != null -> { this.arrayindexed != null && other.arrayindexed != null -> {
if (this.arrayindexed!!.arrayvar.nameInSource == other.arrayindexed!!.arrayvar.nameInSource) { if(this.arrayindexed!!.plainarrayvar!=null && this.arrayindexed!!.plainarrayvar?.nameInSource == other.arrayindexed!!.plainarrayvar?.nameInSource) {
val x1 = this.arrayindexed!!.indexer.constIndex() val x1 = this.arrayindexed!!.indexer.constIndex()
val x2 = other.arrayindexed!!.indexer.constIndex() val x2 = other.arrayindexed!!.indexer.constIndex()
return x1 != null && x2 != null && x1 == x2 return x1 != null && x2 != null && x1 == x2
} }
else if(this.pointerDereference != null && other.pointerDereference != null && this.pointerDereference!!.isSamePointerDeref(other.pointerDereference))
return true
else else
return false return false
} }
pointerDereference !=null && other.pointerDereference !=null -> { pointerDereference !=null && other.pointerDereference !=null -> {
return pointerDereference!! isSameAs other.pointerDereference!! return pointerDereference!! isSameAs other.pointerDereference!!
} }
pointerIndexedDeref !=null && other.pointerIndexedDeref !=null -> {
return pointerIndexedDeref!! isSameAs other.pointerIndexedDeref!!
}
this.multi != null && other.multi != null -> return this.multi == other.multi this.multi != null && other.multi != null -> return this.multi == other.multi
else -> return false else -> return false
} }
@@ -777,7 +756,8 @@ data class AssignTarget(
} }
} }
arrayIdx != null -> { arrayIdx != null -> {
val targetStmt = arrayIdx.arrayvar.targetVarDecl() if(arrayIdx.plainarrayvar!=null) {
val targetStmt = arrayIdx.plainarrayvar!!.targetVarDecl()
return if (targetStmt?.type == VarDeclType.MEMORY) { return if (targetStmt?.type == VarDeclType.MEMORY) {
val addr = targetStmt.value as? NumericLiteral val addr = targetStmt.value as? NumericLiteral
if (addr != null) if (addr != null)
@@ -786,6 +766,9 @@ data class AssignTarget(
false false
} else false } else false
} }
// can't really tell for the other types... assume false.
return false
}
ident != null -> { ident != null -> {
val decl = ident.targetVarDecl() ?: throw FatalAstException("invalid identifier ${ident.nameInSource}") val decl = ident.targetVarDecl() ?: throw FatalAstException("invalid identifier ${ident.nameInSource}")
return if (decl.type == VarDeclType.MEMORY && decl.value is NumericLiteral) return if (decl.type == VarDeclType.MEMORY && decl.value is NumericLiteral)

View File

@@ -106,7 +106,6 @@ abstract class AstWalker {
open fun before(containment: ContainmentCheck, parent: Node): Iterable<IAstModification> = noModifications open fun before(containment: ContainmentCheck, parent: Node): Iterable<IAstModification> = noModifications
open fun before(decl: VarDecl, parent: Node): Iterable<IAstModification> = noModifications open fun before(decl: VarDecl, parent: Node): Iterable<IAstModification> = noModifications
open fun before(deref: PtrDereference, parent: Node): Iterable<IAstModification> = noModifications open fun before(deref: PtrDereference, parent: Node): Iterable<IAstModification> = noModifications
open fun before(idxderef: PtrIndexedDereference, parent: Node): Iterable<IAstModification> = noModifications
open fun before(struct: StructDecl, parent: Node): Iterable<IAstModification> = noModifications open fun before(struct: StructDecl, parent: Node): Iterable<IAstModification> = noModifications
open fun before(field: StructFieldRef, parent: Node): Iterable<IAstModification> = noModifications open fun before(field: StructFieldRef, parent: Node): Iterable<IAstModification> = noModifications
open fun before(directive: Directive, parent: Node): Iterable<IAstModification> = noModifications open fun before(directive: Directive, parent: Node): Iterable<IAstModification> = noModifications
@@ -156,7 +155,6 @@ abstract class AstWalker {
open fun after(containment: ContainmentCheck, parent: Node): Iterable<IAstModification> = noModifications open fun after(containment: ContainmentCheck, parent: Node): Iterable<IAstModification> = noModifications
open fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> = noModifications open fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> = noModifications
open fun after(deref: PtrDereference, parent: Node): Iterable<IAstModification> = noModifications open fun after(deref: PtrDereference, parent: Node): Iterable<IAstModification> = noModifications
open fun after(idxderef: PtrIndexedDereference, parent: Node): Iterable<IAstModification> = noModifications
open fun after(struct: StructDecl, parent: Node): Iterable<IAstModification> = noModifications open fun after(struct: StructDecl, parent: Node): Iterable<IAstModification> = noModifications
open fun after(field: StructFieldRef, parent: Node): Iterable<IAstModification> = noModifications open fun after(field: StructFieldRef, parent: Node): Iterable<IAstModification> = noModifications
open fun after(directive: Directive, parent: Node): Iterable<IAstModification> = noModifications open fun after(directive: Directive, parent: Node): Iterable<IAstModification> = noModifications
@@ -438,7 +436,8 @@ abstract class AstWalker {
fun visit(arrayIndexedExpression: ArrayIndexedExpression, parent: Node) { fun visit(arrayIndexedExpression: ArrayIndexedExpression, parent: Node) {
track(before(arrayIndexedExpression, parent), arrayIndexedExpression, parent) track(before(arrayIndexedExpression, parent), arrayIndexedExpression, parent)
arrayIndexedExpression.arrayvar.accept(this, arrayIndexedExpression) arrayIndexedExpression.plainarrayvar?.accept(this, arrayIndexedExpression)
arrayIndexedExpression.pointerderef?.accept(this, arrayIndexedExpression)
arrayIndexedExpression.indexer.accept(this) arrayIndexedExpression.indexer.accept(this)
track(after(arrayIndexedExpression, parent), arrayIndexedExpression, parent) track(after(arrayIndexedExpression, parent), arrayIndexedExpression, parent)
} }
@@ -449,7 +448,6 @@ abstract class AstWalker {
assignTarget.identifier?.accept(this, assignTarget) assignTarget.identifier?.accept(this, assignTarget)
assignTarget.memoryAddress?.accept(this, assignTarget) assignTarget.memoryAddress?.accept(this, assignTarget)
assignTarget.pointerDereference?.accept(this, assignTarget) assignTarget.pointerDereference?.accept(this, assignTarget)
assignTarget.pointerIndexedDeref?.accept(this, assignTarget)
assignTarget.multi?.forEach { it.accept(this, assignTarget) } assignTarget.multi?.forEach { it.accept(this, assignTarget) }
track(after(assignTarget, parent), assignTarget, parent) track(after(assignTarget, parent), assignTarget, parent)
} }
@@ -539,11 +537,5 @@ abstract class AstWalker {
deref.identifier.accept(this, deref) deref.identifier.accept(this, deref)
track(after(deref, parent), deref, parent) track(after(deref, parent), deref, parent)
} }
fun visit(idxderef: PtrIndexedDereference, parent: Node) {
track(before(idxderef, parent), idxderef, parent)
idxderef.indexed.accept(this, idxderef)
track(after(idxderef, parent), idxderef, parent)
}
} }

View File

@@ -152,7 +152,8 @@ interface IAstVisitor {
} }
fun visit(arrayIndexedExpression: ArrayIndexedExpression) { fun visit(arrayIndexedExpression: ArrayIndexedExpression) {
arrayIndexedExpression.arrayvar.accept(this) arrayIndexedExpression.plainarrayvar?.accept(this)
arrayIndexedExpression.pointerderef?.accept(this)
arrayIndexedExpression.indexer.accept(this) arrayIndexedExpression.indexer.accept(this)
} }
@@ -161,7 +162,6 @@ interface IAstVisitor {
assignTarget.identifier?.accept(this) assignTarget.identifier?.accept(this)
assignTarget.memoryAddress?.accept(this) assignTarget.memoryAddress?.accept(this)
assignTarget.pointerDereference?.accept(this) assignTarget.pointerDereference?.accept(this)
assignTarget.pointerIndexedDeref?.accept(this)
assignTarget.multi?.forEach { it.accept(this) } assignTarget.multi?.forEach { it.accept(this) }
} }
@@ -218,8 +218,4 @@ interface IAstVisitor {
fun visit(deref: PtrDereference) { fun visit(deref: PtrDereference) {
deref.identifier.accept(this) deref.identifier.accept(this)
} }
fun visit(idxderef: PtrIndexedDereference) {
idxderef.indexed.accept(this)
}
} }

View File

@@ -1,6 +1,8 @@
TODO TODO
==== ====
Something changed in array/string/uword indexing codegen? Assem became bigger, rockrunner too.
STRUCTS and TYPED POINTERS STRUCTS and TYPED POINTERS
-------------------------- --------------------------
@@ -56,8 +58,8 @@ STRUCTS and TYPED POINTERS
- fix ptr problems in re.p8 and unit tests - fix ptr problems in re.p8 and unit tests
- add unit tests for expected AST elements for all syntaxes dealing with pointers, dereference(chain), derefs, and indexing (both as value and assigntargets) - add unit tests for expected AST elements for all syntaxes dealing with pointers, dereference(chain), derefs, and indexing (both as value and assigntargets)
- clean up pointerdereference in the grammar, regarding dealing with final ^^ or not - clean up pointerdereference in the grammar, regarding dealing with final ^^ or not
- Can we now get rid of PtPointerIndexedDeref ? Both for expression (value) as assigntarget? All code for translate(idxderef: PtPointerIndexedDeref) in ExpressionGen?
- why does PtrDereference have both identifier and chain property? what goes where? is the distinction needed? - why does PtrDereference have both identifier and chain property? what goes where? is the distinction needed?
- why does PtrDereference have both chain and field property? what goes where? is the distinction needed?
- add unit tests for all changes (pointers and structs) - add unit tests for all changes (pointers and structs)
- 6502 codegen: remove checks in checkForPointerTypesOn6502() - 6502 codegen: remove checks in checkForPointerTypesOn6502()
- 6502 codegen should warn about writing to initialized struct instances when using romable code, like with arrays "can only be used as read-only in ROMable code" - 6502 codegen should warn about writing to initialized struct instances when using romable code, like with arrays "can only be used as read-only in ROMable code"

View File

@@ -2,15 +2,20 @@ main {
struct List { struct List {
^^uword s ^^uword s
ubyte n ubyte n
^^List next
} }
sub start() { sub start() {
^^List l1 = List() ^^List l1 = List()
^^List l2 = List() ^^word @shared wptr
l1.s[2] = 1
l2.n=10
^^List l3 = List() cx16.r1 = l1.s^^
cx16.r0L = l3.next.n cx16.r0 = l1.s[0]
cx16.r2 = l1^^.s^^
l1.s[0] = 4242
cx16.r1 = l1.s^^
cx16.r0s = wptr[0]
cx16.r1s = wptr^^
wptr[0] = 4242
} }
} }

View File

@@ -187,7 +187,6 @@ assign_target:
| arrayindexed #ArrayindexedTarget | arrayindexed #ArrayindexedTarget
| directmemory #MemoryTarget | directmemory #MemoryTarget
| pointerdereference #PointerDereferenceTarget | pointerdereference #PointerDereferenceTarget
| pointerindexedderef #PointerIndexedDerefTarget
| VOID #VoidTarget | VOID #VoidTarget
; ;
@@ -225,7 +224,6 @@ expression :
| expression typecast | expression typecast
| if_expression | if_expression
| pointerdereference | pointerdereference
| pointerindexedderef
; ;
arrayindexed: arrayindexed:
@@ -339,9 +337,6 @@ derefchain : singlederef ('.' singlederef)* ;
singlederef : identifier POINTER ; singlederef : identifier POINTER ;
pointerindexedderef : arrayindexed POINTER ;
branch_stmt : branchcondition EOL? (statement | statement_block) EOL? else_part? ; branch_stmt : branchcondition EOL? (statement | statement_block) EOL? else_part? ;
branchcondition: 'if_cs' | 'if_cc' | 'if_eq' | 'if_z' | 'if_ne' | 'if_nz' | 'if_pl' | 'if_pos' | 'if_mi' | 'if_neg' | 'if_vs' | 'if_vc' ; branchcondition: 'if_cs' | 'if_cc' | 'if_eq' | 'if_z' | 'if_ne' | 'if_nz' | 'if_pl' | 'if_pos' | 'if_mi' | 'if_neg' | 'if_vs' | 'if_vc' ;

View File

@@ -116,7 +116,6 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
is PtRange -> true is PtRange -> true
is PtString -> true is PtString -> true
is PtPointerDeref -> this.startpointer.isSimple() && this.field==null && this.chain.isEmpty() is PtPointerDeref -> this.startpointer.isSimple() && this.field==null && this.chain.isEmpty()
is PtPointerIndexedDeref -> this.index.isSimple()
is PtTypeCast -> value.isSimple() is PtTypeCast -> value.isSimple()
is PtIfExpression -> condition.isSimple() && truevalue.isSimple() && falsevalue.isSimple() is PtIfExpression -> condition.isSimple() && truevalue.isSimple() && falsevalue.isSimple()
} }
@@ -418,16 +417,6 @@ class PtPointerDeref(type: DataType, val chain: List<String>, val field: String?
} }
} }
class PtPointerIndexedDeref(type: DataType, position: Position) : PtExpression(type, position) {
val variable: PtIdentifier
get() = children[0] as PtIdentifier
val index: PtExpression
get() = children[1] as PtExpression
init {
require(!type.isUndefined)
}
}
// special node that isn't created from compiling user code, but used internally in the Intermediate Code // special node that isn't created from compiling user code, but used internally in the Intermediate Code
class PtIrRegister(val register: Int, type: DataType, position: Position) : PtExpression(type, position) class PtIrRegister(val register: Int, type: DataType, position: Position) : PtExpression(type, position)

View File

@@ -193,9 +193,6 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni
val field = if(node.field==null) "" else ".${node.field}" val field = if(node.field==null) "" else ".${node.field}"
"deref {child} $chain $field ${type(node.type)}" "deref {child} $chain $field ${type(node.type)}"
} }
is PtPointerIndexedDeref -> {
"idxderef {child} ${type(node.type)}"
}
} }
} }

View File

@@ -124,8 +124,6 @@ class PtAssignTarget(val void: Boolean, position: Position) : PtNode(position) {
get() = children.single() as? PtMemoryByte get() = children.single() as? PtMemoryByte
val pointerDeref: PtPointerDeref? val pointerDeref: PtPointerDeref?
get() = children.single() as? PtPointerDeref get() = children.single() as? PtPointerDeref
val pointerIndexedDeref: PtPointerIndexedDeref?
get() = children.single() as? PtPointerIndexedDeref
val type: DataType val type: DataType
get() { get() {
@@ -134,7 +132,6 @@ class PtAssignTarget(val void: Boolean, position: Position) : PtNode(position) {
is PtArrayIndexer -> tgt.type is PtArrayIndexer -> tgt.type
is PtMemoryByte -> tgt.type is PtMemoryByte -> tgt.type
is PtPointerDeref -> tgt.type is PtPointerDeref -> tgt.type
is PtPointerIndexedDeref -> tgt.type
else -> throw AssemblyError("weird target $tgt") else -> throw AssemblyError("weird target $tgt")
} }
} }