enforce variable init values are only strings or arrays

This commit is contained in:
Irmen de Jong 2025-01-20 01:25:17 +01:00
parent 0c882836d9
commit 7a13f57ab0
6 changed files with 52 additions and 27 deletions

View File

@ -149,6 +149,18 @@ class PtVariable(
position: Position
) : PtNamedNode(name, position), IPtVariable {
init {
if(value!=null) {
require(value is PtArray || value is PtString) { "variable initializer value must only be array or string" }
// NOTE: the 6502 code generator expects numerical variables to not have an initialization value,
// because that is done via assignment statements. There are no "inline" variables with a given value.
// All variables are put into zeropage or into the BSS section and initialized afterwards during program
// startup or at the start of the subroutine.
// The IR codegen however is different it has a special section <VARIABLESWITHINIT> for all variables
// that have a non-zero initialization value, regardless of the datatype. It removes the initialization
// assignment and puts the value back into the variable (but only in the symboltable).
}
value?.let {it.parent=this}
}
}

View File

@ -674,28 +674,34 @@ internal class ProgramAndVarsGen(
}
private fun staticVariable2asm(variable: StStaticVariable) {
val initialValue: Number =
if(variable.initializationNumericValue!=null) {
if(variable.dt.isFloat)
variable.initializationNumericValue!!
else
variable.initializationNumericValue!!.toInt()
} else 0
if(!variable.dt.isArray && !variable.dt.isString) {
throw AssemblyError("static variables with an initialization value can only be an array or a string, not ${variable.dt} (${variable.name} ${variable.astNode?.position}")
// because numeric variables are in the BSS section and get initialized via assignment statements
}
// val initialValue: Number =
// if(variable.initializationNumericValue!=null) {
// if(variable.dt.isFloat)
// variable.initializationNumericValue!!
// else
// variable.initializationNumericValue!!.toInt()
// } else 0
//
val dt=variable.dt
when {
dt.isBool || dt.isUnsignedByte -> asmgen.out("${variable.name}\t.byte ${initialValue.toHex()}")
dt.isSignedByte -> asmgen.out("${variable.name}\t.char $initialValue")
dt.isUnsignedWord -> asmgen.out("${variable.name}\t.word ${initialValue.toHex()}")
dt.isSignedWord -> asmgen.out("${variable.name}\t.sint $initialValue")
dt.isFloat -> {
if(initialValue==0) {
asmgen.out("${variable.name}\t.byte 0,0,0,0,0 ; float")
} else {
val floatFill = compTarget.getFloatAsmBytes(initialValue)
asmgen.out("${variable.name}\t.byte $floatFill ; float $initialValue")
}
}
// dt.isBool || dt.isUnsignedByte -> asmgen.out("${variable.name}\t.byte ${initialValue.toHex()}")
// dt.isSignedByte -> asmgen.out("${variable.name}\t.char $initialValue")
// dt.isUnsignedWord -> asmgen.out("${variable.name}\t.word ${initialValue.toHex()}")
// dt.isSignedWord -> asmgen.out("${variable.name}\t.sint $initialValue")
// dt.isFloat -> {
// if(initialValue==0) {
// asmgen.out("${variable.name}\t.byte 0,0,0,0,0 ; float")
// } else {
// val floatFill = compTarget.getFloatAsmBytes(initialValue)
// asmgen.out("${variable.name}\t.byte $floatFill ; float $initialValue")
// }
// }
dt.isString -> {
throw AssemblyError("all string vars should have been interned into prog")
}

View File

@ -54,7 +54,7 @@ class TestCodegen: FunSpec({
DataType.forDt(BaseDataType.UBYTE),
ZeropageWish.DONTCARE,
0u,
PtNumber(BaseDataType.UBYTE, 0.0, Position.DUMMY),
null,
null,
Position.DUMMY
))
@ -81,7 +81,7 @@ class TestCodegen: FunSpec({
DataType.forDt(BaseDataType.WORD),
ZeropageWish.DONTCARE,
0u,
PtNumber(BaseDataType.WORD, 1.0, Position.DUMMY),
null,
null,
Position.DUMMY
))

View File

@ -51,7 +51,7 @@ class TestVmCodeGen: FunSpec({
DataType.forDt(BaseDataType.UBYTE),
ZeropageWish.DONTCARE,
0u,
PtNumber(BaseDataType.UBYTE, 0.0, Position.DUMMY),
null,
null,
Position.DUMMY
))
@ -78,7 +78,7 @@ class TestVmCodeGen: FunSpec({
DataType.forDt(BaseDataType.WORD),
ZeropageWish.DONTCARE,
0u,
PtNumber(BaseDataType.WORD, 1.0, Position.DUMMY),
null,
null,
Position.DUMMY
))

View File

@ -19,6 +19,7 @@ import prog8.code.source.SourceCode
import prog8.code.target.C64Target
import prog8.code.target.VMTarget
import prog8.codegen.cpu6502.AsmGen6502Internal
import prog8.compiler.astprocessing.AstChecker
import prog8.compiler.astprocessing.SimplifiedAstMaker
import prog8tests.helpers.*
@ -31,7 +32,7 @@ class TestAsmGenSymbols: StringSpec({
uword var_outside
sub start () {
uword localvar = 1234
uword localvar
uword tgt
locallabel:
@ -48,7 +49,7 @@ class TestAsmGenSymbols: StringSpec({
*/
val varInSub = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.forDt(BaseDataType.UWORD), ZeropageWish.DONTCARE,
SplitWish.DONTCARE, null, "localvar", emptyList(), NumericLiteral.optimalInteger(1234, Position.DUMMY), false, 0u, false, Position.DUMMY)
SplitWish.DONTCARE, null, "localvar", emptyList(), null, false, 0u, false, Position.DUMMY)
val var2InSub = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.forDt(BaseDataType.UWORD), ZeropageWish.DONTCARE,
SplitWish.DONTCARE, null, "tgt", emptyList(), null, false, 0u, false, Position.DUMMY)
val labelInSub = Label("locallabel", Position.DUMMY)
@ -79,6 +80,9 @@ class TestAsmGenSymbols: StringSpec({
fun createTestAsmGen6502(program: Program): AsmGen6502Internal {
val errors = ErrorReporterForTests()
val options = CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, true, C64Target(), 999u, 0xffffu)
val astchecker = AstChecker(program, errors, options)
astchecker.visit(program)
errors.report()
val ptProgram = SimplifiedAstMaker(program, errors).transform()
val st = SymbolTableMaker(ptProgram, options).make()
return AsmGen6502Internal(ptProgram, st, options, errors, 0)

View File

@ -5,12 +5,15 @@
main {
ubyte @nozp @shared staticvar=51
sub start() {
ubyte x = math.rnd()
ubyte a,b = multi1()
ubyte c,d = 99
ubyte c,d = multi2()
x++
x=irmen
txt.print_ub(a)
txt.spc()
txt.print_ub(b)