This commit is contained in:
Irmen de Jong
2025-05-18 17:50:49 +02:00
parent 6d4ccc5feb
commit adf5600a9b
10 changed files with 65 additions and 71 deletions

View File

@@ -84,7 +84,11 @@ class DataType private constructor(val base: BaseDataType, val sub: BaseDataType
}
base==BaseDataType.STR -> require(sub==BaseDataType.UBYTE) { "string subtype should be ubyte" }
base!=BaseDataType.POINTER -> require(sub == null) { "only string, array and pointer base types can have a subtype"}
else -> require(sub == null || (subType == null && subTypeFromAntlr == null)) { "sub and subtype can't both be set" }
else -> {
require(sub == null || (subType == null && subTypeFromAntlr == null)) {
"sub and subtype can't both be set"
}
}
}
}
@@ -144,15 +148,21 @@ class DataType private constructor(val base: BaseDataType, val sub: BaseDataType
}
}
fun arrayOfPointersTo(sub: BaseDataType?, subType: ISubType?): DataType =
DataType(BaseDataType.ARRAY_POINTER, sub, subType)
fun arrayOfPointersTo(sub: BaseDataType): DataType = DataType(BaseDataType.ARRAY_POINTER, sub, null)
fun arrayOfPointersTo(structType: ISubType?): DataType = DataType(BaseDataType.ARRAY_POINTER, null, structType)
fun arrayOfPointersFromAntlrTo(sub: BaseDataType?, identifier: List<String>?): DataType =
DataType(BaseDataType.ARRAY_POINTER, sub, null, identifier)
fun pointer(base: BaseDataType): DataType = DataType(BaseDataType.POINTER, base, null)
fun pointerToType(type: ISubType): DataType = DataType(BaseDataType.POINTER, null, type)
fun structInstance(type: ISubType?): DataType = DataType(BaseDataType.STRUCT_INSTANCE, sub=null, type)
fun pointer(dt: DataType): DataType {
if(dt.isBasic)
return DataType(BaseDataType.POINTER, dt.base, null)
else
return DataType(BaseDataType.POINTER, null, dt.subType, dt.subTypeFromAntlr)
}
fun pointer(structType: ISubType): DataType = DataType(BaseDataType.POINTER, null, structType, null)
fun pointerFromAntlr(identifier: List<String>): DataType = DataType(BaseDataType.POINTER, null, null, identifier)
fun structInstance(type: ISubType?): DataType = DataType(BaseDataType.STRUCT_INSTANCE, sub=null, type)
fun structInstanceFromAntlr(struct: List<String>): DataType = DataType(BaseDataType.STRUCT_INSTANCE, null, null, subTypeFromAntlr = struct)
}
@@ -184,10 +194,10 @@ class DataType private constructor(val base: BaseDataType, val sub: BaseDataType
return pointer(BaseDataType.UBYTE)
val elementDt = elementType()
require(elementDt.isBasic)
return pointer(elementDt.base)
return pointer(elementDt)
}
if (subType != null)
return pointerToType(subType!!)
return pointer(this)
return UWORD
}
}

View File

@@ -98,25 +98,28 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
}
private fun translate(idxderef: PtPointerIndexedDeref): ExpressionCodeResult {
val idx = idxderef.indexer
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>()
val pointerTr = translateExpression(idx.variable)
result += pointerTr.chunks
val pointerReg = pointerTr.resultReg
val constIndex = idx.index.asConstInteger()
if(!idxderef.variable.type.isPointer) {
TODO("expression: indexing non-pointer field ${idxderef.variable}")
}
TODO("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(idx.index)
val indexTr = translateExpression(idxderef.index)
result += indexTr.chunks
result += IRCodeChunk(null, null).also {
val indexReg: Int
if (idx.index.type.isByte) {
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)

View File

@@ -108,21 +108,12 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
val type = idxderef.inferType(program).getOrElse {
throw FatalAstException("unknown dt")
}
require(type.isPointer || type.isUnsignedWord)
if(type.isUnsignedWord) {
if(idxderef.parent is AssignTarget)
TODO("as assignment target: indexing uword field $idxderef") // TODO hmm, wasn't there code elsewhere for this already?
else
TODO("as value: indexing uword field $idxderef") // TODO hmm, wasn't there code elsewhere for this already?
} else {
val deref = PtPointerIndexedDeref(DataType.forDt(type.sub!!), idxderef.position)
val indexer = PtArrayIndexer(DataType.forDt(type.sub!!), idxderef.position)
val identifier = PtIdentifier(idxderef.indexed.arrayvar.nameInSource.joinToString("."), type, idxderef.indexed.arrayvar.position)
indexer.add(identifier)
indexer.add(transformExpression(idxderef.indexed.indexer.indexExpr))
deref.add(indexer)
return deref
}
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 {
@@ -411,8 +402,7 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
val call =
if(targetStruct!=null) {
// a call to a struct yields a pointer to a struct instance and means: allocate a statically initialized struct instance of that type
val pointertype = DataType.pointerToType(targetStruct)
PtBuiltinFunctionCall("structalloc", false, true, pointertype, srcCall.position)
PtBuiltinFunctionCall("structalloc", false, true, DataType.pointer(targetStruct), srcCall.position)
} else {
// regular function call
val (target, _) = srcCall.target.targetNameAndType(program)

View File

@@ -84,7 +84,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
changeDataType = if(decl.datatype.isSplitWordArray) null else {
val eltDt = decl.datatype.elementType()
if(eltDt.isPointer)
DataType.arrayOfPointersTo(eltDt.base, eltDt.subType)
TODO("convert array of pointers to split words array type")
else
DataType.arrayFor(eltDt.base)
}
@@ -95,7 +95,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
changeDataType = if(decl.datatype.isSplitWordArray) null else {
val eltDt = decl.datatype.elementType()
if(eltDt.isPointer)
DataType.arrayOfPointersTo(eltDt.base, eltDt.subType)
TODO("convert array of pointers to split words array type")
else
DataType.arrayFor(eltDt.base)
}

View File

@@ -274,7 +274,7 @@ main {
DataType.arrayFor(BaseDataType.UWORD, false).typeForAddressOf(true) shouldBe DataType.pointer(BaseDataType.UBYTE)
DataType.arrayFor(BaseDataType.UWORD, true).typeForAddressOf(true) shouldBe DataType.pointer(BaseDataType.UBYTE)
DataType.pointerToType(Struct("struct")).typeForAddressOf(false) shouldBe DataType.UWORD
DataType.pointer(Struct("struct")).typeForAddressOf(false) shouldBe DataType.UWORD
DataType.pointerFromAntlr(listOf("struct")).typeForAddressOf(false) shouldBe DataType.UWORD
DataType.pointer(BaseDataType.BOOL).typeForAddressOf(false) shouldBe DataType.UWORD

View File

@@ -1093,7 +1093,10 @@ class ArrayLiteral(val type: InferredTypes.InferredType, // inferred because
val unique = dts.toSet()
if(unique.size==1) {
val dt = unique.single()
return InferredTypes.knownFor(DataType.arrayOfPointersTo(dt.sub, dt.subType))
return if(dt.subType!=null)
InferredTypes.knownFor(DataType.arrayOfPointersTo(dt.subType!!))
else
InferredTypes.knownFor(DataType.arrayOfPointersTo(dt.sub!!))
}
}
return when {
@@ -1474,7 +1477,7 @@ class FunctionCallExpression(override var target: IdentifierReference,
}
is StructDecl -> {
// calling a struct is syntax for allocating a static instance, and returns a pointer to that (not the instance itself)
return InferredTypes.knownFor(DataType.pointerToType(stmt))
return InferredTypes.knownFor(DataType.pointer(stmt))
}
else -> return InferredTypes.unknown()
}
@@ -1691,7 +1694,7 @@ class PtrDereference(val identifier: IdentifierReference, val chain: List<String
struct = fieldDt.subType as StructDecl
}
if(field==null) {
return InferredTypes.knownFor(DataType.pointerToType(struct))
return InferredTypes.knownFor(DataType.pointer(struct))
}
val fieldDt = struct.getFieldType(field)
return if(fieldDt==null)

View File

@@ -93,27 +93,10 @@ object InferredTypes {
else -> throw IllegalArgumentException("invalid sub type")
}
}
type.isPointerArray -> {
InferredType.known(DataType.arrayOfPointersTo(type.sub, type.subType))
}
type.isArray -> {
InferredType.known(DataType.arrayFor(type.sub!!, false))
}
type.isPointer -> {
if(type.subType!=null)
InferredType.known(DataType.pointerToType(type.subType!!))
else if(type.sub!=null)
InferredType.known(DataType.pointer(type.sub!!))
else
InferredType.known(DataType.pointerFromAntlr(type.subTypeFromAntlr!!))
}
type.isPointerArray -> InferredType.known(DataType.arrayOfPointersTo(type.sub, type.subType))
type.isStructInstance -> {
if(type.subType!=null)
InferredType.known(DataType.structInstance(type.subType!!))
else
InferredType.known(DataType.structInstanceFromAntlr(type.subTypeFromAntlr!!))
}
type.isPointerArray -> InferredType.known(type)
type.isArray -> InferredType.known(type)
type.isPointer -> InferredType.known(type)
type.isStructInstance -> InferredType.known(type)
else -> throw IllegalArgumentException("invalid type $type")
}
}

View File

@@ -6,6 +6,9 @@ main {
sub start() {
^^List l1 = List()
cx16.r0= l1.s[2]
l1.s[10] = 2
l1.s[2] = cx16.r1L
; l1.s^^ = 2 TODO fix undefined symbol
}
}

View File

@@ -617,14 +617,14 @@ class IRFileReader {
if(isArray) {
if(type[0]=='^') {
return when(type.drop(1)) {
"bool" -> DataType.arrayOfPointersTo(BaseDataType.BOOL, null)
"byte" -> DataType.arrayOfPointersTo(BaseDataType.BYTE, null)
"ubyte", "str" -> DataType.arrayOfPointersTo(BaseDataType.UBYTE, null)
"word" -> DataType.arrayOfPointersTo(BaseDataType.WORD, null)
"uword" -> DataType.arrayOfPointersTo(BaseDataType.UWORD, null)
"float" -> DataType.arrayOfPointersTo(BaseDataType.FLOAT, null)
"long" -> DataType.arrayOfPointersTo(BaseDataType.LONG, null)
else -> DataType.arrayOfPointersTo(null, IRSubtypePlaceholder(type.drop(1)))
"bool" -> DataType.arrayOfPointersTo(BaseDataType.BOOL)
"byte" -> DataType.arrayOfPointersTo(BaseDataType.BYTE)
"ubyte", "str" -> DataType.arrayOfPointersTo(BaseDataType.UBYTE)
"word" -> DataType.arrayOfPointersTo(BaseDataType.WORD)
"uword" -> DataType.arrayOfPointersTo(BaseDataType.UWORD)
"float" -> DataType.arrayOfPointersTo(BaseDataType.FLOAT)
"long" -> DataType.arrayOfPointersTo(BaseDataType.LONG)
else -> DataType.arrayOfPointersTo(IRSubtypePlaceholder(type.drop(1)))
}
}
return when(type) {
@@ -651,7 +651,7 @@ class IRFileReader {
"float" -> DataType.pointer(BaseDataType.FLOAT)
"long" -> DataType.pointer(BaseDataType.LONG)
// note: 'str' should not occur anymore in IR. Should be 'uword'
else -> DataType.pointerToType(IRSubtypePlaceholder(type.drop(1)))
else -> DataType.pointer(IRSubtypePlaceholder(type.drop(1)))
}
}
return when(type) {

View File

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