1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-07-04 16:29:52 +00:00

Start work on supporting member arrays

This commit is contained in:
Karol Stasiak 2019-12-30 11:50:18 +01:00
parent b1a76cad86
commit b2dd4eadd4
7 changed files with 196 additions and 133 deletions

View File

@ -366,16 +366,17 @@ object AbstractExpressionCompiler {
val (actualFieldName, pointerWrap): (String, Int) = getActualFieldNameAndPointerWrap(fieldName) val (actualFieldName, pointerWrap): (String, Int) = getActualFieldNameAndPointerWrap(fieldName)
currentType match { currentType match {
case PointerType(_, _, Some(targetType)) => case PointerType(_, _, Some(targetType)) =>
val tuples = env.getSubvariables(targetType).filter(x => x._1 == "." + actualFieldName) val tuples = env.getSubvariables(targetType).filter(x => x.suffix == "." + actualFieldName)
if (tuples.isEmpty) { if (tuples.isEmpty) {
log.error(s"Type `$targetType` doesn't have field named `$actualFieldName`", expr.position) log.error(s"Type `$targetType` doesn't have field named `$actualFieldName`", expr.position)
ok = false ok = false
} else { } else {
if (tuples.head.arraySize.isDefined) ??? // TODO
pointerWrap match { pointerWrap match {
case 0 => case 0 =>
currentType = tuples.head._3 currentType = tuples.head.typ
case 1 => case 1 =>
currentType = env.get[Type]("pointer." + tuples.head._3) currentType = env.get[Type]("pointer." + tuples.head.typ)
case 2 => case 2 =>
currentType = env.get[Type]("pointer") currentType = env.get[Type]("pointer")
case 10 | 11 => case 10 | 11 =>

View File

@ -390,15 +390,16 @@ abstract class AbstractStatementPreprocessor(protected val ctx: CompilationConte
val currentResultType = AbstractExpressionCompiler.getExpressionType(env, env.log, result) val currentResultType = AbstractExpressionCompiler.getExpressionType(env, env.log, result)
result = currentResultType match { result = currentResultType match {
case PointerType(_, _, Some(target)) => case PointerType(_, _, Some(target)) =>
val subvariables = env.getSubvariables(target).filter(x => x._1 == "." + actualFieldName) val subvariables = env.getSubvariables(target).filter(x => x.suffix == "." + actualFieldName)
if (subvariables.isEmpty) { if (subvariables.isEmpty) {
ctx.log.error(s"Type `${target.name}` does not contain field `$actualFieldName`", result.position) ctx.log.error(s"Type `${target.name}` does not contain field `$actualFieldName`", result.position)
ok = false ok = false
LiteralExpression(0, 1) LiteralExpression(0, 1)
} else { } else {
if (subvariables.head.arraySize.isDefined) ??? // TODO
val inner = optimizeExpr(result, currentVarValues, optimizeSum = true).pos(pos) val inner = optimizeExpr(result, currentVarValues, optimizeSum = true).pos(pos)
val fieldOffset = subvariables.head._2 val fieldOffset = subvariables.head.offset
val fieldType = subvariables.head._3 val fieldType = subvariables.head.typ
pointerWrap match { pointerWrap match {
case 0 => case 0 =>
DerefExpression(inner, fieldOffset, fieldType) DerefExpression(inner, fieldOffset, fieldType)

View File

@ -1,6 +1,7 @@
package millfork.env package millfork.env
import millfork.DecimalUtils._ import millfork.DecimalUtils._
import millfork.node.ResolvedFieldDesc
import millfork.output.DivisibleAlignment import millfork.output.DivisibleAlignment
object Constant { object Constant {
@ -167,25 +168,27 @@ case class StructureConstant(typ: StructType, fields: List[Constant]) extends Co
override def subbyte(index: Int): Constant = { override def subbyte(index: Int): Constant = {
var offset = 0 var offset = 0
for ((fv, (ft, _)) <- fields.zip(typ.mutableFieldsWithTypes)) { for ((fv, ResolvedFieldDesc(ft, _, arraySize)) <- fields.zip(typ.mutableFieldsWithTypes)) {
// TODO: handle array members?
val fs = ft.size val fs = ft.size
if (index < offset + fs) { if (index < offset + fs) {
val indexInField = index - offset val indexInField = index - offset
return fv.subbyte(indexInField) return fv.subbyte(indexInField)
} }
offset += fs offset += fs * arraySize.getOrElse(1)
} }
Constant.Zero Constant.Zero
} }
override def subbyteBe(index: Int, totalSize: Int): Constant = { override def subbyteBe(index: Int, totalSize: Int): Constant = {
var offset = 0 var offset = 0
for ((fv, (ft, _)) <- fields.zip(typ.mutableFieldsWithTypes)) { for ((fv, ResolvedFieldDesc(ft, _, arraySize)) <- fields.zip(typ.mutableFieldsWithTypes)) {
// TODO: handle array members?
val fs = ft.size val fs = ft.size
if (index < offset + fs) { if (index < offset + fs) {
val indexInField = index - offset val indexInField = index - offset
return fv.subbyteBe(indexInField, fs) return fv.subbyteBe(indexInField, fs)
} }
offset += fs offset += fs * arraySize.getOrElse(1)
} }
Constant.Zero Constant.Zero
} }

View File

@ -518,8 +518,8 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
BranchingOpcodeMapping(Opcode.BPL, IfFlagClear(ZFlag.S), MOpcode.BPL), BranchingOpcodeMapping(Opcode.BPL, IfFlagClear(ZFlag.S), MOpcode.BPL),
BranchingOpcodeMapping(Opcode.BMI, IfFlagSet(ZFlag.S), MOpcode.BMI)), BranchingOpcodeMapping(Opcode.BMI, IfFlagSet(ZFlag.S), MOpcode.BMI)),
None) None)
val byte_and_pointer$ = StructType("byte_and_pointer$", List(FieldDesc("byte", "zp"), FieldDesc("pointer", "branch"))) val byte_and_pointer$ = StructType("byte_and_pointer$", List(FieldDesc("byte", "zp", None), FieldDesc("pointer", "branch", None)))
val hudson_transfer$ = StructType("hudson_transfer$", List(FieldDesc("word", "a"), FieldDesc("word", "b"), FieldDesc("word", "c"))) val hudson_transfer$ = StructType("hudson_transfer$", List(FieldDesc("word", "a", None), FieldDesc("word", "b", None), FieldDesc("word", "c", None)))
addThing(byte_and_pointer$, None) addThing(byte_and_pointer$, None)
addThing(hudson_transfer$, None) addThing(hudson_transfer$, None)
builtinsAdded = true builtinsAdded = true
@ -960,17 +960,17 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
addThing(UnionType(stmt.name, stmt.fields), stmt.position) addThing(UnionType(stmt.name, stmt.fields), stmt.position)
} }
def getTypeSize(name: String, path: Set[String]): Int = { def getTypeSize(t: VariableType, path: Set[String]): Int = {
val name = t.name
if (path.contains(name)) return -1 if (path.contains(name)) return -1
val t = get[Type](name)
t match { t match {
case s: StructType => case s: StructType =>
if (s.mutableSize >= 0) s.mutableSize if (s.mutableSize >= 0) s.mutableSize
else { else {
val newPath = path + name val newPath = path + name
var sum = 0 var sum = 0
for( FieldDesc(fieldType, _) <- s.fields) { for( ResolvedFieldDesc(fieldType, _, count) <- s.mutableFieldsWithTypes) {
val fieldSize = getTypeSize(fieldType, newPath) val fieldSize = getTypeSize(fieldType, newPath) * count.getOrElse(1)
if (fieldSize < 0) return -1 if (fieldSize < 0) return -1
sum += fieldSize sum += fieldSize
} }
@ -980,9 +980,9 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
} }
val b = get[Type]("byte") val b = get[Type]("byte")
var offset = 0 var offset = 0
for( FieldDesc(fieldType, fieldName) <- s.fields) { for( ResolvedFieldDesc(fieldType, fieldName, count) <- s.mutableFieldsWithTypes) {
addThing(ConstantThing(s"$name.$fieldName.offset", NumericConstant(offset, 1), b), None) addThing(ConstantThing(s"$name.$fieldName.offset", NumericConstant(offset, 1), b), None)
offset += getTypeSize(fieldType, newPath) offset += getTypeSize(fieldType, newPath) * count.getOrElse(1)
} }
sum sum
} }
@ -991,8 +991,8 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
else { else {
val newPath = path + name val newPath = path + name
var max = 0 var max = 0
for( FieldDesc(fieldType, _) <- s.fields) { for( ResolvedFieldDesc(fieldType, _, count) <- s.mutableFieldsWithTypes) {
val fieldSize = getTypeSize(fieldType, newPath) val fieldSize = getTypeSize(fieldType, newPath) * count.getOrElse(1)
if (fieldSize < 0) return -1 if (fieldSize < 0) return -1
max = max max fieldSize max = max max fieldSize
} }
@ -1001,7 +1001,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
log.error(s"Union `$name` is larger than 255 bytes") log.error(s"Union `$name` is larger than 255 bytes")
} }
val b = get[Type]("byte") val b = get[Type]("byte")
for (FieldDesc(fieldType, fieldName) <- s.fields) { for (ResolvedFieldDesc(fieldType, fieldName, _) <- s.mutableFieldsWithTypes) {
addThing(ConstantThing(s"$name.$fieldName.offset", NumericConstant(0, 1), b), None) addThing(ConstantThing(s"$name.$fieldName.offset", NumericConstant(0, 1), b), None)
} }
max max
@ -1361,7 +1361,8 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
addThing(v, stmt.position) addThing(v, stmt.position)
registerAddressConstant(v, stmt.position, options, Some(typ)) registerAddressConstant(v, stmt.position, options, Some(typ))
val addr = v.toAddress val addr = v.toAddress
for((suffix, offset, t) <- getSubvariables(typ)) { for(Subvariable(suffix, offset, t, arraySize) <- getSubvariables(typ)) {
if (arraySize.isDefined) ??? // TODO
val subv = RelativeVariable(v.name + suffix, addr + offset, t, zeropage = zp, None, isVolatile = v.isVolatile) val subv = RelativeVariable(v.name + suffix, addr + offset, t, zeropage = zp, None, isVolatile = v.isVolatile)
addThing(subv, stmt.position) addThing(subv, stmt.position)
registerAddressConstant(subv, stmt.position, options, Some(t)) registerAddressConstant(subv, stmt.position, options, Some(t))
@ -1403,7 +1404,10 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
List.fill(tt.size)(LiteralExpression(0, 1)) List.fill(tt.size)(LiteralExpression(0, 1))
} else { } else {
tt.fields.zip(fieldValues).flatMap { tt.fields.zip(fieldValues).flatMap {
case (FieldDesc(fieldTypeName, _), expr) => extractStructArrayContents(expr, Some(get[Type](fieldTypeName))) case (FieldDesc(fieldTypeName, _, count), expr) =>
// TODO: handle array fields
if (count.isDefined) ???
extractStructArrayContents(expr, Some(get[Type](fieldTypeName)))
} }
} }
case _ => case _ =>
@ -1437,7 +1441,10 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
List.fill(tt.size)(LiteralExpression(0, 1)) List.fill(tt.size)(LiteralExpression(0, 1))
} else { } else {
tt.fields.zip(fieldValues).flatMap { tt.fields.zip(fieldValues).flatMap {
case (FieldDesc(fieldTypeName, _), expr) => extractStructArrayContents(expr, Some(get[Type](fieldTypeName))) case (FieldDesc(fieldTypeName, _, count), expr) =>
// TODO: handle array fields
if (count.isDefined) ???
extractStructArrayContents(expr, Some(get[Type](fieldTypeName)))
} }
} }
case _ => case _ =>
@ -1697,7 +1704,8 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
val constantValue: Constant = stmt.initialValue.flatMap(eval).getOrElse(errorConstant(s"`$name` has a non-constant value", position)).fitInto(typ) val constantValue: Constant = stmt.initialValue.flatMap(eval).getOrElse(errorConstant(s"`$name` has a non-constant value", position)).fitInto(typ)
if (constantValue.requiredSize > typ.size) log.error(s"`$name` is has an invalid value: not in the range of `$typ`", position) if (constantValue.requiredSize > typ.size) log.error(s"`$name` is has an invalid value: not in the range of `$typ`", position)
addThing(ConstantThing(prefix + name, constantValue, typ), stmt.position) addThing(ConstantThing(prefix + name, constantValue, typ), stmt.position)
for((suffix, offset, t) <- getSubvariables(typ)) { for(Subvariable(suffix, offset, t, arraySize) <- getSubvariables(typ)) {
if (arraySize.isDefined) ??? // TODO
addThing(ConstantThing(prefix + name + suffix, constantValue.subconstant(offset, t.size), t), stmt.position) addThing(ConstantThing(prefix + name + suffix, constantValue.subconstant(offset, t.size), t), stmt.position)
} }
} else { } else {
@ -1763,145 +1771,165 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
variable match { variable match {
case v: StackVariable => case v: StackVariable =>
addThing(localName, v, position) addThing(localName, v, position)
for ((suffix, offset, t) <- getSubvariables(v.typ)) { for (Subvariable(suffix, offset, t, arraySize) <- getSubvariables(v.typ)) {
addThing(StackVariable(prefix + localName + suffix, t, baseStackOffset + offset), position) if (arraySize.isDefined) {
log.error(s"Cannot create a stack variable $localName of compound type ${v.typ.name} that contains an array member")
} else {
addThing(StackVariable(prefix + localName + suffix, t, baseStackOffset + offset), position)
}
} }
case v: MemoryVariable => case v: MemoryVariable =>
addThing(localName, v, position) addThing(localName, v, position)
for ((suffix, offset, t) <- getSubvariables(v.typ)) { for (Subvariable(suffix, offset, t, arraySize) <- getSubvariables(v.typ)) {
val subv = RelativeVariable(prefix + localName + suffix, v.toAddress + offset, t, zeropage = v.zeropage, declaredBank = v.declaredBank, isVolatile = v.isVolatile) arraySize match {
addThing(subv, position) case None =>
registerAddressConstant(subv, position, options, Some(t)) val subv = RelativeVariable(prefix + localName + suffix, v.toAddress + offset, t, zeropage = v.zeropage, declaredBank = v.declaredBank, isVolatile = v.isVolatile)
addThing(subv, position)
registerAddressConstant(subv, position, options, Some(t))
case Some(_) =>
??? // TODO
}
} }
case v: VariableInMemory => case v: VariableInMemory =>
addThing(localName, v, position) addThing(localName, v, position)
addThing(ConstantThing(v.name + "`", v.toAddress, get[Type]("word")), position) addThing(ConstantThing(v.name + "`", v.toAddress, get[Type]("word")), position)
for ((suffix, offset, t) <- getSubvariables(v.typ)) { for (Subvariable(suffix, offset, t, arraySize) <- getSubvariables(v.typ)) {
val subv = RelativeVariable(prefix + localName + suffix, v.toAddress + offset, t, zeropage = v.zeropage, declaredBank = v.declaredBank, isVolatile = v.isVolatile) arraySize match {
addThing(subv, position) case None =>
registerAddressConstant(subv, position, options, Some(t)) val subv = RelativeVariable(prefix + localName + suffix, v.toAddress + offset, t, zeropage = v.zeropage, declaredBank = v.declaredBank, isVolatile = v.isVolatile)
addThing(subv, position)
registerAddressConstant(subv, position, options, Some(t))
case Some(_) =>
??? // TODO
}
} }
case _ => ??? case _ => ???
} }
} }
def getSubvariables(typ: Type): List[(String, Int, VariableType)] = { def getSubvariables(typ: Type): List[Subvariable] = {
val b = get[VariableType]("byte") val b = get[VariableType]("byte")
val w = get[VariableType]("word") val w = get[VariableType]("word")
if (typ.name == "__reg$type") { if (typ.name == "__reg$type") {
if (options.isBigEndian) { if (options.isBigEndian) {
throw new IllegalArgumentException("__reg$type on 6809???") throw new IllegalArgumentException("__reg$type on 6809???")
} }
return (".lo", 0, b) :: return Subvariable(".lo", 0, b) ::
(".hi", 1, b) :: Subvariable(".hi", 1, b) ::
(".loword", 0, w) :: Subvariable(".loword", 0, w) ::
(".loword.lo", 0, b) :: Subvariable(".loword.lo", 0, b) ::
(".loword.hi", 1, b) :: Subvariable(".loword.hi", 1, b) ::
(".b2b3", 2, w) :: Subvariable(".b2b3", 2, w) ::
(".b2b3.lo", 2, b) :: Subvariable(".b2b3.lo", 2, b) ::
(".b2b3.hi", 3, b) :: Subvariable(".b2b3.hi", 3, b) ::
List.tabulate(typ.size) { i => (".b" + i, i, b) } List.tabulate(typ.size) { i => Subvariable(".b" + i, i, b) }
} }
typ match { typ match {
case _: PlainType => typ.size match { case _: PlainType => typ.size match {
case 2 => if (options.isBigEndian) List( case 2 => if (options.isBigEndian) List(
(".lo", 1, b), Subvariable(".lo", 1, b),
(".hi", 0, b) Subvariable(".hi", 0, b)
) else List( ) else List(
(".lo", 0, b), Subvariable(".lo", 0, b),
(".hi", 1, b)) Subvariable(".hi", 1, b))
case 3 => if (options.isBigEndian) List( case 3 => if (options.isBigEndian) List(
(".loword", 1, w), Subvariable(".loword", 1, w),
(".loword.lo", 2, b), Subvariable(".loword.lo", 2, b),
(".loword.hi", 1, b), Subvariable(".loword.hi", 1, b),
(".hiword", 0, w), Subvariable(".hiword", 0, w),
(".hiword.lo", 1, b), Subvariable(".hiword.lo", 1, b),
(".hiword.hi", 0, b), Subvariable(".hiword.hi", 0, b),
(".b0", 2, b), Subvariable(".b0", 2, b),
(".b1", 1, b), Subvariable(".b1", 1, b),
(".b2", 0, b) Subvariable(".b2", 0, b)
) else List( ) else List(
(".loword", 0, w), Subvariable(".loword", 0, w),
(".loword.lo", 0, b), Subvariable(".loword.lo", 0, b),
(".loword.hi", 1, b), Subvariable(".loword.hi", 1, b),
(".hiword", 1, w), Subvariable(".hiword", 1, w),
(".hiword.lo", 1, b), Subvariable(".hiword.lo", 1, b),
(".hiword.hi", 2, b), Subvariable(".hiword.hi", 2, b),
(".b0", 0, b), Subvariable(".b0", 0, b),
(".b1", 1, b), Subvariable(".b1", 1, b),
(".b2", 2, b)) Subvariable(".b2", 2, b))
case 4 => if (options.isBigEndian) List( case 4 => if (options.isBigEndian) List(
(".loword", 2, w), Subvariable(".loword", 2, w),
(".hiword", 0, w), Subvariable(".hiword", 0, w),
(".loword.lo", 3, b), Subvariable(".loword.lo", 3, b),
(".loword.hi", 2, b), Subvariable(".loword.hi", 2, b),
(".hiword.lo", 1, b), Subvariable(".hiword.lo", 1, b),
(".hiword.hi", 0, b), Subvariable(".hiword.hi", 0, b),
(".b0", 3, b), Subvariable(".b0", 3, b),
(".b1", 2, b), Subvariable(".b1", 2, b),
(".b2", 1, b), Subvariable(".b2", 1, b),
(".b3", 0, b) Subvariable(".b3", 0, b)
) else List( ) else List(
(".loword", 0, w), Subvariable(".loword", 0, w),
(".hiword", 2, w), Subvariable(".hiword", 2, w),
(".loword.lo", 0, b), Subvariable(".loword.lo", 0, b),
(".loword.hi", 1, b), Subvariable(".loword.hi", 1, b),
(".hiword.lo", 2, b), Subvariable(".hiword.lo", 2, b),
(".hiword.hi", 3, b), Subvariable(".hiword.hi", 3, b),
(".b0", 0, b), Subvariable(".b0", 0, b),
(".b1", 1, b), Subvariable(".b1", 1, b),
(".b2", 2, b), Subvariable(".b2", 2, b),
(".b3", 3, b) Subvariable(".b3", 3, b)
) )
case sz if sz > 4 => case sz if sz > 4 =>
if (options.isBigEndian) { if (options.isBigEndian) {
(".lo", sz - 1, b) :: Subvariable(".lo", sz - 1, b) ::
(".loword", sz - 2, w) :: Subvariable(".loword", sz - 2, w) ::
(".loword.lo", sz - 1, b) :: Subvariable(".loword.lo", sz - 1, b) ::
(".loword.hi", sz - 2, b) :: Subvariable(".loword.hi", sz - 2, b) ::
List.tabulate(sz){ i => (".b" + i, sz - 1 - i, b) } List.tabulate(sz){ i => Subvariable(".b" + i, sz - 1 - i, b) }
} else { } else {
(".lo", 0, b) :: Subvariable(".lo", 0, b) ::
(".loword", 0, w) :: Subvariable(".loword", 0, w) ::
(".loword.lo", 0, b) :: Subvariable(".loword.lo", 0, b) ::
(".loword.hi", 1, b) :: Subvariable(".loword.hi", 1, b) ::
List.tabulate(sz){ i => (".b" + i, i, b) } List.tabulate(sz){ i => Subvariable(".b" + i, i, b) }
} }
case _ => Nil case _ => Nil
} }
case p: PointerType => if (options.isBigEndian) List( case p: PointerType => if (options.isBigEndian) List(
(".raw", 0, p), Subvariable(".raw", 0, p),
(".raw.lo", 1, b), Subvariable(".raw.lo", 1, b),
(".raw.hi", 0, b), Subvariable(".raw.hi", 0, b),
(".lo", 1, b), Subvariable(".lo", 1, b),
(".hi", 0, b) Subvariable(".hi", 0, b)
) else List( ) else List(
(".raw", 0, p), Subvariable(".raw", 0, p),
(".raw.lo", 0, b), Subvariable(".raw.lo", 0, b),
(".raw.hi", 1, b), Subvariable(".raw.hi", 1, b),
(".lo", 0, b), Subvariable(".lo", 0, b),
(".hi", 1, b)) Subvariable(".hi", 1, b))
case s: StructType => case s: StructType =>
val builder = new ListBuffer[(String, Int, VariableType)] val builder = new ListBuffer[Subvariable]
var offset = 0 var offset = 0
for(FieldDesc(typeName, fieldName) <- s.fields) { for(ResolvedFieldDesc(typ, fieldName, arraySize) <- s.mutableFieldsWithTypes) {
val typ = get[VariableType](typeName) arraySize match {
val suffix = "." + fieldName case None =>
builder += ((suffix, offset, typ)) val suffix = "." + fieldName
builder ++= getSubvariables(typ).map { builder += Subvariable(suffix, offset, typ, arraySize)
case (innerSuffix, innerOffset, innerType) => (suffix + innerSuffix, offset + innerOffset, innerType) if (arraySize.isEmpty) {
builder ++= getSubvariables(typ).map {
case Subvariable(innerSuffix, innerOffset, innerType, innerSize) => Subvariable(suffix + innerSuffix, offset + innerOffset, innerType, innerSize)
}
}
case Some(_) =>
// TODO
} }
offset += typ.size offset += typ.size * arraySize.getOrElse(1)
} }
builder.toList builder.toList
case s: UnionType => case s: UnionType =>
val builder = new ListBuffer[(String, Int, VariableType)] val builder = new ListBuffer[Subvariable]
for(FieldDesc(typeName, fieldName) <- s.fields) { for(FieldDesc(typeName, fieldName, _) <- s.fields) {
val typ = get[VariableType](typeName) val typ = get[VariableType](typeName)
val suffix = "." + fieldName val suffix = "." + fieldName
builder += ((suffix, 0, typ)) builder += Subvariable(suffix, 0, typ)
builder ++= getSubvariables(typ).map { builder ++= getSubvariables(typ).map {
case (innerSuffix, innerOffset, innerType) => (suffix + innerSuffix, innerOffset, innerType) case Subvariable(innerSuffix, innerOffset, innerType, innerSize) => Subvariable(suffix + innerSuffix, innerOffset, innerType, innerSize)
} }
} }
builder.toList builder.toList
@ -1961,9 +1989,9 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
} }
def fixStructSizes(): Unit = { def fixStructSizes(): Unit = {
val allStructTypes = things.values.flatMap { val allStructTypes: Iterable[VariableType] = things.values.flatMap {
case StructType(name, _) => Some(name) case s@StructType(name, _) => Some(s)
case UnionType(name, _) => Some(name) case s@UnionType(name, _) => Some(s)
case _ => None case _ => None
} }
var iterations = allStructTypes.size var iterations = allStructTypes.size
@ -1979,14 +2007,29 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
} }
def fixStructFields(): Unit = { def fixStructFields(): Unit = {
// TODO: handle arrays?
things.values.foreach { things.values.foreach {
case st@StructType(_, fields) => case st@StructType(_, fields) =>
st.mutableFieldsWithTypes = fields.map { st.mutableFieldsWithTypes = fields.map {
case FieldDesc(tn, name) => get[Type](tn) -> name case FieldDesc(tn, name, arraySize) => ResolvedFieldDesc(get[VariableType](tn), name, arraySize.map { x =>
eval(x) match {
case Some(NumericConstant(c, _)) if c >= 0 && c < 0x10000 => c.toInt
case _ =>
log.error(s"Invalid array size for member array $name in type ${st.toString}")
0
}
})
} }
case ut@UnionType(_, fields) => case ut@UnionType(_, fields) =>
ut.mutableFieldsWithTypes = fields.map { ut.mutableFieldsWithTypes = fields.map {
case FieldDesc(tn, name) => get[Type](tn) -> name case FieldDesc(tn, name, arraySize) => ResolvedFieldDesc(get[VariableType](tn), name, arraySize.map { x =>
eval(x) match {
case Some(NumericConstant(c, _)) if c >= 0 && c < 0x10000 => c.toInt
case _ =>
log.error(s"Invalid array size for member array $name in type ${ut.toString}")
0
}
})
} }
case _ => () case _ => ()
} }
@ -2012,8 +2055,8 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
case s: UnionDefinitionStatement => registerUnion(s) case s: UnionDefinitionStatement => registerUnion(s)
case _ => case _ =>
} }
fixStructSizes()
fixStructFields() fixStructFields()
fixStructSizes()
val pointies = collectPointies(program.declarations) val pointies = collectPointies(program.declarations)
pointiesUsed("") = pointies pointiesUsed("") = pointies
program.declarations.foreach { decl => program.declarations.foreach { decl =>

View File

@ -44,6 +44,8 @@ sealed trait Type extends CallableThing {
sealed trait VariableType extends Type sealed trait VariableType extends Type
case class Subvariable(suffix: String, offset: Int, typ: VariableType, arraySize: Option[Int] = None)
case object VoidType extends Type { case object VoidType extends Type {
def size = 0 def size = 0
@ -119,14 +121,14 @@ sealed trait CompoundVariableType extends VariableType
case class StructType(name: String, fields: List[FieldDesc]) extends CompoundVariableType { case class StructType(name: String, fields: List[FieldDesc]) extends CompoundVariableType {
override def size: Int = mutableSize override def size: Int = mutableSize
var mutableSize: Int = -1 var mutableSize: Int = -1
var mutableFieldsWithTypes: List[(Type, String)] = Nil var mutableFieldsWithTypes: List[ResolvedFieldDesc] = Nil
override def isSigned: Boolean = false override def isSigned: Boolean = false
} }
case class UnionType(name: String, fields: List[FieldDesc]) extends CompoundVariableType { case class UnionType(name: String, fields: List[FieldDesc]) extends CompoundVariableType {
override def size: Int = mutableSize override def size: Int = mutableSize
var mutableSize: Int = -1 var mutableSize: Int = -1
var mutableFieldsWithTypes: List[(Type, String)] = Nil var mutableFieldsWithTypes: List[ResolvedFieldDesc] = Nil
override def isSigned: Boolean = false override def isSigned: Boolean = false
} }

View File

@ -5,12 +5,14 @@ import millfork.assembly.m6809.{MAddrMode, MOpcode}
import millfork.assembly.mos.opt.SourceOfNZ import millfork.assembly.mos.opt.SourceOfNZ
import millfork.assembly.mos.{AddrMode, Opcode} import millfork.assembly.mos.{AddrMode, Opcode}
import millfork.assembly.z80.{ZOpcode, ZRegisters} import millfork.assembly.z80.{ZOpcode, ZRegisters}
import millfork.env.{Constant, ParamPassingConvention, Type} import millfork.env.{Constant, ParamPassingConvention, Type, VariableType}
import millfork.output.MemoryAlignment import millfork.output.MemoryAlignment
case class Position(moduleName: String, line: Int, column: Int, cursor: Int) case class Position(moduleName: String, line: Int, column: Int, cursor: Int)
case class FieldDesc(typeName:String, fieldName: String) case class FieldDesc(typeName:String, fieldName: String, arraySize: Option[Expression])
case class ResolvedFieldDesc(typ:VariableType, fieldName: String, arraySize: Option[Int])
sealed trait Node { sealed trait Node {
var position: Option[Position] = None var position: Option[Position] = None

View File

@ -605,10 +605,21 @@ abstract class MfParser[T](fileId: String, input: String, currentDirectory: Stri
variants <- enumVariants ~/ Pass variants <- enumVariants ~/ Pass
} yield Seq(EnumDefinitionStatement(name, variants).pos(p)) } yield Seq(EnumDefinitionStatement(name, variants).pos(p))
val compoundTypeField: P[FieldDesc] = for { val compoundTypeField: P[FieldDesc] = ("array".! ~ HWS ~/ Pass).?.flatMap {
typ <- identifier ~/ HWS case None =>
name <- identifier ~ HWS for {
} yield FieldDesc(typ, name) typ <- identifier ~/ HWS
name <- identifier ~ HWS
} yield FieldDesc(typ, name, None)
case Some(_) =>
for {
elementType <- ("(" ~/ AWS ~/ identifier ~ AWS ~ ")").? ~/ HWS
if enableDebuggingOptions
name <- identifier ~ HWS
length <- "[" ~/ AWS ~/ mfExpression(nonStatementLevel, false) ~ AWS ~ "]" ~ HWS
} yield FieldDesc(elementType.getOrElse("byte"), name, Some(length))
}
val compoundTypeFields: P[List[FieldDesc]] = val compoundTypeFields: P[List[FieldDesc]] =
("{" ~/ AWS ~ compoundTypeField.rep(sep = NoCut(EOLOrComma) ~ !"}" ~/ Pass) ~/ AWS ~/ "}" ~/ Pass).map(_.toList) ("{" ~/ AWS ~ compoundTypeField.rep(sep = NoCut(EOLOrComma) ~ !"}" ~/ Pass) ~/ AWS ~/ "}" ~/ Pass).map(_.toList)