@(..) now also accepts pointer to ubyte address

This commit is contained in:
Irmen de Jong
2025-05-15 20:07:02 +02:00
parent f4b2264fcf
commit 86eef7039f
6 changed files with 82 additions and 22 deletions

View File

@@ -1970,15 +1970,8 @@ internal class AstChecker(private val program: Program,
}
override fun visit(memread: DirectMemoryRead) {
if(!(memread.addressExpression.inferType(program) issimpletype BaseDataType.UWORD)) {
errors.err("address for memory access isn't uword", memread.position)
}
val tc = memread.addressExpression as? TypecastExpression
if(tc!=null && tc.implicit) {
if(!(tc.expression.inferType(program) issimpletype BaseDataType.UWORD)) {
errors.err("address for memory access isn't uword", memread.position)
}
}
if(!allowedMemoryAccessAddressExpression(memread.addressExpression, program))
errors.err("invalid address type for memory access", memread.position)
val pointervar = memread.addressExpression as? IdentifierReference
if(pointervar!=null)
@@ -1990,16 +1983,22 @@ internal class AstChecker(private val program: Program,
super.visit(memread)
}
override fun visit(memwrite: DirectMemoryWrite) {
if(!(memwrite.addressExpression.inferType(program) issimpletype BaseDataType.UWORD)) {
errors.err("address for memory access isn't uword", memwrite.position)
}
val tc = memwrite.addressExpression as? TypecastExpression
private fun allowedMemoryAccessAddressExpression(addressExpression: Expression, program: Program): Boolean {
val dt = addressExpression.inferType(program)
if(dt.isUnsignedWord || (dt.isPointer && dt.getOrUndef().sub==BaseDataType.UBYTE))
return true
val tc = addressExpression as? TypecastExpression
if(tc!=null && tc.implicit) {
if(!(tc.expression.inferType(program) issimpletype BaseDataType.UWORD)) {
errors.err("address for memory access isn't uword", memwrite.position)
}
val dt = tc.expression.inferType(program)
if(dt.isUnsignedWord || (dt.isPointer && dt.getOrUndef().sub==BaseDataType.UBYTE))
return true
}
return false
}
override fun visit(memwrite: DirectMemoryWrite) {
if(!allowedMemoryAccessAddressExpression(memwrite.addressExpression, program))
errors.err("invalid address type for memory access", memwrite.position)
val pointervar = memwrite.addressExpression as? IdentifierReference
if(pointervar!=null)
@@ -2355,8 +2354,10 @@ internal class AstChecker(private val program: Program,
if(sourceDatatype.isPointer) {
if(!(sourceDatatype isAssignableTo targetDatatype))
errors.err("cannot assign different pointer type", position)
} else if(sourceDatatype.isString && targetDatatype.sub?.isByte==true) {
// assigning a string to a byte pointer is allowed.
} else if(!sourceDatatype.isUnsignedWord && !sourceDatatype.isStructInstance)
errors.err("can only assign uword or correct pointer type to a pointer", position)
errors.err("incompatible value type, can only assign uword or correct pointer type", position)
}
else if(targetDatatype.isString && sourceDatatype.isUnsignedWord)
errors.err("can't assign uword to str. If the source is a string pointer and you actually want to overwrite the target string, use an explicit strings.copy(src,tgt) instead.", position)

View File

@@ -26,6 +26,7 @@ internal class CodeDesugarer(val program: Program, private val target: ICompilat
// - remove alias nodes
// - convert on..goto/call to jumpaddr array and separate goto/call
// - replace implicit pointer dereference chains (a.b.c.d) with explicit ones (a^^.b^^.c^^.d)
// - replace ptr^^ by @(ptr) if ptr is just an uword.
override fun after(alias: Alias, parent: Node): Iterable<IAstModification> {
return listOf(IAstModification.Remove(alias, parent as IStatementContainer))
@@ -451,4 +452,17 @@ _after:
, ongoto.position)
return listOf(IAstModification.ReplaceNode(ongoto, replacementScope, parent))
}
override fun after(deref: PtrDereference, parent: Node): Iterable<IAstModification> {
// TODO what about DirectMemoryWrite ?? (LHS of assignment?)
if(deref.field==null && deref.chain.isEmpty()) {
val varDt = deref.identifier.targetVarDecl()?.datatype
if(varDt?.isUnsignedWord==true || (varDt?.isPointer==true && varDt.sub==BaseDataType.UBYTE)) {
// replace ptr^^ by @(ptr) when ptr is uword or ^^byte
val memread = DirectMemoryRead(deref.identifier, deref.position)
return listOf(IAstModification.ReplaceNode(deref, memread, parent))
}
}
return noModifications
}
}

View File

@@ -243,7 +243,7 @@ main {
compileText(VMTarget(), false, src, outputDir, errors=errors)
val err = errors.errors
err.size shouldBe 1
err[0] shouldContain("15:16: can only assign uword or correct pointer type to a pointer")
err[0] shouldContain("15:16: incompatible value type, can only assign uword or correct pointer")
}
})

View File

@@ -131,7 +131,7 @@ main {
val errors = ErrorReporterForTests()
compileText(C64Target(), false, text, outputDir, writeAssembly = true, errors = errors)
errors.errors.size shouldBe 2
errors.errors[0] shouldContain "isn't uword"
errors.errors[0] shouldContain "invalid address type"
errors.errors[1] shouldContain "undefined symbol: doesnotexist"
}

View File

@@ -44,8 +44,10 @@ STRUCTS and TYPED POINTERS
- DONE: existing ARRAY type remains unchanged (it doesn't become a typed pointer) so we can keep doing register-indexed LDA array,Y addressing directly on them.
- DONE: passing STR to a subroutine: parameter type becomes ^^UBYTE (rather than UWORD) (we still lose the bounds check)
- DONE: passing ARRAY to a subroutine: parameter type becomes ^^ElementDt (rather than UWORD) (we still lose the bounds check)
- DONE: @(ptr) complains that ptr is not uword when ptr is ^^ubyte (should be allowed)
- fix actual _msb/_lsb storage of the split-words pointer-arrays
- STR should be asssignment compatible with UBYTE^^ but local scoped STR should still be accessed directly using LDA str,Y instead of through the pointer, like arrays.
- what about uword^^ -> @(uword) when it's assignment target (LHS)?
- make typeForAddressOf() be even more specific about the typed pointers it returns for the address-of operator. + unit test. Needs fixes in 6502 codegen too though... (also recheck passing STR and ARRAY types to subroutines)
- fixing the pointer dereferencing issues (cursed hybrid beween IdentifierReference, PtrDereferece and PtrIndexedDereference) may require getting rid of scoped identifiers altogether and treat '.' as a "scope or pointer following operator"
- (later, nasty parser problem:) support chaining pointer dereference on function calls that return a pointer. (type checking now fails on stuff like func().field and func().next.field)

View File

@@ -10,9 +10,25 @@ main {
word[] @nosplit values = [111,222,-999,-888]
stringinfo("hello")
^^byte @shared bptr
^^ubyte @shared ubptr
str name = "irmen"
stringinfo1("hello")
stringinfo2(name)
stringinfo3("apple")
arrayinfo(values)
arrayinfo(&values[2])
bptr = name
ubptr = name
txt.print_uw(&name)
txt.spc()
txt.print_uw(bptr)
txt.spc()
txt.print_uw(ubptr)
txt.nl()
}
sub info(^^thing.Node node) {
@@ -32,7 +48,8 @@ main {
txt.nl()
}
sub stringinfo(^^ubyte message) {
sub stringinfo1(^^ubyte message) {
txt.print("string1: ")
txt.print_uw(message)
txt.spc()
txt.print(message)
@@ -44,6 +61,32 @@ main {
txt.nl()
}
sub stringinfo2(str message) {
txt.print("string2: ")
txt.print_uw(message)
txt.spc()
txt.print(message)
txt.spc()
do {
txt.chrout(message^^)
message++
} until message^^==0
txt.nl()
}
sub stringinfo3(uword message) {
txt.print("string3: ")
txt.print_uw(message)
txt.spc()
txt.print(message)
txt.spc()
do {
txt.chrout(message^^) ; equivalent to @(message) in this case
message++
} until message^^==0 ; equivalent to @(message) in this case
txt.nl()
}
sub arrayinfo(^^word valueptr) {
txt.print_uw(valueptr)
txt.spc()