mirror of
https://github.com/irmen/prog8.git
synced 2025-02-22 16:29:05 +00:00
adding @alignword/page on individual variables
This commit is contained in:
parent
97b8cb748d
commit
1cd754f05d
@ -2,6 +2,7 @@ package prog8.code
|
||||
|
||||
import prog8.code.ast.PtNode
|
||||
import prog8.code.ast.PtProgram
|
||||
import prog8.code.ast.PtVariable
|
||||
import prog8.code.core.*
|
||||
|
||||
|
||||
@ -182,6 +183,7 @@ class StStaticVariable(name: String,
|
||||
val initializationArrayValue: StArray?,
|
||||
val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
|
||||
val zpwish: ZeropageWish, // used in the variable allocator
|
||||
val align: PtVariable.Alignment,
|
||||
astNode: PtNode) : StNode(name, StNodeType.STATICVAR, astNode) {
|
||||
|
||||
var initializationNumericValue: Double? = null
|
||||
@ -216,6 +218,10 @@ class StStaticVariable(name: String,
|
||||
require(dt == DataType.STR)
|
||||
require(length == initializationStringValue.first.length+1)
|
||||
}
|
||||
if(align!=PtVariable.Alignment.NONE) {
|
||||
require(dt == DataType.STR || dt in ArrayDatatypes)
|
||||
require(zpwish != ZeropageWish.REQUIRE_ZEROPAGE && zpwish != ZeropageWish.PREFER_ZEROPAGE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,6 @@ package prog8.code
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.*
|
||||
import prog8.code.target.VMTarget
|
||||
import kotlin.collections.ArrayDeque
|
||||
|
||||
|
||||
class SymbolTableMaker(private val program: PtProgram, private val options: CompilationOptions) {
|
||||
@ -98,7 +97,7 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp
|
||||
// if(node.type in SplitWordArrayTypes) {
|
||||
// ... split array also add _lsb and _msb to symboltable?
|
||||
// }
|
||||
val stVar = StStaticVariable(node.name, node.type, initialString, initialArray, numElements, node.zeropage, node)
|
||||
val stVar = StStaticVariable(node.name, node.type, initialString, initialArray, numElements, node.zeropage, node.align, node)
|
||||
if(initialNumeric!=null)
|
||||
stVar.setOnetimeInitNumeric(initialNumeric)
|
||||
stVar
|
||||
|
@ -126,13 +126,18 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni
|
||||
}
|
||||
is PtVariable -> {
|
||||
val split = if(node.type in SplitWordArrayTypes) "@split" else ""
|
||||
val align = when(node.align) {
|
||||
PtVariable.Alignment.NONE -> ""
|
||||
PtVariable.Alignment.WORD -> "@alignword"
|
||||
PtVariable.Alignment.PAGE -> "@alignpage"
|
||||
}
|
||||
val str = if(node.arraySize!=null) {
|
||||
val eltType = ArrayToElementTypes.getValue(node.type)
|
||||
"${eltType.name.lowercase()}[${node.arraySize}] $split ${node.name}"
|
||||
"${eltType.name.lowercase()}[${node.arraySize}] $split $align ${node.name}"
|
||||
}
|
||||
else if(node.type in ArrayDatatypes) {
|
||||
val eltType = ArrayToElementTypes.getValue(node.type)
|
||||
"${eltType.name.lowercase()}[] $split ${node.name}"
|
||||
"${eltType.name.lowercase()}[] $split $align ${node.name}"
|
||||
}
|
||||
else
|
||||
"${node.type.name.lowercase()} ${node.name}"
|
||||
|
@ -149,10 +149,24 @@ sealed interface IPtVariable {
|
||||
}
|
||||
|
||||
|
||||
class PtVariable(name: String, override val type: DataType, val zeropage: ZeropageWish, val value: PtExpression?, val arraySize: UInt?, position: Position) : PtNamedNode(name, position), IPtVariable {
|
||||
class PtVariable(
|
||||
name: String,
|
||||
override val type: DataType,
|
||||
val zeropage: ZeropageWish,
|
||||
val align: Alignment,
|
||||
val value: PtExpression?,
|
||||
val arraySize: UInt?,
|
||||
position: Position
|
||||
) : PtNamedNode(name, position), IPtVariable {
|
||||
init {
|
||||
value?.let {it.parent=this}
|
||||
}
|
||||
|
||||
enum class Alignment {
|
||||
NONE,
|
||||
WORD,
|
||||
PAGE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -9,7 +9,6 @@ import prog8.code.ast.*
|
||||
import prog8.code.core.*
|
||||
import prog8.code.target.Cx16Target
|
||||
import prog8.codegen.cpu6502.assignment.*
|
||||
import kotlin.collections.ArrayDeque
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.writeLines
|
||||
|
||||
@ -162,7 +161,7 @@ private fun PtVariable.prefix(parent: PtNode, st: SymbolTable): PtVariable {
|
||||
else -> throw AssemblyError("weird array value element $elt")
|
||||
}
|
||||
}
|
||||
val result = PtVariable(name, type, zeropage, newValue, arraySize, position)
|
||||
val result = PtVariable(name, type, zeropage, align, newValue, arraySize, position)
|
||||
result.parent = parent
|
||||
result
|
||||
}
|
||||
|
@ -517,12 +517,12 @@ internal class ProgramAndVarsGen(
|
||||
|
||||
stringVarsWithInitInZp.forEach {
|
||||
val varname = asmgen.asmVariableName(it.name)+"_init_value"
|
||||
outputStringvar(varname, it.value.second, it.value.first)
|
||||
outputStringvar(varname, PtVariable.Alignment.NONE, it.value.second, it.value.first)
|
||||
}
|
||||
|
||||
arrayVarsWithInitInZp.forEach {
|
||||
val varname = asmgen.asmVariableName(it.name)+"_init_value"
|
||||
arrayVariable2asm(varname, it.alloc.dt, it.value, null)
|
||||
arrayVariable2asm(varname, it.alloc.dt, PtVariable.Alignment.NONE, it.value, null)
|
||||
}
|
||||
|
||||
asmgen.out("+")
|
||||
@ -599,6 +599,7 @@ internal class ProgramAndVarsGen(
|
||||
stringvars.forEach {
|
||||
outputStringvar(
|
||||
it.name,
|
||||
it.align,
|
||||
it.initializationStringValue!!.second,
|
||||
it.initializationStringValue!!.first
|
||||
)
|
||||
@ -617,11 +618,13 @@ internal class ProgramAndVarsGen(
|
||||
DataType.WORD -> asmgen.out("${variable.name}\t.sint ?")
|
||||
DataType.FLOAT -> asmgen.out("${variable.name}\t.fill ${compTarget.machine.FLOAT_MEM_SIZE}")
|
||||
in SplitWordArrayTypes -> {
|
||||
alignVar(variable.align)
|
||||
val numbytesPerHalf = compTarget.memorySize(variable.dt, variable.length!!) / 2
|
||||
asmgen.out("${variable.name}_lsb\t.fill $numbytesPerHalf")
|
||||
asmgen.out("${variable.name}_msb\t.fill $numbytesPerHalf")
|
||||
}
|
||||
in ArrayDatatypes -> {
|
||||
alignVar(variable.align)
|
||||
val numbytes = compTarget.memorySize(variable.dt, variable.length!!)
|
||||
asmgen.out("${variable.name}\t.fill $numbytes")
|
||||
}
|
||||
@ -631,6 +634,14 @@ internal class ProgramAndVarsGen(
|
||||
}
|
||||
}
|
||||
|
||||
private fun alignVar(align: PtVariable.Alignment) {
|
||||
when(align) {
|
||||
PtVariable.Alignment.NONE -> {}
|
||||
PtVariable.Alignment.WORD -> asmgen.out("\t.align 2")
|
||||
PtVariable.Alignment.PAGE -> asmgen.out("\t.align $100")
|
||||
}
|
||||
}
|
||||
|
||||
private fun staticVariable2asm(variable: StStaticVariable) {
|
||||
val initialValue: Number =
|
||||
if(variable.initializationNumericValue!=null) {
|
||||
@ -656,14 +667,15 @@ internal class ProgramAndVarsGen(
|
||||
DataType.STR -> {
|
||||
throw AssemblyError("all string vars should have been interned into prog")
|
||||
}
|
||||
in ArrayDatatypes -> arrayVariable2asm(variable.name, variable.dt, variable.initializationArrayValue, variable.length)
|
||||
in ArrayDatatypes -> arrayVariable2asm(variable.name, variable.dt, variable.align, variable.initializationArrayValue, variable.length)
|
||||
else -> {
|
||||
throw AssemblyError("weird dt")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun arrayVariable2asm(varname: String, dt: DataType, value: StArray?, orNumberOfZeros: Int?) {
|
||||
private fun arrayVariable2asm(varname: String, dt: DataType, align: PtVariable.Alignment, value: StArray?, orNumberOfZeros: Int?) {
|
||||
alignVar(align)
|
||||
when(dt) {
|
||||
DataType.ARRAY_UB, DataType.ARRAY_BOOL -> {
|
||||
val data = makeArrayFillDataUnsigned(dt, value, orNumberOfZeros)
|
||||
@ -759,7 +771,8 @@ internal class ProgramAndVarsGen(
|
||||
}
|
||||
}
|
||||
|
||||
private fun outputStringvar(varname: String, encoding: Encoding, value: String) {
|
||||
private fun outputStringvar(varname: String, align: PtVariable.Alignment, encoding: Encoding, value: String) {
|
||||
alignVar(align)
|
||||
asmgen.out("$varname\t; $encoding:\"${value.escape().replace("\u0000", "<NULL>")}\"", false)
|
||||
val bytes = compTarget.encodeString(value, encoding).plus(0.toUByte())
|
||||
val outputBytes = bytes.map { "$" + it.toString(16).padStart(2, '0') }
|
||||
|
@ -6,6 +6,7 @@ import prog8.code.StNode
|
||||
import prog8.code.StNodeType
|
||||
import prog8.code.StStaticVariable
|
||||
import prog8.code.SymbolTable
|
||||
import prog8.code.ast.PtVariable
|
||||
import prog8.code.core.*
|
||||
|
||||
|
||||
@ -49,8 +50,8 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
|
||||
val varsRequiringZp = allVariables.filter { it.zpwish == ZeropageWish.REQUIRE_ZEROPAGE }
|
||||
val varsPreferringZp = allVariables.filter { it.zpwish == ZeropageWish.PREFER_ZEROPAGE }
|
||||
val varsNotZp = allVariables.filter { it.zpwish == ZeropageWish.NOT_IN_ZEROPAGE }
|
||||
val varsDontCare = allVariables.filter { it.zpwish == ZeropageWish.DONTCARE }
|
||||
require(varsDontCare.size + varsRequiringZp.size + varsPreferringZp.size + varsNotZp.size == numberOfAllocatableVariables)
|
||||
val (varsDontCareWithoutAlignment, varsDontCareWithAlignment) = allVariables.filter { it.zpwish == ZeropageWish.DONTCARE }.partition { it.align==PtVariable.Alignment.NONE }
|
||||
require(varsDontCareWithAlignment.size + varsDontCareWithoutAlignment.size + varsRequiringZp.size + varsPreferringZp.size + varsNotZp.size == numberOfAllocatableVariables)
|
||||
|
||||
var numVariablesAllocatedInZP = 0
|
||||
var numberOfNonIntegerVariables = 0
|
||||
@ -89,7 +90,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
|
||||
// try to allocate the "don't care" interger variables into the zeropage until it is full.
|
||||
// TODO some form of intelligent priorization? most often used variables first? loopcounter vars first? ...?
|
||||
if(errors.noErrors()) {
|
||||
val sortedList = varsDontCare.sortedByDescending { it.scopedName }
|
||||
val sortedList = varsDontCareWithoutAlignment.sortedByDescending { it.scopedName }
|
||||
for (variable in sortedList) {
|
||||
if(variable.dt in IntegerDatatypesWithBoolean) {
|
||||
if(zeropage.free.isEmpty()) {
|
||||
|
@ -47,10 +47,42 @@ class TestCodegen: FunSpec({
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main",false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("pi", DataType.UBYTE, ZeropageWish.DONTCARE, PtNumber(DataType.UBYTE, 0.0, Position.DUMMY), null, Position.DUMMY))
|
||||
sub.add(PtVariable("particleX", DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, 3u, Position.DUMMY))
|
||||
sub.add(PtVariable("particleDX", DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, 3u, Position.DUMMY))
|
||||
sub.add(PtVariable("xx", DataType.WORD, ZeropageWish.DONTCARE, PtNumber(DataType.WORD, 1.0, Position.DUMMY), null, Position.DUMMY))
|
||||
sub.add(PtVariable(
|
||||
"pi",
|
||||
DataType.UBYTE,
|
||||
ZeropageWish.DONTCARE,
|
||||
PtVariable.Alignment.NONE,
|
||||
PtNumber(DataType.UBYTE, 0.0, Position.DUMMY),
|
||||
null,
|
||||
Position.DUMMY
|
||||
))
|
||||
sub.add(PtVariable(
|
||||
"particleX",
|
||||
DataType.ARRAY_UB,
|
||||
ZeropageWish.DONTCARE,
|
||||
PtVariable.Alignment.NONE,
|
||||
null,
|
||||
3u,
|
||||
Position.DUMMY
|
||||
))
|
||||
sub.add(PtVariable(
|
||||
"particleDX",
|
||||
DataType.ARRAY_UB,
|
||||
ZeropageWish.DONTCARE,
|
||||
PtVariable.Alignment.NONE,
|
||||
null,
|
||||
3u,
|
||||
Position.DUMMY
|
||||
))
|
||||
sub.add(PtVariable(
|
||||
"xx",
|
||||
DataType.WORD,
|
||||
ZeropageWish.DONTCARE,
|
||||
PtVariable.Alignment.NONE,
|
||||
PtNumber(DataType.WORD, 1.0, Position.DUMMY),
|
||||
null,
|
||||
Position.DUMMY
|
||||
))
|
||||
|
||||
val assign = PtAugmentedAssign("+=", Position.DUMMY)
|
||||
val target = PtAssignTarget(false, Position.DUMMY).also {
|
||||
|
@ -44,10 +44,42 @@ class TestVmCodeGen: FunSpec({
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("pi", DataType.UBYTE, ZeropageWish.DONTCARE, PtNumber(DataType.UBYTE, 0.0, Position.DUMMY), null, Position.DUMMY))
|
||||
sub.add(PtVariable("particleX", DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, 3u, Position.DUMMY))
|
||||
sub.add(PtVariable("particleDX", DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, 3u, Position.DUMMY))
|
||||
sub.add(PtVariable("xx", DataType.WORD, ZeropageWish.DONTCARE, PtNumber(DataType.WORD, 1.0, Position.DUMMY), null, Position.DUMMY))
|
||||
sub.add(PtVariable(
|
||||
"pi",
|
||||
DataType.UBYTE,
|
||||
ZeropageWish.DONTCARE,
|
||||
PtVariable.Alignment.NONE,
|
||||
PtNumber(DataType.UBYTE, 0.0, Position.DUMMY),
|
||||
null,
|
||||
Position.DUMMY
|
||||
))
|
||||
sub.add(PtVariable(
|
||||
"particleX",
|
||||
DataType.ARRAY_UB,
|
||||
ZeropageWish.DONTCARE,
|
||||
PtVariable.Alignment.NONE,
|
||||
null,
|
||||
3u,
|
||||
Position.DUMMY
|
||||
))
|
||||
sub.add(PtVariable(
|
||||
"particleDX",
|
||||
DataType.ARRAY_UB,
|
||||
ZeropageWish.DONTCARE,
|
||||
PtVariable.Alignment.NONE,
|
||||
null,
|
||||
3u,
|
||||
Position.DUMMY
|
||||
))
|
||||
sub.add(PtVariable(
|
||||
"xx",
|
||||
DataType.WORD,
|
||||
ZeropageWish.DONTCARE,
|
||||
PtVariable.Alignment.NONE,
|
||||
PtNumber(DataType.WORD, 1.0, Position.DUMMY),
|
||||
null,
|
||||
Position.DUMMY
|
||||
))
|
||||
|
||||
val assign = PtAugmentedAssign("+=", Position.DUMMY)
|
||||
val target = PtAssignTarget(false, Position.DUMMY).also {
|
||||
@ -123,7 +155,15 @@ class TestVmCodeGen: FunSpec({
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("f1", DataType.FLOAT, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||
sub.add(PtVariable(
|
||||
"f1",
|
||||
DataType.FLOAT,
|
||||
ZeropageWish.DONTCARE,
|
||||
PtVariable.Alignment.NONE,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
val cmp1 = PtBinaryExpression("==", DataType.BOOL, Position.DUMMY)
|
||||
cmp1.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||
@ -186,7 +226,15 @@ class TestVmCodeGen: FunSpec({
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("f1", DataType.FLOAT, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||
sub.add(PtVariable(
|
||||
"f1",
|
||||
DataType.FLOAT,
|
||||
ZeropageWish.DONTCARE,
|
||||
PtVariable.Alignment.NONE,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
val cmp1 = PtBinaryExpression("==", DataType.BOOL, Position.DUMMY)
|
||||
cmp1.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||
@ -245,7 +293,15 @@ class TestVmCodeGen: FunSpec({
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("f1", DataType.FLOAT, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||
sub.add(PtVariable(
|
||||
"f1",
|
||||
DataType.FLOAT,
|
||||
ZeropageWish.DONTCARE,
|
||||
PtVariable.Alignment.NONE,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
val cmp1 = PtBinaryExpression("==", DataType.BOOL, Position.DUMMY)
|
||||
cmp1.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||
@ -292,7 +348,15 @@ class TestVmCodeGen: FunSpec({
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("sb1", DataType.BYTE, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||
sub.add(PtVariable(
|
||||
"sb1",
|
||||
DataType.BYTE,
|
||||
ZeropageWish.DONTCARE,
|
||||
PtVariable.Alignment.NONE,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
val cmp1 = PtBinaryExpression("==", DataType.BOOL, Position.DUMMY)
|
||||
cmp1.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
|
||||
@ -355,7 +419,15 @@ class TestVmCodeGen: FunSpec({
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("sb1", DataType.BYTE, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||
sub.add(PtVariable(
|
||||
"sb1",
|
||||
DataType.BYTE,
|
||||
ZeropageWish.DONTCARE,
|
||||
PtVariable.Alignment.NONE,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
val cmp1 = PtBinaryExpression("==", DataType.BOOL, Position.DUMMY)
|
||||
cmp1.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
|
||||
@ -414,7 +486,15 @@ class TestVmCodeGen: FunSpec({
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable("ub1", DataType.UBYTE, ZeropageWish.DONTCARE, null, null, Position.DUMMY))
|
||||
sub.add(PtVariable(
|
||||
"ub1",
|
||||
DataType.UBYTE,
|
||||
ZeropageWish.DONTCARE,
|
||||
PtVariable.Alignment.NONE,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
val cmp1 = PtBinaryExpression("==", DataType.BOOL, Position.DUMMY)
|
||||
cmp1.add(PtIdentifier("main.start.ub1", DataType.UBYTE, Position.DUMMY))
|
||||
|
@ -76,7 +76,7 @@ class VarConstantValueTypeAdjuster(
|
||||
if (declValue != null) {
|
||||
// variable is never written to, so it can be replaced with a constant, IF the value is a constant
|
||||
errors.info("variable '${decl.name}' is never written to and was replaced by a constant", decl.position)
|
||||
val const = VarDecl(VarDeclType.CONST, decl.origin, decl.datatype, decl.zeropage, decl.arraysize, decl.name, decl.names, declValue, decl.sharedWithAsm, decl.splitArray, decl.position)
|
||||
val const = VarDecl(VarDeclType.CONST, decl.origin, decl.datatype, decl.zeropage, decl.arraysize, decl.name, decl.names, declValue, decl.sharedWithAsm, decl.splitArray, decl.alignment, decl.position)
|
||||
decl.value = null
|
||||
return listOf(
|
||||
IAstModification.ReplaceNode(decl, const, parent)
|
||||
@ -96,7 +96,7 @@ class VarConstantValueTypeAdjuster(
|
||||
}
|
||||
// variable only has a single write and it is the initialization value, so it can be replaced with a constant, IF the value is a constant
|
||||
errors.info("variable '${decl.name}' is never written to and was replaced by a constant", decl.position)
|
||||
val const = VarDecl(VarDeclType.CONST, decl.origin, decl.datatype, decl.zeropage, decl.arraysize, decl.name, decl.names, singleAssignment.value, decl.sharedWithAsm, decl.splitArray, decl.position)
|
||||
val const = VarDecl(VarDeclType.CONST, decl.origin, decl.datatype, decl.zeropage, decl.arraysize, decl.name, decl.names, singleAssignment.value, decl.sharedWithAsm, decl.splitArray, decl.alignment, decl.position)
|
||||
return listOf(
|
||||
IAstModification.ReplaceNode(decl, const, parent),
|
||||
IAstModification.Remove(singleAssignment, singleAssignment.parent as IStatementContainer)
|
||||
@ -271,7 +271,6 @@ class VarConstantValueTypeAdjuster(
|
||||
// This is needed because further constant optimizations depend on those.
|
||||
internal class ConstantIdentifierReplacer(
|
||||
private val program: Program,
|
||||
private val options: CompilationOptions,
|
||||
private val errors: IErrorReporter
|
||||
) : AstWalker() {
|
||||
|
||||
@ -399,7 +398,7 @@ internal class ConstantIdentifierReplacer(
|
||||
if(targetDatatype.isArray) {
|
||||
val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.ARRAYLITERAL, targetDatatype.getOr(DataType.UNDEFINED),
|
||||
ZeropageWish.DONTCARE, null, "dummy", emptyList(),
|
||||
assignment.value, false, false, Position.DUMMY)
|
||||
assignment.value, false, false, VarAlignment.NONE, Position.DUMMY)
|
||||
val replaceValue = createConstArrayInitializerValue(decl)
|
||||
if(replaceValue!=null) {
|
||||
return listOf(IAstModification.ReplaceNode(assignment.value, replaceValue, assignment))
|
||||
|
@ -12,7 +12,7 @@ fun Program.constantFold(errors: IErrorReporter, options: CompilationOptions) {
|
||||
if(errors.noErrors()) {
|
||||
valuetypefixer.applyModifications()
|
||||
|
||||
val replacer = ConstantIdentifierReplacer(this, options, errors)
|
||||
val replacer = ConstantIdentifierReplacer(this, errors)
|
||||
replacer.visit(this)
|
||||
if (errors.noErrors()) {
|
||||
replacer.applyModifications()
|
||||
|
@ -890,6 +890,19 @@ internal class AstChecker(private val program: Program,
|
||||
errors.err("split can only be used on word arrays", decl.position)
|
||||
}
|
||||
}
|
||||
|
||||
if(decl.alignment!=VarAlignment.NONE) {
|
||||
if(!decl.isArray && decl.datatype!=DataType.STR)
|
||||
err("only string and array variables can have an alignment option")
|
||||
else if(decl.type==VarDeclType.MEMORY)
|
||||
err("only normal variables can have an alignment option")
|
||||
else if (decl.zeropage == ZeropageWish.REQUIRE_ZEROPAGE || decl.zeropage == ZeropageWish.PREFER_ZEROPAGE) {
|
||||
err("zeropage variables can't have alignment")
|
||||
} else if(decl.alignment==VarAlignment.PAGE) {
|
||||
errors.info("page-aligned variables might waste a lot of memory (check Gaps in assembler output)", decl.position)
|
||||
}
|
||||
}
|
||||
|
||||
super.visit(decl)
|
||||
}
|
||||
|
||||
|
@ -197,7 +197,7 @@ class AstPreprocessor(val program: Program,
|
||||
private fun makeSplitArray(decl: VarDecl): Iterable<IAstModification> {
|
||||
val newDecl = VarDecl(
|
||||
decl.type, decl.origin, decl.datatype, decl.zeropage, decl.arraysize, decl.name, emptyList(),
|
||||
decl.value, decl.sharedWithAsm, true, decl.position
|
||||
decl.value, decl.sharedWithAsm, true, decl.alignment, decl.position
|
||||
)
|
||||
return listOf(IAstModification.ReplaceNode(decl, newDecl, decl.parent))
|
||||
}
|
||||
|
@ -11,9 +11,9 @@ import prog8.ast.statements.*
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.*
|
||||
import prog8.compiler.builtinFunctionReturnType
|
||||
import java.io.File
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.isRegularFile
|
||||
import java.io.File
|
||||
|
||||
|
||||
/**
|
||||
@ -520,6 +520,11 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr
|
||||
when(srcVar.type) {
|
||||
VarDeclType.VAR -> {
|
||||
val value = if(srcVar.value!=null) transformExpression(srcVar.value!!) else null
|
||||
val align = when(srcVar.alignment) {
|
||||
VarAlignment.NONE -> PtVariable.Alignment.NONE
|
||||
VarAlignment.WORD -> PtVariable.Alignment.WORD
|
||||
VarAlignment.PAGE -> PtVariable.Alignment.PAGE
|
||||
}
|
||||
if(srcVar.isArray) {
|
||||
if(value==null) {
|
||||
val blockOptions = srcVar.definingBlock.options()
|
||||
@ -529,11 +534,27 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr
|
||||
repeat(srcVar.arraysize!!.constIndex()!!) {
|
||||
zeros.children.add(PtNumber(ArrayToElementTypes.getValue(srcVar.datatype), 0.0, srcVar.position))
|
||||
}
|
||||
return PtVariable(srcVar.name, srcVar.datatype, srcVar.zeropage, zeros, srcVar.arraysize?.constIndex()?.toUInt(), srcVar.position)
|
||||
return PtVariable(
|
||||
srcVar.name,
|
||||
srcVar.datatype,
|
||||
srcVar.zeropage,
|
||||
align,
|
||||
zeros,
|
||||
srcVar.arraysize?.constIndex()?.toUInt(),
|
||||
srcVar.position
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return PtVariable(srcVar.name, srcVar.datatype, srcVar.zeropage, value, srcVar.arraysize?.constIndex()?.toUInt(), srcVar.position)
|
||||
return PtVariable(
|
||||
srcVar.name,
|
||||
srcVar.datatype,
|
||||
srcVar.zeropage,
|
||||
align,
|
||||
value,
|
||||
srcVar.arraysize?.constIndex()?.toUInt(),
|
||||
srcVar.position
|
||||
)
|
||||
}
|
||||
VarDeclType.CONST -> return PtConstant(srcVar.name, srcVar.datatype, (srcVar.value as NumericLiteral).number, srcVar.position)
|
||||
VarDeclType.MEMORY -> return PtMemMapped(srcVar.name, srcVar.datatype, (srcVar.value as NumericLiteral).number.toUInt(), srcVar.arraysize?.constIndex()?.toUInt(), srcVar.position)
|
||||
|
@ -41,7 +41,15 @@ private fun setDeferMasks(program: PtProgram, errors: IErrorReporter): Map<PtSub
|
||||
}
|
||||
|
||||
// define the bitmask variable and set it to zero
|
||||
val deferVariable = PtVariable(maskVarName, DataType.UBYTE, ZeropageWish.NOT_IN_ZEROPAGE, null, null, sub.position)
|
||||
val deferVariable = PtVariable(
|
||||
maskVarName,
|
||||
DataType.UBYTE,
|
||||
ZeropageWish.NOT_IN_ZEROPAGE,
|
||||
PtVariable.Alignment.NONE,
|
||||
null,
|
||||
null,
|
||||
sub.position
|
||||
)
|
||||
val assignZero = PtAssignment(sub.position)
|
||||
assignZero.add(PtAssignTarget(false, sub.position).also {
|
||||
it.add(PtIdentifier(sub.scopedName+"."+maskVarName, DataType.UBYTE, sub.position))
|
||||
|
@ -6,6 +6,7 @@ import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.Assignment
|
||||
import prog8.ast.statements.VarAlignment
|
||||
import prog8.ast.statements.VarDecl
|
||||
import prog8.ast.statements.WhenChoice
|
||||
import prog8.ast.walk.AstWalker
|
||||
@ -94,6 +95,11 @@ internal class LiteralsToAutoVars(private val program: Program, private val erro
|
||||
// and not in CodeDesugarer, that one is too late (identifiers can't be found otherwise)
|
||||
if(decl.datatype !in NumericDatatypesWithBoolean)
|
||||
errors.err("can only multi declare numeric and boolean variables", decl.position)
|
||||
if(decl.alignment != VarAlignment.NONE) {
|
||||
errors.err("only single variable declarations can have alignment", decl.position)
|
||||
return noModifications
|
||||
}
|
||||
|
||||
if(errors.noErrors()) {
|
||||
// desugar into individual vardecl per name.
|
||||
return decl.desugarMultiDecl().map {
|
||||
|
@ -220,6 +220,7 @@ internal class StatementReorderer(
|
||||
null,
|
||||
it.sharedWithAsm,
|
||||
it.splitArray,
|
||||
it.alignment,
|
||||
it.position
|
||||
)
|
||||
IAstModification.ReplaceNode(it, newvar, subroutine)
|
||||
|
@ -12,7 +12,10 @@ import prog8.ast.expressions.IdentifierReference
|
||||
import prog8.ast.expressions.NumericLiteral
|
||||
import prog8.ast.expressions.PrefixExpression
|
||||
import prog8.ast.statements.*
|
||||
import prog8.code.core.*
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.Position
|
||||
import prog8.code.core.SourceCode
|
||||
import prog8.code.core.ZeropageWish
|
||||
import prog8.code.target.*
|
||||
import prog8tests.helpers.DummyFunctions
|
||||
import prog8tests.helpers.DummyMemsizer
|
||||
@ -111,7 +114,7 @@ class TestMemory: FunSpec({
|
||||
}
|
||||
|
||||
fun createTestProgramForMemoryRefViaVar(address: UInt, vartype: VarDeclType): AssignTarget {
|
||||
val decl = VarDecl(vartype, VarDeclOrigin.USERCODE, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY)
|
||||
val decl = VarDecl(vartype, VarDeclOrigin.USERCODE, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, VarAlignment.NONE, Position.DUMMY)
|
||||
val memexpr = IdentifierReference(listOf("address"), Position.DUMMY)
|
||||
val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
|
||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
@ -149,7 +152,7 @@ class TestMemory: FunSpec({
|
||||
}
|
||||
|
||||
test("regular variable not in mapped IO ram on C64") {
|
||||
val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", emptyList(), null, false, false, Position.DUMMY)
|
||||
val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", emptyList(), null, false, false, VarAlignment.NONE, Position.DUMMY)
|
||||
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, null, false, 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)
|
||||
@ -161,7 +164,7 @@ class TestMemory: FunSpec({
|
||||
|
||||
test("memory mapped variable not in mapped IO ram on C64") {
|
||||
val address = 0x1000u
|
||||
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY)
|
||||
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, VarAlignment.NONE, Position.DUMMY)
|
||||
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, null, false, 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)
|
||||
@ -173,7 +176,7 @@ class TestMemory: FunSpec({
|
||||
|
||||
test("memory mapped variable in mapped IO ram on C64") {
|
||||
val address = 0xd020u
|
||||
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY)
|
||||
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, VarAlignment.NONE, Position.DUMMY)
|
||||
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, null, false, 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)
|
||||
@ -184,7 +187,7 @@ class TestMemory: FunSpec({
|
||||
}
|
||||
|
||||
test("array not in mapped IO ram") {
|
||||
val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", emptyList(), null, false, false, Position.DUMMY)
|
||||
val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", emptyList(), null, false, false, VarAlignment.NONE, Position.DUMMY)
|
||||
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
||||
val target = AssignTarget(null, arrayindexed, null, null, false, Position.DUMMY)
|
||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
@ -197,7 +200,7 @@ class TestMemory: FunSpec({
|
||||
|
||||
test("memory mapped array not in mapped IO ram") {
|
||||
val address = 0x1000u
|
||||
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY)
|
||||
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, VarAlignment.NONE, Position.DUMMY)
|
||||
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
||||
val target = AssignTarget(null, arrayindexed, null, null, false, Position.DUMMY)
|
||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
@ -210,7 +213,7 @@ class TestMemory: FunSpec({
|
||||
|
||||
test("memory mapped array in mapped IO ram") {
|
||||
val address = 0xd800u
|
||||
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY)
|
||||
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, VarAlignment.NONE, Position.DUMMY)
|
||||
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
||||
val target = AssignTarget(null, arrayindexed, null, null, false, Position.DUMMY)
|
||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
|
@ -85,14 +85,14 @@ class TestSymbolTable: FunSpec({
|
||||
|
||||
test("static vars") {
|
||||
val node = PtIdentifier("dummy", DataType.UBYTE, Position.DUMMY)
|
||||
val stVar1 = StStaticVariable("initialized", DataType.UBYTE, null, null, null, ZeropageWish.DONTCARE, node)
|
||||
val stVar1 = StStaticVariable("initialized", DataType.UBYTE, null, null, null, ZeropageWish.DONTCARE, PtVariable.Alignment.NONE, node)
|
||||
stVar1.setOnetimeInitNumeric(99.0)
|
||||
val stVar2 = StStaticVariable("uninitialized", DataType.UBYTE, null, null, null, ZeropageWish.DONTCARE, node)
|
||||
val stVar2 = StStaticVariable("uninitialized", DataType.UBYTE, null, null, null, ZeropageWish.DONTCARE, PtVariable.Alignment.NONE, node)
|
||||
val arrayInitNonzero = listOf(StArrayElement(1.1, null, null), StArrayElement(2.2, null, null), StArrayElement(3.3, null, null))
|
||||
val arrayInitAllzero = listOf(StArrayElement(0.0, null, null), StArrayElement(0.0, null, null), StArrayElement(0.0, null, null))
|
||||
val stVar3 = StStaticVariable("initialized", DataType.ARRAY_UW, null, arrayInitNonzero, 3, ZeropageWish.DONTCARE, node)
|
||||
val stVar4 = StStaticVariable("initialized", DataType.ARRAY_UW, null, arrayInitAllzero, 3, ZeropageWish.DONTCARE, node)
|
||||
val stVar5 = StStaticVariable("uninitialized", DataType.ARRAY_UW, null, null, 3, ZeropageWish.DONTCARE, node)
|
||||
val stVar3 = StStaticVariable("initialized", DataType.ARRAY_UW, null, arrayInitNonzero, 3, ZeropageWish.DONTCARE, PtVariable.Alignment.NONE, node)
|
||||
val stVar4 = StStaticVariable("initialized", DataType.ARRAY_UW, null, arrayInitAllzero, 3, ZeropageWish.DONTCARE, PtVariable.Alignment.NONE, node)
|
||||
val stVar5 = StStaticVariable("uninitialized", DataType.ARRAY_UW, null, null, 3, ZeropageWish.DONTCARE, PtVariable.Alignment.NONE, node)
|
||||
|
||||
stVar1.uninitialized shouldBe false
|
||||
stVar1.length shouldBe null
|
||||
@ -119,12 +119,60 @@ private fun makeSt(): SymbolTable {
|
||||
astBlock1.add(astConstant2)
|
||||
val astSub1 = PtSub("sub1", emptyList(), null, Position.DUMMY)
|
||||
val astSub2 = PtSub("sub2", emptyList(), null, Position.DUMMY)
|
||||
val astSub1v1 = PtVariable("v1", DataType.BYTE, ZeropageWish.DONTCARE, null, null, Position.DUMMY)
|
||||
val astSub1v2 = PtVariable("v2", DataType.BYTE, ZeropageWish.DONTCARE,null, null, Position.DUMMY)
|
||||
val astSub1v3 = PtVariable("v3", DataType.FLOAT, ZeropageWish.DONTCARE,null, null, Position.DUMMY)
|
||||
val astSub1v4 = PtVariable("slab1", DataType.UWORD, ZeropageWish.DONTCARE,null, null, Position.DUMMY)
|
||||
val astSub2v1 = PtVariable("v1", DataType.BYTE, ZeropageWish.DONTCARE,null, null, Position.DUMMY)
|
||||
val astSub2v2 = PtVariable("v2", DataType.BYTE, ZeropageWish.DONTCARE,null, null, Position.DUMMY)
|
||||
val astSub1v1 = PtVariable(
|
||||
"v1",
|
||||
DataType.BYTE,
|
||||
ZeropageWish.DONTCARE,
|
||||
PtVariable.Alignment.NONE,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
)
|
||||
val astSub1v2 = PtVariable(
|
||||
"v2",
|
||||
DataType.BYTE,
|
||||
ZeropageWish.DONTCARE,
|
||||
PtVariable.Alignment.NONE,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
)
|
||||
val astSub1v3 = PtVariable(
|
||||
"v3",
|
||||
DataType.FLOAT,
|
||||
ZeropageWish.DONTCARE,
|
||||
PtVariable.Alignment.NONE,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
)
|
||||
val astSub1v4 = PtVariable(
|
||||
"slab1",
|
||||
DataType.UWORD,
|
||||
ZeropageWish.DONTCARE,
|
||||
PtVariable.Alignment.NONE,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
)
|
||||
val astSub2v1 = PtVariable(
|
||||
"v1",
|
||||
DataType.BYTE,
|
||||
ZeropageWish.DONTCARE,
|
||||
PtVariable.Alignment.NONE,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
)
|
||||
val astSub2v2 = PtVariable(
|
||||
"v2",
|
||||
DataType.BYTE,
|
||||
ZeropageWish.DONTCARE,
|
||||
PtVariable.Alignment.NONE,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
)
|
||||
astSub1.add(astSub1v1)
|
||||
astSub1.add(astSub1v2)
|
||||
astSub1.add(astSub1v3)
|
||||
@ -156,12 +204,12 @@ private fun makeSt(): SymbolTable {
|
||||
block1.add(sub12)
|
||||
block1.add(StConstant("c1", DataType.UWORD, 12345.0, astConstant1))
|
||||
block1.add(StConstant("blockc", DataType.UWORD, 999.0, astConstant2))
|
||||
sub11.add(StStaticVariable("v1", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, astSub1v1))
|
||||
sub11.add(StStaticVariable("v2", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, astSub1v2))
|
||||
sub11.add(StStaticVariable("v1", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, PtVariable.Alignment.NONE, astSub1v1))
|
||||
sub11.add(StStaticVariable("v2", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, PtVariable.Alignment.NONE, astSub1v2))
|
||||
sub11.add(StMemVar("v3", DataType.FLOAT, 12345u, null, astSub1v3))
|
||||
sub11.add(StMemorySlab("slab1", 200u, 64u, astSub1v4))
|
||||
sub12.add(StStaticVariable("v1", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, astSub2v1))
|
||||
sub12.add(StStaticVariable("v2", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, astSub2v2))
|
||||
sub12.add(StStaticVariable("v1", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, PtVariable.Alignment.NONE, astSub2v1))
|
||||
sub12.add(StStaticVariable("v2", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, PtVariable.Alignment.NONE, astSub2v2))
|
||||
val block2 = StNode("block2", StNodeType.BLOCK, astBlock2)
|
||||
val sub21 = StNode("sub1", StNodeType.SUBROUTINE, astSub21)
|
||||
val sub22 = StNode("sub2", StNodeType.SUBROUTINE, astSub22)
|
||||
|
@ -46,8 +46,8 @@ class TestAsmGenSymbols: StringSpec({
|
||||
}
|
||||
|
||||
*/
|
||||
val varInSub = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.UWORD, ZeropageWish.DONTCARE, null, "localvar", emptyList(), NumericLiteral.optimalInteger(1234, Position.DUMMY), false, false, Position.DUMMY)
|
||||
val var2InSub = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.UWORD, ZeropageWish.DONTCARE, null, "tgt", emptyList(), null, false, false, Position.DUMMY)
|
||||
val varInSub = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.UWORD, ZeropageWish.DONTCARE, null, "localvar", emptyList(), NumericLiteral.optimalInteger(1234, Position.DUMMY), false, false, VarAlignment.NONE, Position.DUMMY)
|
||||
val var2InSub = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.UWORD, ZeropageWish.DONTCARE, null, "tgt", emptyList(), null, false, false, VarAlignment.NONE, Position.DUMMY)
|
||||
val labelInSub = Label("locallabel", Position.DUMMY)
|
||||
|
||||
val tgt = AssignTarget(IdentifierReference(listOf("tgt"), Position.DUMMY), null, null, null, false, Position.DUMMY)
|
||||
@ -63,7 +63,7 @@ class TestAsmGenSymbols: StringSpec({
|
||||
val statements = mutableListOf(varInSub, var2InSub, labelInSub, assign1, assign2, assign3, assign4, assign5, assign6, assign7, assign8)
|
||||
val subroutine = Subroutine("start", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, statements, Position.DUMMY)
|
||||
val labelInBlock = Label("label_outside", Position.DUMMY)
|
||||
val varInBlock = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.UWORD, ZeropageWish.DONTCARE, null, "var_outside", emptyList(),null, false, false, Position.DUMMY)
|
||||
val varInBlock = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.UWORD, ZeropageWish.DONTCARE, null, "var_outside", emptyList(),null, false, false, VarAlignment.NONE, Position.DUMMY)
|
||||
val block = Block("main", null, mutableListOf(labelInBlock, varInBlock, subroutine), false, Position.DUMMY)
|
||||
|
||||
val module = Module(mutableListOf(block), Position.DUMMY, SourceCode.Generated("test"))
|
||||
|
@ -157,6 +157,11 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
|
||||
output(" @zp")
|
||||
if(decl.sharedWithAsm)
|
||||
output(" @shared")
|
||||
when(decl.alignment) {
|
||||
VarAlignment.NONE -> {}
|
||||
VarAlignment.WORD -> output(" @alignword")
|
||||
VarAlignment.PAGE -> output(" @alignpage")
|
||||
}
|
||||
if(decl.names.size>1)
|
||||
output(decl.names.joinToString(prefix=" "))
|
||||
else
|
||||
|
@ -87,7 +87,7 @@ class Program(val name: String,
|
||||
val varName = "string_${internedStringsBlock.statements.size}"
|
||||
val decl = VarDecl(
|
||||
VarDeclType.VAR, VarDeclOrigin.STRINGLITERAL, DataType.STR, ZeropageWish.NOT_IN_ZEROPAGE, null, varName, emptyList(), string,
|
||||
sharedWithAsm = false, splitArray = false, position = string.position
|
||||
sharedWithAsm = false, splitArray = false, alignment = VarAlignment.NONE, position = string.position
|
||||
)
|
||||
internedStringsBlock.statements.add(decl)
|
||||
decl.linkParents(internedStringsBlock)
|
||||
|
@ -314,6 +314,8 @@ private fun SubroutineContext.toAst() : Subroutine {
|
||||
private fun Sub_paramsContext.toAst(): List<SubroutineParameter> =
|
||||
vardecl().map {
|
||||
val options = it.decloptions()
|
||||
if(options.ALIGNPAGE().isNotEmpty() || options.ALIGNWORD().isNotEmpty())
|
||||
throw SyntaxError("cannot use alignments on parameters", it.toPosition())
|
||||
val zp = getZpOption(options)
|
||||
var datatype = it.datatype()?.toAst() ?: DataType.UNDEFINED
|
||||
if(it.ARRAYSIG()!=null || it.arrayindex()!=null)
|
||||
@ -718,6 +720,10 @@ private fun VardeclContext.toAst(type: VarDeclType, value: Expression?): VarDecl
|
||||
val name = if(identifiers.size==1) identifiername.text else "<multiple>"
|
||||
val isArray = ARRAYSIG() != null || arrayindex() != null
|
||||
val split = options.SPLIT().isNotEmpty()
|
||||
val alignword = options.ALIGNWORD().isNotEmpty()
|
||||
val alignpage = options.ALIGNPAGE().isNotEmpty()
|
||||
if(alignpage && alignword)
|
||||
throw SyntaxError("choose a single alignment option", toPosition())
|
||||
val origDt = datatype()?.toAst() ?: DataType.UNDEFINED
|
||||
val dt = if(isArray) {
|
||||
val arrayDt = ElementToArrayTypes.getValue(origDt)
|
||||
@ -743,6 +749,7 @@ private fun VardeclContext.toAst(type: VarDeclType, value: Expression?): VarDecl
|
||||
value,
|
||||
options.SHARED().isNotEmpty(),
|
||||
split,
|
||||
if(alignword) VarAlignment.WORD else if(alignpage) VarAlignment.PAGE else VarAlignment.NONE,
|
||||
toPosition()
|
||||
)
|
||||
}
|
||||
|
@ -216,6 +216,11 @@ enum class VarDeclType {
|
||||
MEMORY
|
||||
}
|
||||
|
||||
enum class VarAlignment {
|
||||
NONE,
|
||||
WORD,
|
||||
PAGE
|
||||
}
|
||||
|
||||
class VarDecl(val type: VarDeclType,
|
||||
val origin: VarDeclOrigin,
|
||||
@ -227,6 +232,7 @@ class VarDecl(val type: VarDeclType,
|
||||
var value: Expression?,
|
||||
val sharedWithAsm: Boolean,
|
||||
val splitArray: Boolean,
|
||||
val alignment: VarAlignment,
|
||||
override val position: Position) : Statement(), INamedStatement {
|
||||
override lateinit var parent: Node
|
||||
var allowInitializeWithZero = true
|
||||
@ -239,6 +245,7 @@ class VarDecl(val type: VarDeclType,
|
||||
return VarDecl(VarDeclType.VAR, VarDeclOrigin.SUBROUTINEPARAM, dt, param.zp, null, param.name, emptyList(), null,
|
||||
sharedWithAsm = false,
|
||||
splitArray = false,
|
||||
alignment = VarAlignment.NONE,
|
||||
position = param.position
|
||||
)
|
||||
}
|
||||
@ -248,7 +255,7 @@ class VarDecl(val type: VarDeclType,
|
||||
val arrayDt = array.type.getOrElse { throw FatalAstException("unknown dt") }
|
||||
val arraysize = ArrayIndex.forArray(array)
|
||||
return VarDecl(VarDeclType.VAR, VarDeclOrigin.ARRAYLITERAL, arrayDt, ZeropageWish.NOT_IN_ZEROPAGE, arraysize, autoVarName, emptyList(), array,
|
||||
sharedWithAsm = false, splitArray = splitArray, position = array.position)
|
||||
sharedWithAsm = false, splitArray = splitArray, alignment = VarAlignment.NONE, position = array.position)
|
||||
}
|
||||
}
|
||||
|
||||
@ -285,7 +292,7 @@ class VarDecl(val type: VarDeclType,
|
||||
if(names.size>1)
|
||||
throw FatalAstException("should not copy a vardecl that still has multiple names")
|
||||
val copy = VarDecl(type, origin, datatype, zeropage, arraysize?.copy(), name, names, value?.copy(),
|
||||
sharedWithAsm, splitArray, position)
|
||||
sharedWithAsm, splitArray, alignment, position)
|
||||
copy.allowInitializeWithZero = this.allowInitializeWithZero
|
||||
return copy
|
||||
}
|
||||
@ -295,23 +302,24 @@ class VarDecl(val type: VarDeclType,
|
||||
this.arraysize?.referencesIdentifier(nameInSource)==true
|
||||
|
||||
fun desugarMultiDecl(): List<VarDecl> {
|
||||
require(alignment==VarAlignment.NONE)
|
||||
if(value==null || value?.isSimple==true) {
|
||||
// just copy the initialization value to a separata vardecl for each component
|
||||
// just copy the initialization value to a separate vardecl for each component
|
||||
return names.map {
|
||||
val copy = VarDecl(type, origin, datatype, zeropage, arraysize?.copy(), it, emptyList(), value?.copy(),
|
||||
sharedWithAsm, splitArray, position)
|
||||
sharedWithAsm, splitArray, alignment, position)
|
||||
copy.allowInitializeWithZero = this.allowInitializeWithZero
|
||||
copy
|
||||
}
|
||||
} else {
|
||||
// evaluate the value once in the vardecl for the first component, and set the other components to the first
|
||||
val first = VarDecl(type, origin, datatype, zeropage, arraysize?.copy(), names[0], emptyList(), value?.copy(),
|
||||
sharedWithAsm, splitArray, position)
|
||||
sharedWithAsm, splitArray, alignment, position)
|
||||
first.allowInitializeWithZero = this.allowInitializeWithZero
|
||||
val firstVar = firstVarAsValue(first)
|
||||
return listOf(first) + names.drop(1 ).map {
|
||||
val copy = VarDecl(type, origin, datatype, zeropage, arraysize?.copy(), it, emptyList(), firstVar.copy(),
|
||||
sharedWithAsm, splitArray, position)
|
||||
sharedWithAsm, splitArray, alignment, position)
|
||||
copy.allowInitializeWithZero = this.allowInitializeWithZero
|
||||
copy
|
||||
}
|
||||
|
@ -1,6 +1,13 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
- are uninitialized (bss) variables correctly @aligned now? (%option align docs say they're not, but maybe the new @align tag fixes this too)
|
||||
- aligned vars codegen: sort to do all word alignments first then the page alignments
|
||||
- what to use to align a label ? (%align $100 ?) to support aligned asmincludes for example.
|
||||
|
||||
- remove %option align_xxx ? (block level alignment, as we now have individual variable alignments)
|
||||
|
||||
|
||||
Improve register load order in subroutine call args assignments:
|
||||
in certain situations, the "wrong" order of evaluation of function call arguments is done which results
|
||||
in overwriting registers that already got their value, which requires a lot of stack juggling (especially on plain 6502 cpu!)
|
||||
@ -29,8 +36,6 @@ Future Things and Ideas
|
||||
- OR.... make all this more generic and use some %segment option to create real segments for 64tass?
|
||||
- (need separate step in codegen and IR to write the "golden" variables)
|
||||
|
||||
- do we need (array)variable alignment tag instead of block alignment tag? You want to align the data, not the code in the block?
|
||||
- ir: related to the one above: block alignment doesn't translate well to variables in the block (the actual stuff that needs to be aligned in memory) but: need variable alignment tag instead of block alignment tag, really
|
||||
- ir: fix call() return value handling
|
||||
- ir: proper code gen for the CALLI instruction and that it (optionally) returns a word value that needs to be assigned to a reg
|
||||
- ir: idea: (but LLVM IR simply keeps the variables, so not a good idea then?...): replace all scalar variables by an allocated register. Keep a table of the variable to register mapping (including the datatype)
|
||||
|
@ -1,23 +1,20 @@
|
||||
%import textio
|
||||
%option no_sysinit
|
||||
%zeropage basicsafe
|
||||
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
word @shared ww = 11111
|
||||
txt.print_ub(if ww==11111 111 else 222)
|
||||
txt.spc()
|
||||
txt.print_ub(if ww!=11111 111 else 222)
|
||||
txt.nl()
|
||||
|
||||
if ww==11111
|
||||
txt.print("one\n")
|
||||
else
|
||||
txt.print("two\n")
|
||||
if ww!=11111
|
||||
txt.print("one\n")
|
||||
else
|
||||
txt.print("two\n")
|
||||
str @alignword @shared name = "wordaligned"
|
||||
str @alignpage @shared @nozp name2 = "pagealigned"
|
||||
ubyte[20] @alignword @shared array1
|
||||
ubyte[20] @alignword @shared array2
|
||||
ubyte[20] @alignpage @shared array3
|
||||
ubyte[20] @alignpage @shared array4
|
||||
ubyte[] @alignword @shared array5 = [1,2,3,4]
|
||||
ubyte[] @alignword @shared array6 = [1,2,3,4]
|
||||
ubyte[] @alignpage @shared array7 = [1,2,3,4]
|
||||
ubyte[] @alignpage @shared array8 = [1,2,3,4]
|
||||
uword[20] @alignword @split @shared array9
|
||||
uword[] @alignword @split @shared array10 = [1111,2222,3333,4444]
|
||||
}
|
||||
}
|
||||
|
@ -157,19 +157,20 @@ class IRFileReader {
|
||||
return if(text.isBlank())
|
||||
emptyList()
|
||||
else {
|
||||
val varPattern = Regex("(.+?)(\\[.+?\\])? (.+) (zp=(.+))?")
|
||||
val varPattern = Regex("(.+?)(\\[.+?\\])? (.+) zp=(.+) align=(.+)")
|
||||
val variables = mutableListOf<StStaticVariable>()
|
||||
text.lineSequence().forEach { line ->
|
||||
// example: uword main.start.qq2 zp=DONTCARE
|
||||
val match = varPattern.matchEntire(line) ?: throw IRParseException("invalid VARIABLESNOINIT $line")
|
||||
val (type, arrayspec, name, _, zpwish) = match.destructured
|
||||
val (type, arrayspec, name, zpwish, alignment) = match.destructured
|
||||
if('.' !in name)
|
||||
throw IRParseException("unscoped varname: $name")
|
||||
val arraysize = if(arrayspec.isNotBlank()) arrayspec.substring(1, arrayspec.length-1).toInt() else null
|
||||
val dt = parseDatatype(type, arraysize!=null)
|
||||
val zp = if(zpwish.isBlank()) ZeropageWish.DONTCARE else ZeropageWish.valueOf(zpwish)
|
||||
val dummyNode = PtVariable(name, dt, zp, null, null, Position.DUMMY)
|
||||
val newVar = StStaticVariable(name, dt, null, null, arraysize, zp, dummyNode)
|
||||
val align = if(alignment.isBlank()) PtVariable.Alignment.NONE else PtVariable.Alignment.valueOf(alignment)
|
||||
val dummyNode = PtVariable(name, dt, zp, align, null, null, Position.DUMMY)
|
||||
val newVar = StStaticVariable(name, dt, null, null, arraysize, zp, align, dummyNode)
|
||||
variables.add(newVar)
|
||||
}
|
||||
return variables
|
||||
@ -186,19 +187,20 @@ class IRFileReader {
|
||||
return if(text.isBlank())
|
||||
emptyList()
|
||||
else {
|
||||
val varPattern = Regex("(.+?)(\\[.+?\\])? (.+)=(.*?) (zp=(.+))?")
|
||||
val varPattern = Regex("(.+?)(\\[.+?\\])? (.+)=(.*?) zp=(.+) align=(.+)")
|
||||
val variables = mutableListOf<StStaticVariable>()
|
||||
text.lineSequence().forEach { line ->
|
||||
// examples:
|
||||
// uword main.start.qq2=0 zp=REQUIRE_ZP
|
||||
// ubyte[6] main.start.namestring=105,114,109,101,110,0
|
||||
val match = varPattern.matchEntire(line) ?: throw IRParseException("invalid VARIABLE $line")
|
||||
val (type, arrayspec, name, value, _, zpwish) = match.destructured
|
||||
val (type, arrayspec, name, value, zpwish, alignment) = match.destructured
|
||||
if('.' !in name)
|
||||
throw IRParseException("unscoped varname: $name")
|
||||
val arraysize = if(arrayspec.isNotBlank()) arrayspec.substring(1, arrayspec.length-1).toInt() else null
|
||||
val dt: DataType = parseDatatype(type, arraysize!=null)
|
||||
val zp = if(zpwish.isBlank()) ZeropageWish.DONTCARE else ZeropageWish.valueOf(zpwish)
|
||||
val align = if(alignment.isBlank()) PtVariable.Alignment.NONE else PtVariable.Alignment.valueOf(alignment)
|
||||
var initNumeric: Double? = null
|
||||
var initArray: StArray? = null
|
||||
when(dt) {
|
||||
@ -220,11 +222,11 @@ class IRFileReader {
|
||||
DataType.STR -> throw IRParseException("STR should have been converted to byte array")
|
||||
else -> throw IRParseException("weird dt")
|
||||
}
|
||||
val dummyNode = PtVariable(name, dt, zp, null, null, Position.DUMMY)
|
||||
val dummyNode = PtVariable(name, dt, zp, align, null, null, Position.DUMMY)
|
||||
if(arraysize!=null && initArray!=null && initArray.all { it.number==0.0 }) {
|
||||
initArray=null // arrays with just zeros can be left uninitialized
|
||||
}
|
||||
val stVar = StStaticVariable(name, dt, null, initArray, arraysize, zp, dummyNode)
|
||||
val stVar = StStaticVariable(name, dt, null, initArray, arraysize, zp, align, dummyNode)
|
||||
if(initNumeric!=null)
|
||||
stVar.setOnetimeInitNumeric(initNumeric)
|
||||
variables.add(stVar)
|
||||
@ -253,7 +255,15 @@ class IRFileReader {
|
||||
val (type, arrayspec, name, address) = match.destructured
|
||||
val arraysize = if(arrayspec.isNotBlank()) arrayspec.substring(1, arrayspec.length-1).toInt() else null
|
||||
val dt: DataType = parseDatatype(type, arraysize!=null)
|
||||
val dummyNode = PtVariable(name, dt, ZeropageWish.NOT_IN_ZEROPAGE, null, null, Position.DUMMY)
|
||||
val dummyNode = PtVariable(
|
||||
name,
|
||||
dt,
|
||||
ZeropageWish.NOT_IN_ZEROPAGE,
|
||||
PtVariable.Alignment.NONE,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
)
|
||||
memvars.add(StMemVar(name, dt, parseIRValue(address).toUInt(), arraysize, dummyNode))
|
||||
}
|
||||
memvars
|
||||
@ -276,7 +286,15 @@ class IRFileReader {
|
||||
// example: "slabname 4096 0"
|
||||
val match = slabPattern.matchEntire(line) ?: throw IRParseException("invalid slab $line")
|
||||
val (name, size, align) = match.destructured
|
||||
val dummyNode = PtVariable(name, DataType.ARRAY_UB, ZeropageWish.NOT_IN_ZEROPAGE, null, null, Position.DUMMY)
|
||||
val dummyNode = PtVariable(
|
||||
name,
|
||||
DataType.ARRAY_UB,
|
||||
ZeropageWish.NOT_IN_ZEROPAGE,
|
||||
PtVariable.Alignment.NONE,
|
||||
null,
|
||||
null,
|
||||
Position.DUMMY
|
||||
)
|
||||
slabs.add(StMemorySlab(name, size.toUInt(), align.toUInt(), dummyNode))
|
||||
}
|
||||
slabs
|
||||
|
@ -210,10 +210,10 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
for (variable in variablesNoInit) {
|
||||
if(variable.dt in SplitWordArrayTypes) {
|
||||
// split into 2 ubyte arrays lsb+msb
|
||||
xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_lsb zp=${variable.zpwish}\n")
|
||||
xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_msb zp=${variable.zpwish}\n")
|
||||
xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_lsb zp=${variable.zpwish} align=${variable.align}\n")
|
||||
xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_msb zp=${variable.zpwish} align=${variable.align}\n")
|
||||
} else {
|
||||
xml.writeCharacters("${variable.typeString} ${variable.name} zp=${variable.zpwish}\n")
|
||||
xml.writeCharacters("${variable.typeString} ${variable.name} zp=${variable.zpwish} align=${variable.align}\n")
|
||||
}
|
||||
}
|
||||
|
||||
@ -243,8 +243,8 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
"@>${it.addressOfSymbol}"
|
||||
}
|
||||
}
|
||||
xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_lsb=$lsbValue zp=${variable.zpwish}\n")
|
||||
xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_msb=$msbValue zp=${variable.zpwish}\n")
|
||||
xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_lsb=$lsbValue zp=${variable.zpwish} align=${variable.align}\n")
|
||||
xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_msb=$msbValue zp=${variable.zpwish} align=${variable.align}\n")
|
||||
} else {
|
||||
val value: String = when(variable.dt) {
|
||||
DataType.BOOL -> variable.onetimeInitializationNumericValue?.toInt()?.toString() ?: ""
|
||||
@ -279,7 +279,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
}
|
||||
else -> throw InternalCompilerException("weird dt")
|
||||
}
|
||||
xml.writeCharacters("${variable.typeString} ${variable.name}=$value zp=${variable.zpwish}\n")
|
||||
xml.writeCharacters("${variable.typeString} ${variable.name}=$value zp=${variable.zpwish} align=${variable.align}\n")
|
||||
}
|
||||
}
|
||||
xml.writeEndElement()
|
||||
|
@ -1,10 +1,8 @@
|
||||
package prog8.intermediate
|
||||
|
||||
import prog8.code.*
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.Encoding
|
||||
import prog8.code.core.ZeropageWish
|
||||
import prog8.code.core.internedStringsModuleName
|
||||
import prog8.code.ast.PtVariable
|
||||
import prog8.code.core.*
|
||||
|
||||
|
||||
// In the Intermediate Representation, all nesting has been removed.
|
||||
@ -86,7 +84,8 @@ class IRSymbolTable {
|
||||
variable.initializationStringValue,
|
||||
fixupAddressOfInArray(variable.initializationArrayValue),
|
||||
variable.length,
|
||||
variable.zpwish
|
||||
variable.zpwish,
|
||||
IRStStaticVariable.mapAlign(variable.align)
|
||||
)
|
||||
}
|
||||
table[scopedName] = varToadd
|
||||
@ -196,7 +195,8 @@ class IRStStaticVariable(name: String,
|
||||
val onetimeInitializationStringValue: IRStString?,
|
||||
val onetimeInitializationArrayValue: IRStArray?,
|
||||
val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
|
||||
val zpwish: ZeropageWish // used in the variable allocator
|
||||
val zpwish: ZeropageWish, // used in the variable allocator
|
||||
val align: Alignment,
|
||||
) : IRStNode(name, IRStNodeType.STATICVAR) {
|
||||
companion object {
|
||||
fun from(variable: StStaticVariable): IRStStaticVariable {
|
||||
@ -206,7 +206,29 @@ class IRStStaticVariable(name: String,
|
||||
variable.initializationStringValue,
|
||||
variable.initializationArrayValue?.map { IRStArrayElement.from(it) },
|
||||
variable.length,
|
||||
variable.zpwish)
|
||||
variable.zpwish,
|
||||
mapAlign(variable.align))
|
||||
}
|
||||
|
||||
fun mapAlign(ptAlign: PtVariable.Alignment): Alignment {
|
||||
return when(ptAlign) {
|
||||
PtVariable.Alignment.NONE -> Alignment.NONE
|
||||
PtVariable.Alignment.WORD -> Alignment.WORD
|
||||
PtVariable.Alignment.PAGE -> Alignment.PAGE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class Alignment {
|
||||
NONE,
|
||||
WORD,
|
||||
PAGE
|
||||
}
|
||||
|
||||
init {
|
||||
if(align!=Alignment.NONE) {
|
||||
require(dt == DataType.STR || dt in ArrayDatatypes)
|
||||
require(zpwish != ZeropageWish.REQUIRE_ZEROPAGE && zpwish != ZeropageWish.PREFER_ZEROPAGE)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,11 +51,11 @@ loadAddress=$0000
|
||||
</ASMSYMBOLS>
|
||||
|
||||
<VARIABLESNOINIT>
|
||||
uword sys.bssvar zp=DONTCARE
|
||||
uword sys.bssvar zp=DONTCARE align=NONE
|
||||
</VARIABLESNOINIT>
|
||||
<VARIABLESWITHINIT>
|
||||
uword sys.wait.jiffies=10 zp=DONTCARE
|
||||
ubyte[3] sys.emptystring=0,0,0 zp=DONTCARE
|
||||
uword sys.wait.jiffies=10 zp=DONTCARE align=NONE
|
||||
ubyte[3] sys.emptystring=0,0,0 zp=DONTCARE align=NONE
|
||||
</VARIABLESWITHINIT>
|
||||
|
||||
<MEMORYMAPPEDVARIABLES>
|
||||
|
@ -63,6 +63,10 @@ SHARED : '@shared' ;
|
||||
|
||||
SPLIT: '@split' ;
|
||||
|
||||
ALIGNWORD: '@alignword' ;
|
||||
|
||||
ALIGNPAGE: '@alignpage' ;
|
||||
|
||||
ARRAYSIG : '[' [ \t]* ']' ;
|
||||
|
||||
NOT_IN: 'not' [ \t]+ 'in' [ \t] ;
|
||||
@ -143,7 +147,7 @@ directivearg : stringliteral | identifier | integerliteral ;
|
||||
|
||||
vardecl: datatype (arrayindex | ARRAYSIG)? decloptions identifier (',' identifier)* ;
|
||||
|
||||
decloptions: (SHARED | ZEROPAGE | ZEROPAGEREQUIRE | ZEROPAGENOT | SPLIT)* ;
|
||||
decloptions: (SHARED | ZEROPAGE | ZEROPAGEREQUIRE | ZEROPAGENOT | SPLIT | ALIGNWORD | ALIGNPAGE)* ;
|
||||
|
||||
varinitializer : vardecl '=' expression ;
|
||||
|
||||
|
@ -12,8 +12,8 @@
|
||||
<option name="HAS_STRING_ESCAPES" value="true" />
|
||||
</options>
|
||||
<keywords keywords="&;->;@;and;as;asmsub;break;clobbers;continue;do;downto;else;false;for;goto;if;if_cc;if_cs;if_eq;if_mi;if_ne;if_neg;if_nz;if_pl;if_pos;if_vc;if_vs;if_z;in;inline;not;or;repeat;return;romsub;step;sub;to;true;unroll;until;when;while;xor;~" ignore_case="false" />
|
||||
<keywords2 keywords="%address;%asm;%asmbinary;%asminclude;%breakpoint;%encoding;%import;%ir;%launcher;%option;%output;%zeropage;%zpallowed;%zpreserved;atascii:;cp437:;default:;iso16:;iso5:;iso:;kata:;petscii:;sc:" />
|
||||
<keywords3 keywords="@nozp;@requirezp;@shared;@split;@zp;bool;byte;const;float;str;ubyte;uword;void;word" />
|
||||
<keywords2 keywords="%address;%asm;%asmbinary;%asminclude;%breakpoint;%encoding;%import;%ir;%launcher;%option;%output;%zeropage;%zpallowed;%zpreserved;@alignpage;@alignword;@nozp;@requirezp;@shared;@split;@zp;atascii:;cp437:;default:;iso16:;iso5:;iso:;kata:;petscii:;sc:" />
|
||||
<keywords3 keywords="bool;byte;const;float;str;ubyte;uword;void;word" />
|
||||
<keywords4 keywords="abs;call;callfar;callfar2;clamp;cmp;defer;divmod;len;lsb;max;memory;min;mkword;msb;peek;peekf;peekw;poke;pokef;pokew;rol;rol2;ror;ror2;rrestore;rrestorex;rsave;rsavex;setlsb;setmsb;sgn;sizeof;sqrt" />
|
||||
</highlighting>
|
||||
<extensionMap>
|
||||
|
@ -43,7 +43,7 @@ syn region prog8ArrayType matchgroup=prog8Type
|
||||
\ start="\<\%(u\?byte\|u\?word\|float\|str\|bool\)\[" end="\]"
|
||||
\ transparent
|
||||
syn keyword prog8StorageClass const
|
||||
syn match prog8StorageClass "\(^\|\s\)\(@zp\|@shared\|@split\|@nozp\|@requirezp\)\>"
|
||||
syn match prog8StorageClass "\(^\|\s\)\(@zp\|@shared\|@split\|@nozp\|@requirezp\|@alignword\|@alignpage\)\>"
|
||||
|
||||
syn region prog8Block start="{" end="}" transparent
|
||||
syn region prog8Expression start="(" end=")" transparent
|
||||
|
Loading…
x
Reference in New Issue
Block a user