mirror of
https://github.com/irmen/prog8.git
synced 2026-04-24 21:17:10 +00:00
fix ptr errors
This commit is contained in:
@@ -1678,7 +1678,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
}
|
||||
if(targetPointerDeref.field!=null) {
|
||||
val fieldinfo = struct!!.getField(targetPointerDeref.field!!, codeGen.program.memsizer)
|
||||
require(fieldinfo.first == targetPointerDeref.type)
|
||||
require(fieldinfo.first == targetPointerDeref.type) {
|
||||
"field type mismatch: expected ${targetPointerDeref.type}, got ${fieldinfo.first} ${targetPointerDeref.position}"
|
||||
}
|
||||
if(fieldinfo.second>0u) {
|
||||
// add the field offset
|
||||
addInstr(result, IRInstruction(Opcode.ADD, IRDataType.WORD, reg1 = pointerReg, immediate = fieldinfo.second.toInt()), null)
|
||||
|
||||
@@ -437,13 +437,13 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr
|
||||
// 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, arrayIndexedExpression.position)
|
||||
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, arrayIndexedExpression.position)
|
||||
val deref = PtrDereference(arrayIndexedExpression.arrayvar, emptyList(), null, true,arrayIndexedExpression.position)
|
||||
return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, deref, parent))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1351,15 +1351,14 @@ internal class AstChecker(private val program: Program,
|
||||
if(leftDt.isPointer) {
|
||||
val struct = (leftDt.getOrUndef().subType as? StructDecl)
|
||||
if(struct!=null) {
|
||||
if (rightIdentifier.nameInSource.size > 1) {
|
||||
TODO("astcheck ${struct.name} . $rightIdentifier at ${expr.position}")
|
||||
if (rightIdentifier.nameInSource.size == 1) {
|
||||
val fieldDt = struct.getFieldType(rightIdentifier.nameInSource.single())
|
||||
if (fieldDt == null)
|
||||
errors.err(
|
||||
"no such field '${rightIdentifier.nameInSource.single()}' in struct '${struct.name}'",
|
||||
rightIdentifier.position
|
||||
)
|
||||
}
|
||||
val fieldDt = struct.getFieldType(rightIdentifier.nameInSource.single())
|
||||
if (fieldDt == null)
|
||||
errors.err(
|
||||
"no such field '${rightIdentifier.nameInSource.single()}' in struct '${struct.name}'",
|
||||
rightIdentifier.position
|
||||
)
|
||||
}
|
||||
} else
|
||||
errors.err("cannot find struct type", expr.left.position)
|
||||
|
||||
@@ -399,8 +399,8 @@ _after:
|
||||
if(parent is PtrIndexedDereference || parent.parent is PtrIndexedDereference)
|
||||
return noModifications
|
||||
|
||||
if(identifier.nameInSource.size>1 && identifier.targetStatement()==null) {
|
||||
// the a.b.c.d could be a pointer dereference chain a^^.b^^^.c^^^.d
|
||||
if(identifier.targetStatement()==null) {
|
||||
// the a.b.c.d could be a pointer dereference chain a^^.b^^.c^^.d
|
||||
for(i in identifier.nameInSource.size-1 downTo 1) {
|
||||
val symbol = identifier.definingScope.lookup(identifier.nameInSource.take(i)) as? VarDecl
|
||||
if(symbol!=null) {
|
||||
@@ -431,8 +431,8 @@ _after:
|
||||
}
|
||||
val deref = PtrIndexedDereference(parent, parent.position)
|
||||
return listOf(IAstModification.ReplaceNode(parent, deref, parent.parent))
|
||||
} else {
|
||||
val deref = PtrDereference(IdentifierReference(identifier.nameInSource.take(i), identifier.position), chain, field, identifier.position)
|
||||
} else if (parent !is PtrDereference) {
|
||||
val deref = PtrDereference(IdentifierReference(identifier.nameInSource.take(i), identifier.position), chain, field, false, identifier.position)
|
||||
return listOf(IAstModification.ReplaceNode(identifier, deref, parent))
|
||||
}
|
||||
}
|
||||
@@ -508,17 +508,17 @@ _after:
|
||||
}
|
||||
}
|
||||
|
||||
if(deref.chain.isEmpty() && deref.field==null) {
|
||||
val expr = deref.parent as? BinaryExpression
|
||||
if (expr != null && expr.operator == ".") {
|
||||
if (expr.left is IdentifierReference && expr.right === deref) {
|
||||
// replace (a) . (b^^) by (a.b)^^
|
||||
val identifier = IdentifierReference((expr.left as IdentifierReference).nameInSource + deref.identifier.nameInSource, expr.left.position)
|
||||
val replacement = PtrDereference(identifier, emptyList(), null, deref.position)
|
||||
return listOf(IAstModification.ReplaceNode(expr, replacement, expr.parent))
|
||||
}
|
||||
val expr = deref.parent as? BinaryExpression
|
||||
if (expr != null && expr.operator == ".") {
|
||||
if (expr.left is IdentifierReference && expr.right === deref) {
|
||||
// replace (a) . (b^^) by (a.b)^^
|
||||
val name = (expr.left as IdentifierReference).nameInSource + deref.identifier.nameInSource
|
||||
val identifier = IdentifierReference(name, expr.left.position)
|
||||
val replacement = PtrDereference(identifier, deref.chain, deref.field, deref.derefPointerValue, deref.position)
|
||||
return listOf(IAstModification.ReplaceNode(expr, replacement, expr.parent))
|
||||
}
|
||||
}
|
||||
|
||||
return noModifications
|
||||
}
|
||||
|
||||
|
||||
@@ -421,4 +421,63 @@ main {
|
||||
dr5.chain.size shouldBe 0
|
||||
dr5.field shouldBe null
|
||||
}
|
||||
|
||||
test("global and local pointer vars") {
|
||||
val src="""
|
||||
main {
|
||||
^^uword g_wptr
|
||||
|
||||
sub start() {
|
||||
^^uword l_wptr
|
||||
|
||||
cx16.r0 = g_wptr
|
||||
cx16.r1 = g_wptr^^
|
||||
cx16.r0 = l_wptr
|
||||
cx16.r1 = l_wptr^^
|
||||
}
|
||||
}"""
|
||||
compileText(VMTarget(), true, src, outputDir) shouldNotBe null
|
||||
}
|
||||
|
||||
test("global struct var deref type") {
|
||||
val src="""
|
||||
main {
|
||||
struct State {
|
||||
uword c
|
||||
^^uword ptr
|
||||
}
|
||||
|
||||
^^State matchstate
|
||||
|
||||
sub start() {
|
||||
cx16.r0 = matchstate.ptr
|
||||
cx16.r1 = matchstate.ptr^^
|
||||
cx16.r2 = matchstate^^.ptr^^ ; equivalent to previous
|
||||
cx16.r3 = matchstate.c
|
||||
}
|
||||
}"""
|
||||
|
||||
compileText(VMTarget(), true, src, outputDir) shouldNotBe null
|
||||
}
|
||||
|
||||
|
||||
test("local struct var deref type") {
|
||||
val src="""
|
||||
main {
|
||||
struct State {
|
||||
uword c
|
||||
^^uword ptr
|
||||
}
|
||||
|
||||
sub start() {
|
||||
^^State matchstate
|
||||
cx16.r0 = matchstate.ptr
|
||||
cx16.r1 = matchstate.ptr^^
|
||||
cx16.r2 = matchstate^^.ptr^^ ; equivalent to previous
|
||||
cx16.r3 = matchstate.c
|
||||
}
|
||||
}"""
|
||||
|
||||
compileText(VMTarget(), true, src, outputDir) shouldNotBe null
|
||||
}
|
||||
})
|
||||
@@ -689,16 +689,10 @@ private fun PointerdereferenceContext.toAst(): PtrDereference {
|
||||
IdentifierReference(scopeprefix.nameInSource + derefchain.first(), toPosition())
|
||||
else
|
||||
IdentifierReference(listOf(derefchain.first()), toPosition())
|
||||
return PtrDereference(firstIdentifier, derefchain.drop(1), field?.text, toPosition())
|
||||
val actualDereference = field==null
|
||||
return PtrDereference(firstIdentifier, derefchain.drop(1), field?.text, actualDereference, toPosition())
|
||||
}
|
||||
|
||||
/* TODO:
|
||||
private fun SinglederefContext.toAst(): Pair<String, ArrayIndex?> {
|
||||
val ident = identifier()!!.name()
|
||||
val index = arrayindex()?.toAst()
|
||||
return ident to index
|
||||
}*/
|
||||
|
||||
private fun CharliteralContext.toAst(): CharLiteral {
|
||||
val text = this.SINGLECHAR().text
|
||||
val enc = this.encoding?.text
|
||||
|
||||
@@ -1630,8 +1630,10 @@ class PtrIndexedDereference(val indexed: ArrayIndexedExpression, override val po
|
||||
}
|
||||
val vardecl = indexed.arrayvar.targetVarDecl()
|
||||
if(vardecl!=null &&vardecl.datatype.isPointer) {
|
||||
if(vardecl.datatype.sub!=null)
|
||||
if(vardecl.datatype.sub!=null) {
|
||||
TODO("is this type correct?")
|
||||
return InferredTypes.knownFor(vardecl.datatype.dereference())
|
||||
}
|
||||
TODO("cannot determine type of dereferenced indexed pointer(?) that is not a pointer to a basic type")
|
||||
}
|
||||
|
||||
@@ -1641,7 +1643,10 @@ class PtrIndexedDereference(val indexed: ArrayIndexedExpression, override val po
|
||||
dt.isUndefined -> InferredTypes.unknown()
|
||||
dt.isUnsignedWord -> InferredTypes.knownFor(BaseDataType.UBYTE)
|
||||
dt.isPointer -> {
|
||||
return if(dt.sub!=null) InferredTypes.knownFor(dt.dereference())
|
||||
return if(dt.sub!=null) {
|
||||
TODO("is this type correct?")
|
||||
InferredTypes.knownFor(dt.dereference())
|
||||
}
|
||||
else InferredTypes.unknown()
|
||||
}
|
||||
else -> InferredTypes.unknown()
|
||||
@@ -1656,7 +1661,13 @@ class PtrIndexedDereference(val indexed: ArrayIndexedExpression, override val po
|
||||
override fun referencesIdentifier(nameInSource: List<String>) = indexed.referencesIdentifier(nameInSource)
|
||||
}
|
||||
|
||||
class PtrDereference(val identifier: IdentifierReference, val chain: List<String>, val field: String?, override val position: Position) : Expression() {
|
||||
class PtrDereference(
|
||||
val identifier: IdentifierReference,
|
||||
val chain: List<String>,
|
||||
val field: String?,
|
||||
val derefPointerValue: Boolean,
|
||||
override val position: Position
|
||||
) : Expression() {
|
||||
// TODO why both identifier and chain?
|
||||
|
||||
override lateinit var parent: Node
|
||||
@@ -1666,17 +1677,26 @@ class PtrDereference(val identifier: IdentifierReference, val chain: List<String
|
||||
identifier.linkParents(this)
|
||||
}
|
||||
|
||||
init {
|
||||
if(field==null) require(derefPointerValue)
|
||||
if(field!=null) require(!derefPointerValue)
|
||||
}
|
||||
|
||||
override val isSimple = false
|
||||
override fun copy(): PtrDereference = PtrDereference(identifier.copy(), chain.toList(), field, position)
|
||||
override fun copy(): PtrDereference = PtrDereference(identifier.copy(), chain.toList(), field, derefPointerValue, 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 {
|
||||
|
||||
fun resultType(dt: DataType?) = if(dt==null) InferredTypes.unknown() else InferredTypes.knownFor(if(derefPointerValue) dt.dereference() else dt)
|
||||
|
||||
val first = identifier.targetStatement()
|
||||
if(first==null)
|
||||
return InferredTypes.unknown()
|
||||
if(first is StructFieldRef) {
|
||||
return InferredTypes.knownFor(first.type.dereference())
|
||||
require(chain.isEmpty() && field==null)
|
||||
return resultType(first.type)
|
||||
}
|
||||
val vardecl = identifier.targetVarDecl()
|
||||
if(vardecl==null || vardecl.datatype.isUndefined || (!vardecl.datatype.isPointer && !vardecl.datatype.isStructInstance) )
|
||||
@@ -1684,16 +1704,12 @@ class PtrDereference(val identifier: IdentifierReference, val chain: List<String
|
||||
|
||||
if(chain.isEmpty()) {
|
||||
return if(field==null) {
|
||||
require(vardecl.datatype.sub!=null) { "can only dereference a pointer to a simple datatype " }
|
||||
InferredTypes.knownFor(vardecl.datatype.dereference())
|
||||
resultType(vardecl.datatype)
|
||||
} else {
|
||||
// lookup struct field type
|
||||
val struct = vardecl.datatype.subType as StructDecl
|
||||
val fieldDt = struct.getFieldType(field)
|
||||
if (fieldDt == null)
|
||||
InferredTypes.unknown()
|
||||
else
|
||||
InferredTypes.knownFor(fieldDt.dereference())
|
||||
resultType(fieldDt)
|
||||
}
|
||||
} else {
|
||||
// lookup type of field at the end of a dereference chain
|
||||
@@ -1707,17 +1723,16 @@ class PtrDereference(val identifier: IdentifierReference, val chain: List<String
|
||||
struct = fieldDt.subType as StructDecl
|
||||
}
|
||||
if(field==null) {
|
||||
TODO("is this type correct?")
|
||||
return InferredTypes.knownFor(DataType.structInstance(struct))
|
||||
}
|
||||
val fieldDt = struct.getFieldType(field)
|
||||
return if(fieldDt==null)
|
||||
InferredTypes.unknown()
|
||||
else
|
||||
InferredTypes.knownFor(fieldDt.dereference())
|
||||
return resultType(fieldDt)
|
||||
}
|
||||
}
|
||||
|
||||
override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here")
|
||||
override fun replaceChildNode(node: Node, replacement: Node) =
|
||||
throw FatalAstException("can't replace here")
|
||||
override fun referencesIdentifier(nameInSource: List<String>) = identifier.referencesIdentifier(nameInSource)
|
||||
}
|
||||
|
||||
|
||||
@@ -136,7 +136,8 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
||||
allIdentifiersAndTargets.add(identifier to scopeTarget)
|
||||
break
|
||||
} else if(scopeTarget is StructFieldRef) {
|
||||
TODO("register struct field ref in callgraph? $scopeTarget")
|
||||
allIdentifiersAndTargets.add(identifier to scopeTarget)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ STRUCTS and TYPED POINTERS
|
||||
- DONE: what about static initialization of an array of struct pointers? -> impossible right now because the pointer values are not constants.
|
||||
- DONE: make typeForAddressOf() be even more specific about the typed pointers it returns for the address-of operator.
|
||||
- fix ptr problems in re.p8
|
||||
- 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?
|
||||
- add unit tests for all changes (pointers and structs)
|
||||
|
||||
+8
-8
@@ -1,12 +1,12 @@
|
||||
main {
|
||||
struct List {
|
||||
^^uword s
|
||||
ubyte n
|
||||
}
|
||||
^^uword g_wptr
|
||||
|
||||
sub start() {
|
||||
^^List l1 = List()
|
||||
cx16.r1 = l1.s^^
|
||||
^^uword l_wptr
|
||||
|
||||
cx16.r0 = g_wptr
|
||||
cx16.r1 = g_wptr^^
|
||||
cx16.r0 = l_wptr
|
||||
cx16.r1 = l_wptr^^
|
||||
}
|
||||
}
|
||||
|
||||
; TODO also fix the compilation error in re.p8
|
||||
|
||||
@@ -333,12 +333,11 @@ if_expression : 'if' expression EOL? expression EOL? ELSE EOL? expression ;
|
||||
// but it is needed for now to not have to rewrite all of Prog8's dependence on how the IdentifierReference now works (fully qualified identifier string inside)
|
||||
// in the future this probably has to be reworked completely to split up the scoped identifier names and just rely on the '.' operator exclusively,
|
||||
// but that also requires rewriting al name lookup code. Ah well, we'll cross that bridge when we get there.
|
||||
pointerdereference: (prefix = scoped_identifier '.')? derefchain ('.' field = identifier)? ;
|
||||
pointerdereference: (prefix = scoped_identifier '.')? derefchain ('.' field = identifier)? ; // TODO this doesn't look pretty when dealing with the difference between a final ^^ at the end or not
|
||||
|
||||
derefchain : singlederef ('.' singlederef)* ;
|
||||
|
||||
singlederef : identifier POINTER ;
|
||||
// TODO singlederef : identifier arrayindex? POINTER ;
|
||||
|
||||
pointerindexedderef : arrayindexed POINTER ;
|
||||
|
||||
|
||||
@@ -414,7 +414,7 @@ class PtPointerDeref(type: DataType, val chain: List<String>, val field: String?
|
||||
get() = children.single() as PtExpression
|
||||
|
||||
init {
|
||||
require(!type.isUndefined && !type.isPointer) { "no support for pointer to pointer" }
|
||||
require(!type.isUndefined)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user